TkAstral3D/packages/sdk/public/resource/shaders/water/cylinder_utils.glsl
2026-04-08 15:34:43 +08:00

74 lines
2.3 KiB
GLSL

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;
}