# Three.js 的工作机制及基础概念
整个概念之间的结构:
Three.js
使得在浏览器展示 3D 图像变得容易,它的底层是基于WebGL
,它使浏览器能借助系统显卡在 canvas 中绘制 3D 画面。
WebGL
自身只能绘制点(points)、线(lines)和三角形(triangles),而Three.js
对WebGL
进行了封装,使我们能够非常方便地创建 物体(objects), 纹理(textures), 进行 3D 计算等操作。
使用Three.js
,我们将所有物体(objects)添加到场景(scene)中,然后将需要渲染的数据传递给渲染器(renderer),渲染器负责将场景在 <canvas>
画布上绘制出来。
# 1. 场景: scene
对于一个 Three.js
应用,最核心的就是场景(scene object),上面是一张场景图(scene graph)。
在一个 3D 引擎中,场景图是一个层级结构的树状图,树中的每一个节点代表空间中的一部分。这种结构有点像 DOM 树,但Three.js
的场景(scene)更像虚拟 DOM,它只更新和渲染场景中有变化的部分。而这一切的基础,是 Three.js 的 WebGLRenderer
类,它把我们的代码转换成 GPU 中的数据,浏览器再将这些数据渲染出来。
var scene = new THREE.Scene();
# 2. 网格:Mesh
场景中的物体,也叫Mesh
。在 Three.js
的世界中,Mesh 是由 几何体Geometry
(决定物体形状) + 材质Material
(决定物体外观)构成。
//创建一个Mesh(绿色的3D立方体),并添加到场景中
var geometry = new THREE.BoxGeometry();
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
# 3. 相机: camera
场景中的另一个重要元素,就是相机camera
,它决定了场景中 哪些部分以怎样的视觉效果 被绘制在canvas
画布上。
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
//设置照相机的位置
camera.position.z = 5;
# 4. 动画: animation
然后是动画,为了实现动画,渲染器(renderer)通常使用requestAnimationFrame()
方法,以每秒 60 次的频率将场景更新绘制在canvas
上。requestAnimationFrame()
方法的原理和使用可以参考MDN (opens new window)。
//创建渲染器,设置尺寸为窗口尺寸,并将渲染后的元素添加到body
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
function render() {
renderer.render(scene, camera); //执行渲染操作
cube.rotateY(0.01); //每次绕y轴旋转0.01弧度
requestAnimationFrame(render); //请求再次执行渲染函数render
}
render();
在实际执行程序的时候,可能requestAnimationFrame(render)请求的函数并不一定能按照理想的60FPS频率执行,两次执行渲染函数的时间间隔也不一定相同,如果执行旋转命令的rotateY的时间间隔不同,旋转运动就不均匀,为了解决这个问题需要记录两次执行绘制函数的时间间隔。
使用下面的渲染函数替换原来的渲染函数即可,rotateY()的参数是0.001t,也意味着两次调用渲染函数执行渲染操作的间隔t毫秒时间内,立方体旋转了0.001t弧度,很显然立方体的角速度是0.001弧度每毫秒(0.0001 rad/ms = 1 rad/s = 180度/s)。CPU和GPU执行一条指令时间是纳秒ns级,相比毫秒ms低了6个数量级,所以一般不用考虑渲染函数中几个计时语句占用的时间,除非你编写的是要精确到纳秒ns的级别的标准时钟程序。
let T0 = new Date();//上次时间
function render() {
let T1 = new Date();//本次时间
let t = T1-T0;//时间差
T0 = T1;//把本次时间赋值给上次时间
requestAnimationFrame(render);
renderer.render(scene,camera);//执行渲染操作
mesh.rotateY(0.001*t);//旋转角速度0.001弧度每毫秒
}
render();
# 材质
摘录自: Three.js零基础入门教程(郭隆邦) (opens new window)
为了方便开发Threejs提供了一系列的材质,所有材质就是对WebGL着色器代码的封装,如果你不了解WebGL,会通过查阅Threejs文档使用相关材质类即可。
# 点材质PointsMaterial
点材质比较简单,只有PointsMaterial
,通常使用点模型的时候会使用点材质PointsMaterial
。
点材质PointsMaterial
的.size
属性可以每个顶点渲染的方形区域尺寸像素大小。
var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象
// 创建一个点材质对象
var material = new THREE.PointsMaterial({
color: 0x0000ff, //颜色
size: 3, //点渲染尺寸
});
//点模型对象 参数:几何体 点材质
var point = new THREE.Points(geometry, material);
scene.add(point); //网格模型添加到场景中
# 线材质
线材质有基础线材质LineBasicMaterial
和虚线材质LineDashedMaterial
两个,通常使用使用Line
等线模型才会用到线材质。
# 基础线材质LineBasicMaterial
。
var geometry = new THREE.SphereGeometry(100, 25, 25);//球体
// 直线基础材质对象
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var line = new THREE.Line(geometry, material); //线模型对象
scene.add(line); //点模型添加到场景中
# 虚线材质LineDashedMaterial
。
// 虚线材质对象:产生虚线效果
var material = new THREE.LineDashedMaterial({
color: 0x0000ff,
dashSize: 10,//显示线段的大小。默认为3。
gapSize: 5,//间隙的大小。默认为1
});
var line = new THREE.Line(geometry, material); //线模型对象
// computeLineDistances方法 计算LineDashedMaterial所需的距离数组
line.computeLineDistances();
# 网格模型
Threejs提供的网格类材质比较多,网格材质涉及的材质种类和材质属性也比较多,一节课也无法讲解完,本节课先有一个感性的认知。
网格材质顾名思义,网格类模型才会使用的材质对象。
基础网格材质对象MeshBasicMaterial
,不受带有方向光源影响,没有棱角感。
var material = new THREE.MeshBasicMaterial({
color: 0x0000ff,
})
MeshLambertMaterial
材质可以实现网格Mesh表面与光源的漫反射光照计算,有了光照计算,物体表面分界的位置才会产生棱角感。
var material = new THREE.MeshLambertMaterial({
color: 0x00ff00,
});
高光网格材质MeshPhongMaterial
除了和MeshLambertMaterial
一样可以实现光源和网格表面的漫反射光照计算,还可以产生高光效果(镜面反射)。
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
specular:0x444444,//高光部分的颜色
shininess:20,//高光部分的亮度,默认30
});
# 精灵材质
精灵是一个总是面朝着摄像机的平面,通常含有使用一个半透明的纹理。
var spriteMap = new THREE.TextureLoader().load( "sprite.png" );
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap, color: 0xffffff } );
var sprite = new THREE.Sprite( spriteMaterial );
scene.add( sprite );
# 材质和模型对象对应关系
使用材质的时候,要注意材质和模型的对应关系,通过前面课程案例学习,目前为止你至少应该了解到了网格模型Mesh
、点模型Points
、线模型Line
,随着课程的学习其它的模型对象也会接触到,这里先有个印象就可以。
- 本文链接: https://mrgaogang.github.io/threejs/threejs%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.html
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!