ThreeJS Learning

Three.js是一个3D JavaScript库。

Three.js封装了底层的图形接口,使得程序员能够在无需掌握繁冗的图形学知识的情况下,也能用简单的代码实现三维场景的渲染。

优点:
使用Three.js开发要比WebGL更快更高效。
对于不熟悉图形学知识的程序员而言,使用Three.js能够降低学习成本,提高三维图形程序开发的效率。

一、WebGL

WebGL是基于OpenGL ES 2.0 的Web标准,可以通过 HTML5 Canvas元素作为 DOM接口访问。
WebGL可以看做是将 OpenGL ES(OpenGL for Embedded Systems,OpenGL嵌入式版本,针对手机、游戏机等设备相对较轻量级的版本)移植到了网页平台,像Chrome、Firefox 这些现代浏览器都实现了WebGL标准,使用JavaScript就可以用你熟悉的、类似OpenGL的代码编写了。

你可以把 WebGL简单地认为是一种网络标准,定义了一些较底层的图形接口,至于究竟多底层,稍后我们和Three.js代码对比来看。
现在,我们知道了WebGL是一个底层的标准,在这些标准被定义之后,Chrome、Firefox之类的浏览器实现了这些标准。然后,程序员就能通过JavaScript代码,在网页上实现三维图形的渲染了。

二、ThreeJS程序

一个典型的Three.js程序至少要包括:
渲染器(Renderer)、场景(Scene)、照相机(Camera),以及你在场景中创建的物体。

渲染器(Render)

WebGL的渲染是需要 HTML5 Canvas元素 的,可以手动在HTML的 部分中定义 Canvas元素,或者用Three.js生成。

手动在 HTML中定义:

<body onload="init()">
   <canvas id="mainCanvas" width="400px" height="300px" ></canvas>
</body>

用Three.js生成 Canvas元素:

var renderer = new THREE.WebGLRenderer();
renderer.setSize(400, 300);
document.getElementsByTagName('body')[0].appendChild(renderer.domElement);

上面代码的第二行表示设置 Canvas的宽 400 像素,高 300 像素。第三行将渲染器对应的Canvas元素添加到中。
我们可以使用下面的代码将背景色(用于清除画面的颜色)设置为黑色:

renderer.setClearColor(0x000000);

场景(Scene)

在Three.js中添加的物体都是添加到场景中的,因此它相当于一个大容器。一般说,场景
来没有很复杂的操作,在程序最开始的时候进行实例化,然后将物体添加到场景中即可。

var scene = new THREE.Scene();

照相机(Camera)

在介绍照相机设置前,我们先来简单了解下坐标系。WebGL和 Three.js使用的坐标系是右手坐标系。
这里,我们定义了一直透视投影的照相机,具体原理将在下一章中展开。

var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
camera.position.set(0, 0, 5);
scene.add(camera);

值得注意的是,照相机也需要被添加到场景中。

我们使用Three.js创建的场景是三维的,而通常情况下显示屏是二维的,那么三维的场景如何显示到二维的显示屏上呢?
照相机就是这样一个抽象,它定义了三维空间到二维屏幕的投影方式,用“照相机”这样一个类比,可以使我们直观地理解这一投影方式。

针对投影方式的不同,照相机又分为正交投影照相机与透视投影照相机。

一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例;而对于其他大多数应用,通常使用透视投影,因为这更接近人眼的观察效果。当然,照相机的选择并没有对错之分,你可以更具应用的特性,选择一个效果更佳的照相机。

1、正交投影照相机(Orthographic Camera)

设置起来较为直观,它的构造函数是:

THREE.OrthographicCamera(left, right, top, bottom, near, far)

这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,这两个面围成一个长方体,我们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才可能显示在屏幕上,而视景体外的物体会在显示之前被裁减掉。
设置照相机:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

在原点处创建一个边长为1的正方体,为了和透视效果做对比,这里我们使用wireframe而不是实心的材质,以便看到正方体后方的边:

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: true
    }) 
);
scene.add(cube);

现在,如果我们将照相机向右移动 1 个单位:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(1, 0, 5);

得到的效果是物体看上去向左移动了 。。。

换个角度看世界

到现在为止,我们使用照相机都是沿z轴负方向观察的,因此看到的都是一个正方形。现在,我们想尝试一下仰望这个正方体。我们已经学会设置照相机的位置,不妨将其设置在(4, -3, 5)处:

camera.position.set(4, -3, 5);

但是现在照相机沿z轴负方向观察的,因此观察不到正方体,只看到一片黑。我们可以通过 lookAt 函数指定它看着原点方向:

camera.lookAt(new THREE.Vector3(0, 0, 0));

这样我们就能过仰望正方体啦。

2、透视投影照相机(Perspective Camera)

构造函数是:

THREE.PerspectiveCamera(fov, aspect, near, far)

fov 是视景体竖直方向上的张角(是角度制而非弧度制)

aspect 等于 width / height,是照相机水平方向和竖直方向长度的比值,通常设为Canvas的横纵比例。

near 和 far 分别是照相机到视景体最近、最远的距离,均为正值,且 far 应大于near。

设置透视投影照相机,这里 Canvas长 400px,宽 300px,所以 aspect设为 400 / 300:

var camera = new THREE.PerspectiveCamera(45, 400 / 300, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

和例2.3.1一样,设置一个在原点处的边长为 1的正方体:

// a cube in the scene
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: true
    })
);
scene.add(cube);

长方体

我们要创建一个x、y、z方向长度分别为 1、2、 3 的长方体,并将其设置为红色。

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3),
    new THREE.MeshBasicMaterial({
        color: 0xff0000
    })
);
scene.add(cube);

立方体(CubeGeometry)

虽然这一形状的名字叫立方体(CubeGeometry),但它其实是长方体,也就是长宽高可以设置为不同的值。其构造函数是:

THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)

这里,width 是x方向上的长度; height 是 y方向上的长度; depth 是z方向上的长度;后三个参数分别是在三个方向上的分段数,如 widthSegments 为 3 的话,代表 x方向上水平分为三份。一般情况下不需要分段的话,可以不设置后三个参数,后三个参数的缺省值为 1。其他几何形状中的分段也是类似的,下面不做说明。
长宽高

创建立方体直观简单,如:

new THREE.CubeGeometry(1, 2, 3); 

可以创建一个x方向长度为 1,y方向长度为 2,z方向长度为 3 的立方体。
物体的默认位置是原点,对于立方体而言,是其几何中心在原点的位置。

分段

而在设置了分段

new THREE.CubeGeometry(1, 2, 3, 2, 2, 3)

注意这个分段是对六个面进行分段,而不是对立方体的体素分段,因此在立方体的中间是不分段的,只有六个侧面被分段。

平面
这里的平面(PlaneGeometry)其实是一个长方形,而不是数学意义上无限大小的平面。其构造函数为:

THREE.PlaneGeometry(width, height, widthSegments, heightSegments)

其中,width 是x方向上的长度; height 是 y方向上的长度;后两个参数同样表示分段。

new THREE.PlaneGeometry(2, 4);

创建的平面在x轴和y轴所在平面内

球体
球体(SphereGeometry)的构造函数是:

THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, the taStart, thetaLength)

其中,radius 是半径; segmentsWidth 表示经度上的切片数; segmentsHeight 表示纬度上的切片数;phiStart 表示经度开始的弧度;phiLength 表示经度跨过的弧度;
thetaStart 表示纬度开始的弧度; thetaLength 表示纬度跨过的弧度。

圆形
圆形(CircleGeometry)可以创建圆形或者扇形,其构造函数是:

THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)

这四个参数都是球体中介绍过的,这里不再赘述,直接来看个例子。

new THREE.CircleGeometry(3, 18, Math.PI / 3, Math.PI / 3 * 4)

可以创建一个在x轴和y轴所在平面的三分之二圆的扇形

文字形状

文字形状(TextGeometry)可以用来创建三维的文字形状。
略……

实例剖析

实例1:

预览图:

代码分析:

在页面中对应设置id为mainCanvas的canvas标签,设置宽高:width="400px" height="300px"

在页面加载完成后调用:    <body onload="init()">


引入three.js文件


​ 在script标签中,定义init()函数:

//渲染器WebGLRenderer
var renderer= new THREE.WebGLRenderer({

//创建场景
var scene= new THREE.Scene();

//创建照相机,并添加到场景中
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000); 

//创建长方体,设置为红色,并添加到场景中
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3), 

//渲染
renderer.render(scene, camera); 

完整代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="three.js"></script>
        <script>
            function init(){
                //渲染器WebGLRenderer
                var renderer= new THREE.WebGLRenderer({
                    canvas: document.getElementById('mainCanvas')
                    //指定id的canvas标签
                })
                renderer.setClearColor(0x000000); 

                //创建场景
                var scene= new THREE.Scene();

                //创建照相机,并添加到场景中
                var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000); 
                camera.position.set(0, 0, 5); 
                scene.add(camera); 

                //创建长方体,设置为红色
                var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3), 
            new THREE.MeshBasicMaterial({ 
                color: 0xff0000 
                }) 
                ); 
                scene.add(cube); 

                //渲染
                renderer.render(scene, camera); 
            }
        </script>
    </head>
    <body onload="init()">
        <!--页面加载后执行init函数-->

        <canvas id="mainCanvas" width="400px" height="300px"></canvas>

    </body>
</html>

实例2:

预览图:

设置照相机的位置:

camera.position.set(4, 3, 5); //设置照相机的位置
camera.lookAt(new THREE.Vector3(0, 0, 0)); 

示意图:

完整代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script src="three.js"></script>
        <script>
            //正交投影照相机(Orthographic Camera)
            //

            function init(){
                //渲染器WebGLRenderer
                var renderer= new THREE.WebGLRenderer({
                    canvas: document.getElementById('mainCanvas')
                    //指定id的canvas标签
                })
                renderer.setClearColor(0x000000); 

                //创建场景
                var scene= new THREE.Scene();

                //创建照相机,并添加到场景中
                var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
                camera.position.set(4, 3, 5); //设置照相机的位置,在此位置上有新视角!
                camera.lookAt(new THREE.Vector3(0, 0, 0)); //设置照相机向着原点而非z轴负方向。
                scene.add(camera); 

                //创建长方体,设置为红色
                var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 3), 
                    new THREE.MeshBasicMaterial({ 
                        color: 0xff0000,
                        wireframe:true
                    }) 
                ); 
                scene.add(cube); 

                //渲染
                renderer.render(scene, camera); 
            }
        </script>
    </head>
    <body onload="init()">
        <!--页面加载后执行init函数-->

        <canvas id="mainCanvas" width="400px" height="300px"></canvas>

    <!--WebGL No.1 - Three.js 入门-->
    </body>
</html>

1

Contents
  1. 1. 一、WebGL
  2. 2. 二、ThreeJS程序
    1. 2.1. 渲染器(Render)
    2. 2.2. 场景(Scene)
    3. 2.3. 照相机(Camera)
    4. 2.4. 长方体
    5. 2.5. 立方体(CubeGeometry)
    6. 2.6. 文字形状
  3. 3. 实例剖析
    1. 3.1. 实例1:
    2. 3.2. 实例2:
|