feat(all): 迁移扩展相关功能
This commit is contained in:
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 |
Reference in New Issue
Block a user