跳到主要内容

coffee smoke shader

· 阅读需 3 分钟
Yangbingrui
Front End Engineer @ grg

这个 vertex.glsl 代码好难理解

github

vertex.glsl

varying vec2 vUv;
uniform float uTime;
uniform sampler2D uPerlinTexture;

vec2 rotate2D(vec2 value, float angle) {
float s = sin(angle);
float c = cos(angle);
mat2 m = mat2(c, s, -s, c);
return m * value;
}

void main() {
vec3 newPosition = position;
float twistPerlin = texture(uPerlinTexture, vec2(0.5, uv.y * 0.2 - uTime * 0.005)).r;
float angle = twistPerlin * 10.0;
newPosition.xz = rotate2D(newPosition.xz, angle);

vec2 windOffset = vec2(
texture(uPerlinTexture, vec2(0.25, uTime * 0.01)).r - 0.5,
texture(uPerlinTexture, vec2(0.75, uTime * 0.01)).r - 0.5);
windOffset *= pow(uv.y, 2.0) * 10.0;
newPosition.xz += windOffset;

// Final position
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
vUv = uv;
}

主要效果实现(main函数)

  1. 扭曲效果
float twistPerlin = texture(uPerlinTexture, vec2(0.5, uv.y * 0.2 - uTime * 0.005)).r;
float angle = twistPerlin * 10.0;
newPosition.xz = rotate2D(newPosition.xz, angle);
  • 使用柏林噪声纹理创建扭曲效果
  • 根据y坐标和时间采样噪声
  • 将采样结果用于旋转xz平面
  1. 风力效果
vec2 windOffset = vec2(
texture(uPerlinTexture, vec2(0.25, uTime * 0.01)).r - 0.5,
texture(uPerlinTexture, vec2(0.75, uTime * 0.01)).r - 0.5);
windOffset *= pow(uv.y, 2.0) * 10.0;
newPosition.xz += windOffset;
  • 使用两个不同位置的噪声采样创建风力偏移
  • 风力效果随高度(y坐标)增强
  • 应用到xz平面上

效果说明

这个着色器主要用于创建咖啡烟雾的效果:

  • 通过柏林噪声创建自然的扭曲运动
  • 使用时间变量使效果随时间变化
  • 风力效果随高度增强,模拟真实烟雾上升时的扩散
  • 整体效果结合了旋转和偏移,创造出流动的烟雾效果
  • 这个着色器很可能是用于粒子系统或者平面网格,用来模拟上升的烟雾效果。通过柏林噪声的使用,可以创建出非常自然的随机运动效果。
fragment.glsl
uniform sampler2D uPerlinTexture;
varying vec2 vUv;
uniform float uTime;

void main() {

// scale
vec2 smokeUv = vUv;

smokeUv.x *= .5;
smokeUv.y *= .3;
smokeUv.y -= uTime * .03;

float smoke = texture(uPerlinTexture, smokeUv).r;

smoke = smoothstep(0.4, 1.0, smoke);

smoke *= smoothstep(0.0, 0.1, vUv.x);
smoke *= smoothstep(0.0, 0.1, 1.0 - vUv.x);
smoke *= smoothstep(1.0, .4, vUv.y);
smoke *= smoothstep(.0, .1, vUv.y);

gl_FragColor = vec4(.6, .3, .2, smoke);
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
#include <tonemapping_fragment>
#include <colorspace_fragment>
}