Three.js 入门:如何使用并绘制基础 3D 图形

啊大大 7年前
   <p style="text-align:center"><img src="https://simg.open-open.com/show/186f6b1f941e479b33c141be0737361e.jpg"></p>    <h2>一、 前言</h2>    <p>Three.js 是一款 webGL(3D绘图标准,在此不赘述)引擎,可以运行于所有支持 webGL 的浏览器。Three.js 封装了 webGL 底层的 API ,为我们提供了高级的开发接口,可以使用简单的代码去实现 3D 渲染。</p>    <h2>二、 为什么要选择Three.js?</h2>    <p>Three.js 作为原生 web3D 引擎,对插件式 web3D 引擎的优势不言而喻: <strong>不需要安装插件、在移动端支持好。</strong></p>    <h2>Three.js 与其他原生 web3D 引擎对比:</h2>    <ol>     <li> <p>Babylon.js:一个强大的 3D 游戏引擎,由 Microsoft 的员工 David Cathue 主导开发。和 Three.js 相比,three.js 更倾向于动画,而 Babylon.js 则更适合游戏开发。</p> </li>     <li> <p>PhiloGL:增加了额外的功能帮助你可以使用本地的 WebGL ,这个 WebGL 的接口不是百分之百的被封装好了的,这使得 PhiloGL 上手难度较高。</p> </li>     <li> <p>SceneJS:一个开源的 JavaScript 3D 引擎,特别适合需要高精度细节的模型需求,比如工程学和医学上常用的高精度模型。</p> </li>     <li> <p>CopperLicht:一个“商业级别的 WebGL 3D 引擎和编辑器”,你可以免费使用,但是要想获得未压缩的完整版带支持文档的源码和其他服务,则需要购买授权。</p> </li>    </ol>    <p>相对这些 web3D 引擎,Three.js 的还有以下几点优势:</p>    <ul>     <li>      <ul>       <li> <p>开发和维护比较活跃;</p> </li>      </ul> </li>    </ul>    <ul>     <li> <p>文档齐全,案例丰富,易于学习;</p> </li>     <li> <p>设计灵活、方便拓展以及增加新的特性;</p> </li>    </ul>    <p>我们可以根据自己的需要去选择web3D引擎。</p>    <h2>三、 开始Three.js</h2>    <h2>1、 引导</h2>    <p>在开始我们的第一个 3D 程序之前,我们需要了解 Three.js 的一些基础,以下是 Three.js 制作 3D 的五要素:</p>    <ol>     <li> <p>渲染器(render)</p> <p>我们可以把渲染器想想成为一个画布,我们需要在这个画布上去画出我们需要展示的东西。</p> </li>     <li> <p>场景(scene)</p> <p>相当于一个空间,我们需要将展示的东西放在这个空间里,然后再在画布上绘制出来。</p> </li>     <li> <p>照相机(camera)</p> <p>相当于眼睛,我们想要看到物体,就需要眼睛去看。</p> </li>     <li> <p>光源(light)</p> <p>物体需要光照才能看见,不然就是漆黑一片(但是在某些情况下展示物体不需要光源)。</p> </li>     <li> <p>物体(object)</p> <p>我们想要表现的内容,会有形状和材质属性。</p> </li>    </ol>    <p>了解了五要素之后,就可以开始写我们的代码了。</p>    <h2>2、 创建渲染器</h2>    <p>首先,我们创建一个渲染器。创建渲染器有两种方式:</p>    <h3>a. 在 html 上写出 canvas 元素</h3>    <pre>  <code class="language-java"><canvas id="mainCanvas" width="600px" height="450px" ></canvas>  然后创建渲染器时绑定此元素  var renderer = new THREE.WebGLRenderer({    canvas: document.getElementById('mainCanvas')  });  renderer.setClearColor(“#000”); // 设置渲染器背景为黑色</code></pre>    <h3>b. html 上不创建 canvas 元素,而是使用普通的元素作为容器</h3>    <pre>  <code class="language-java"><div id="mainCanvas" style="width:600px;height:450px;" ></div>  然后创建渲染器,放入容器中  var canvasContainer = document.getElementById('mainCanvas');  var width = canvasContainer.clientWidth;  //获取画布的宽  var height = canvasContainer.clientHeight;  //获取画布的高  var renderer = new THREE.WebGLRenderer({    antialias: true  //抗锯齿开  });  renderer.setSize(width, height);  //设置渲染器的宽和高  renderer.setClearColor(0x000000); //设置渲染器的背景颜色为黑色  var canvas = renderer.domElement; //获取渲染器的画布元素  canvasContainer.appendChild(canvas); //将画布写入html元素中</code></pre>    <p>这样,我们的渲染器就创建成功了。</p>    <p>创建渲染器时,还可以设置多个属性,比如抗锯齿、透明度等等,详见 three.js 官方文档。</p>    <h2>3、 创建场景</h2>    <p>渲染器创建之后,我们再创建场景,准备将我们需要绘制的东西放入场景。</p>    <pre>  <code class="language-java">var scene = new THREE.Scene();</code></pre>    <h2>4、 创建照相机</h2>    <p>照相机常用的有两种,一种叫正投影相机:</p>    <pre>  <code class="language-java">THREE.OrthographicCamera( left, right, top, bottom, near, far );</code></pre>    <p>下图为该照相机的视野:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f863d8a51eb63d93e5c5a6267e32ab82.jpg"></p>    <p>一种叫做透视照相机:</p>    <pre>  <code class="language-java">THREE.PerspectiveCamera( fov, aspect, near, far ) ;</code></pre>    <p>下图为该照相机的视野:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/64bbdef139ddb03fb99a1beaec056a22.jpg"></p>    <p>下图为两个照相机展示效果的对比:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e774b56b65291947e7c4e6f996a6b1b8.jpg"></p>    <p>**左边为正投照相机,远近大小都一样;</p>    <p>右边为透视照相机,远小近大,更接近于人眼观察物体的感觉。**</p>    <p>在此以正投照相举例:</p>    <pre>  <code class="language-java">var camera = new THREE.OrthographicCamera(-6, 6, 4.5, -4.5, 0, 50); //创建照相机  camera.position.set(35, 15, 25);  //设置照相机的位置  camera.lookAt(new THREE.Vector3(0, 0, 0)); //设置照相机面向(0,0,0)坐标观察  照相机默认坐标为(0,0,0);  默认面向为沿z轴向里观察;</code></pre>    <h2>5、 创建光源</h2>    <p>常用光源有:</p>    <ul>     <li> <p>平行光(DirectionalLight),效果类似太阳光</p> </li>    </ul>    <p>DirectionalLight ( color, intensity )</p>    <p>color — 光源颜色的RBG数值。</p>    <p>intensity — 光强的数值。</p>    <ul>     <li> <p>点光源(PointLight),效果类似灯泡</p> </li>    </ul>    <p>PointLight ( color, intensity, distance, decay )</p>    <p>color — 光源颜色的RBG数值。</p>    <p>intensity — 光强的数值。</p>    <p>distance -- 光强为0处到光源的距离,0表示无穷大。</p>    <p>decay -- 沿着光照距离的衰退量。</p>    <ul>     <li> <p>聚光光源(SpotLight),效果类似聚光灯</p> </li>    </ul>    <p>SpotLight ( color, intensity, distance, angle, penumbra, decay )</p>    <p>color — 光源颜色的RBG数值。</p>    <p>intensity — 光强的数值。</p>    <p>distance -- 光强为0处到光源的距离,0表示无穷大。</p>    <p>angle -- 光线散射角度,最大为Math.PI/2。</p>    <p>penumbra -- 聚光锥的半影衰减百分比。在0和1之间的值。默认为0。</p>    <p>decay -- 沿着光照距离的衰退量。</p>    <p>在此以点光源举例:</p>    <p>var light = new THREE.PointLight(0xffffff, 1, 100); //创建光源</p>    <p>light.position.set(12, 15, 10); //设置光源的位置</p>    <p>scene.add(light); //在场景中添加光源</p>    <h2>6、 创建物体</h2>    <p>制作物体的方法是 Mesh:</p>    <pre>  <code class="language-java">new THREE.Mesh(Geometry, Material);</code></pre>    <p>Geometry 为物体的形状,Material 为物体的材质;</p>    <ul>     <li> <p>形状(Geometry)</p> <p>three.js 给出了很多方法去生成固定的形状,比如长方体(BoxGeometry)、球体(SphereGeometry)、圆形(CircleGeometry)等等。还有根据坐标去生成具体形状的方法,可以借助第三方建模软件建模之后引入,转换为坐标后再生成,就可以做比较复杂的形状了,比如人脸、汽车等等。</p> </li>    </ul>    <p>在此以长方体为例生成形状:</p>    <pre>  <code class="language-java">//设置正方体宽度,高度,深度分别为5,5,5  var geometry = new THREE.BoxGeometry (5, 5, 5);</code></pre>    <p>- <strong>材质(Material)</strong></p>    <p>材质就像是物体的皮肤,决定物体外表的样子,例如物体的颜色,看起来是否光滑,是否有贴图等等。</p>    <p>常用材质有:</p>    <ul>     <li> <p>网格基础材质(MeshBasicMaterial)</p> <p>该材质不受光照的影响,不需要光源即可显示出来,设置颜色后,各个面都是同一个颜色。</p> </li>     <li> <p>网格法向材质(MeshNormalMaterial)</p> <p>该材质不受光照的影响,不需要光源即可显示出来,并且每个方向的面的颜色都不同,同但一个方向的面颜色是相同的,该材质一般用于调试。</p> </li>     <li> <p>网格朗博材质(MeshLambertMaterial)</p> <p>该材质会受到光照的影响,没有光源时不会显示出来,用于创建表面暗淡,不光亮的物体。</p> </li>     <li> <p>网格 Phong 材质(MeshPhongMaterial)该材质会受到光照的影响,没有光源时不会显示出来,用于创建光亮的物体。</p> </li>    </ul>    <p>在此以网格 Phong 材质为例创建材质:</p>    <pre>  <code class="language-java">var material = new THREE.MeshPhongMaterial({         color: "yellow" //设置颜色为yellow  });</code></pre>    <p>创建形状和材质之后,就可以创建该物体了:</p>    <pre>  <code class="language-java">//创建物体  var cube = new THREE.Mesh(geometry, material);</code></pre>    <h2>7、 渲染画布</h2>    <p>通过以上步骤,我们已经有了渲染器(renderer)、场景(scene)、照相机(camera)、光源(light)和物体(cube),此时我们需要将光源和物体加入场景中:</p>    <pre>  <code class="language-java">scene.add(light);  scene.add(cube);  然后再使用渲染器将场景和照相机渲染出来:  renderer.render(scene, camera);</code></pre>    <p>效果如下图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1ad9b5646e57418898aefaa0256958c5.jpg"></p>    <h2>四、 结束语</h2>    <p>在以上内容中,只写到了 Three.js 中提供的基础功能,还有很多高级的功能需要大家去探索。希望大家看完这篇文章后能对 Three.js 有一个初步的了解,并能够使用 Three.js 绘制出基础的 3D 图形。</p>    <p>大家可以去 Three.js 官网的 examples 中看看,这里面都是一些很优秀和典型的 examples,并且还有代码可以下载,大家可以去研究探索一番。</p>    <p>在此附上几个精彩的例子供大家欣赏:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e1bdcf86bd61c414b5f014c7932e507b.jpg"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2c7ebd3afab08f8462f65203d92e18dc.jpg"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/32e05595f0e8ff4af97ea64e34de1f4b.jpg"></p>    <p>Jason 岂安科技前端研发工程师三年互联网前端开发经验,曾参与过多个系统框架的搭建和组件开发,负责岂安科技产品的数据可视化和公用组件开发。</p>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000009206983</p>    <p> </p>