-
shape 图形
-
option 配置
-
配置:steps 沿着路径的节点数目
-
配置:excludePath 拉伸路径
-
更多直接看 doc
Geometry 提供 vertices、faces、uvs 的属性操作的是普通数组,BufferGeometry 直接操作的是类型数组,将类型数组作为 Attribute 来管理,从速度上来说 BufferGeometry 更快,Geometry 内部会将以上属性转化成类型数组传给 GPU,从类的方法来说,两者除了操作自身私有属性的方法不同,对几何图形的操作的方法接口一致
WebGL 点线面
WebGL 没有图形的概念,只有点和索引组成的三角片
点和索引:WebGL 对图形有一种标准的处理方式,与我们拥有的表面的复杂性和顶点个数无关,只有两种基础的数据类型来表达 3D 物体的几何形状:Vertices 和 Indices,也就是顶点和索引
Vertices:代表 3D 物体的拐点,每个顶点用 3 个数字来表达 x/y/z,WebGL 中没有提供 API 来将独立的顶点传递到渲染管线中,因此需要将所有的顶点放在数组当中,然后通过这个数组来构造一个 WebGL 顶点缓存区(Vertices buffer)
Indices:索引是在一个给定的 3D 场景中所有顶点的数字标识,索引告诉 WebGL 如何有序的链接顶点生成一个表面。和顶点一样,索引也是存储在数组中,然后使用WebGL 索引缓存区传递给 WebGL 的渲染管线
有两种 WebGL 缓存区来描述和处理几何图形
-
包含顶点数据的缓存区:Vertex Buffer Objects(VBO)
-
包含索引数据的缓存区:Index Buffer Objects(IBO)
存在另一种表现形式,不用索引数据,直接使用顶点数组,同时表示出点之间的关系,但由于会存在图形公用顶点的情况,因此数据会有冗余
-
顶点着色器
-
片元着色器
WebGL 的渲染管线,JavaScript 数组通过类型数组传递到缓存区,缓存去传递到 GPU,经过顶点着色器确定点位置,顶点颜色等,然后进入片元着色器为其中的每个像素进行着色
WebGL 渲染流程
-
获取 WebGL 上下文
-
初始化着色器程序
-
初始化缓存区
Three 对渲染管线的封装,BufferGeometry 绘制三角形,设置三个重要的 attribute 数据
-
顶点 position
-
法线 normal:光照模型的渲染
-
颜色 color
现实生活中我们能看见物体是因为它们反射光,所有的物体根据它们的位置和与光源的相对距离反射的光是不同的,物体表面的法线代表表面的方向决定反射光的反向,表面的材料决定多少强度的光会被反射
光源:光源可以具有位置也可以只具有方向。当光源的位置能够影响场景的照亮时它就是点光源。方向光源指的是无论它的位置在哪都将对场景产生相同的光亮效果,如太阳光,这类光源也叫平行光。点光源通常用一个场景中的点来建模,而平行光通常用向量来代表它的方向,为了简便计算,通常用单位向量
法线:法线是垂直于我们想要照亮的物体表面的向量。法线代表表面的的方向,因此它们为光源和物体的交互建模中具有决定性作用
如何确定一个三角形的法线呢?
-
确定三角形的两边向量,两个向量确定一个面
-
两向量叉乘计算出该面法线向量
材料:WebGL 中的物体的材料需要结合它的颜色、纹理等多个参数来建模。材料颜色通常用 RGB 表示,材料的纹理与被匹配在物体表面的图像有关,为表面匹配图像的过程叫做纹理贴图
Goraud 插值:Goraud 插值方法在顶点着色器中计算最终颜色。顶点法线在这里的计算中使用,然后顶点的最终颜色使用 varying 变量传递到片元着色器中。由于 varying 变量在渲染管道中会被自动进行插值,每一个片元的最终颜色是由包含它的封闭三角形的三个顶点颜色决定的
Phong 插值:Phong 插值在片元着色器中计算出最终颜色。每个顶点法线通过 varying 变量沿着顶点着色器传递到片元着色器中。因为 varying 类型的插值机制被包含在管线中,所以每一个片元都有自己的法线,然后片元法线在片元着色器中来计算出最终的颜色。
Lambertian 反射模型:Lambertian 反射常用于计算机图形学中为漫反射建模,漫反射指的是入射光朝多个角度发射而不是只朝一个角度反射(镜面反射)。该条件下光照模型遵循余弦反射模型。Lambertian 反射通常使用表面法线和光照方向的负向量的点乘积,然后得到的结果乘以材料颜色和光源颜色。
Phong 反射模型:在 Phong 反射模型的描述中,表面反射光由三部分组成:环境光 + 漫反射 + 镜面反射
Three.js 的封装
-
Light:所有光源的基类
-
AmbientLight:周围环境光只有颜色,没有位置和方向
-
DirectionalLight:方向光只有方向和颜色,没有位置,position 属性代表向
-
PointLight:从一个点向周围发射光线,光照强度随距离衰减,position 代表位置
-
SpotLight 聚光灯
-
RectAreaLight:矩形区域光源,可以用来模拟透光窗户或条形灯
ELSL 着色器语言
存储限定符
-
attribute
-
只存在于顶点着色器
-
用于保存顶点属性数据,如位置、法线、颜色等
-
uniform
-
依次渲染中始终保持不变的量
-
可以存在于顶点着色器和片元着色器中
-
如果存在于两种着色器中,则变量名必须保持一致
-
varying
-
在顶点着色器和片元着色器之间传递插值数据
-
两种着色器中声明的变量名需要保持一致
-
基本变量类型:bool、int、float
-
向量类型:vec2、vec3……
-
矩阵类型:mt2、mt3、mt4
-
纹理类型:sampler2D、samplerCube
-
{x,y,z,w}
-
{r,g,b,a}
-
{s,t,p,q} 纹理坐标
操作符和函数
-
dot(x,y) 点乘
-
cross(x,y) 叉乘
-
matrixCompMult(mat x,mat y) 矩阵相乘
-
normalize(x) 向量标准化
-
reflect(t,n) 根据向量 t 求出关于法线 n 的反射向量
Three.js 对着色器的封装
-
WebGLProgram
-
WebGLShader
-
shaders 目录
ShaderMaterial:Three.js 暴露给开发者的着色器底层封装类,可以通过直接编写着色器来实现 Three.js 未提供的效果,灵活性高,难度大
WebGL 矩阵
空间变换工具:矩阵
-
加/减:简单的各位置相加减
-
数乘:均乘以该数
-
转置:行变列
-
乘法:
m * n
和
n * p
的乘积是一个
m * p
矩阵
-
逆矩阵:AB = BA = E
WebGL 使用的是列向量
平移和旋转的先后顺序,当矩阵相乘时,在最右边的是第一个与向量相乘的,所以应该从右往左读这个乘法。因此先旋转后平移的矩阵操作是 TRV。因为矩阵乘法不遵循交换率,因此顺序很重要。
因此在组合矩阵时,建议先缩放操作,然后是旋转,最后才是位移,否则他们会消极的互相影响
点击拾取基本原理
-
屏幕坐标转 ndc 坐标([-1, 1])
-
ndc 坐标转 3D 坐标
-
依次判断每个物体包络球是否与射线相交
-
依次判断每个物体的表面是否与射线相交
RayCaster:Three.js 封装的用来做射线检测的类,通常用它来做点击拾取等需要射线检测的场景
-
new THREE.Raycaster
-
raycaster.setFromCamera(ndc, camera)
-
raycaster.intersectObjects(objects)
-
distance:相机距离相交点具体
-
face:与射线相交的物体的第一个表面
-
faceIndex:与射线相交的物体的第一个表面的索引
-
object:相交物体
-
point:射线与物体相交点
-
uv:相交点的纹理坐标
天空盒效果
-
六张简单的图片实现天空的效果和场景背景效果
-
本质是立方体模型,需要前后左右上下天上 6 个不同的图片作为贴图
Three 内置 ImageUtils 提供了 loadTexture 函数用来加载贴图
背景音乐:直接使用 audio 标签即可
Object3D 函数解释
-
add:添加对象到这个对象的子级,被添加对象坐标变换变成相对该对象的局部坐标
-
attach:将 object 作为子级来添加到该对象中,同时保持该object 的世界变换。
-
clone:返回物体的克隆
-
copy:复制给定对象到该对象中
释放内存:dispose 函数 -- 有待深入研究
针对大规模的建筑群,可以将不很重要的建筑进行 merge,这样可以大大的提高渲染效率。
废置对象目标:几何体(不仅仅是 Mesh)、材质(Material)、纹理(Texture)、渲染目标、Scene、其他项:(来自 example 目录类,比如控制器和后期处理过程)
原则:如果存在 dispose 函数,就应当在清理的时候使用它
你可能需要知道:
-
对于 mesh 清除,它的 geometry 和 material 并不会自动清除
-
非 Group 对象 children 也是可能有值的,比如调用 add/attach 函数
-
traverse 会迭代自身以及子子孙孙,从上到下,从左到右
-
material 可能是数组
-
检查 material 上是否存在 texture
经实践,dispose 只是清除 three 中对象的引用,自身对于 geometry、material 等引用也必须切断(赋空或 delete 表达式),否则无效
更新几何体
基于性能的原因,改变几何体的某些属性不会引起浏览器对几何体的重新绘制。Three.js 会缓存一些数据,比如几何体的顶点和面信息,修改这些属性的时候需要通知 Three.js 去更新几何体,这些几何体才能得到重新计算并更新
下面属性的变动需要通知 THREE.js 更新
-
geometry.vertices
-
geometry.faces
-
geometry.morphTargets
-
geometry.faceVertexUvs
-
geometry.faces[i].normal and geometry.vertices[i].normal
-
geometry.faces[i].color and geometry.vertices[i].color
-
geometry.vertices[i].tangent
-
geometry.lineDistances
针对不同的属性变化,都可以设置该几何体实例的某个属性值为 true 来通知 THREE.js 重新计算这些几何体并更新,当更新了这些几何体之后,这些属性值又会被重新设置为 false。
-
colorsNeedUpdate : geometry.faces[i].color and geometry.vertices[i].color发生变化的时候设置为true
-
verticesNeedUpdate:geometry.vertices发生变化的时候设置为true
-
elementsNeedUpdate:geometry.faces发生变化的时候设置为true
-
morphTargetsNeedUpdate:geometry.morphTargets发生变化的时候设置为true
-
uvsNeedUpdate:geometry.faceVertexUvs发生变化的时候设置为true
-
normalsNeedUpdate:geometry.faces[i].normal and geometry.vertices[i].normal发生变化的时候设置true
-
tangentsNeedUpdate:geometry.vertices[i].tangent发生变化的时候设置为true
-
needsUpdate:我们也可以动态的修改纹理和材质,材质发生改变的时候将material.needsUpdate设置为true来通知THREE.js重新进行计算绘制。
-
Three.js入门指南
-
一篇文章弄懂THREE.js中的各种矩阵关系
-
Three.js 内存清理
-
Three.js Cleanup