技术咨询、项目合作、广告投放、简历咨询、技术文档下载 点击这里 联系博主

# Three.js 的工作机制及基础概念

整个概念之间的结构:

Three.js使得在浏览器展示 3D 图像变得容易,它的底层是基于WebGL,它使浏览器能借助系统显卡在 canvas 中绘制 3D 画面。

WebGL自身只能绘制点(points)、线(lines)和三角形(triangles),而Three.jsWebGL进行了封装,使我们能够非常方便地创建 物体(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,随着课程的学习其它的模型对象也会接触到,这里先有个印象就可以。

【未经作者允许禁止转载】 Last Updated: 2/4/2024, 6:06:40 AM