webGL 消融特效

418 阅读1分钟

静态世界

使用three.js 创建相机,场景什么的太基础不写了。直接看shader代码

Shader

vertexShader
   // vertex.glsl
   varying vec2 vUv;
   void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
   }

简单解释下,three.js 会帮我们声明好投影矩阵projectionMatrix,模型视图矩阵,以及uv。直接拿来用就好

fragmentShader
   // fragment.glsl
   precision mediump float;
   precision lowp sampler2D;
   uniform sampler2D noiseTexture;
   uniform sampler2D boxTexture;
   uniform float threshold;
   varying vec2 vUv;
   void main() {
      vec4 noise = texture2D(noiseTexture, vUv);
      vec4 box = texture2D(boxTexture, vUv);
      vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
      if (noise.g < threshold) {
        discard;
      }
      float t = 1.0 - smoothstep(0.0, 1.0, noise.g - threshold);
      vec4 dissolveColor = mix(box, color, t);
      gl_FragColor = mix(box, dissolveColor, t * step(0.0001, threshold));
   }

这里我们用噪声图创建 随机消融。

color为消融边缘色, 这里设置的是白色

因为噪声图是灰度图,rgb3个值相同,所以这里随机取一个值noise.g(鸡你太美,笑) 与 阈值 比对,做到消融

后面就是颜色混合了

最后一行 t * step(0.001, threshold)是为了处理bug。

有时候噪声通道的值noise.g - threshold 不一定大于线宽

Typescript

ts大概的代码

import { BoxGeometry, Mesh, ShaderMaterial,LoadingManager, TextureLoader, DoubleSide } from 'three';

// 我这里使用vite加载glsl。
import vertexShader from './vertex.glsl?raw';
import fragmentShader from './fragment.glsl?raw';
 
 // 用manage统一管理资源加载 
 const manage = new LoadingManager();
 const textureLoader = new TextureLoader(manage);
 
 const noiseTexture = textureLoader.load('/noise.png');
 const boxTexture = textureLoader.load('/box.png');
  
 /** 以下需要判断manage.onLoad 加载完毕在进行 **/ 
 
 let threshold = 0.0;
 
 const boxGeometry = new BoxGeometry(10, 10, 10);
 
 const uniforms: ShaderMaterial['uniforms'] = {
      noiseTexture: {
        value: noiseTexture,
      },
      boxTexture: {
        value: boxTexture,
      },
      threshold: {
        value: threshold,
      }
  }
  
  const shaderMaterial = new ShaderMaterial({
     uniforms: this.uniforms,
     vertexShader: vertexShader,
     fragmentShader: boxFramentShader, 
     side: DoubleSide 
  });
  
  const mesh = new Mesh(boxGeometry, shaderMaterial)
  
  /**
   * 剩下的就是把mesh加载到场景中渲染
   * 在 requestAnimationFrame 修改 threshold 的值即可
   */

以上 消融特效 非常简单的实现