From 1da53713b7fc7a69e37263e194686a805db56fcb Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 11 Sep 2022 20:23:52 +0300 Subject: [PATCH] Remove the separate clamping step from forest pond fluid simulation Instead calculate clamping on the fly in the integration shader. This ends up using a few less texture reads in total. --- demos/forestpond/data/fluidsim.glsl | 14 +++++-- demos/forestpond/data/fluidsim_clamp.glsl | 21 ---------- demos/forestpond/data/fluidsim_fill.glsl | 2 - demos/forestpond/data/fluidsim_integrate.glsl | 42 ++++++++++--------- demos/forestpond/data/fluidsim_velocity.glsl | 22 ++++------ demos/forestpond/source/water.cpp | 10 ----- demos/forestpond/source/water.h | 2 - 7 files changed, 40 insertions(+), 73 deletions(-) delete mode 100644 demos/forestpond/data/fluidsim_clamp.glsl diff --git a/demos/forestpond/data/fluidsim.glsl b/demos/forestpond/data/fluidsim.glsl index c4400268..0f58a9b2 100644 --- a/demos/forestpond/data/fluidsim.glsl +++ b/demos/forestpond/data/fluidsim.glsl @@ -19,13 +19,19 @@ layout(push_constant) uniform Time uniform sampler2D surface_in; uniform sampler2D velocity_in; -uniform sampler2D clamping_in; uniform sampler2D bottom_in; layout(r32f) uniform image2D surface_out; layout(rg32f) uniform image2D velocity_out; -layout(r32f) uniform image2D clamping_out; -float get_depth(ivec2 coord) +vec2 get_depth(ivec2 coord) { - return texelFetch(surface_in, coord, 0).x-texelFetch(bottom_in, coord, 0).x; + float surface = texelFetch(surface_in, coord, 0).x; + float bottom = texelFetch(bottom_in, coord, 0).x; + return vec2(surface, surface-bottom); +} + +vec4 get_data(ivec2 coord) +{ + vec2 velocity = texelFetch(velocity_in, coord, 0).xy; + return vec4(velocity, get_depth(coord)); } diff --git a/demos/forestpond/data/fluidsim_clamp.glsl b/demos/forestpond/data/fluidsim_clamp.glsl deleted file mode 100644 index 93e8bbcf..00000000 --- a/demos/forestpond/data/fluidsim_clamp.glsl +++ /dev/null @@ -1,21 +0,0 @@ -import fluidsim; - -#pragma MSP stage(compute) -void main() -{ - ivec2 size = imageSize(clamping_out); - ivec2 coord = ivec2(gl_GlobalInvocationID.xy)+ivec2(1, 1); - if(coord.x>=size.x-1 || coord.y>=size.y-1) - return; - - float depth = get_depth(coord); - vec2 velocity = texelFetch(velocity_in, coord, 0).xy; - float left_vx = texelFetch(velocity_in, coord-ivec2(1, 0), 0).x; - float down_vy = texelFetch(velocity_in, coord-ivec2(0, 1), 0).y; - - // Clamping step: prevent fluid depth from going negative - float total_out = max(velocity.x, 0.0)+max(velocity.y, 0.0)-min(left_vx, 0.0)-min(down_vy, 0.0); - float scale = min(max_flow_fraction/(total_out*delta_time), depth/residual_depth); - - imageStore(clamping_out, coord, vec4(clamp(scale, 0.0, 1.0), 0.0, 0.0, 0.0)); -} diff --git a/demos/forestpond/data/fluidsim_fill.glsl b/demos/forestpond/data/fluidsim_fill.glsl index 61f1f320..495ea1c3 100644 --- a/demos/forestpond/data/fluidsim_fill.glsl +++ b/demos/forestpond/data/fluidsim_fill.glsl @@ -6,7 +6,6 @@ layout(local_size_x=8, local_size_y=8) in; uniform sampler2D bottom; layout(r32f) uniform image2D surface_out; layout(rg32f) uniform image2D velocity_out; -layout(r32f) uniform image2D clamping_out; void main() { @@ -14,5 +13,4 @@ void main() float surface = max(texelFetch(bottom, coord, 0).x, 0.0); imageStore(surface_out, coord, vec4(surface, 0.0, 0.0, 0.0)); imageStore(velocity_out, coord, vec4(0.0)); - imageStore(clamping_out, coord, vec4(0.0)); } diff --git a/demos/forestpond/data/fluidsim_integrate.glsl b/demos/forestpond/data/fluidsim_integrate.glsl index f3805e8a..da3e8c18 100644 --- a/demos/forestpond/data/fluidsim_integrate.glsl +++ b/demos/forestpond/data/fluidsim_integrate.glsl @@ -8,28 +8,30 @@ void main() if(coord.x>=size.x-1 || coord.y>=size.y-1) return; - float surface = texelFetch(surface_in, coord, 0).x; - float bottom = texelFetch(bottom_in, coord, 0).x; - float depth = surface-bottom; - vec2 velocity = texelFetch(velocity_in, coord, 0).xy; - float clamping = texelFetch(clamping_in, coord, 0).x; - float left_depth = get_depth(coord-ivec2(1, 0)); - float left_clamping = texelFetch(clamping_in, coord-ivec2(1, 0), 0).x; - float left_vx = texelFetch(velocity_in, coord-ivec2(1, 0), 0).x; - float right_depth = get_depth(coord+ivec2(1, 0)); - float right_clamping = texelFetch(clamping_in, coord+ivec2(1, 0), 0).x; - float down_depth = get_depth(coord-ivec2(0, 1)); - float down_clamping = texelFetch(clamping_in, coord-ivec2(0, 1), 0).x; - float down_vy = texelFetch(velocity_in, coord-ivec2(0, 1), 0).y; - float up_depth = get_depth(coord+ivec2(0, 1)); - float up_clamping = texelFetch(clamping_in, coord+ivec2(0, 1), 0).x; + vec4 data = get_data(coord); + vec4 right_data = get_data(coord+ivec2(1, 0)); + vec4 up_data = get_data(coord+ivec2(0, 1)); + vec4 left_data = get_data(coord-ivec2(1, 0)); + vec4 down_data = get_data(coord-ivec2(0, 1)); + + float ul_vx = texelFetch(velocity_in, coord+ivec2(-1, 1), 0).x; + float left2_vx = texelFetch(velocity_in, coord-ivec2(2, 0), 0).x; + vec2 dl_velocity = texelFetch(velocity_in, coord-ivec2(1, 1), 0).xy; + float down2_vy = texelFetch(velocity_in, coord-ivec2(0, 2), 0).y; + float dr_vy = texelFetch(velocity_in, coord+ivec2(1, -1), 0).y; + + float clamping = get_clamping(data.w, data.x, data.y, left_data.x, down_data.y); + float right_cl = get_clamping(right_data.w, right_data.x, right_data.y, data.x, dr_vy); + float up_cl = get_clamping(up_data.w, up_data.x, up_data.y, ul_vx, data.y); + float left_cl = get_clamping(left_data.w, left_data.x, left_data.y, left2_vx, dl_velocity.y); + float down_cl = get_clamping(down_data.w, down_data.x, down_data.y, dl_velocity.x, down2_vy); // Integration step: change surface level based on velocities - float total_flow = left_vx*mix(left_depth*left_clamping, depth*clamping, left_vx<0)- - velocity.x*mix(depth*clamping, right_depth*right_clamping, velocity.x<0)+ - down_vy*mix(down_depth*down_clamping, depth*clamping, down_vy<0)- - velocity.y*mix(depth*clamping, up_depth*up_clamping, velocity.y<0); - float new_surface = surface+total_flow*delta_time; + float total_flow_out = data.x*mix(data.w*clamping, right_data.w*right_cl, data.x<0)+ + data.y*mix(data.w*clamping, up_data.w*up_cl, data.y<0)- + left_data.x*mix(data.w*clamping, left_data.w*left_cl, left_data.x>0)- + down_data.y*mix(data.w*clamping, down_data.w*down_cl, down_data.y>0); + float new_surface = data.z-total_flow_out*delta_time; imageStore(surface_out, coord, vec4(new_surface, 0.0, 0.0, 0.0)); } diff --git a/demos/forestpond/data/fluidsim_velocity.glsl b/demos/forestpond/data/fluidsim_velocity.glsl index b564b231..375e205e 100644 --- a/demos/forestpond/data/fluidsim_velocity.glsl +++ b/demos/forestpond/data/fluidsim_velocity.glsl @@ -8,30 +8,24 @@ void main() if(coord.x>=size.x-1 || coord.y>=size.y-1) return; - float surface = texelFetch(surface_in, coord, 0).x; - float depth = surface-texelFetch(bottom_in, coord, 0).x; - float surface_left = texelFetch(surface_in, coord-ivec2(1, 0), 0).x; - float surface_right = texelFetch(surface_in, coord+ivec2(1, 0), 0).x; - float depth_right = surface_right-texelFetch(bottom_in, coord+ivec2(1, 0), 0).x; - float surface_down = texelFetch(surface_in, coord-ivec2(0, 1), 0).x; - float surface_up = texelFetch(surface_in, coord+ivec2(0, 1), 0).x; - float depth_up = surface_up-texelFetch(bottom_in, coord+ivec2(0, 1), 0).x; - vec2 velocity = texelFetch(velocity_in, coord, 0).xy; + vec4 data = get_data(coord); + vec2 sd_right = get_depth(coord+ivec2(1, 0)); + vec2 sd_up = get_depth(coord+ivec2(0, 1)); // Advection step: move velocity vectors vec2 uv_coord = (vec2(coord)+vec2(0.5))/size; vec2 offset = vec2(0.5, -0.5)/size; vec2 multi = delta_time/size; - vec2 v_right = vec2(velocity.x, textureLod(velocity_in, uv_coord+offset, 0).y); - vec2 v_up = vec2(textureLod(velocity_in, uv_coord-offset, 0).x, velocity.y); + vec2 v_right = vec2(data.x, textureLod(velocity_in, uv_coord+offset, 0).y); + vec2 v_up = vec2(textureLod(velocity_in, uv_coord-offset, 0).x, data.y); vec2 new_velocity = vec2(textureLod(velocity_in, uv_coord-v_right*multi, 0).x, textureLod(velocity_in, uv_coord-v_up*multi, 0).y)*velocity_damping; // Update step: change velocities based on surface level differences - vec2 source_depth = mix(vec2(depth_right, depth_up), vec2(depth), greaterThan(vec2(surface), vec2(surface_right, surface_up))); - new_velocity += (vec2(surface)-vec2(surface_right, surface_up))*0.1*gravity*delta_time*min(source_depth/residual_depth, 1.0); + vec2 source_depth = mix(vec2(sd_right.y, sd_up.y), vec2(data.w), greaterThan(vec2(data.z), vec2(sd_right.x, sd_up.x))); + new_velocity += (vec2(data.z)-vec2(sd_right.x, sd_up.x))*0.1*gravity*delta_time*min(source_depth/residual_depth, 1.0); - if(time>=drop_time && time<=drop_time+0.01 && depth>1.0) + if(time>=drop_time && time<=drop_time+0.01 && data.w>1.0) { ivec2 d = coord-drop_pos; if(d.x*d.x+d.y*d.y<4) diff --git a/demos/forestpond/source/water.cpp b/demos/forestpond/source/water.cpp index 03709034..d44e7089 100644 --- a/demos/forestpond/source/water.cpp +++ b/demos/forestpond/source/water.cpp @@ -17,7 +17,6 @@ Water::Water(const GL::Object &o, DataFile::Collection &resources, const Region sampler(resources.get("linear_clip.samp")), sim_integrate(resources.get("fluidsim_integrate.glsl.shader")), sim_velocity(resources.get("fluidsim_velocity.glsl.shader")), - sim_clamp(resources.get("fluidsim_clamp.glsl.shader")), normals_shader(resources.get("water_normals.glsl.shader")), variance_x_shader(resources.get("water_variance_x.glsl.shader")), variance_y_shader(resources.get("water_variance_y.glsl.shader")) @@ -41,8 +40,6 @@ Water::Water(const GL::Object &o, DataFile::Collection &resources, const Region state[i].surface.set_debug_name(format("Water surface[%d]", i)); state[i].velocity.storage(GL::RG32F, width, height, 1); state[i].velocity.set_debug_name(format("Water velocity[%d]", i)); - state[i].clamping.storage(GL::R32F, width, height, 1); - state[i].clamping.set_debug_name(format("Water clamping[%d]", i)); } normals.storage(GL::RG8, width, height, 1); @@ -77,7 +74,6 @@ Water::Water(const GL::Object &o, DataFile::Collection &resources, const Region { renderer.set_storage_texture("surface_out", &state[i].surface); renderer.set_storage_texture("velocity_out", &state[i].velocity); - renderer.set_storage_texture("clamping_out", &state[i].clamping); renderer.dispatch((width+7)/8, (height+7)/8); } renderer.end(); @@ -107,20 +103,14 @@ void Water::setup_frame(GL::Renderer &renderer) renderer.set_shader_program(&sim_integrate); renderer.set_storage_texture("surface_out", &next->surface); renderer.set_storage_texture("velocity_out", &next->velocity); - renderer.set_storage_texture("clamping_out", &next->clamping); renderer.set_texture("surface_in", ¤t->surface, &sampler); renderer.set_texture("velocity_in", ¤t->velocity, &sampler); - renderer.set_texture("clamping_in", ¤t->clamping, &sampler); renderer.dispatch(groups_x, groups_y); renderer.set_shader_program(&sim_velocity); renderer.set_texture("surface_in", &next->surface, &sampler); renderer.dispatch(groups_x, groups_y); - renderer.set_shader_program(&sim_clamp); - renderer.set_texture("velocity_in", &next->velocity, &sampler); - renderer.dispatch(groups_x, groups_y); - time += stepsize; swap(current, next); } diff --git a/demos/forestpond/source/water.h b/demos/forestpond/source/water.h index 88bf9359..3ef5862a 100644 --- a/demos/forestpond/source/water.h +++ b/demos/forestpond/source/water.h @@ -22,7 +22,6 @@ private: { Msp::GL::Texture2D surface; Msp::GL::Texture2D velocity; - Msp::GL::Texture2D clamping; }; unsigned width; @@ -40,7 +39,6 @@ private: const Msp::GL::Sampler &sampler; const Msp::GL::Program &sim_integrate; const Msp::GL::Program &sim_velocity; - const Msp::GL::Program &sim_clamp; const Msp::GL::Program &normals_shader; const Msp::GL::Program &variance_x_shader; const Msp::GL::Program &variance_y_shader; -- 2.45.2