render3d: under a fog wall the volumetric air is marched only to it, SSGI stops where it is solid, and card casters that fill the wall stop rebuilding
The volumetric pass marched 800 m in a fixed number of steps whatever the wall: it now stops at the wall with steps in proportion (at least 8) - 0.57 -> 0.33 ms at 30 m by the pass timers. SSGI skipped only past 900 m; it now also skips past 0.85 of a wall, where the fog is solid (u_ao_far). applyFog samples the fog's colour only where its weight is above zero. A card layer whose casters inside the wall are 80% or more of it (a kilometre's wall) casts from its static list and is not refiltered and re-uploaded every 4 m of camera motion. Fog off: the frame unchanged (0 pixels over 8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5b3cfac48e
commit
329439cf61
32 changed files with 36 additions and 14 deletions
|
|
@ -11,7 +11,10 @@ function fog_casters(render3d_st: mut Render3dState, l: Layer) -> int {
|
||||||
if w <= 0.0 { return l.sh_buf }
|
if w <= 0.0 { return l.sh_buf }
|
||||||
let dx = render3d_st.cam_pos[0] - l.fog_x
|
let dx = render3d_st.cam_pos[0] - l.fog_x
|
||||||
let dz = render3d_st.cam_pos[2] - l.fog_z
|
let dz = render3d_st.cam_pos[2] - l.fog_z
|
||||||
if l.fog_wall == w and l.fog_src == l.n_sh and dx * dx + dz * dz < FOG_CAST_STEP * FOG_CAST_STEP { return l.fog_buf }
|
if l.fog_wall == w and l.fog_src == l.n_sh and (l.fog_all or dx * dx + dz * dz < FOG_CAST_STEP * FOG_CAST_STEP) {
|
||||||
|
if l.fog_all { return l.sh_buf }
|
||||||
|
return l.fog_buf
|
||||||
|
}
|
||||||
l.fog_wall = w; l.fog_src = l.n_sh
|
l.fog_wall = w; l.fog_src = l.n_sh
|
||||||
l.fog_x = render3d_st.cam_pos[0]; l.fog_z = render3d_st.cam_pos[2]
|
l.fog_x = render3d_st.cam_pos[0]; l.fog_z = render3d_st.cam_pos[2]
|
||||||
let far = w + R3D_FOG_MARGIN + FOG_CAST_THROW + FOG_CAST_STEP
|
let far = w + R3D_FOG_MARGIN + FOG_CAST_THROW + FOG_CAST_STEP
|
||||||
|
|
@ -30,11 +33,15 @@ function fog_casters(render3d_st: mut Render3dState, l: Layer) -> int {
|
||||||
n += 1
|
n += 1
|
||||||
}
|
}
|
||||||
l.fog_n = n
|
l.fog_n = n
|
||||||
|
# a wall that keeps nearly the whole layer (a kilometre): the static list, and no rebuild as the camera
|
||||||
|
# moves - copying and uploading 60k cards every 4 m bought nothing there
|
||||||
|
l.fog_all = n * 5 >= total * 4
|
||||||
|
if l.fog_all { return l.sh_buf }
|
||||||
if n > 0 { gpu_buffer_upload(render3d_st, l.fog_buf, n * INST_FLOATS * 4, data_of(dst), GPU_DYNAMIC) }
|
if n > 0 { gpu_buffer_upload(render3d_st, l.fog_buf, n * INST_FLOATS * 4, data_of(dst), GPU_DYNAMIC) }
|
||||||
return l.fog_buf
|
return l.fog_buf
|
||||||
}
|
}
|
||||||
|
|
||||||
function fog_casters_n(render3d_st: Render3dState, l: Layer) -> int {
|
function fog_casters_n(render3d_st: Render3dState, l: Layer) -> int {
|
||||||
if render3d_st.r3d_fog_wall <= 0.0 { return l.n_sh }
|
if render3d_st.r3d_fog_wall <= 0.0 or l.fog_all { return l.n_sh }
|
||||||
return l.fog_n
|
return l.fog_n
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,10 @@ function post_ssao_pass(render3d_st: mut Render3dState) -> void {
|
||||||
u_f2(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_texel"), 1.0 / float(render3d_st.post_w), 1.0 / float(render3d_st.post_h))
|
u_f2(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_texel"), 1.0 / float(render3d_st.post_w), 1.0 / float(render3d_st.post_h))
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_radius"), render3d_st.post_ao_radius)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_radius"), render3d_st.post_ao_radius)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_intensity"), render3d_st.post_ao_intensity)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_intensity"), render3d_st.post_ao_intensity)
|
||||||
|
# nothing to shade past where a fog wall is solid (0.85 of it)
|
||||||
|
var ao_far = 900.0
|
||||||
|
if render3d_st.r3d_fog_wall > 0.0 { ao_far = Math.min(ao_far, 0.85 * render3d_st.r3d_fog_wall) }
|
||||||
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_ao_far"), ao_far)
|
||||||
var contact = render3d_st.post_contact
|
var contact = render3d_st.post_contact
|
||||||
if r3d_env_has(render3d_st, "R3D_NOCONTACT") { contact = 0.0 }
|
if r3d_env_has(render3d_st, "R3D_NOCONTACT") { contact = 0.0 }
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_contact"), contact)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_ao, "u_contact"), contact)
|
||||||
|
|
@ -266,10 +270,17 @@ function post_volumetric_pass(render3d_st: mut Render3dState) -> void {
|
||||||
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_cam_pos"), render3d_st.cam_pos)
|
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_cam_pos"), render3d_st.cam_pos)
|
||||||
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_sun_dir"), render3d_st.sun_dir)
|
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_sun_dir"), render3d_st.sun_dir)
|
||||||
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_sun_color"), render3d_st.sun_color)
|
u_v3(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_sun_color"), render3d_st.sun_color)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_steps"), render3d_st.post_vol_steps)
|
# under a fog wall the air is marched only as far as it, with steps in proportion (at least 8)
|
||||||
|
var vfar = render3d_st.post_vol_far
|
||||||
|
var vsteps = render3d_st.post_vol_steps
|
||||||
|
if render3d_st.r3d_fog_wall > 0.0 and render3d_st.r3d_fog_wall < vfar {
|
||||||
|
vsteps = Math.max(8.0, Math.floor(vsteps * render3d_st.r3d_fog_wall / vfar))
|
||||||
|
vfar = render3d_st.r3d_fog_wall
|
||||||
|
}
|
||||||
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_steps"), vsteps)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_density"), render3d_st.post_vol_density)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_density"), render3d_st.post_vol_density)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_falloff"), render3d_st.post_vol_falloff)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_falloff"), render3d_st.post_vol_falloff)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_far"), render3d_st.post_vol_far)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_far"), vfar)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_g"), render3d_st.post_vol_g)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_g"), render3d_st.post_vol_g)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_mist"), render3d_st.post_vol_mist)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_mist"), render3d_st.post_vol_mist)
|
||||||
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_mist_h"), render3d_st.post_vol_mist_h)
|
u_f(render3d_st, gpu_uniform(render3d_st, render3d_st.post_p_vol, "u_vol_mist_h"), render3d_st.post_vol_mist_h)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ property Layer {
|
||||||
fog_buf: int = 0, # the casters inside the fog wall (fog_casters.ludic)
|
fog_buf: int = 0, # the casters inside the fog wall (fog_casters.ludic)
|
||||||
fog_n: int = 0,
|
fog_n: int = 0,
|
||||||
fog_src: int = -1,
|
fog_src: int = -1,
|
||||||
|
fog_all: bool = false, # the wall keeps (nearly) all of it: casters from sh_buf, no rebuild
|
||||||
fog_wall: float = 0.0,
|
fog_wall: float = 0.0,
|
||||||
fog_x: float = 0.0,
|
fog_x: float = 0.0,
|
||||||
fog_z: float = 0.0,
|
fog_z: float = 0.0,
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ vec3 applyFog(vec3 col, vec3 wpos, float dist) {
|
||||||
if (u_fog_wall > 0.0) {
|
if (u_fog_wall > 0.0) {
|
||||||
// full by 0.85 of the wall, so whatever is cut at the wall is cut inside solid fog
|
// full by 0.85 of the wall, so whatever is cut at the wall is cut inside solid fog
|
||||||
float w = smoothstep(0.3 * u_fog_wall, 0.85 * u_fog_wall, dist);
|
float w = smoothstep(0.3 * u_fog_wall, 0.85 * u_fog_wall, dist);
|
||||||
col = mix(col, fogWallCol(dir), w);
|
if (w > 0.0) col = mix(col, fogWallCol(dir), w);
|
||||||
}
|
}
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -551,7 +551,7 @@ T 3e4b62f9 u_tershadow 8
|
||||||
T 3e4b62f9 u_tershadow_aux 9
|
T 3e4b62f9 u_tershadow_aux 9
|
||||||
T 3e4b62f9 u_ts_height 10
|
T 3e4b62f9 u_ts_height 10
|
||||||
P 676965ab fullscreen.vert ssgi.frag
|
P 676965ab fullscreen.vert ssgi.frag
|
||||||
B 676965ab frag 1 984
|
B 676965ab frag 1 1000
|
||||||
U 676965ab frag u_cascade_vp 0 mat4 5 64
|
U 676965ab frag u_cascade_vp 0 mat4 5 64
|
||||||
U 676965ab frag u_cascade_split 320 float 5 16
|
U 676965ab frag u_cascade_split 320 float 5 16
|
||||||
U 676965ab frag u_cascade_range 400 float 5 16
|
U 676965ab frag u_cascade_range 400 float 5 16
|
||||||
|
|
@ -588,13 +588,14 @@ U 676965ab frag u_time 816 float 1 0
|
||||||
U 676965ab frag u_fog_inscatter 820 float 1 0
|
U 676965ab frag u_fog_inscatter 820 float 1 0
|
||||||
U 676965ab frag u_fog_desat 824 float 1 0
|
U 676965ab frag u_fog_desat 824 float 1 0
|
||||||
U 676965ab frag u_fog_wall 828 float 1 0
|
U 676965ab frag u_fog_wall 828 float 1 0
|
||||||
U 676965ab frag u_inv_proj 832 mat4 1 0
|
U 676965ab frag u_ao_far 832 float 1 0
|
||||||
U 676965ab frag u_proj 896 mat4 1 0
|
U 676965ab frag u_inv_proj 848 mat4 1 0
|
||||||
U 676965ab frag u_texel 960 vec2 1 0
|
U 676965ab frag u_proj 912 mat4 1 0
|
||||||
U 676965ab frag u_radius 968 float 1 0
|
U 676965ab frag u_texel 976 vec2 1 0
|
||||||
U 676965ab frag u_intensity 972 float 1 0
|
U 676965ab frag u_radius 984 float 1 0
|
||||||
U 676965ab frag u_contact 976 float 1 0
|
U 676965ab frag u_intensity 988 float 1 0
|
||||||
U 676965ab frag u_frame 980 float 1 0
|
U 676965ab frag u_contact 992 float 1 0
|
||||||
|
U 676965ab frag u_frame 996 float 1 0
|
||||||
T 676965ab u_brdf 2
|
T 676965ab u_brdf 2
|
||||||
T 676965ab u_depth 3
|
T 676965ab u_depth 3
|
||||||
T 676965ab u_irradiance 4
|
T 676965ab u_irradiance 4
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// frame's lit colour; half resolution, denoised over time by the TAA history it feeds
|
// frame's lit colour; half resolution, denoised over time by the TAA history it feeds
|
||||||
in vec2 v_uv;
|
in vec2 v_uv;
|
||||||
out vec4 o_color;
|
out vec4 o_color;
|
||||||
|
uniform float u_ao_far;
|
||||||
uniform sampler2D u_depth;
|
uniform sampler2D u_depth;
|
||||||
uniform sampler2D u_prev_color; // last frame's anti-aliased HDR colour
|
uniform sampler2D u_prev_color; // last frame's anti-aliased HDR colour
|
||||||
uniform mat4 u_inv_proj;
|
uniform mat4 u_inv_proj;
|
||||||
|
|
@ -18,7 +19,8 @@ vec3 viewPos(vec2 uv) {
|
||||||
}
|
}
|
||||||
void main() {
|
void main() {
|
||||||
vec3 P = viewPos(v_uv);
|
vec3 P = viewPos(v_uv);
|
||||||
if (-P.z > 900.0) { o_color = vec4(0.0, 0.0, 0.0, 1.0); return; }
|
// past 900 m, or where a fog wall has already hidden everything (u_ao_far, post.ludic)
|
||||||
|
if (-P.z > (u_ao_far > 0.0 ? u_ao_far : 900.0)) { o_color = vec4(0.0, 0.0, 0.0, 1.0); return; }
|
||||||
vec3 Pr = viewPos(v_uv + vec2(u_texel.x, 0.0)), Pl = viewPos(v_uv - vec2(u_texel.x, 0.0));
|
vec3 Pr = viewPos(v_uv + vec2(u_texel.x, 0.0)), Pl = viewPos(v_uv - vec2(u_texel.x, 0.0));
|
||||||
vec3 Pu = viewPos(v_uv + vec2(0.0, u_texel.y)), Pd = viewPos(v_uv - vec2(0.0, u_texel.y));
|
vec3 Pu = viewPos(v_uv + vec2(0.0, u_texel.y)), Pd = viewPos(v_uv - vec2(0.0, u_texel.y));
|
||||||
vec3 dx = (abs(Pr.z - P.z) < abs(P.z - Pl.z)) ? Pr - P : P - Pl;
|
vec3 dx = (abs(Pr.z - P.z) < abs(P.z - Pl.z)) ? Pr - P : P - Pl;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue