美文网首页虚拟现实开发程序员今日看点
[WebAR和WebVR学习之路]从Three.js开始掌握We

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

作者: 养薛定谔的猫 | 来源:发表于2017-02-24 15:07 被阅读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

    相关文章

      网友评论

      本文标题:[WebAR和WebVR学习之路]从Three.js开始掌握We

      本文链接:https://www.haomeiwen.com/subject/brjwwttx.html