在 Three.js 中提供了两种类型的 Shader 对象
- ShaderMaterial 将自动添加一些基础代码到着色器中
- RawShaderMaterial 不任何基础代码
着色器中同样也可以使用材质对象中的属性,如 wirefreme, side, transparent, flagShading 等。但 map, alphaMap, opacity, color 等属性将失效。
基础用法
const material = new THREE.RawShaderMaterial({
vertexShader: `
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
void main()
{
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
GLSL 语法
1、不能使用 console.log
进行打印
2、每句代码的末尾必须使用分号断开,一行可以写多句代码,但没句代码结束都需要分号断开。uniform mat4 viewMatrix; uniform mat4 modelMatrix;
3、变量声明必须提供类型
float fooBar = 4.0;
4、浮点数不能与整数一起运算,如需要运算则需将数据类型进行转换
float a = 1.0;
int b = 2;
float c = a * float(b);
数据类型
float 浮点数
float foo = 1.0;
int 整数
float a = 1;
float b = 2;
bool 布尔值
float foo = true;
vec2 二维向量
// X, Y 均为 1.0
vec2 foo = vec2(1.0);
// X 为 -1.0, Y 为 2.0
vec2 foo = vec2(- 1.0, 2.0);
// 运算,x与y相乘再乘以 2.0
foo *= 2.0 //(结果为4.0)
// 重新赋值
foo.x = 2.0
foo.y = 3.0
vec3 三位向量
可以是 X, Y, Z 或者 R, G, B
// X, Y, Z 均为 1.0
vec3 foo = vec3(1.0);
// X 为 -1.0, Y 为 2.0,Z 为 3.0
vec3 foo = vec3(- 1.0, 2.0, 3.0);
// 通过二维向量数据设置三位向量
vec2 foo = vec2(1.0, 2.0);
vec3 bar = vec3(foo, 3.0);
// 通过三位向量数据设置二维向量
vec3 foo = vec3(1.0, 2.0, 3.0);
vec2 a = foo.xy;
vec2 b = foo.xz;
vec2 c = foo.zy;
vec4 四维向量
分别为 X, Y, Z, W 或者 R, G, B, A
vec4 foo = vec4(1.0, 2.0, 3.0, 4.0);
mat2 二维矩阵
mat3 三维矩阵
mat4 四维矩阵
sampler2D
2D采样器,用于纹理等。
运算
支持使用 + – * /,但不支持 %,可用内置函数 mod 代替
函数
// 有返回值
float name(float a, float b) {
return a * b;
}
float result = name(1.0, 2.0);
// 没有返回值,只是一个方法
void name() {
...
}
内置函数
sin, cos, max, min, pow, exp, mod, clamp, cross, dot, mix, step, smoothstep, length, distance, reflect, refract, normalize
mod()
取模
float foo = mod(vUv.y * 10.0, 1.0);
step()
float foo = step(0.5, mod(vUv.y * 10.0, 1.0)); // 大于0.5时为1,否则为0
abs()
绝对值
float foo = abs(vUv.x - 0.5);
min()
最小值
float foo = min(abs(vUv.x - 0.5), abs(vUv.y - 0.5));
max()
最大值
float foo = max(abs(vUv.x - 0.5), abs(vUv.y - 0.5));
round()
四舍五入
floor()
length()
可用于绘制径向渐变
float strength = length(vUv);
distance()
float strength = distance(vUv, vec2(0.5));
atan()
mix()
用于混合颜色
float strength = step(0.9, sin(cnoise(vUv * 10.0) * 20.0));
vec3 blackColor = vec3(0.0);
vec3 uvColor = vec3(vUV, 1.0);
vec3 mixedColor = mix(blackColor, uvColor, strength);
clamp()
float strength = clamp(strength, 0.0, 1.0);
自定义函数
创建自定义函数需在 main 函数前创建。
random()
仅是一个伪随机
float random(vec2 st)
{
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
// main 内调用
float foo= random(vUv);
rotate()
用于旋转uv
vec2 rotate(vec2 uv, float rotation, vec2 mid)
{
return vec2(
cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
);
}
vec2 rotatedUv = rotate(vUv, 1.0, vec(0.5));
相关网站
噪波
https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
Classic Perlin Noise
void main
该函数将自动调用,不会返回任何值
顶点着色器 vertexShader
gl_Position
一个包含顶点在屏幕上位置的变量,该变量已经存在,无需重新声明,是一个四维向量,他将顶点定位在屏幕上的正确位置。
位置属性 Postion Attribute
每个顶点之间变化的数据,是一个三维向量。该属性来自几何图形中,值由 javascript 提供。
attribute vec3 postion;
modelMatrix
模型矩阵,将相对于网格位置、旋转和缩放对每个顶点应用变换。
viewMatrix
关于相机的,
projectionMatrix
投影矩阵会将坐标转换为最终的剪辑空间坐标
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
void main()
{
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.z += sin(modelPosition.x * 10.0) * 0.1;
vec4 viewPostion = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPostion;
gl_Position = projectedPosition;
}
varying
通过顶点着色器声明变量并赋值,并传递给片段着色器,再在片段着色器中使用该变量
const vertexShader =
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
attribute vec3 position;
attribute float aRandom;
// 需要传递到片段着色器的变量
varying float vRandom;
void main()
{
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.z += aRandom * 0.1;
vec4 viewPostion = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPostion;
gl_Position = projectedPosition;
vRandom = aRandom;
}
`;
const fragmentShader = `
precision mediump float;
// 从顶点着色器获取变量
varying float vRandom;
void main()
{
gl_FragColor = vec4(0.5, vRandom, 1.0, 1.0);
}
`;
const geometry = new THREE.PlaneGeometry(1, 1, 32, 32);
const { count } = geometry.attributes.position;
// 添加自定义变量
const randoms = new Float32Array(count);
for (let i = 0; i < count; i++) {
randoms[i] = Math.random();
}
geometry.setAttribute('aRandom', new THREE.BufferAttribute(randoms, 1));
const material = new THREE.RawShaderMaterial({
vertexShader,
fragmentShader,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
uniform
可在顶点着色器与片段着色器中使用。
- 使用同一个着色器,但产生不同的结果
- 可调整这些值
- 可制作动画
- 给uniforms赋值必须使用对象,且为value
const vertexShader =
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform float uFrequency;
attribute vec3 position;
void main()
{
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
modelPosition.z += sin(modelPosition.x * uFrequency) * 0.1;
vec4 viewPostion = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPostion;
gl_Position = projectedPosition;
}
;
const fragmentShader = `
precision mediump float;
uniform vec3 uColor;
void main()
{
gl_FragColor = vec4(uColor, 1.0);
}
`;
const material = new THREE.RawShaderMaterial({
vertexShader,
fragmentShader,
uniforms: {
uFrequency: { value: 10 },
uColor: { value: new THREE.Color('orange') }
},
});
片段着色器 fragmentShader
gl_FragColor
precision
浮点数的精度,包含 highp, mediump, lowp。精度越高越影响性能,但细节更丰富。
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
ShaderMaterial
主要属性
- uniforms 全局变量
- vertexShader 顶点着色器,定义位置信息
- fragmentShader 片段着色器,定义颜色
shader 着色器,是一段 glsl (opengl shading language)语言,在gpu上运行,性能比cpu更好。
用处:
- 现有的material无法满足要求
- 绑定多个对象到一个 buffergeometry,已提高性能
注意点
- 只能使用 webglrenderer, vertexshader 和 fragmentshader 代码只能使用 webgl 编译在gpu 上运行
- 必须配套使用 buffergeometry,并且使用bufferattribute定义attributes
- 可以使用 texture property
vertex shader 与 fragmentshader
- vertex shader 首先运行,接受 attributes,计算每个顶点的位置,并把其他数据varying传递到fragment shader
- fragment shader 接着运行,设置每个片段的颜色
着色器有三种类型的变量
- uniforms 所有顶点相同值的变量,能被两种着色器访问
- attributes 与每个顶点关联的变量,如顶点位置
- varying 从vertex shader 传递到 fragment shader 的变量