Three.js快速⼊门教程
引⾔
本⽂主要是讲解Three.js的相关概念,帮助读者对Three.js以及相关知识形成⽐较完整的理解。
近年来web得到了快速的发展。随着HTML5的普及,⽹页的表现能⼒越来越强⼤。⽹页上已经可以做出很多复杂的动画,精美的效果。
但是,⼈总是贪的。那么,在此之上还能做什么呢?其中⼀种就是通过WebGL在⽹页中绘制⾼性能的3D图形。
OpenGL,WebGL到Three.js
OpenGL⼤概许多⼈都有所⽿闻,它是最常⽤的跨平台图形库。
WebGL是基于OpenGL设计的⾯向web的图形标准,提供了⼀系列JavaScript API,通过这些API进⾏图形渲染将得以利⽤图形硬件从⽽获得较⾼性能。
⽽Three.js是通过对WebGL接⼝的封装与简化⽽形成的⼀个易⽤的图形库。
简单点的说法:WebGL可以看成是浏览器给我们提供的接⼝,在javascript中可以直接⽤这些API进⾏3D图形的绘制;⽽Three.js就是在这些接⼝上⼜帮我们封装得更好⽤⼀些。
WebGL与Three.js对⽐
既然有了WebGL,我们为什么还需要Three.js?
这是因为WebGL门槛相对较⾼,需要相对较多的数学知识。虽然WebGL提供的是⾯向前端的API,但本质上WebGL跟前端开发完全是两个不同的⽅向,知识的重叠很少。相关性只是他们都在web平台上,都是⽤javascript⽽已。⼀个前端程序员或许还熟悉解析⼏何,但是还熟悉线性代数的应该寥寥⽆⼏了(⽐如求个逆转置矩阵试试?),更何况使⽤中强调矩阵运算中的物理意义,这在教学中也是⽐较缺失的。
因此,前端⼯程师想要短时间上⼿WebGL还是挺有难度的。
于是,Three.js对WebGL提供的接⼝进⾏了⾮常好的封装,简化了很多细节,⼤⼤降低了学习成本。并且,⼏乎没有损失WebGL的灵活性。
因此,从Three.js⼊⼿是值得推荐的,这可以让你在较短的学习后就能⾯对⼤部分需求场景。
Three.js的学习问题
Three.js的⼊门是相对简单的,但是当我们真的去学的时候,会发现⼀个很尴尬的问题:相关的学习资料很少。
通常这种流⾏的库都有很完善的⽂档,很多时候跟着官⽅的⽂档或官⽅的⼊门教程学习就是最好的路线。但Three不是的,它的⽂档对初学者来说太过简明扼要。
不过官⽅提供了⾮常丰富的examples,⼏乎所有你需要的⽤法都在某个example中有所体现。但这些example不太适合⽤来⼊门,倒是适合⼊门之后的进⼀步学习。
这⾥推荐⼀些相对较好的教程:
这是⼀份很好的Three.js 轻量级⼊门教程,作者⽂笔很好,基础知识讲解得简明易懂。
Learning Three.js:The JavaScript 3D Library for WebGL是现在不多的也是最好的Three.js⼊门书,⽐较全⾯地讲解了Three.js 的各种功能。
如果有能⼒的话,建议阅读英⽂版第⼆版,出版于2015年,与现在的Three.js区别很⼩。
中⽂版翻译⾃出版于2012年的原书第⼀版,⼤部分概念是适⽤的,但很多细节已经有所改变。
这是对国外⼀份教程的翻译,⼀共六篇⽂章。讲解不多,更多的是展⽰各个基本功能怎么⽤。更适合有⼀些图形基础的同学。
当然,实际的学习过程中这些资料肯定是不太够的,遇到问题还是要⾃⼰去查资料。不过这⾥要提醒⼀下,Three.js的更新是相当频繁的,现在是r80版本,⾃2010年4⽉发布r1以来,这已经是第72个版本了(中间有的版本号跳过了)。因此,在⽹上到的资料有些可能是不适合当前版本的,需要注意甄别(前⾯推荐的资料也都或多或少存在这样的问题)。
Three.js中的⼀些概念
要在屏幕上展⽰3D图形,思路⼤体上都是这样的:
构建⼀个三维空间
Three中称之为场景(Scene)选择⼀个观察点,并确定观察⽅向/⾓度等
Three中称之为相机(Camera)在场景中添加供观察的物体
Three中的物体有很多种,包括Mesh,Line,Points等,它们都继承⾃Object3D类将观察到的场景渲染到屏幕上的指定区域
Three中使⽤Renderer完成这⼀⼯作
下⾯来具体看⼀看Three中的这些概念。
Scene
场景是所有物体的容器,也对应着我们创建的三维世界。
Camera 坐标系
Camera是三维世界中的观察者,为了观察这个世界,⾸先我们要描述空间中的位置。
Three中使⽤采⽤常见的右⼿坐标系定位。
三维投影
Three中的相机有两种,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。
正交投影与透视投影的区别如上图所⽰,左图是正交投影,物体发出的光平⾏地投射到屏幕上,远近的⽅块都是⼀样⼤的;右图是透视投影,近⼤远⼩,符合我们平时看东西的感觉。
:三维投影
正交投影相机
注:图中的”视点”对应着Three中的Camera。
这⾥补充⼀个视景体的概念:视景体是⼀个⼏何体,只有视景体内的物体才会被我们看到,视景体之外的物体将被裁剪掉。这是为了去除不必要的运算。
正交投影相机的视景体是⼀个长⽅体,OrthographicCamera的构造函数是这样的:OrthographicCamera( left, right, top, bottom, near, far )
Camera本⾝可以看作是⼀个点,left则表⽰左平⾯在左右⽅向上与Camera的距离。另外⼏个参数同理。
于是六个参数分别定义了视景体六个⾯的位置。
可以近似地认为,视景体⾥的物体平⾏投影到近平⾯上,然后近平⾯上的图像被渲染到屏幕上。
透视投影相机
透视投影相机的视景体是个四棱台,它的构造函数是这样的:PerspectiveCamera( fov, aspect, near, far )
fov对应着图中的视⾓,是上下两⾯的夹⾓。aspect是近平⾯的宽⾼⽐。在加上近平⾯距离near,远平⾯距离far,就可以唯⼀确定这个视景体了。
透视投影相机很符合我们通常的看东西的感觉,因此⼤多数情况下我们都是⽤透视投影相机展⽰3D效果。
Objects
有了相机,总要看点什么吧?在场景中添加⼀些物体吧。
Three中供显⽰的物体有很多,它们都继承⾃Object3D类,这⾥我们主要看⼀下Mesh和Points两种。
Mesh
我们都知道,计算机的世界⾥,⼀条弧线是由有限个点构成的有限条线段连接得到的。线段很多时,看起来就是⼀条平滑的弧线了。
计算机中的三维模型也是类似的,普遍的做法是⽤三⾓形组成的⽹格来描述,我们把这种模型称之为Mesh模型。
这是那只著名的斯坦福兔⼦。它在3D图形中的地位与数字图像处理领域中著名的lena是类似的。
看这只兔⼦,随着三⾓形数量的增加,它的表⾯越来越平滑/准确。
在Three中,Mesh的构造函数是这样的:Mesh( geometry, material )
geometry是它的形状,material是它的材质。
不⽌是Mesh,创建很多物体都要⽤到这两个属性。下⾯我们来看看这两个重要的属性。
Geometry
Geometry,形状,相当直观。Geometry通过存储模型⽤到的点集和点间关系(哪些点构成⼀个三⾓形)来达到描述物体形状的⽬的。
Three提供了⽴⽅体(其实是长⽅体)、平⾯(其实是长⽅形)、球体、圆形、圆柱、圆台等许多基本形状;
你也可以通过⾃⼰定义每个点的位置来构造形状;
对于⽐较复杂的形状,我们还可以通过外部的模型⽂件导⼊。
Material
Material,材质,这就没有形状那么直观了。
材质其实是物体表⾯除了形状以为所有可视属性的集合,例如⾊彩、纹理、光滑度、透明度、反射率、折射率、发光度。
这⾥讲⼀下材质(Material)、贴图(Map)和纹理(Texture)的关系。
材质上⾯已经提到了,它包括了贴图以及其它。
贴图其实是‘贴'和‘图',它包括了图⽚和图⽚应当贴到什么位置。
纹理嘛,其实就是‘图'了。
Three提供了多种材质可供选择,能够⾃由地选择漫反射/镜⾯反射等材质。
Points
讲完了Mesh,我们来看看另⼀种Object——Points。
Points其实就是⼀堆点的集合,它在之前很长时间都被称为ParticleSystem(粒⼦系统),r68版本时更名为PointCloud,r72版本时才更名为Points。更名主要是因为,Mr.doob认为,粒⼦系统应当是包括粒⼦和相关的物理特性的处理的⼀套完整体系,⽽Three中的Points简单得多。因此最终这个类被命名为Points。
Points能够⽤来实现的典型效果是这样的:官⽅example
Light
神说:要有光!
光影效果是让画⾯丰富的重要因素。
Three提供了包括环境光AmbientLight、点光源PointLight、聚光灯SpotLight、⽅向光DirectionalLight、半球光HemisphereLight等多种光源。
只要在场景中添加需要的光源就好了。
Renderer
在场景中建⽴了各种物体,也有了光,还有观察物体的相机,是时候把看到的东西渲染到屏幕上了。这就是Render做的事情了。
Renderer绑定⼀个canvas对象,并可以设置⼤⼩,默认背景颜⾊等属性。
调⽤Renderer的render函数,传⼊scene和camera,就可以把图像渲染到canvas中了。
让画⾯动起来
现在,⼀个静态的画⾯已经可以得到了,怎么才能让它动起来?
很简单的想法,改变场景中object的位置啊⾓度啊各种属性,然后重新调⽤render函数渲染就好了。
那么重新渲染的时机怎么确定?
HTML5为我们提供了requestAnimFrame,它会⾃动在每次页⾯重绘前调⽤传⼊的函数。
如果我们⼀开始这样渲染:
function render()
{
}
只需要改成这样:
function render()
{
requestAnimationFrame(render);
object.position.x += 1;
}
object就可以动起来了!
举个栗⼦
下⾯我们⽤⼀个简单的例⼦来梳理⼀下这个过程。
⾸先写⼀个有Canvas元素的页⾯吧。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>⽴⽅体</title>
<script src="sqimg.qq/qq_product_operations/mma/javanli_test/lib/three.min.js"></script>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
}
#three_canvas {
position: absolute;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="three_canvas"></canvas>
</body>
</html>
下⾯来做Javascript的部分
⾸先初始化Renderer
function initRenderer() {
width = ElementById('three_canvas').clientWidth;
height = ElementById('three_canvas').clientHeight;
renderer = new THREE.WebGLRenderer({
//将Canvas绑定到renderer
canvas: ElementById('three_canvas')
});
renderer.setSize(width, height);//将渲染的⼤⼩设为与Canvas相同
renderer.setClearColor(0xFFFFFF, 1.0);//设置默认颜⾊与透明度
}
初始化场景:
function initScene() {
scene = new THREE.Scene();
}
初始化相机:
function initCamera() {
//简单的正交投影相机,正对着视⼝的中⼼,视⼝⼤⼩与Canvas⼤⼩相同。
camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, 1, 1000);
//设置相机的位置
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 200;
//设置相机的上⽅向
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
//设置相机聚焦的位置(其实就是确定⼀个⽅向)
camera.lookAt({
x: 0,
y: 0,
javascript是什么意思中文翻译z: 0
});
}
要唯⼀确定⼀个相机的位置与⽅向,position、up、lookAt三个属性是缺⼀不可的。
这⾥我们创建了⼀个正交投影相机,这⾥我将视景体⼤⼩与屏幕分辨率保持⼀致只是为了⽅便,这样坐标系中的⼀个单位长度就对应屏幕的⼀个像素了。
我们将相机放在Z轴上,⾯向坐标原点,相机的上⽅向为Y轴⽅向,注意up的⽅向和lookAt的⽅向必然是垂直的(类⽐⾃⼰的头就知道了)。
下⾯添加⼀个⽴⽅体到场景中:
function initObject() {
//创建⼀个边长为100的⽴⽅体
var geometry = new THREE.CubeGeometry(100, 100, 100);
object = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial());
scene.add(object);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。