[WebAR和WebVR學習之路]從Three.js開始掌握WebAR和WebVR的開發

《為什么要學習Three.js》

Three.js是JavaScript編寫的WebGL第三方庫。提供了非常多的3D顯示功能。
Three.js對WebGL進行了封裝,省去了很多WebGL底層的代碼,使得編寫Web的3D程序十分方便。
現如今,WebAR和WebVR逐漸進入人們的視野。由于Web不需要下載程序的簡便性使得更多的人傾向于在Web頁面開發VR/AR應用(快速捕捉客戶)。因此,學習WebGL的開發使得一個VR/AR開發者更具有競爭力。
今天,我們將簡單的從幾個方面來講解Three.js,已達到快速入門的目的。

知識需求:

簡單的Web前端知識(HTML、CSS和JS)
簡單的OpenGL的知識(包括OpenGL ES和WebGL)

《一個簡單的Three.js頁面框架》

由于Three.js需要一個簡單的web服務器來測試,所以我們需要搭建一個簡單的HTTP服務器。
對于大多數人來說,搭建web服務器是一個十分簡單的事情,但對一些新手我們可以使用集成環境來快速搭建web服務器來測試(像是eclipse中集成的tomcat服務器一樣)。
在這里我推薦使用Web Storm軟件,搞前端開發的程序員對此軟件并不陌生,其擴展性高使用十分便捷。
下面我們開始搭建一個簡單的Three.js頁面的框架。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example 01.01 - Bacis skeleton</title>
    <script type="text/javascript"
            src="../libs/three.js"></script>
    <script type="text/javascript"
            src="../libs/jquery-3.1.1.js"></script>
    <style>
        body{
            /*設置頁面的樣式*/
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!—用于顯示WebGL輸出的div-->
<div id="WebGL-output">

</div>
<!—以下為Three.js的具體代碼-->
<script type="text/javascript">
    //在加載過后自動運行的函數
    $(function () {
        //在此輸入Three.js代碼
    });
</script>

</body>
</html>

《渲染并創建一個三維對象》

在上文的注釋 在此輸入Three.js代碼的地方刪除該注釋,輸入以下代碼。
運行測試一下,效果如圖。



后面我們將會講解這一段簡單的代碼。

$(function () {
        var scene=new THREE.Scene();

        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

        var renderer=new THREE.WebGLRenderer();
        renderer.setClearColor(0xEEEEEE,0.5);
        renderer.setSize(window.innerWidth,window.innerHeight);

        var axes=new THREE.AxisHelper(20);
        scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
        var planeMaterial = new THREE.MeshBasicMaterial({color:0xcccccc});
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);

        plane.rotation.x=-0.5*Math.PI;
        plane.position.x=15;plane.position.y=0;plane.position.z=0;

        scene.add(plane);

        var cubeGeometry = new THREE.CubeGeometry(4,4,4);
        var cubeMaterial = new THREE.MeshBasicMaterial({color:0xff0000,wireframe:true});
        var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);

        cube.position.x=-4;cube.position.y=3;cube.position.z=0;

        scene.add(cube);

        var sphereGeometry=new THREE.SphereGeometry(4,20,20);
        var sphereMaterial=new THREE.MeshBasicMaterial({color:0x7777ff,wireframe:true});
        var sphere=new THREE.Mesh(sphereGeometry,sphereMaterial);

        sphere.position.x=20;sphere.position.y=4;sphere.position.z=2;

        scene.add(sphere);

        camera.position.x=-30;camera.position.y=40;camera.position.z=30;
        camera.lookAt(scene.position);
        $("#WebGL-output").append(renderer.domElement);
        renderer.render(scene,camera);
    });
var scene=new THREE.Scene();

var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

var renderer=new THREE.WebGLRenderer();

在本章的一開始,定義了scene、camera和renderer(場景、相機和渲染器)。
scene是一個容器,保存并跟蹤想要渲染的物體,在后面創建了幾何體之后(如立方體和球體等)會添加到scene變量中。
camera變量定義了在渲染好的scene里看到什么。
最后是renderer對象,renderer對象負責計算指定的相機角度下的瀏覽器中scene的呈現樣子。
在以上實例中,我們創建了一個WebGLRenderer對象,使用計算機的圖形卡來渲染場景。

renderer.setClearColor(0xEEEEEE,0.5);
renderer.setSize(window.innerWidth,window.innerHeight);

接下來通過renderer的setClearColor函數來設置renderer的背景色為接近白色的顏色(0xEEEEEE),并通過setSize()函數來告訴renderer將scene渲染為多大的尺寸。
通過以上的代碼,我們有了一個空白的scene、一個renderer和一個camera。
下面我們來創建一個坐標軸對象,并添加到場景中。

var axes=new THREE.AxisHelper(20);
scene.add(axes);

通過THREE的AxisHelper函數我們創建了一個長度為20的坐標軸,并通過scene的add函數將其添加到了場景中。
下面我們再創建一個平面(plane)并修改其旋轉和位置。

var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
var planeMaterial = new THREE.MeshBasicMaterial({color:0xcccccc});
var plane=new THREE.Mesh(planeGeometry,planeMaterial);

plane.rotation.x=-0.5*Math.PI;
plane.position.x=15;plane.position.y=0;plane.position.z=0;

scene.add(plane);

首先通過THREE.PlaneGeometry(60,20)來定義該平面的尺寸,在該章節中,我們將平面的尺寸設置為寬60,高20。在創建完幾何體之后我們還需要給plane指定材質,在這里我們使用MeshBasicMaterial()方法來創建一個基本的材質,其顏色為0xcccccc。接下來將兩個對象合并到一個名為plane的Mesh(網格)對象中。在將其放入場景之前還要修改其旋轉和位置,先將其繞著x軸旋轉90度,然后修改其position的x、y和z分量,最后將其加入scene中。
最后

camera.position.x=-30;camera.position.y=40;camera.position.z=30;
camera.lookAt(scene.position);
$("#WebGL-output").append(renderer.domElement);
renderer.render(scene,camera);

我們通過修改camera的位置和使用LookAt函數(對Unity和OpenGL熟悉的應該對此也不陌生)來修改camera的位置和朝向。在這里,我們的lookAt函數指向scene的中心。
最后,我們應該將renderer的輸出掛接到HTML頁面框架中的<div>元素中;在這里我們使用jQuery來選擇正確的輸出元素,并告訴 renderer用我們提供的相機來渲染scene。

《添加材質、燈光和陰影》

由于線框的渲染模式不會對燈光產生反應,因此我們需要修改cube和sphere的材質。
先將上一節的例子復制,并改名。
在創建完renderer之后,我們開始創建燈光:

var spotLight=new THREE.SpotLight(0xffffff);
spotLight.position.set(-40,60,-10);
scene.add(spotLight);

上述通過SpotLight()方法來創建的一個探照燈光源,并通過spotLight對象的position.set(-40,60,-10)位置來照射我們的場景。
修改Material的類型為Lambert材質:

var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
var planeMaterial = new THREE.MeshLambertMaterial({color:0xffffff});

同時修改cube和sphere的材質類型
同理,我們也可以使用Phong光照模型來產生光照效果,MeshPhongMaterial();
最后,我們開始添加陰影。因為陰影的計算比較消耗計算資源,因此默認情況下Three.js不會渲染陰影。
我們在renderer下面加入

renderer.shadowMapEnabled=true;

在plane創建完成之后加入

plane.receiveShadow=true;
cube.castShadow=true;
sphere.castShadow=true;

spotLight.castShadow=true;

來使其接收陰影。
最后產生的效果如下圖:


該節的整體代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example 01.03 - Light and shadow</title>
    <script type="text/javascript"
            src="../libs/three.js"></script>
    <script type="text/javascript"
            src="../libs/jquery-3.1.1.js"></script>
    <style>
        body{
            /*set margin to 0 and overflow to hidden,to use the complete page*/

            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!--Div which will hold the Output-->
<div id="WebGL-output">

</div>
<!--Javascript code that runs out Three.js examples-->
<script type="text/javascript">
    //once everything is loaded, we run out Three.js stuff.
    $(function () {
        var scene=new THREE.Scene();

        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

        var renderer=new THREE.WebGLRenderer();

        renderer.setClearColor(0xEEEEEE,0.5);
        renderer.setSize(window.innerWidth,window.innerHeight);
        renderer.shadowMapType=THREE.PCFSoftShadowMap;
        renderer.shadowMapEnabled=true;

        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);

        spotLight.castShadow=true;
        spotLight.shadowMapHeight=4096;
        spotLight.shadowMapWidth=4096;
        scene.add(spotLight);

        var ambientLight=new THREE.AmbientLight(0xffffff);
        ambientLight.intensity=0.3;
        scene.add(ambientLight);

        var axes=new THREE.AxisHelper(20);
        scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
        var planeMaterial = new THREE.MeshPhongMaterial({color:0xffffff});
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);

        plane.rotation.x=-0.5*Math.PI;
        plane.position.x=15;plane.position.y=0;plane.position.z=0;

        plane.receiveShadow=true;

        scene.add(plane);

        var cubeGeometry = new THREE.CubeGeometry(4,4,4);
        var cubeMaterial = new THREE.MeshPhongMaterial({color:0xff0000});
        var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);

        cube.position.x=-4;cube.position.y=3;cube.position.z=0;

        cube.castShadow=true;

        scene.add(cube);

        var sphereGeometry=new THREE.SphereGeometry(4,20,20);
        var sphereMaterial=new THREE.MeshPhongMaterial({color:0x7777ff});
        var sphere=new THREE.Mesh(sphereGeometry,sphereMaterial);

        sphere.position.x=20;sphere.position.y=4;sphere.position.z=2;

        sphere.castShadow=true;

        scene.add(sphere);

        camera.position.x=-30;camera.position.y=40;camera.position.z=30;
        camera.lookAt(scene.position);
        $("#WebGL-output").append(renderer.domElement);
        renderer.render(scene,camera);
    });
</script>

</body>
</html>

《簡單的動畫和幀率監控》

在Three.js中,使用requestAnimationFrame()方法可以指定一個渲染函數,按照瀏覽器的時間間隔(通常是每秒60幀)來調用該函數。在指定的渲染函數中,可以對場景中的物體的位置 、旋轉和縮放等進行更新。
那么在進行動畫之前,我們先來引入幀率檢測的代碼。首先在HTML頁面引入stats.js這個庫。

<script type="text/javascript" src="../libs/stats.js"></script>

然后再添加一個用于展示統計信息的div

<div id="Stats-output"></div>

最后編寫初始化stats的代碼:

function initStats() {
    var stats=new Stats();
    stats.setMode(0);
    stats.domElement.style.position='absolute';
    stats.domElement.style.left='0px';
    stats.domElement.style.top='0px';
    document.getElementById("Stats-output").appendChild(stats.domElement);

     return stats;
}

并在主體代碼的開頭引入stats對象

var stats=initStats();

下面,我們來編寫每一幀需要調用的渲染函數

function renderScene() {
    stats.update();

    //animate cube
    cube.rotation.x+=0.02;cube.rotation.y+=0.02;cube.rotation.z+=0.02;

    //animate sphere
    step+=0.04;
    sphere.position.x=20+(10*Math.cos(step));
    sphere.position.y=2+(10*Math.abs(Math.sin(step)));

    requestAnimationFrame(renderScene);
    renderer.render(scene,camera);
}

該渲染函數在每次調用會更新stats信息,更新方塊的旋轉和球體的運動位置。最后通過requestAnimationFrame函數來指定renderScene函數為指定時間間隔渲染的函數。最后調用renderer渲染器的render函數重新渲染。
最后我們在代碼的主體加入一次對renderScene函數的調用。
本節所有代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example 01.04 - Simple Animation</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/jquery-3.1.1.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <style>
        body{
            /*set margin to 0 and overflow to hidden,to use the complete page*/
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output"></div>
<!--Div which will hold the Output-->
<div id="WebGL-output"></div>

<!--Javascript code that runs out Three.js examples-->
<script type="text/javascript">
    //once everything is loaded, we run out Three.js stuff.
    function init() {
        var scene=new THREE.Scene();

        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

        var renderer=new THREE.WebGLRenderer();

        var stats=initStats();

        renderer.setClearColor(0xEEEEEE,0.5);
        renderer.setSize(window.innerWidth,window.innerHeight);
        renderer.shadowMapType=THREE.PCFSoftShadowMap;
        renderer.shadowMapEnabled=true;

        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);

        spotLight.castShadow=true;
        spotLight.shadowMapHeight=4096;
        spotLight.shadowMapWidth=4096;
        scene.add(spotLight);

        var ambientLight=new THREE.AmbientLight(0xffffff);
        ambientLight.intensity=0.3;
        scene.add(ambientLight);

        var axes=new THREE.AxisHelper(20);
        scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
        var planeMaterial = new THREE.MeshPhongMaterial({color:0xffffff});
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);

        plane.rotation.x=-0.5*Math.PI;
        plane.position.x=15;plane.position.y=0;plane.position.z=0;

        plane.receiveShadow=true;

        scene.add(plane);

        var cubeGeometry = new THREE.CubeGeometry(4,4,4);
        var cubeMaterial = new THREE.MeshPhongMaterial({color:0xff0000});
        var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);

        cube.position.x=-4;cube.position.y=3;cube.position.z=0;

        cube.castShadow=true;

        scene.add(cube);

        var sphereGeometry=new THREE.SphereGeometry(4,20,20);
        var sphereMaterial=new THREE.MeshPhongMaterial({color:0x7777ff});
        var sphere=new THREE.Mesh(sphereGeometry,sphereMaterial);

        sphere.position.x=20;sphere.position.y=4;sphere.position.z=2;

        sphere.castShadow=true;

        scene.add(sphere);

        camera.position.x=-30;camera.position.y=40;camera.position.z=30;
        camera.lookAt(scene.position);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        renderer.render(scene,camera);

        renderScene();


        var step=0;
        function renderScene() {
            stats.update();

            //animate cube
            cube.rotation.x+=0.02;cube.rotation.y+=0.02;cube.rotation.z+=0.02;

            //animate sphere
            step+=0.04;
            sphere.position.x=20+(10*Math.cos(step));
            sphere.position.y=2+(10*Math.abs(Math.sin(step)));

            requestAnimationFrame(renderScene);
            renderer.render(scene,camera);
        }

        function initStats() {
            var stats=new Stats();
            stats.setMode(0);
            stats.domElement.style.position='absolute';
            stats.domElement.style.left='0px';
            stats.domElement.style.top='0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);

             return stats;
        }
    }
    window.onload=init;
</script>

</body>
</html>

《使用dat.GUI來編寫一個簡單的UI》

dat.GUI為Google公司的一些人創建的庫,該庫的文檔(http://code.google.com/p/dat-gui/ 需翻墻)通過這個庫,我們可以實現用slider滑動條來控制立方體的自旋速度和球體的彈跳速度。
首先需要引用dat.GUI.js庫

<script type="text/javascript" src="../libs/dat.gui.js"></script>

接下來添加一個JavaScript對象:

var controls = new function () {
    this.rotationSpeed = 0.02;
    this.bouncingSpeed = 0.03;
};

然后創建一個gui對象并添加控制器:

var gui=new dat.GUI();
gui.add(controls,'rotationSpeed',0,0.5);
gui.add(controls,'bouncingSpeed',0,0.5);

注意,這些代碼需要寫在渲染函數之前。
接下來修改上一節的renderScene函數中的方塊和球體的動畫控制代碼:

function renderScene() {
    stats.update();

    //animate cube
    cube.rotation.x+=controls.rotationSpeed;cube.rotation.y+=controls.rotationSpeed;cube.rotation.z+=controls.rotationSpeed;

    //animate sphere
    step+=controls.bouncingSpeed;
    sphere.position.x=20+(10*Math.cos(step));
    sphere.position.y=2+(10*Math.abs(Math.sin(step)));

    requestAnimationFrame(renderScene);
    renderer.render(scene,camera);
}

編寫完成之后運行效果如下:


本節的完整代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example 01.05 - dat.GUI UserInterface</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/jquery-3.1.1.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body{
            /*set margin to 0 and overflow to hidden,to use the complete page*/
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output"></div>
<!--Div which will hold the Output-->
<div id="WebGL-output"></div>

<!--Javascript code that runs out Three.js examples-->
<script type="text/javascript">
    //once everything is loaded, we run out Three.js stuff.
    function init() {
        var scene=new THREE.Scene();

        var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

        var renderer=new THREE.WebGLRenderer();

        var stats=initStats();

        renderer.setClearColor(0xEEEEEE,0.5);
        renderer.setSize(window.innerWidth,window.innerHeight);
        renderer.shadowMapType=THREE.PCFSoftShadowMap;
        renderer.shadowMapEnabled=true;

        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);

        spotLight.castShadow=true;
        spotLight.shadowMapHeight=4096;
        spotLight.shadowMapWidth=4096;
        scene.add(spotLight);

        var ambientLight=new THREE.AmbientLight(0xffffff);
        ambientLight.intensity=0.3;
        scene.add(ambientLight);

        var axes=new THREE.AxisHelper(20);
        scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
        var planeMaterial = new THREE.MeshPhongMaterial({color:0xffffff});
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);

        plane.rotation.x=-0.5*Math.PI;
        plane.position.x=15;plane.position.y=0;plane.position.z=0;

        plane.receiveShadow=true;

        scene.add(plane);

        var cubeGeometry = new THREE.CubeGeometry(4,4,4);
        var cubeMaterial = new THREE.MeshPhongMaterial({color:0xff0000});
        var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);

        cube.position.x=-4;cube.position.y=3;cube.position.z=0;

        cube.castShadow=true;

        scene.add(cube);

        var sphereGeometry=new THREE.SphereGeometry(4,20,20);
        var sphereMaterial=new THREE.MeshPhongMaterial({color:0x7777ff});
        var sphere=new THREE.Mesh(sphereGeometry,sphereMaterial);

        sphere.position.x=20;sphere.position.y=4;sphere.position.z=2;

        sphere.castShadow=true;

        scene.add(sphere);

        camera.position.x=-30;camera.position.y=40;camera.position.z=30;
        camera.lookAt(scene.position);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        renderer.render(scene,camera);

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.bouncingSpeed = 0.03;
        };

        var gui=new dat.GUI();
        gui.add(controls,'rotationSpeed',0,0.5);
        gui.add(controls,'bouncingSpeed',0,0.5);

        //this renderScene() function should be called after every
        renderScene();

        var step=0;
        function renderScene() {
            stats.update();

            //animate cube
            cube.rotation.x+=controls.rotationSpeed;cube.rotation.y+=controls.rotationSpeed;cube.rotation.z+=controls.rotationSpeed;

            //animate sphere
            step+=controls.bouncingSpeed;
            sphere.position.x=20+(10*Math.cos(step));
            sphere.position.y=2+(10*Math.abs(Math.sin(step)));

            requestAnimationFrame(renderScene);
            renderer.render(scene,camera);
        }

        function initStats() {
            var stats=new Stats();
            stats.setMode(0);
            stats.domElement.style.position='absolute';
            stats.domElement.style.left='0px';
            stats.domElement.style.top='0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);

             return stats;
        }
    }
    window.onload=init;
</script>

</body>
</html>

《動態改變渲染大小》

在使用Three.js的時候,我們還可以根據窗口大小的改變來調整渲染的大小。
在這里我們需要添加一個onSizeChanged函數

function onSizeChanged() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

編寫完該函數之后我們需要對窗口大小改變的事件增加監聽:

window.addEventListener('resize', onSizeChanged, false);

注意,這里要把renderer、camera等變量定義成作用域更廣的變量,具體參見詳細代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example 01.06 - Resize</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/jquery-3.1.1.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body{
            /*set margin to 0 and overflow to hidden,to use the complete page*/
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output"></div>
<!--Div which will hold the Output-->
<div id="WebGL-output"></div>

<!--Javascript code that runs out Three.js examples-->
<script type="text/javascript">
    //once everything is loaded, we run out Three.js stuff.
    var scene;
    var camera;
    var stats;
    var renderer;
    function init() {
        scene=new THREE.Scene();

        camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);

        renderer=new THREE.WebGLRenderer();

        stats=initStats();

        renderer.setClearColor(0xEEEEEE,0.5);
        renderer.setSize(window.innerWidth,window.innerHeight);
        renderer.shadowMapType=THREE.PCFSoftShadowMap;
        renderer.shadowMapEnabled=true;

        var spotLight=new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40,60,-10);

        spotLight.castShadow=true;
        spotLight.shadowMapHeight=4096;
        spotLight.shadowMapWidth=4096;
        scene.add(spotLight);

        var ambientLight=new THREE.AmbientLight(0xffffff);
        ambientLight.intensity=0.3;
        scene.add(ambientLight);

        var axes=new THREE.AxisHelper(20);
        scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
        var planeMaterial = new THREE.MeshPhongMaterial({color:0xffffff});
        var plane=new THREE.Mesh(planeGeometry,planeMaterial);

        plane.rotation.x=-0.5*Math.PI;
        plane.position.x=15;plane.position.y=0;plane.position.z=0;

        plane.receiveShadow=true;

        scene.add(plane);

        var cubeGeometry = new THREE.CubeGeometry(4,4,4);
        var cubeMaterial = new THREE.MeshPhongMaterial({color:0xff0000});
        var cube=new THREE.Mesh(cubeGeometry,cubeMaterial);

        cube.position.x=-4;cube.position.y=3;cube.position.z=0;

        cube.castShadow=true;

        scene.add(cube);

        var sphereGeometry=new THREE.SphereGeometry(4,20,20);
        var sphereMaterial=new THREE.MeshPhongMaterial({color:0x7777ff});
        var sphere=new THREE.Mesh(sphereGeometry,sphereMaterial);

        sphere.position.x=20;sphere.position.y=4;sphere.position.z=2;

        sphere.castShadow=true;

        scene.add(sphere);

        camera.position.x=-30;camera.position.y=40;camera.position.z=30;
        camera.lookAt(scene.position);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        //effect.render(scene,camera);

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.bouncingSpeed = 0.03;
        };

        var gui=new dat.GUI();
        gui.add(controls,'rotationSpeed',0,0.5);
        gui.add(controls,'bouncingSpeed',0,0.5);

        //this renderScene() function should be called after every
        renderScene();

        var step=0;
        function renderScene() {
            stats.update();

            //animate cube
            cube.rotation.x+=controls.rotationSpeed;cube.rotation.y+=controls.rotationSpeed;cube.rotation.z+=controls.rotationSpeed;

            //animate sphere
            step+=controls.bouncingSpeed;
            sphere.position.x=20+(10*Math.cos(step));
            sphere.position.y=2+(10*Math.abs(Math.sin(step)));

            requestAnimationFrame(renderScene);
            renderer.render(scene,camera);
        }

        function initStats() {
            var stats=new Stats();
            stats.setMode(0);
            stats.domElement.style.position='absolute';
            stats.domElement.style.left='0px';
            stats.domElement.style.top='0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);

            return stats;
        }
    }
    function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }
    window.onload=init;

    window.addEventListener('resize', onResize, false);
</script>

</body>
</html>

那么到這里,我們就完成了對Three.js的入門學習。下面我們會更加深入的講解Three.js。

參考資料:
Learning Three.js The JavaSctipt 3D Library for WebGL ·Jos Dirksen

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文主要是講解 Three.js 的相關概念,幫助大家對 Three.js 以及相關知識形成比較完整的理解。今年來...
    Simon王小白閱讀 8,500評論 2 9
  • 1、三大組建 在Three.js中,要渲染物體到網頁中,我們需要3個組建:場景(scene)、相機(camera)...
    依依玖玥閱讀 642評論 0 0
  • react vr中文網:www.vr-react.com react vr qq群:481244084 示例源碼 ...
    liu_520閱讀 3,722評論 4 6
  • 簡書連載風云錄《選擇》目錄上一章回顧:選擇 (十二) 情書第十三章:相見歡 王凌云收到何嘉慧的回信,歡喜不已。但拆...
    林燕娜閱讀 688評論 8 9
  • 狂暴的靈力,一的在牧塵氣海之中翻涌著,九幽雀那燃燒著黑炎的眼睛中,有著難掩的急促與激動,它的那種情緒,就連牧塵都能...
    混沌天書閱讀 395評論 0 0