本节课讲解如何通过ShaderMaterial
编写顶点矩阵变换的代码,Three.js的渲染器解析场景和相机参数进行渲染的时候,会从模型对象获得几何体顶点对应的模型矩阵modelMatrix
,从相机对象获得视图矩阵viewMatrix
和投影矩阵projectionMatrix
,在着色器中通过获得模型矩阵、视图矩阵、投影矩阵对顶点位置坐标进行矩阵变换。
本节课不会详细去解释模型矩阵、视图矩阵、投影矩阵的具体算法,主要是讲解这些矩阵在three.js自定义着色器的时候,如何更好的使用。
模型矩阵包含了一个几何体的旋转、平移、缩放变换。
如果你有基本的图形学和线性代数知识,应该知道几何平移、缩放、旋转变换都是几何变换的一部分,几何变换可以使用线性代数的矩阵来表示,平移对应一个平移矩阵,旋转一个对应旋转矩阵,一个几何体经过了多次旋转、平移等几何变换,每一个变换都有一个对应的矩阵可以表示,所有几何变换对应矩阵的乘积就是一个复合矩阵,可以称为模型矩阵modelMatrix
。
使用ShaderMaterial编写着色器代码的时候,模型矩阵modelMatrix
不用程序员手动声明,Three.js渲染器
系统渲染的时候会自动往ShaderMaterial顶点着色器字符串中插入一句uniform mat4 modelMatrix;
<script id="vertexShader" type="x-shader/x-vertex">
// uniform mat4 modelMatrix;//不需要声明
void main(){
// 模型矩阵modelMatrix对顶点位置坐标进行模型变换
gl_Position = modelMatrix*vec4( position, 1.0 );
}
</script>
modelMatrix
变量数据传递查看网格模型Mesh的基类Object3D
可知道网格模型有一个本地矩阵属性.matrix
,.matrix
的属性值是一个Three.js的矩阵对象Matrix4
。对网格模型进行平移、旋转、缩放等几何变换都会改变网格模型本地矩阵属性.matrix
的属性值。
mesh.rotateY(Math.PI/6);
mesh.rotateX(Math.PI/6);
如果网格模型mesh有一个父对象,父对象的几何变换同样会传递到网格模型,也就是说顶点着色器中默认的模型矩阵变量modelMatrix
对应的不是网格模型自身的几何变换,而是网格模型的自身以及它所有父对象的几何变换,一个网格模型自身以及父对象所有的几何变换,会体现在自己的世界矩阵属性.matrixWorld
上。
一个网格模型mesh都包含一个几何体Geometry,一个几何体中有一系列的顶点位置数据,这些顶点位置数据需要传递给着色器中顶点位置变量position,同样着色器中uniform
关键字声明的模型矩阵变量modelMatrix也需要传递矩阵数据。
Three.js渲染器渲染的时候会自动从一个Threejs的模型对象提取它世界矩阵属性.matrixWorld
的属性值,然后传递给着色器的模型矩阵变量modelMatrix,这个过程不需要程序员设置,Three.js系统会自动完成。如果你编写WebGL原生代码都知道需要调用WebGL的相关API完成数据的传递过程,比较麻烦,对于开发者来说不太友好,为了开发者更好的编写着色器代码,Three.js引擎封装了这些WebGL API。
相机对象本质上就是存储视图矩阵和投影矩阵的信息的一个对象,基类Camera
的.matrixWorldInverse
属性对应的就是着色器中视图矩阵变量viewMatrix
,基类Camera
的投影矩阵属性.projectionMatrix
对应着色器中的投影矩阵变量projectionMatrix
。
使用ShaderMaterial构造函数自定义顶点着色器的时候,视图矩阵viewMatrix
和投影矩阵projectionMatrix
一样不需要手动声明,WebGL渲染器会通过WebGLProgram.js
模块自动声明这两个变量,在顶点着色器代码中插入uniform mat4 viewMatrix;
和uniform mat4 projectionMatrix;
。
Three.js渲染器执行renderer.render(scene, camera)
的时候,会解析相机对象的信息,把相机的矩阵数据自动传递给着色器中的视图矩阵变量viewMatrix
和投影矩阵变量projectionMatrix
。
<script id="vertexShader" type="x-shader/x-vertex">
void main(){
gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );
}
</script>
模型矩阵和视图矩阵构成的复合矩阵称为模型视图矩阵,简称模视矩阵modelViewMatrix
,模视矩阵和模型、视图、投影矩阵的使用方式是一样,系统会在着色器代码自动声明该变量,同时把相关的矩阵数据传递给该变量。
<script id="vertexShader" type="x-shader/x-vertex">
void main(){
gl_Position = projectionMatrix*modelViewMatrix*vec4( position, 1.0 );
}
</script>
在原生WebGL编程的时候,WebGL坐标系的z轴垂直canvas画布,x和y轴分别对应于canvas画布的水平和竖直方向,你可以发现能够显示在canvas画布上的顶点坐标范围是[-1,1],如果顶点的xyz某个分量上的坐标值不在-1~1区间内会被剪裁掉不显示。
平时编写Three.js应用程序程序,默认情况下,在Three.js系统中一个模型对应的顶点要经过模型、视图和投影变换后才会在canvas画布上显示出来,如果一个顶点的坐标向量经过一系列的矩阵变换后超出了[-1,1]范围,就不会显示在canvas画布上,平时编程的时候,你可以能会遇到相机参数设置不合适看不到场景中模型的情况,因为视图、投影矩阵的值是由相机的具体参数决定的,相机参数不合适,视图、投影矩阵就会对模型进行不合理的缩放和偏移,导致canvas画布上看不到场景中的模型。