fix(render3d): lakes clipped to their ellipse; r3d_fog_base
A water body other than the reflecting one drew its whole bounding rectangle, so the corners outside the lake's carved ellipse showed water over dry ground; those bodies now discard outside the ellipse. r3d_fog_base (default 0) is the height the height fog is measured from, so maps sharing one datum at different heights get the same air. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
7a0c03dd21
commit
3e76785b40
6 changed files with 26 additions and 1 deletions
|
|
@ -8,6 +8,7 @@
|
|||
var r3d_sky_prog: int = 0
|
||||
var r3d_fog_density: int = 0
|
||||
var r3d_fog_falloff: int = 0
|
||||
var r3d_fog_base: int = 0 # the height fog is measured from (float bits); 0 = y = 0
|
||||
var r3d_time: int = 0
|
||||
var r3d_ready: bool = false
|
||||
# set before r3d_init to build the landscape from a real height map
|
||||
|
|
@ -30,6 +31,7 @@ function fog_bind(prog: int) -> void {
|
|||
u_f(gl_uniform(prog, "u_spec_scale"), F_ONE)
|
||||
u_f(gl_uniform(prog, "u_fog_density"), r3d_fog_density)
|
||||
u_f(gl_uniform(prog, "u_fog_height_falloff"), r3d_fog_falloff)
|
||||
u_f(gl_uniform(prog, "u_fog_base"), r3d_fog_base)
|
||||
var cs = r3d_cloud_shadow
|
||||
if Os.has_env("R3D_NOCLOUD") { cs = F_ZERO }
|
||||
u_f(gl_uniform(prog, "u_cloud_shadow"), cs)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ uniform vec3 u_cam_pos;
|
|||
uniform float u_prefilter_levels;
|
||||
uniform float u_fog_density;
|
||||
uniform float u_fog_height_falloff;
|
||||
uniform float u_fog_base; // the height the fog's density is measured from (0 = the world's y = 0)
|
||||
uniform float u_clip_y; // planar-reflection pass: discard everything below this height
|
||||
uniform float u_spec_scale; // 1 for surfaces; foliage crowns get a fraction: needles are
|
||||
// tiny rough cylinders, not sheets, and a crown of card quads
|
||||
|
|
@ -263,7 +264,9 @@ vec3 applyFog(vec3 col, vec3 wpos, float dist) {
|
|||
float hf = u_fog_height_falloff;
|
||||
float t = dir.y * hf;
|
||||
float integ = (abs(t) > 1e-4) ? (1.0 - exp(-dist * t)) / t : dist * (1.0 - 0.5 * dist * t);
|
||||
float fogAmt = u_fog_density * exp(-u_cam_pos.y * hf) * integ;
|
||||
// measured from u_fog_base: two maps on one height datum, one a thousand metres lower,
|
||||
// would otherwise have that one's air exp(falloff * 1000) times thicker
|
||||
float fogAmt = u_fog_density * exp(-(u_cam_pos.y - u_fog_base) * hf) * integ;
|
||||
float f = 1.0 - exp(-fogAmt);
|
||||
vec3 fogCol = skyPrefiltered(vec3(dir.x, max(dir.y, 0.02), dir.z), 0.6);
|
||||
float sunAmt = pow(max(dot(dir, u_sun_dir), 0.0), 8.0);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ uniform mat4 u_inv_vp;
|
|||
uniform vec2 u_screen;
|
||||
uniform sampler2D u_refl; // the world mirrored in the surface (rendered by the reflection pass)
|
||||
uniform float u_refl_on;
|
||||
uniform vec2 u_center; // this body's centre and half extents (world xz)
|
||||
uniform vec2 u_extent;
|
||||
uniform float u_clip_ellipse; // 1: the body is the ellipse inside its rectangle (a lake), 0: the whole plane (the sea)
|
||||
uniform sampler2D u_scene; // the scene as drawn before the water: the bed, to refract
|
||||
// wind-streaked capillary ripples (stretched along the wind) over slower swells
|
||||
float waterH(vec2 p, float t) {
|
||||
|
|
@ -21,6 +24,13 @@ vec3 rippleNormal(vec2 p, float t) {
|
|||
return normalize(vec3(-(hx - h) * 0.26 / e, 1.0, -(hz - h) * 0.26 / e));
|
||||
}
|
||||
void main() {
|
||||
// A lake is an ellipse - the carved bed, the grass and a game's own water test all use
|
||||
// one - but its plane is the rectangle around it, and the corners between the two hold
|
||||
// ground below the lake's level. Without this they show as sheets of water on dry land.
|
||||
if (u_clip_ellipse > 0.5) {
|
||||
vec2 q = (v_wpos.xz - u_center) / max(u_extent, vec2(0.001));
|
||||
if (dot(q, q) > 1.0) discard;
|
||||
}
|
||||
vec3 v = normalize(u_cam_pos - v_wpos);
|
||||
float dist = length(u_cam_pos - v_wpos);
|
||||
vec3 n = rippleNormal(v_wpos.xz, u_time);
|
||||
|
|
|
|||
|
|
@ -177,6 +177,10 @@ function water_draw(depth_tex: int) -> void {
|
|||
var r = F_ZERO
|
||||
if i == wb_primary { r = ron }
|
||||
u_f(gl_uniform(p, "u_refl_on"), r)
|
||||
# every body but the mirrored sea is clipped to the ellipse inside its bounds
|
||||
var clip = F_ONE
|
||||
if i == wb_primary { clip = F_ZERO }
|
||||
u_f(gl_uniform(p, "u_clip_ellipse"), clip)
|
||||
mesh_draw(water_mesh)
|
||||
}
|
||||
gl_disable(GL_BLEND)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue