跳到主要内容
← Water

Water

Water Surface Normal

shader-learning 自学第 6 课:Water Surface Normal

实时渲染 · 网格 GLSL

第 6 课:Water Surface Normal

实现

uniform float iTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform mat4 inverseViewMatrix;

const float PI = 3.14;
const float frequency = 8.0;
const float amplitude = 0.1;
const float speed = -3.0;
const float maxDistance = 0.5;
const float refractiveIndex = 1.33;
const float distortionScale = 0.25;

in vec2 vUv;
in vec3 vPos;

out vec4 FragColor;

vec3 getViewPos() {
  return (inverseViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
}

float getAmplitude(float distanceToOrigin) {
  return amplitude * clamp((1.0 - distanceToOrigin / maxDistance), 0.0, 1.0);
}

vec2 getDistortion(vec2 pos, vec2 origin) {
  float distanceToOrigin = distance(pos, origin);
  float t = distanceToOrigin * 2.0 * PI * frequency + iTime * speed;
  float distortion = sin(t) * getAmplitude(distanceToOrigin);
  return vec2(distortion);
}

vec3 getNormal(vec2 pos, vec2 origin) {
  float dist = distance(pos, origin);
  float A = getAmplitude(dist);
  float S = 2.0 * PI * frequency;
  float T = iTime * speed;

  float dfdx = A * cos(dist * S + T) * S * (pos.x - origin.x) / dist;
  float dfdz = A * cos(dist * S + T) * S * (pos.y - origin.y) / dist;

  return normalize(vec3(-dfdx, 1.0, -dfdz));
}

void main() {
  vec2 uv = vUv;
  vec3 viewPos = getViewPos();

  vec2 w1 = vec2(0.3);
  vec2 w2 = vec2(0.7);

  vec3 normal = normalize(getNormal(uv, w1) + getNormal(uv, w2));

  vec2 distortion = getDistortion(uv, vec2(0.3));
  distortion += getDistortion(uv, vec2(0.7));
  vec2 texCoords = uv + distortion;

  vec3 reflectColor = texture(iChannel0, texCoords).rgb;

  vec3 curvedPos = vPos + vec3(0.0, distortion.x, 0.0);
  vec3 viewDirection = curvedPos - viewPos;

  vec3 incident = normalize(viewDirection);
  float eta = 1.0 / refractiveIndex;
  vec3 refractedRay = refract(incident, normal, eta);
  vec2 offset = refractedRay.xy * distortionScale;

  vec3 baseTexture = texture(iChannel1, uv+offset).rgb;

  FragColor = vec4(mix(reflectColor, baseTexture, 0.2) , 1.0);
}