虚拟现实开发程序员今日看点

[WebAR和WebVR学习之路]从Three.js开始掌握We

2017-02-24  本文已影响1039人  养薛定谔的猫

《为什么要学习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

上一篇下一篇

猜你喜欢

热点阅读