feat(all): 迁移扩展相关功能

This commit is contained in:
plum
2026-04-08 15:34:43 +08:00
parent ad2dd979eb
commit d7c0dba569
278 changed files with 25207 additions and 62 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

@@ -0,0 +1,28 @@
precision highp float;
precision highp int;
#include <utils>
in vec3 oldPos;
in vec3 newPos;
in vec3 ray;
out vec4 fragColor;
void main() {
/* if the triangle gets smaller, it gets brighter, and vice versa */
float oldArea = length(dFdx(oldPos)) * length(dFdy(oldPos));
float newArea = length(dFdx(newPos)) * length(dFdy(newPos));
fragColor = vec4(oldArea / newArea * 0.2, 1.0, 0.0, 0.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
/* shadow for the rim of the pool */
vec2 t = intersectCube(
newPos,
-refractedLight,
vec3(-poolHalfSize.x, -poolHeight, -poolHalfSize.y),
vec3(poolHalfSize.x, poolHeight * 2.0, poolHalfSize.y)
);
fragColor.r *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (newPos.y - refractedLight.y * t.y - poolHeight * 2.0 / 12.0)));
}
@@ -0,0 +1,39 @@
out vec3 oldPos;
out vec3 newPos;
out vec3 ray;
in vec3 position;
#include <utils>
/* project the ray onto the plane */
vec3 project(vec3 origin, vec3 ray, vec3 refractedLight) {
vec2 tcube = intersectCube(
origin,
ray,
vec3(-poolHalfSize.x, -poolHeight, -poolHalfSize.y),
vec3(poolHalfSize.x, poolHeight * 2.0, poolHalfSize.y)
);
origin += ray * tcube.y;
float tplane = (-origin.y - poolHeight) / refractedLight.y;
return origin + refractedLight * tplane;
}
void main() {
vec4 info = texture(water, position.xy * 0.5 + 0.5);
info.ba *= 0.5;
vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a);
/* project the vertices along the refracted vertex ray */
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
vec3 basePos = vec3(position.x * poolHalfSize.x, 0.0, position.y * poolHalfSize.y);
ray = refract(-light, normal, IOR_AIR / IOR_WATER);
oldPos = project(basePos, refractedLight, refractedLight);
newPos = project(basePos + vec3(0.0, info.r, 0.0), ray, refractedLight);
vec2 normalizedPos = vec2(newPos.x / poolHalfSize.x, newPos.z / poolHalfSize.y);
vec2 refractedOffset = vec2(refractedLight.x / poolHalfSize.x, refractedLight.z / poolHalfSize.y) / refractedLight.y;
gl_Position = vec4(0.75 * (normalizedPos + refractedOffset), 0.0, 1.0);
}
@@ -0,0 +1,22 @@
precision highp float;
precision highp int;
#include <utils>
#include <cylinder_utils>
in vec3 oldPos;
in vec3 newPos;
in vec3 ray;
out vec4 fragColor;
void main() {
float oldArea = length(dFdx(oldPos)) * length(dFdy(oldPos));
float newArea = length(dFdx(newPos)) * length(dFdy(newPos));
fragColor = vec4(oldArea / newArea * 0.2, 1.0, 0.0, 0.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
vec2 t = intersectCylinder(newPos, -refractedLight, poolRadius, -poolHeight, poolHeight * 2.0);
fragColor.r *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (newPos.y - refractedLight.y * t.y - poolHeight * 2.0 / 12.0)));
}
@@ -0,0 +1,42 @@
out vec3 oldPos;
out vec3 newPos;
out vec3 ray;
in vec3 position;
#include <utils>
#include <cylinder_utils>
vec3 project(vec3 origin, vec3 ray, vec3 refractedLight) {
vec2 tcyl = intersectCylinder(origin, ray, poolRadius, -poolHeight, poolHeight * 2.0);
origin += ray * tcyl.y;
float tplane = (-origin.y - poolHeight) / refractedLight.y;
return origin + refractedLight * tplane;
}
void main() {
// Collapse vertices outside the unit circle to avoid degenerate caustic triangles
if (position.x * position.x + position.y * position.y > 1.0) {
oldPos = vec3(0.0);
newPos = vec3(0.0);
ray = vec3(0.0);
gl_Position = vec4(0.0);
return;
}
vec4 info = texture(water, position.xy * 0.5 + 0.5);
info.ba *= 0.5;
vec3 normal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
vec3 basePos = vec3(position.x * poolRadius, 0.0, position.y * poolRadius);
ray = refract(-light, normal, IOR_AIR / IOR_WATER);
oldPos = project(basePos, refractedLight, refractedLight);
newPos = project(basePos + vec3(0.0, info.r, 0.0), ray, refractedLight);
vec2 normalizedPos = newPos.xz / poolRadius;
vec2 refractedOffset = (refractedLight.xz / poolRadius) / refractedLight.y;
gl_Position = vec4(0.75 * (normalizedPos + refractedOffset), 0.0, 1.0);
}
@@ -0,0 +1,48 @@
precision highp float;
precision highp int;
#include <utils>
#include <cylinder_utils>
uniform float wallOpacity;
uniform float wallMode;
uniform vec3 volumeColor;
uniform sampler2D sceneTexture;
uniform vec2 resolution;
uniform float useSceneRefraction;
uniform float surfaceTransmittance;
uniform float normalStrength;
uniform float refractionStrength;
in vec3 pos;
out vec4 fragColor;
void main() {
vec3 baseColor = wallMode > 0.5 ? volumeColor : getCylinderWallColor(pos) * volumeColor;
vec4 info = texture(water, pos.xz * 0.5 + 0.5);
vec2 screenUV = gl_FragCoord.xy / resolution;
vec2 offset = info.ba * normalStrength * refractionStrength;
vec3 mixedColor = baseColor;
if (useSceneRefraction > 0.5) {
vec2 refractedUV = clamp(screenUV + offset, 0.0, 1.0);
vec3 sceneColor = texture(sceneTexture, refractedUV).rgb;
mixedColor = mix(baseColor, sceneColor, surfaceTransmittance);
}
float depth = 0.0;
if (pos.y < info.r) {
depth = clamp((info.r - pos.y) / max(poolHeight, 0.0001), 0.0, 1.0);
float atten = wallMode > 0.5 ? mix(0.95, 0.35, depth) : mix(0.98, 0.6, depth);
mixedColor *= atten;
}
float alpha = wallOpacity;
if (wallMode > 0.5 && pos.y < info.r) {
alpha = mix(wallOpacity * 0.6, min(1.0, wallOpacity + 0.5), depth);
}
fragColor = vec4(mixedColor, alpha);
}
@@ -0,0 +1,73 @@
vec2 intersectCylinder(vec3 origin, vec3 ray, float radius, float yMin, float yMax) {
float a = ray.x * ray.x + ray.z * ray.z;
float b = 2.0 * (origin.x * ray.x + origin.z * ray.z);
float c = origin.x * origin.x + origin.z * origin.z - radius * radius;
float tNear = -1e10;
float tFar = 1e10;
if (a > 1e-6) {
float discriminant = b * b - 4.0 * a * c;
if (discriminant < 0.0) return vec2(1e10, -1e10);
float sqrtDisc = sqrt(discriminant);
tNear = (-b - sqrtDisc) / (2.0 * a);
tFar = (-b + sqrtDisc) / (2.0 * a);
}
if (abs(ray.y) > 1e-6) {
float tBottom = (yMin - origin.y) / ray.y;
float tTop = (yMax - origin.y) / ray.y;
float tCapNear = min(tBottom, tTop);
float tCapFar = max(tBottom, tTop);
tNear = max(tNear, tCapNear);
tFar = min(tFar, tCapFar);
} else {
if (origin.y < yMin || origin.y > yMax) return vec2(1e10, -1e10);
}
return vec2(tNear, tFar);
}
vec3 getCylinderWallColor(vec3 point) {
float scale = 0.5;
vec3 wallColor = tilesColor;
vec3 normal;
float r = length(point.xz);
float edge = poolRadius - 0.001;
if (r > edge) {
float angle = atan(point.z, point.x);
vec2 uv = vec2(angle / 3.14159 * 0.5 + 0.5, point.y / poolHeight * 0.5 + 0.5);
if (useTiles > 0.5) {
wallColor = texture(tiles, uv).rgb;
}
normal = vec3(-point.x / r, 0.0, -point.z / r);
} else {
vec2 uv = point.xz / (poolRadius * 2.0) + 0.5;
if (useTiles > 0.5) {
wallColor = texture(tiles, uv).rgb;
}
normal = vec3(0.0, 1.0, 0.0);
}
scale /= length(point);
vec3 refractedLight = -refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
float diffuse = max(0.0, dot(refractedLight, normal));
vec2 waterCoord = point.xz / (poolRadius * 2.0) + 0.5;
vec4 info = texture(water, waterCoord);
if (point.y < info.r) {
vec2 causticCoord = (point.xz - point.y * refractedLight.xz / refractedLight.y) / (poolRadius * 2.0);
vec4 caustic = texture(causticTex, 0.75 * causticCoord + 0.5);
scale += diffuse * caustic.r * 2.0 * caustic.g;
} else {
vec2 t = intersectCylinder(point, refractedLight, poolRadius, -poolHeight, poolHeight * 2.0);
diffuse *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (point.y + refractedLight.y * t.y - poolHeight * 2.0 / 12.0)));
scale += diffuse * 0.5;
}
return wallColor * scale;
}
@@ -0,0 +1,114 @@
precision highp float;
precision highp int;
#include <utils>
#include <cylinder_utils>
uniform float underwater;
uniform samplerCube sky;
uniform float useSky;
uniform sampler2D sceneTexture;
uniform vec2 resolution;
uniform float useSceneRefraction;
uniform float surfaceTransmittance;
uniform float normalStrength;
uniform float refractionStrength;
uniform float hasWall;
uniform vec3 surfaceColor;
uniform vec3 volumeColor;
in vec3 eye;
in vec3 pos;
out vec4 fragColor;
vec3 getSurfaceRayColor(vec3 origin, vec3 ray, vec3 waterColor) {
vec3 color;
if (ray.y < 0.0) {
vec2 t = intersectCylinder(origin, ray, poolRadius, -poolHeight, poolHeight * 2.0);
color = getCylinderWallColor(origin + ray * t.y);
} else {
vec2 t = intersectCylinder(origin, ray, poolRadius, -poolHeight, poolHeight * 2.0);
vec3 hit = origin + ray * t.y;
if (hit.y < poolHeight * 7.0 / 12.0) {
color = getCylinderWallColor(hit);
} else {
if (useSky > 0.5) {
color = texture(sky, ray).rgb;
color += 0.01 * vec3(pow(max(0.0, dot(light, ray)), 20.0)) * vec3(10.0, 8.0, 6.0);
} else {
color = waterColor;
}
}
}
if (ray.y < 0.0) color *= waterColor;
return color;
}
void main() {
if (pos.x * pos.x + pos.z * pos.z > poolRadius * poolRadius) discard;
vec2 coord = pos.xz / (poolRadius * 2.0) + 0.5;
vec4 info = texture(water, coord);
for (int i = 0; i < 5; i++) {
coord += info.ba * 0.005;
info = texture(water, coord);
}
vec2 normalXY = info.ba * normalStrength;
vec3 normal = vec3(normalXY.x, sqrt(max(0.0, 1.0 - dot(normalXY, normalXY))), normalXY.y);
vec3 incomingRay = normalize(pos - eye);
vec3 surfaceTint = surfaceColor;
vec3 volumeTint = volumeColor;
if (underwater == 1.) {
normal = -normal;
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_WATER / IOR_AIR);
float fresnel = mix(0.5, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, volumeTint);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, vec3(1.0)) * vec3(0.8, 1.0, 1.1);
if (useSceneRefraction > 0.5) {
vec2 screenUV = gl_FragCoord.xy / resolution;
vec2 refractedUV = clamp(screenUV + normal.xz * refractionStrength, 0.0, 1.0);
vec3 sceneColor = texture(sceneTexture, refractedUV).rgb;
// 有墙体时降低屏幕空间折射占比,避免水面过于“薄”
float mixFactor = surfaceTransmittance;
if (hasWall > 0.5) {
mixFactor *= 0.6;
}
refractedColor = mix(refractedColor, sceneColor, mixFactor);
}
fragColor = vec4(mix(reflectedColor, refractedColor, (1.0 - fresnel) * length(refractedRay)), 1.0);
} else {
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_AIR / IOR_WATER);
float fresnel = mix(0.25, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, surfaceTint);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, surfaceTint);
if (useSceneRefraction > 0.5) {
vec2 screenUV = gl_FragCoord.xy / resolution;
vec2 refractedUV = clamp(screenUV + normal.xz * refractionStrength, 0.0, 1.0);
vec3 sceneColor = texture(sceneTexture, refractedUV).rgb;
// 有墙体时降低屏幕空间折射占比,避免水面过于“薄”
float mixFactor = surfaceTransmittance;
if (hasWall > 0.5) {
mixFactor *= 0.6;
}
refractedColor = mix(refractedColor, sceneColor, mixFactor);
}
fragColor = vec4(mix(refractedColor, reflectedColor, fresnel), 1.0);
}
}
@@ -0,0 +1,13 @@
precision highp float;
precision highp int;
uniform sampler2D tInput;
in vec2 coord;
out vec4 fragColor;
void main() {
vec4 color = texture(tInput, coord);
fragColor = vec4(color.x, color.y, color.z, 1.);
}
@@ -0,0 +1,10 @@
uniform sampler2D tInput;
in vec3 position;
out vec2 coord;
void main() {
coord = position.xy + 0.5;
gl_Position = vec4(position.xy * 2., 0., 1.);
}
@@ -0,0 +1,47 @@
precision highp float;
precision highp int;
#include <utils>
uniform float wallOpacity;
uniform float wallMode;
uniform vec3 volumeColor;
uniform sampler2D sceneTexture;
uniform vec2 resolution;
uniform float useSceneRefraction;
uniform float surfaceTransmittance;
uniform float normalStrength;
uniform float refractionStrength;
in vec3 pos;
out vec4 fragColor;
void main() {
vec3 baseColor = wallMode > 0.5 ? volumeColor : getWallColor(pos) * volumeColor;
vec4 info = texture(water, pos.xz * 0.5 + 0.5);
vec2 screenUV = gl_FragCoord.xy / resolution;
vec2 offset = info.ba * normalStrength * refractionStrength;
vec3 mixedColor = baseColor;
if (useSceneRefraction > 0.5) {
vec2 refractedUV = clamp(screenUV + offset, 0.0, 1.0);
vec3 sceneColor = texture(sceneTexture, refractedUV).rgb;
mixedColor = mix(baseColor, sceneColor, surfaceTransmittance);
}
float depth = 0.0;
if (pos.y < info.r) {
depth = clamp((info.r - pos.y) / max(poolHeight, 0.0001), 0.0, 1.0);
float atten = wallMode > 0.5 ? mix(0.95, 0.35, depth) : mix(0.98, 0.6, depth);
mixedColor *= atten;
}
float alpha = wallOpacity;
if (wallMode > 0.5 && pos.y < info.r) {
alpha = mix(wallOpacity * 0.6, min(1.0, wallOpacity + 0.5), depth);
}
fragColor = vec4(mixedColor, alpha);
}
@@ -0,0 +1,19 @@
#include <utils>
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
in vec3 position;
out vec3 pos;
void main() {
pos = position.xyz;
pos.x *= poolHalfSize.x;
pos.z *= poolHalfSize.y;
// 墙体高度与水面齐平:y ∈ [-1, 1] 映射到 [-poolHeight, 0]
pos.y = ((1.0 - pos.y) * 0.5 - 1.0) * poolHeight;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
@@ -0,0 +1,23 @@
precision highp float;
precision highp int;
const float PI = 3.141592653589793;
uniform sampler2D tInput;
uniform vec2 center;
uniform float radius;
uniform float strength;
in vec2 coord;
out vec4 fragColor;
void main() {
/* Get vertex info */
vec4 info = texture(tInput, coord);
/* Add the drop to the height */
float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - coord) / radius);
drop = 0.5 - cos(drop * PI) * 0.5;
info.r += drop * strength;
fragColor = info;
}
@@ -0,0 +1,20 @@
precision highp float;
precision highp int;
uniform sampler2D tInput;
uniform vec2 delta;
in vec2 coord;
out vec4 fragColor;
void main() {
/* get vertex info */
vec4 info = texture(tInput, coord);
/* update the normal */
vec3 dx = vec3(delta.x, texture(tInput, vec2(coord.x + delta.x, coord.y)).r - info.r, 0.0);
vec3 dy = vec3(0.0, texture(tInput, vec2(coord.x, coord.y + delta.y)).r - info.r, delta.y);
info.ba = normalize(cross(dy, dx)).xz;
fragColor = info;
}
@@ -0,0 +1,34 @@
precision highp float;
precision highp int;
uniform sampler2D tInput;
uniform vec2 delta;
in vec2 coord;
out vec4 fragColor;
void main() {
/* get vertex info */
vec4 info = texture(tInput, coord);
/* calculate average neighbor height */
vec2 dx = vec2(delta.x, 0.0);
vec2 dy = vec2(0.0, delta.y);
float average = (
texture(tInput, coord - dx).r +
texture(tInput, coord - dy).r +
texture(tInput, coord + dx).r +
texture(tInput, coord + dy).r
) * 0.25;
/* change the velocity to move toward the average */
info.g += (average - info.r) * 2.0;
/* attenuate the velocity a little so waves do not last forever */
info.g *= 0.995;
/* move the vertex along the velocity */
info.r += info.g;
fragColor = info;
}
@@ -0,0 +1,9 @@
in vec3 position;
out vec2 coord;
void main() {
coord = position.xy * 0.5 + 0.5;
gl_Position = vec4(position.xyz, 1.0);
}
@@ -0,0 +1,87 @@
const float IOR_AIR = 1.0;
const float IOR_WATER = 1.333;
const vec3 abovewaterColor = vec3(0.25, 1.0, 1.25);
const vec3 underwaterColor = vec3(0.4, 0.9, 1.0);
uniform float poolHeight;
uniform vec2 poolHalfSize;
uniform float poolRadius;
uniform vec3 light;
uniform sampler2D tiles;
uniform sampler2D causticTex;
uniform sampler2D water;
uniform float useTiles;
uniform vec3 tilesColor;
vec2 intersectCube(vec3 origin, vec3 ray, vec3 cubeMin, vec3 cubeMax) {
vec3 tMin = (cubeMin - origin) / ray;
vec3 tMax = (cubeMax - origin) / ray;
vec3 t1 = min(tMin, tMax);
vec3 t2 = max(tMin, tMax);
float tNear = max(max(t1.x, t1.y), t1.z);
float tFar = min(min(t2.x, t2.y), t2.z);
return vec2(tNear, tFar);
}
vec3 getWallColor(vec3 point) {
float scale = 0.5;
vec3 wallColor = tilesColor;
vec3 normal;
float edgeX = poolHalfSize.x - 0.001;
float edgeZ = poolHalfSize.y - 0.001;
if (abs(point.x) > edgeX) {
vec2 uv = vec2(point.y / poolHeight, point.z / poolHalfSize.y);
if (useTiles > 0.5) {
wallColor = texture(tiles, uv * 0.5 + vec2(1.0, 0.5)).rgb;
}
normal = vec3(-sign(point.x), 0.0, 0.0);
} else if (abs(point.z) > edgeZ) {
vec2 uv = vec2(point.y / poolHeight, point.x / poolHalfSize.x);
if (useTiles > 0.5) {
wallColor = texture(tiles, uv * 0.5 + vec2(1.0, 0.5)).rgb;
}
normal = vec3(0.0, 0.0, -sign(point.z));
} else {
vec2 uv = vec2(point.x / poolHalfSize.x, point.z / poolHalfSize.y);
if (useTiles > 0.5) {
wallColor = texture(tiles, uv * 0.5 + 0.5).rgb;
}
normal = vec3(0.0, 1.0, 0.0);
}
scale /= length(point); /* pool ambient occlusion */
/* caustics */
vec3 refractedLight = -refract(-light, vec3(0.0, 1.0, 0.0), IOR_AIR / IOR_WATER);
float diffuse = max(0.0, dot(refractedLight, normal));
vec2 waterCoord = vec2(
point.x / (poolHalfSize.x * 2.0) + 0.5,
point.z / (poolHalfSize.y * 2.0) + 0.5
);
vec4 info = texture(water, waterCoord);
if (point.y < info.r) {
vec2 poolScale = poolHalfSize * 2.0;
vec2 causticCoord = (point.xz - point.y * refractedLight.xz / refractedLight.y) / poolScale;
vec4 caustic = texture(causticTex, 0.75 * causticCoord + 0.5);
scale += diffuse * caustic.r * 2.0 * caustic.g;
} else {
/* shadow for the rim of the pool */
vec2 t = intersectCube(
point,
refractedLight,
vec3(-poolHalfSize.x, -poolHeight, -poolHalfSize.y),
vec3(poolHalfSize.x, poolHeight * 2.0, poolHalfSize.y)
);
diffuse *= 1.0 / (1.0 + exp(-200.0 / (1.0 + 10.0 * (t.y - t.x)) * (point.y + refractedLight.y * t.y - poolHeight * 2.0 / 12.0)));
scale += diffuse * 0.5;
}
return wallColor * scale;
}
@@ -0,0 +1,111 @@
precision highp float;
precision highp int;
#include <utils>
uniform float underwater;
uniform samplerCube sky;
uniform float useSky;
uniform float normalStrength;
uniform sampler2D sceneTexture;
uniform vec2 resolution;
uniform float useSceneRefraction;
uniform float surfaceTransmittance;
uniform float refractionStrength;
uniform float hasWall;
uniform vec3 surfaceColor;
uniform vec3 volumeColor;
in vec3 eye;
in vec3 pos;
out vec4 fragColor;
vec3 getSurfaceRayColor(vec3 origin, vec3 ray, vec3 waterColor) {
vec3 color;
if (ray.y < 0.0) {
vec2 t = intersectCube(
origin,
ray,
vec3(-poolHalfSize.x, -poolHeight, -poolHalfSize.y),
vec3(poolHalfSize.x, poolHeight * 2.0, poolHalfSize.y)
);
color = getWallColor(origin + ray * t.y);
} else {
vec2 t = intersectCube(
origin,
ray,
vec3(-poolHalfSize.x, -poolHeight, -poolHalfSize.y),
vec3(poolHalfSize.x, poolHeight * 2.0, poolHalfSize.y)
);
vec3 hit = origin + ray * t.y;
if (hit.y < poolHeight * 7.0 / 12.0) {
color = getWallColor(hit);
} else {
if (useSky > 0.5) {
color = texture(sky, ray).rgb;
color += 0.01 * vec3(pow(max(0.0, dot(light, ray)), 20.0)) * vec3(10.0, 8.0, 6.0);
} else {
color = waterColor;
}
}
}
if (ray.y < 0.0) color *= waterColor;
return color;
}
void main() {
vec2 coord = vec2(
pos.x / (poolHalfSize.x * 2.0) + 0.5,
pos.z / (poolHalfSize.y * 2.0) + 0.5
);
vec4 info = texture(water, coord);
/* make water look more "peaked" */
for (int i = 0; i < 5; i++) {
coord += info.ba * 0.005;
info = texture(water, coord);
}
vec2 normalXY = info.ba * normalStrength;
vec3 normal = vec3(normalXY.x, sqrt(max(0.0, 1.0 - dot(normalXY, normalXY))), normalXY.y);
vec3 incomingRay = normalize(pos - eye);
vec3 surfaceTint = surfaceColor;
vec3 volumeTint = volumeColor;
if (underwater == 1.) {
normal = -normal;
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_WATER / IOR_AIR);
float fresnel = mix(0.5, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, volumeTint);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, vec3(1.0)) * vec3(0.8, 1.0, 1.1);
fragColor = vec4(mix(reflectedColor, refractedColor, (1.0 - fresnel) * length(refractedRay)), 1.0);
} else {
vec3 reflectedRay = reflect(incomingRay, normal);
vec3 refractedRay = refract(incomingRay, normal, IOR_AIR / IOR_WATER);
float fresnel = mix(0.25, 1.0, pow(1.0 - dot(normal, -incomingRay), 3.0));
vec3 reflectedColor = getSurfaceRayColor(pos, reflectedRay, surfaceTint);
vec3 refractedColor = getSurfaceRayColor(pos, refractedRay, surfaceTint);
if (useSceneRefraction > 0.5) {
vec2 screenUV = gl_FragCoord.xy / resolution;
vec2 refractedUV = clamp(screenUV + normal.xz * refractionStrength, 0.0, 1.0);
vec3 sceneColor = texture(sceneTexture, refractedUV).rgb;
// 有墙体时降低屏幕空间折射占比,避免水面过于“薄”
float mixFactor = surfaceTransmittance;
if (hasWall > 0.5) {
mixFactor *= 0.6;
}
refractedColor = mix(refractedColor, sceneColor, mixFactor);
}
fragColor = vec4(mix(refractedColor, reflectedColor, fresnel), 1.0);
}
}
@@ -0,0 +1,27 @@
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform sampler2D water;
uniform vec2 poolHalfSize;
in vec3 position;
out vec3 eye;
out vec3 pos;
void main() {
vec4 info = texture(water, position.xy * 0.5 + 0.5);
vec2 scaled = position.xy * poolHalfSize;
pos = vec3(scaled.x, info.r, scaled.y);
vec3 axis_x = vec3(modelViewMatrix[0].x, modelViewMatrix[0].y, modelViewMatrix[0].z);
vec3 axis_y = vec3(modelViewMatrix[1].x, modelViewMatrix[1].y, modelViewMatrix[1].z);
vec3 axis_z = vec3(modelViewMatrix[2].x, modelViewMatrix[2].y, modelViewMatrix[2].z);
vec3 offset = vec3(modelViewMatrix[3].x, modelViewMatrix[3].y, modelViewMatrix[3].z);
eye = vec3(dot(-offset, axis_x), dot(-offset, axis_y), dot(-offset, axis_z));
eye.x *= poolHalfSize.x;
eye.z *= poolHalfSize.y;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB