Three.js 着色器 shader_ShaderMaterial 介绍

发布于 2021-12-07 13:00:39 字数 5790 浏览 1823 评论 0

学习 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 的时候,会启用点渲染模式,解析线模型 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

偏爱自由

暂无简介

0 文章
0 评论
21388 人气
更多

推荐作者

无远思近则忧

文章 0 评论 0

久伴你

文章 0 评论 0

萌无敌

文章 0 评论 0

新一帅帅

文章 0 评论 0

莫多说

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文