[WebAR和WebVR學(xué)習(xí)之路]從Three.js開始掌握WebAR和WebVR的開發(fā)

《為什么要學(xué)習(xí)Three.js》

Three.js是JavaScript編寫的WebGL第三方庫。提供了非常多的3D顯示功能闸度。
Three.js對WebGL進行了封裝竭贩,省去了很多WebGL底層的代碼,使得編寫Web的3D程序十分方便莺禁。
現(xiàn)如今留量,WebAR和WebVR逐漸進入人們的視野。由于Web不需要下載程序的簡便性使得更多的人傾向于在Web頁面開發(fā)VR/AR應(yīng)用(快速捕捉客戶)。因此楼熄,學(xué)習(xí)WebGL的開發(fā)使得一個VR/AR開發(fā)者更具有競爭力忆绰。
今天,我們將簡單的從幾個方面來講解Three.js可岂,已達(dá)到快速入門的目的错敢。

知識需求:

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

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

由于Three.js需要一個簡單的web服務(wù)器來測試缕粹,所以我們需要搭建一個簡單的HTTP服務(wù)器稚茅。
對于大多數(shù)人來說,搭建web服務(wù)器是一個十分簡單的事情平斩,但對一些新手我們可以使用集成環(huán)境來快速搭建web服務(wù)器來測試(像是eclipse中集成的tomcat服務(wù)器一樣)峰锁。
在這里我推薦使用Web Storm軟件,搞前端開發(fā)的程序員對此軟件并不陌生双戳,其擴展性高使用十分便捷虹蒋。
下面我們開始搭建一個簡單的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{
            /*設(shè)置頁面的樣式*/
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<!—用于顯示W(wǎng)ebGL輸出的div-->
<div id="WebGL-output">

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

</body>
</html>

《渲染并創(chuàng)建一個三維對象》

在上文的注釋 在此輸入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是一個容器呻惕,保存并跟蹤想要渲染的物體荆责,在后面創(chuàng)建了幾何體之后(如立方體和球體等)會添加到scene變量中。
camera變量定義了在渲染好的scene里看到什么亚脆。
最后是renderer對象做院,renderer對象負(fù)責(zé)計算指定的相機角度下的瀏覽器中scene的呈現(xiàn)樣子。
在以上實例中濒持,我們創(chuàng)建了一個WebGLRenderer對象键耕,使用計算機的圖形卡來渲染場景。

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

接下來通過renderer的setClearColor函數(shù)來設(shè)置renderer的背景色為接近白色的顏色(0xEEEEEE)柑营,并通過setSize()函數(shù)來告訴renderer將scene渲染為多大的尺寸屈雄。
通過以上的代碼,我們有了一個空白的scene官套、一個renderer和一個camera酒奶。
下面我們來創(chuàng)建一個坐標(biāo)軸對象蚁孔,并添加到場景中。

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

通過THREE的AxisHelper函數(shù)我們創(chuàng)建了一個長度為20的坐標(biāo)軸讥蟆,并通過scene的add函數(shù)將其添加到了場景中勒虾。
下面我們再創(chuàng)建一個平面(plane)并修改其旋轉(zhuǎn)和位置。

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)來定義該平面的尺寸瘸彤,在該章節(jié)中修然,我們將平面的尺寸設(shè)置為寬60,高20质况。在創(chuàng)建完幾何體之后我們還需要給plane指定材質(zhì)愕宋,在這里我們使用MeshBasicMaterial()方法來創(chuàng)建一個基本的材質(zhì),其顏色為0xcccccc结榄。接下來將兩個對象合并到一個名為plane的Mesh(網(wǎng)格)對象中中贝。在將其放入場景之前還要修改其旋轉(zhuǎn)和位置,先將其繞著x軸旋轉(zhuǎn)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函數(shù)(對Unity和OpenGL熟悉的應(yīng)該對此也不陌生)來修改camera的位置和朝向绣否。在這里,我們的lookAt函數(shù)指向scene的中心挡毅。
最后蒜撮,我們應(yīng)該將renderer的輸出掛接到HTML頁面框架中的<div>元素中;在這里我們使用jQuery來選擇正確的輸出元素跪呈,并告訴 renderer用我們提供的相機來渲染scene段磨。

《添加材質(zhì)、燈光和陰影》

由于線框的渲染模式不會對燈光產(chǎn)生反應(yīng)耗绿,因此我們需要修改cube和sphere的材質(zhì)苹支。
先將上一節(jié)的例子復(fù)制,并改名缭乘。
在創(chuàng)建完renderer之后沐序,我們開始創(chuàng)建燈光:

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

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

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

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

renderer.shadowMapEnabled=true;

在plane創(chuàng)建完成之后加入

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

spotLight.castShadow=true;

來使其接收陰影。
最后產(chǎn)生的效果如下圖:


該節(jié)的整體代碼:

<!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>

《簡單的動畫和幀率監(jiān)控》

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

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

然后再添加一個用于展示統(tǒng)計信息的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();

下面拄显,我們來編寫每一幀需要調(diào)用的渲染函數(shù)

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);
}

該渲染函數(shù)在每次調(diào)用會更新stats信息苟径,更新方塊的旋轉(zhuǎn)和球體的運動位置。最后通過requestAnimationFrame函數(shù)來指定renderScene函數(shù)為指定時間間隔渲染的函數(shù)躬审。最后調(diào)用renderer渲染器的render函數(shù)重新渲染棘街。
最后我們在代碼的主體加入一次對renderScene函數(shù)的調(diào)用。
本節(jié)所有代碼如下:

<!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公司的一些人創(chuàng)建的庫承边,該庫的文檔(http://code.google.com/p/dat-gui/ 需翻墻)通過這個庫遭殉,我們可以實現(xiàn)用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;
};

然后創(chuàng)建一個gui對象并添加控制器:

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

注意炒刁,這些代碼需要寫在渲染函數(shù)之前恩沽。
接下來修改上一節(jié)的renderScene函數(shù)中的方塊和球體的動畫控制代碼:

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);
}

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


本節(jié)的完整代碼:

<!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>

《動態(tài)改變渲染大小》

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

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

編寫完該函數(shù)之后我們需要對窗口大小改變的事件增加監(jiān)聽:

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

注意罗心,這里要把renderer、camera等變量定義成作用域更廣的變量城瞎,具體參見詳細(xì)代碼:

<!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的入門學(xué)習(xí)。下面我們會更加深入的講解Three.js脖镀。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末飒箭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜒灰,更是在濱河造成了極大的恐慌弦蹂,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件强窖,死亡現(xiàn)場離奇詭異凸椿,居然都是意外死亡,警方通過查閱死者的電腦和手機翅溺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門脑漫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來髓抑,“玉大人,你說我怎么就攤上這事优幸《峙模” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵网杆,是天一觀的道長羹饰。 經(jīng)常有香客問我,道長跛璧,這世上最難降的妖魔是什么严里? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮追城,結(jié)果婚禮上刹碾,老公的妹妹穿的比我還像新娘。我一直安慰自己座柱,他們只是感情好迷帜,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著色洞,像睡著了一般戏锹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上火诸,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天锦针,我揣著相機與錄音,去河邊找鬼置蜀。 笑死奈搜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盯荤。 我是一名探鬼主播馋吗,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼秋秤!你這毒婦竟也來了宏粤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤灼卢,失蹤者是張志新(化名)和其女友劉穎绍哎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞋真,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蛇摸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了灿巧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赶袄。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抠藕,靈堂內(nèi)的尸體忽然破棺而出饿肺,到底是詐尸還是另有隱情,我是刑警寧澤盾似,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布敬辣,位于F島的核電站,受9級特大地震影響零院,放射性物質(zhì)發(fā)生泄漏溉跃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一告抄、第九天 我趴在偏房一處隱蔽的房頂上張望撰茎。 院中可真熱鬧,春花似錦打洼、人聲如沸龄糊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炫惩。三九已至,卻和暖如春阿浓,著一層夾襖步出監(jiān)牢的瞬間他嚷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工芭毙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留筋蓖,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓稿蹲,卻偏偏與公主長得像扭勉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子苛聘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

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