初面网初面网

着色器

普通的着色器

普通的着色器,能够使用默认的配置进行基本的着色器创建。

// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: `
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0)
  `,
  fragmentShader: `
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0)
  `
});

const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(1,1,64,64),
  shaderMaterial
)
scene.add(floor);

直接在js中写着色器没有代码提示。在vscode中安装插件Shader languages suport for VS Code,可以让我们在外面书写shader文件。

在src目录下创建Shader/basic文件夹路径。在basic文件夹里创建两个文件:vertex.glsl和fragment.glsl。

// vertex.glsl
void main(){
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
// fragment.glsl
void main(){
  gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}

这样一来将shader代码写在了外部,通过导入的方式进行使用

import basicFragmentShader from '../shader/basic/fragment.glsl';
import basicVertexShader from '../shader/basic/vertex.glsl';

// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader
});

原生着色器

原生着色器需要我们更多的配置,但这也意味着更加灵活。

import basicFragmentShader from '../shader/basic/fragment.glsl';
import basicVertexShader from '../shader/basic/vertex.glsl';

// 创建着色器材质。注意下面用的是RawShaderMaterial
const shaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader
});
// vertex.glsl

// highp -2^16 ~ 2^16
// mediump -2^10 ~ 2^10
// lowp -2^8 ~ 2^8
precision lowp float;

attribute vec3 position;
attribute vec2 uv;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

varying vec2 vUv;

void main(){
  vUv = uv;
  gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
// fragment.glsl
precision lowp float;
varying vec2 vUv;

void main(){
  gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}

线框效果

import basicFragmentShader from '../shader/basic/fragment.glsl';
import basicVertexShader from '../shader/basic/vertex.glsl';

// 创建着色器材质
const shaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
  wireframe: true,  // 线框
});

const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(1,1,1,1), // 注意这里后两个参数,18已经很大了。太大了点数密集,不能够很好展示线框。
  shaderMaterial
)
scene.add(floor);

形变

// vertex.glsl
precision lowp float;

attribute vec3 position;
attribute vec2 uv;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

varying vec2 vUv;

varying float vElevation;

void main(){
  vUv = uv;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);

  modelPosition.z = sin(modelPosition.x * 10.0) * 0.05;
  modelPosition.z += sin(modelPosition.y *10.0) * 0.05;
  vElevation =  modelPosition.z;

  gl_Position = projectionMatrix * viewMatrix * modelPosition;
}
// fragment.glsl
precision lowp float;
varying vec2 vUv;
varying float vElevation;

void main(){
  float height = (vElevation + 0.05) * 10.0;
  gl_FragColor = vec4(1.0 * height, 0.0, 0.0, 1.0);
}

顶点运动

就是让形变动起来

// 创建着色器材质
const shaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,

  // 这里的值会传给着色器去使用
  uniforms: {
    uTime: {
      value: 0,
    }
  }
});

function animate() {
  // 其他代码略

  // 将变量赋值
  shaderMaterial.uniforms.uTime.value = clock.getElapsedTime();

}
// vertex.glsl
precision lowp float;

attribute vec3 position;
attribute vec2 uv;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

// 获取时间
uniform float uTime;

varying vec2 vUv;

varying float vElevation;

void main(){
  vUv = uv;
  vec4 modelPosition = modelMatrix * vec4(position, 1.0);

  modelPosition.z = sin((modelPosition.x+uTime) * 10.0) * 0.05;
  modelPosition.z += sin((modelPosition.y+uTime) *10.0) * 0.05;
  vElevation =  modelPosition.z;

  gl_Position = projectionMatrix * viewMatrix * modelPosition;
}

纹理映射

// 创建纹理对象
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load("./imgs/123.jpg"); // 文件路径要根据实际情况来写

// 创建着色器材质
const shaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
  uniforms: {
    uTime: {
      value: 0,
    },
    uTexture: {
      value: texture,
    }
  }
});
precision lowp float;
varying vec2 vUv;
varying float vElevation;

// 创建纹理
uniform sampler2D uTexture;

void main(){
  // float height = (vElevation + 0.05) * 10.0;
  // gl_FragColor = vec4(1.0 * height, 0.0, 0.0, 1.0);

  // UV采样
  vec4 textureColor = texture2D(uTexture, vUv);
  gl_FragColor = textureColor;
}

如果希望带有本身的明暗,可以写成


// 其他忽略

void main(){
  // UV采样
  vec4 textureColor = texture2D(uTexture, vUv);
  float height = (vElevation + 0.05) * 10.0;
  textureColor.rgb *= height;
  gl_FragColor = textureColor;
}

更新于 2025/2/26