光影编程师:Threejs Shader 基础全攻略

介绍

Shader 是一种运行在 GPU 上的小程序,用于实现一些图形效果。在 Three.js 中,我们可以使用 GLSL ES 语言来编写 Shader,并将其应用到材质上,从而实现各种图形效果。

可以做什么

  • 实现各种图形效果,如光照、阴影、反射、折射等。

  • 实现自定义的材质,如金属、塑料、玻璃等。

  • 实现粒子效果,如烟雾、火焰、水波等。

  • 实现动态纹理,如动态纹理、动态贴图等。

GLSL ES

GLSL ES 是一种用于编写 Shader 的编程语言,它是一种基于 C 语言的编程语言,具有 C 语言的大部分语法和特性。在 GLSL ES 中,我们可以使用一些特殊的语法和函数来实现各种图形效果。

基础语法

  • 变量声明:在 GLSL ES 中,我们可以使用 floatintbool 等数据类型来声明变量,例如:
glsl 复制代码
float x = 1.0;
int y = 2;
bool z = true;
  • 函数声明:在 GLSL ES 中,我们可以使用 voidfloatint 等数据类型来声明函数,例如:
glsl 复制代码
void myFunction(float a, int b) {
  // 函数体
}
float myFunction2(int a) {
  // 函数体
  return 1.0;
}
  • 循环和条件语句:在 GLSL ES 中,我们可以使用 forwhileif 等循环和条件语句,例如:
glsl 复制代码
for (int i = 0; i < 10; i++) {
  // 循环体
}
if (x > 0.5) {
  // 条件体
}

向量

GLSL ES 中,向量可以标时多种数据,也能进行多种数学运算。

例如,我们可以使用 vec3 来表示颜色,其中 vec3 是一个包含三个浮点数的向量,分别表示红、绿、蓝三个颜色通道的值。例如:

glsl 复制代码
vec3 color = vec3(1.0, 0.0, 0.0); // 红色

我们也可以使用 vec3 来表示位置、方向、法线等,例如:

glsl 复制代码
vec3 position = vec3(0.0, 0.0, 0.0); // 位置
vec3 direction = vec3(0.0, 0.0, 1.0); // 方向
vec3 normal = vec3(0.0, 1.0, 0.0); // 法线

常用关键字:

  • vec2: 二维向量,分量是浮点数。

  • vec3: 三维向量,分量是浮点数。

  • vec4: 四维向量,分量是浮点数。

  • ivec2: 二维向量,分量是整数。

  • ivec3: 三维向量,分量是整数。

  • ivec4: 四维向量,分量是整数。

  • bvec2: 二维向量,分量是布尔值。

  • bvec3: 三维向量,分量是布尔值。

  • bvec4: 四维向量,分量是布尔值。

  • mat2: 二维矩阵,包含两个二维向量。

  • mat3: 三维矩阵,包含三个三维向量。

  • mat4: 四维矩阵,包含四个四维向量。

着色器材质

Three.js 中,我们可以使用 ShaderMaterial 来创建一个着色器材质,并将其应用到几何体上,从而实现各种图形效果。

使用 ShaderMaterial

之前介绍了很多材质,例如:创建一个平面,使用基础网格材质 MeshBasicMaterial

js 复制代码
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.MeshBasicMaterial({
  color: 0xff0000,
});
const mesh = new THREE.Mesh(geometry, material);

现在,我们使用 ShaderMaterial 来创建一个材质,并应用到平面上。

js 复制代码
const geometry = new THREE.PlaneGeometry(100, 50);
const material = new THREE.ShaderMaterial({
  vertexShader: "...", // 顶点着色器
  fragmentShader: "...", // 片元着色器
});
const mesh = new THREE.Mesh(geometry, material);

设置顶点着色器

ShaderMaterial 顶点着色器属性 vertexShader,是一个字符串,表示顶点着色器的代码。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: "", // 顶点着色器
});

设置顶点着色器主函数

根据 GLSL ES 的语法,顶点着色器需要有一个主函数 main(),函数无返回值,前面加上 void 关键字。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    void main() {
      // 顶点着色器代码
    }
  `,
});

内置变量

GLSL ES 中,我们可以使用 attributeuniformvarying 等关键字来声明变量,这些变量可以在顶点着色器和片元着色器之间传递。

  • gl_Position

gl_Position 是顶点着色器的一个内置变量,表示顶点的位置。在 GLSL ES 中,顶点着色器需要输出一个 vec4 类型的变量 gl_Position,表示顶点的位置。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    //注意在主函数外面声明,默认提供,不用自己写
    attribute vec3 position; 
    void main() {
      gl_Position = vec4(position, 1.0);
    }
  `,
});

attribute: 顶点属性,只能在顶点着色器中使用,用于传递几何体的顶点数据,例如顶点的位置、法线、颜色等。

使用 ShaderMaterial 的时候,Threejs 会在内部把内置变量 position 与几何体的顶点位置数据 geometry.attributes.position 进行绑定,这就意味着,在顶点着色器代码中访问 position 变量,就相当于访问几何体的顶点位置数据。

  • modelMatrix

modelMatrix 是顶点着色器的一个内置变量,表示模型的模型矩阵。在 GLSL ES 中,顶点着色器可以访问 mesh.matrixWorld 变量,用于计算顶点的位置。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    uniform mat4 modelMatrix;
    void main() {
      gl_Position = modelMatrix * vec4(position, 1.0);
    }
  `,
});

使用 ShaderMaterial 的时候,Threejs 会自动获取模型世界矩阵 mesh.matrixWorld 的值,赋值给变量 modelMatrix。这意味着,模型矩阵 modelMatrix 包含了模型自身的位置、缩放、姿态角度信息。

uniform: 全局变量,可以在顶点着色器和片元着色器中使用,用于传递全局数据,例如光源位置、颜色等。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    uniform float opacity;//uniform声明透明度变量opacity
    void main() {
     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
  `,
});

uniform 变量传值,在 Three.js 中,我们可以在创建 ShaderMaterial 的时候,通过 uniforms 属性来传递。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    uniform float opacity;
    void main() {
      gl_Position = vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    void main() {
      gl_FragColor = vec4(1.0, 0.0, 0.0, opacity);
    }
  `,
  uniforms: {
    opacity: { value: 1.0 }, // 传递透明度变量opacity的值
  },
});
  • viewMatrix

viewMatrix 是顶点着色器的一个内置变量,表示视图矩阵。在 GLSL ES 中,顶点着色器可以访问 camera.matrixWorldInverse 变量,用于计算顶点的位置。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    uniform mat4 viewMatrix;
    void main() {
      gl_Position = viewMatrix * modelMatrix * vec4(position, 1.0);
    }
  `,
});
  • projectionMatrix

projectionMatrix 是顶点着色器的一个内置变量,表示投影矩阵。在 GLSL ES 中,顶点着色器可以访问 camera.projectionMatrix 变量,用于计算顶点的位置。

js 复制代码
const material = new THREE.ShaderMaterial({
  vertexShader: `
    uniform mat4 projectionMatrix;
    void main() {
      gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
    }
  `,
});

设置片元着色器

ShaderMaterial 片元着色器属性 fragmentShader,是一个字符串,表示片元着色器的代码。

js 复制代码
const material = new THREE.ShaderMaterial({
  fragmentShader: "", // 片元着色器
});
  • gl_FragColor

gl_FragColor 是片元着色器的一个内置变量,表示片元的颜色。在 GLSL ES 中,片元着色器需要输出一个 vec4 类型的变量 gl_FragColor,表示片元的颜色。

js 复制代码
const material = new THREE.ShaderMaterial({
  fragmentShader: `
    void main() {
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 红色
    }
  `,
});

效果

js 复制代码
//创建平面
const geometry = new THREE.PlaneGeometry(1, 1);
const material = new THREE.ShaderMaterial({
  vertexShader: `
    void main() {
        // 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点位置,如果不乘模型矩阵,则不会有模型变换
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
  `,
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);

modelViewMatrix :视图矩阵 * 模型矩阵

js 复制代码
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

注意: 每个语句后面要加分号,否则会报错。

Threejs基础系列课程差不多临近结尾了,大家还有什么想学的可以留言。接下来会准备一些项目实战教程,大家可以学到Threejs的应用,在做案例的过程中对之前的基础知识做补充,敬请期待吧!!!

书洞笔记

相关推荐
有事没事实验室26 分钟前
CSS 浮动与定位以及定位中z-index的堆叠问题
前端·css·开源
2501_915373881 小时前
Vue路由深度解析:Vue Router与导航守卫
前端·javascript·vue.js
小妖6661 小时前
前端表格滑动滚动条太费事,做个浮动滑动插件
前端
读心悦1 小时前
5000 字总结CSS 中的过渡、动画和变换详解
前端·css·tensorflow
__BMGT()1 小时前
C++ QT 打开图片
前端·c++·qt
仍然探索未知中2 小时前
前端扫盲HTML
前端·html
Brilliant Nemo2 小时前
Vue2项目中使用videojs播放mp4视频
开发语言·前端·javascript
酷爱码3 小时前
Linux实现临时RAM登录的方法汇总
linux·前端·javascript
LuckyLay3 小时前
Vue百日学习计划Day16-18天详细计划-Gemini版
前端·vue.js·学习
想要飞翔的pig3 小时前
uniapp+vue3页面滚动加载数据
前端·vue.js·uni-app