Three.js 着色器 shader_ShaderMaterial 介绍
学习 Three.js 的着色器的内容之前,最好有一些 WebGL 的基础,可以不深入了解,但是要对 WebGL 渲染流程和着色器语言 GLSL 有一定的基本认知。如果你没有 WebGL 基础,可以学习下本站的 WebGL 视频教程。
MeshPhongMaterial、PointsMaterial 等 three.js 的材质材质对象本质上都是着色器代码,Three.js 的 WebGL 渲染器在调用渲染方法render渲染场景的时候,会根据材质的 type 值调用路径 src\renderers\shaders
下的着色器代码编译后在GPU中执行。
Three.js 提供了 RawShaderMaterial
和 ShaderMaterial
两个 API 用来辅助开发者自定义着色器代码。这个着色器 API 和其它的 three.js 的材质对象的基类一样都是 Material
,会继承基类 Material
的属性和方法。
ShaderMaterial
ShaderMaterial 构造函数的参数和其它材质对象构造函数一样是一个对象,参数对象包含一些特定的属性,执行构造函数参数对象的属性会转化为材质对象对应的属性。
ShaderMaterial 顶点着色器和片元着色器属性
GPU的顶点着色器单元用来处理顶点位置、顶点颜色、顶点向量等等顶点数据,片元着色器单元用来处理片元(像素)数据。一个WebGL程序的着色器代码包含顶点着色器和片元着色器,顶点着色器代码运行在GPU的顶点着色器单元,片元着色器代码运行在片元着色器单元。
ShaderMaterial对象具有两个用来设置自定义着色器代码的属性,顶点着色器属性vertexShader
和片元着色器属性fragmentShader
,顶点着色器属性vertexShader
的属性值是顶点着色器代码字符串,片元着色器属性fragmentShader
的属性值是片元着色器代码字符串。
着色器代码编写
通过three.js的着色器材质构造函数ShaderMaterial编写着色器代码和原生WebGL中编写着色器代码语法上是一样的,不同的地方在于更加方便,有些代码不用自己写,Three.js渲染器会帮你自动设置一些代码,比如声明一些常见的变量,通常来说在顶点着色器中把表示顶点的位置数据的变量position
赋值给着色器内置变量gl_Position
,需要首先声明attribute vec3 position;
,如果使用ShaderMaterial
构造函数,则不用程序员手动声明position
变量,Three.js渲染器后自动帮你拼接一段该代码,具体的原理可以参考路径three.js-master\src\renderers\webgl\WebGLProgram.js
下的WebGLProgram.js
代码模块,Threejs渲染器在渲染场景的时候从ShaderMaterial提取着色器代码后,会拼接一段前缀字符串,然后才会传入GPU中执行,前缀包含一些常用的attribute
变量和uniform
变量。关于着色器材质对象ShaderMaterial的一些系统自动化处理的地方这里先不展开讲解,后面会逐步讲解。
顶点着色器代码
<script id="vertexShader" type="x-shader/x-vertex">
// 使用ShaderMaterial类,顶点位置变量position无需声明,顶点着色器可以直接调用
// attribute vec3 position;
void main(){
// 逐顶点处理:顶点位置数据赋值给内置变量gl_Position
gl_Position = vec4( position, 1.0 );
}
</script>
片元着色器代码
<script id="fragmentShader" type="x-shader/x-fragment">
void main() {
// 逐片元处理:每个片元或者说像素设置为红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
设置 vertexShader
和 fragmentShader
属性值
通过元素 .textContent
属性返回<script>
标签中着色器代码字符串,然后把着色器字符串赋值给ShaderMaterial材质对象对应的属性。
var material = new THREE.ShaderMaterial({
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
});
ShaderMaterial和其它Three.js的材质一样作为网格模型或点线模型对象的参数使用。
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
顶点数据自动化传递
在原生WebGL代码中,如果顶点或片元着色器代码如果声明了一个变量,比如顶点着色器中声明了一个顶点位置变量attribute vec3 position;
,需要通过WebGL API把JavaScript中的几何体顶点位置数据传递给顶点着色器中的顶点位置变量position
,这样的话,CPU执行顶点着色器代码的时候才能够处理顶点数据。
使用ShaderMaterial API的好处就是这个过程Three.js渲染器系统会自动解析几何体对象Geometry
中顶点位置、颜色、法向量等数据,然后传递给着色器中的相应变量。具体的解析过程可以参考路径three.js-master\src\renderers\
下的渲染器代码WebGLRenderer.js
文件和路径three.js-master\src\renderers\webgl
下面多个three.js文件。
WebGL渲染器在解析模型几何体中顶点数据的时候,Geometry
类型的几何体会自动转化为缓冲类型的几何体BufferGeometry
,
BufferGeometry几何体对象具有.attributes
属性,BufferGeometry.attributes
具有顶点位置、顶点法向量、顶点uv坐标等属性,对应着色器中相应的attribute变量。
可以通过 BufferGeometry
或 Geometry
API创建一个空的几何体,然后手动设置顶点数据,也可以使用一些立方体或其他几何体的API创建一个几何体API,使用这些几何体API的时候,会自动生成顶点的相关数据,然后渲染的时候,WebGL渲染器自动传递给着色器中声明的相应变量。关于几何体BufferGeometry
和顶点相关知识这里不再展示详述,有不理解的地方可以多学习原生WebGL教程和本站Threejs视频教程中关于几何体顶点讲解的章节。
var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
var vertices = new Float32Array([
0.6, 0.2, 0, //顶点1坐标
0.7, 0.6, 0, //顶点2坐标
0.8, 0.2, 0, //顶点3坐标
-0.6, -0.2, 0, //顶点4坐标
-0.7, -0.6, 0, //顶点5坐标
-0.8, -0.2, 0, //顶点6坐标
]);
// 创建属性缓冲区对象 3个为一组,表示一个顶点的xyz坐标
var attribue = new THREE.BufferAttribute(vertices, 3);
// 设置几何体attributes属性的位置属性
geometry.addAttribute( 'position', attribue );
RawShaderMaterial
原生着色器材质对象 RawShaderMaterial 和着色器材质对象 ShaderMaterial 一样具有顶点着色器和片元着色器属性,同样可以自动传递顶点数据,区别在于着色器中使用的一些常见attribute或 uniform 变量,原生着色器材质对象RawShaderMaterial需要程序员手动编写,系统不会自动化添加变量声明的前缀。
顶点着色器代码,自动声明顶点位置属性 position
变量。
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec3 position;
void main(){
gl_Position = vec4( position, 1.0 );
}
</script>
绘制模式
如果你对WebGL或OpenGL有一点了解,应该都知道,一系列的顶点数据可以通过绘制模式来控制渲染效果,一个顶点数据可以渲染为一个点,也可以使用线条模式把点连成线绘制出来,也可以通过三角形模式每三个点绘制一个三角面来,一系列三角形构成一个网格模型。
Three.js 渲染器解析渲染的时候会根据模型的类型来判断如何渲染,解析点模型 Points
的时候,会启用点渲染模式,解析线模型 Line
、LineLoop
、LineSegments
的时候,会启用对应的线条绘制模式,解析网格模型 Mesh
会启用三角形绘制模式。
点绘制模式,在顶点着色器代码中可以通过设置内置变量 gl_PointSize
设置点的渲染大小,如果直线或三角形绘制模式不需要内置变量 gl_PointSize
。
var point = new THREE.Points(geometry, material);
void main(){
gl_PointSize=20.0;// 控制渲染的点大小
gl_Position = vec4( position, 1.0 );
}
直线绘制模式,连点成线
var line = new THREE.Line(geometry, material);
三角形绘制模式,三个顶点确定一个三角形,一个个三角形区域构成一个网格模型
var mesh = new THREE.Mesh(geometry, material);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论