WebGL教程_Three.js教程_郭隆邦技术博客 郭隆邦_技术博客 注册

Three.js自定义着色器Shader

学习Three.js的着色器的内容之前,最好有一些WebGL的基础,可以不深入了解,但是要对WebGL渲染流程和着色器语言GLSL有一定的基本认知。如果你没有WebGL基础,可以学习下本站的WebGL视频教程。

MeshPhongMaterial、PointsMaterial等three.js的材质材质对象本质上都是着色器代码, Three.js的WebGL渲染器在调用渲染方法render渲染场景的时候,会根据材质的type值调用路径 src\renderers\shaders下的着色器代码编译后在GPU中执行。

Three.js提供了RawShaderMaterialShaderMaterial两个API用来辅助开发者自定义着色器代码。这个着色器API和其它的three.js的材质对象的基类一样都是Material,会继承基类Material的属性和方法。

视频和源码

视频讲解和源码下载——Three.js视频教程进阶部分

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>

设置vertexShaderfragmentShader属性值

通过元素.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变量。

可以通过BufferGeometryGeometryAPI创建一个空的几何体,然后手动设置顶点数据,也可以使用一些立方体或其他几何体的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的时候,会启用点渲染模式,解析线模型LineLineLoopLineSegments的时候,会启用对应的线条绘制模式,解析网格模型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);

更多相关文章

Three.js着色器——矩阵变换
本站版权所有,本站任何内容未经允许不得转载   备案号:豫ICP备16004767号 QQ群:187740169 (WebGL-Three.js教程)   邮箱:guolongbang@163.com