From: Steinar H. Gunderson Date: Thu, 2 Aug 2018 18:17:30 +0000 (+0200) Subject: Compute diffusivity instead of smoothness, which saves a flow-size texture; shaves... X-Git-Tag: 1.8.0~76^2~144 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=632cf18d06090795ea725117b4c48bd230dda72f Compute diffusivity instead of smoothness, which saves a flow-size texture; shaves about 0.2 ms off 720p flow on GTX 950. --- diff --git a/diffusivity.frag b/diffusivity.frag new file mode 100644 index 0000000..8e83e48 --- /dev/null +++ b/diffusivity.frag @@ -0,0 +1,39 @@ +#version 450 core + +in vec2 tc; +out float g; +const float eps_sq = 0.001 * 0.001; + +uniform sampler2D flow_tex, diff_flow_tex; + +// Relative weighting of smoothness term. +uniform float alpha; + +uniform bool zero_diff_flow; + +// This must be a macro, since the offset needs to be a constant expression. +#define get_flow(x_offs, y_offs) \ + (textureOffset(flow_tex, tc, ivec2((x_offs), (y_offs))).xy + \ + textureOffset(diff_flow_tex, tc, ivec2((x_offs), (y_offs))).xy) + +#define get_flow_no_diff(x_offs, y_offs) \ + textureOffset(flow_tex, tc, ivec2((x_offs), (y_offs))).xy + +float diffusivity(float u_x, float u_y, float v_x, float v_y) +{ + return alpha * inversesqrt(u_x * u_x + u_y * u_y + v_x * v_x + v_y * v_y + eps_sq); +} + +void main() +{ + // Find diffusivity (g) for this pixel, using central differences. + if (zero_diff_flow) { + vec2 uv_x = get_flow_no_diff(1, 0) - get_flow_no_diff(-1, 0); + vec2 uv_y = get_flow_no_diff(0, 1) - get_flow_no_diff( 0, -1); + g = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); + } else { + vec2 uv_x = get_flow(1, 0) - get_flow(-1, 0); + vec2 uv_y = get_flow(0, 1) - get_flow( 0, -1); + g = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); + } +} diff --git a/equations.frag b/equations.frag index 6c4fa5d..ae32ed7 100644 --- a/equations.frag +++ b/equations.frag @@ -1,12 +1,12 @@ #version 450 core -in vec2 tc; +in vec2 tc, tc_left, tc_down; out uvec4 equation; uniform sampler2D I_x_y_tex, I_t_tex; uniform sampler2D diff_flow_tex, base_flow_tex; uniform sampler2D beta_0_tex; -uniform sampler2D smoothness_x_tex, smoothness_y_tex; +uniform sampler2D diffusivity_tex; // Relative weighting of intensity term. uniform float delta; @@ -55,6 +55,16 @@ uint pack_floats_shared(float a, float b) return (qa & 0xfffu) | ((qb & 0xfffu) << 12) | e; } +float zero_if_outside_border(vec4 val) +{ + if (val.w < 1.0f) { + // We hit the border (or more like half-way to it), so zero smoothness. + return 0.0f; + } else { + return val.x; + } +} + void main() { // Read the flow (on top of the u0/v0 flow). @@ -128,10 +138,15 @@ void main() // E_S term, sans the part on the right-hand side that deals with // the neighboring pixels. The gamma is multiplied in in smoothness.frag. - float smooth_l = textureOffset(smoothness_x_tex, tc, ivec2(-1, 0)).x; - float smooth_r = texture(smoothness_x_tex, tc).x; - float smooth_d = textureOffset(smoothness_y_tex, tc, ivec2( 0, -1)).x; - float smooth_u = texture(smoothness_y_tex, tc).x; + // + // Note that we sample in-between two texels, which gives us the 0.5 * + // (x[-1] + x[0]) part for free. If one of the texels is a border + // texel, it will have zero alpha, and zero_if_outside_border() will + // set smoothness to zero. + float smooth_l = zero_if_outside_border(texture(diffusivity_tex, tc_left)); + float smooth_r = zero_if_outside_border(textureOffset(diffusivity_tex, tc_left, ivec2(1, 0))); + float smooth_d = zero_if_outside_border(texture(diffusivity_tex, tc_down)); + float smooth_u = zero_if_outside_border(textureOffset(diffusivity_tex, tc_down, ivec2(0, 1))); A11 += smooth_l + smooth_r + smooth_d + smooth_u; A22 += smooth_l + smooth_r + smooth_d + smooth_u; diff --git a/equations.vert b/equations.vert new file mode 100644 index 0000000..6ace577 --- /dev/null +++ b/equations.vert @@ -0,0 +1,20 @@ +#version 450 core + +layout(location=0) in vec2 position; +out vec2 tc, tc_left, tc_down; + +uniform sampler2D diffusivity_tex; + +void main() +{ + // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: + // + // 2.000 0.000 0.000 -1.000 + // 0.000 2.000 0.000 -1.000 + // 0.000 0.000 -2.000 -1.000 + // 0.000 0.000 0.000 1.000 + gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); + tc = position; + tc_left = vec2(tc.x - 0.5f / textureSize(diffusivity_tex, 0).x, tc.y); + tc_down = vec2(tc.x, tc.y - 0.5f / textureSize(diffusivity_tex, 0).y); +} diff --git a/flow.cpp b/flow.cpp index feeae6b..4b69c09 100644 --- a/flow.cpp +++ b/flow.cpp @@ -625,62 +625,54 @@ void Derivatives::exec(GLuint input_tex, GLuint I_x_y_tex, GLuint beta_0_tex, in glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } -// Calculate the smoothness constraints between neighboring pixels; -// s_x(x,y) stores smoothness between pixel (x,y) and (x+1,y), -// and s_y(x,y) stores between (x,y) and (x,y+1). We'll sample with -// border color (0,0) later, so that there's zero diffusion out of -// the border. +// Calculate the diffusivity for each pixels, g(x,y). Smoothness (s) will +// be calculated in the shaders on-the-fly by sampling in-between two +// neighboring g(x,y) pixels, plus a border tweak to make sure we get +// zero smoothness at the border. // // See variational_refinement.txt for more information. -class ComputeSmoothness { +class ComputeDiffusivity { public: - ComputeSmoothness(); - void exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, int level_width, int level_height, bool zero_diff_flow); + ComputeDiffusivity(); + void exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint diffusivity_tex, int level_width, int level_height, bool zero_diff_flow); private: - PersistentFBOSet<2> fbos; + PersistentFBOSet<1> fbos; - GLuint smoothness_vs_obj; - GLuint smoothness_fs_obj; - GLuint smoothness_program; + GLuint diffusivity_vs_obj; + GLuint diffusivity_fs_obj; + GLuint diffusivity_program; GLuint uniform_flow_tex, uniform_diff_flow_tex; GLuint uniform_alpha, uniform_zero_diff_flow; }; -ComputeSmoothness::ComputeSmoothness() +ComputeDiffusivity::ComputeDiffusivity() { - smoothness_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); - smoothness_fs_obj = compile_shader(read_file("smoothness.frag"), GL_FRAGMENT_SHADER); - smoothness_program = link_program(smoothness_vs_obj, smoothness_fs_obj); - - uniform_flow_tex = glGetUniformLocation(smoothness_program, "flow_tex"); - uniform_diff_flow_tex = glGetUniformLocation(smoothness_program, "diff_flow_tex"); - uniform_alpha = glGetUniformLocation(smoothness_program, "alpha"); - uniform_zero_diff_flow = glGetUniformLocation(smoothness_program, "zero_diff_flow"); + diffusivity_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); + diffusivity_fs_obj = compile_shader(read_file("diffusivity.frag"), GL_FRAGMENT_SHADER); + diffusivity_program = link_program(diffusivity_vs_obj, diffusivity_fs_obj); + + uniform_flow_tex = glGetUniformLocation(diffusivity_program, "flow_tex"); + uniform_diff_flow_tex = glGetUniformLocation(diffusivity_program, "diff_flow_tex"); + uniform_alpha = glGetUniformLocation(diffusivity_program, "alpha"); + uniform_zero_diff_flow = glGetUniformLocation(diffusivity_program, "zero_diff_flow"); } -void ComputeSmoothness::exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, int level_width, int level_height, bool zero_diff_flow) +void ComputeDiffusivity::exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint diffusivity_tex, int level_width, int level_height, bool zero_diff_flow) { - glUseProgram(smoothness_program); + glUseProgram(diffusivity_program); - bind_sampler(smoothness_program, uniform_flow_tex, 0, flow_tex, nearest_sampler); - bind_sampler(smoothness_program, uniform_diff_flow_tex, 1, diff_flow_tex, nearest_sampler); - glProgramUniform1f(smoothness_program, uniform_alpha, vr_alpha); - glProgramUniform1i(smoothness_program, uniform_zero_diff_flow, zero_diff_flow); + bind_sampler(diffusivity_program, uniform_flow_tex, 0, flow_tex, nearest_sampler); + bind_sampler(diffusivity_program, uniform_diff_flow_tex, 1, diff_flow_tex, nearest_sampler); + glProgramUniform1f(diffusivity_program, uniform_alpha, vr_alpha); + glProgramUniform1i(diffusivity_program, uniform_zero_diff_flow, zero_diff_flow); glViewport(0, 0, level_width, level_height); glDisable(GL_BLEND); - fbos.render_to(smoothness_x_tex, smoothness_y_tex); + fbos.render_to(diffusivity_tex); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - // Make sure the smoothness on the right and upper borders is zero. - // We could have done this by making (W-1)xH and Wx(H-1) textures instead - // (we're sampling smoothness with all-zero border color), but we'd - // have to adjust the sampling coordinates, which is annoying. - glClearTexSubImage(smoothness_x_tex, 0, level_width - 1, 0, 0, 1, level_height, 1, GL_RED, GL_FLOAT, nullptr); - glClearTexSubImage(smoothness_y_tex, 0, 0, level_height - 1, 0, level_width, 1, 1, GL_RED, GL_FLOAT, nullptr); } // Set up the equations set (two equations in two unknowns, per pixel). @@ -696,7 +688,7 @@ void ComputeSmoothness::exec(GLuint flow_tex, GLuint diff_flow_tex, GLuint smoot class SetupEquations { public: SetupEquations(); - void exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex, GLuint flow_tex, GLuint beta_0_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, GLuint equation_tex, int level_width, int level_height, bool zero_diff_flow); + void exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex, GLuint flow_tex, GLuint beta_0_tex, GLuint diffusivity_tex, GLuint equation_tex, int level_width, int level_height, bool zero_diff_flow); private: PersistentFBOSet<1> fbos; @@ -708,13 +700,13 @@ private: GLuint uniform_I_x_y_tex, uniform_I_t_tex; GLuint uniform_diff_flow_tex, uniform_base_flow_tex; GLuint uniform_beta_0_tex; - GLuint uniform_smoothness_x_tex, uniform_smoothness_y_tex; + GLuint uniform_diffusivity_tex; GLuint uniform_gamma, uniform_delta, uniform_zero_diff_flow; }; SetupEquations::SetupEquations() { - equations_vs_obj = compile_shader(read_file("vs.vert"), GL_VERTEX_SHADER); + equations_vs_obj = compile_shader(read_file("equations.vert"), GL_VERTEX_SHADER); equations_fs_obj = compile_shader(read_file("equations.frag"), GL_FRAGMENT_SHADER); equations_program = link_program(equations_vs_obj, equations_fs_obj); @@ -723,14 +715,13 @@ SetupEquations::SetupEquations() uniform_diff_flow_tex = glGetUniformLocation(equations_program, "diff_flow_tex"); uniform_base_flow_tex = glGetUniformLocation(equations_program, "base_flow_tex"); uniform_beta_0_tex = glGetUniformLocation(equations_program, "beta_0_tex"); - uniform_smoothness_x_tex = glGetUniformLocation(equations_program, "smoothness_x_tex"); - uniform_smoothness_y_tex = glGetUniformLocation(equations_program, "smoothness_y_tex"); + uniform_diffusivity_tex = glGetUniformLocation(equations_program, "diffusivity_tex"); uniform_gamma = glGetUniformLocation(equations_program, "gamma"); uniform_delta = glGetUniformLocation(equations_program, "delta"); uniform_zero_diff_flow = glGetUniformLocation(equations_program, "zero_diff_flow"); } -void SetupEquations::exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex, GLuint base_flow_tex, GLuint beta_0_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, GLuint equation_tex, int level_width, int level_height, bool zero_diff_flow) +void SetupEquations::exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex, GLuint base_flow_tex, GLuint beta_0_tex, GLuint diffusivity_tex, GLuint equation_tex, int level_width, int level_height, bool zero_diff_flow) { glUseProgram(equations_program); @@ -739,8 +730,7 @@ void SetupEquations::exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex bind_sampler(equations_program, uniform_diff_flow_tex, 2, diff_flow_tex, nearest_sampler); bind_sampler(equations_program, uniform_base_flow_tex, 3, base_flow_tex, nearest_sampler); bind_sampler(equations_program, uniform_beta_0_tex, 4, beta_0_tex, nearest_sampler); - bind_sampler(equations_program, uniform_smoothness_x_tex, 5, smoothness_x_tex, zero_border_sampler); - bind_sampler(equations_program, uniform_smoothness_y_tex, 6, smoothness_y_tex, zero_border_sampler); + bind_sampler(equations_program, uniform_diffusivity_tex, 5, diffusivity_tex, zero_border_sampler); glProgramUniform1f(equations_program, uniform_delta, vr_delta); glProgramUniform1f(equations_program, uniform_gamma, vr_gamma); glProgramUniform1i(equations_program, uniform_zero_diff_flow, zero_diff_flow); @@ -758,7 +748,7 @@ void SetupEquations::exec(GLuint I_x_y_tex, GLuint I_t_tex, GLuint diff_flow_tex class SOR { public: SOR(); - void exec(GLuint diff_flow_tex, GLuint equation_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, int level_width, int level_height, int num_iterations, bool zero_diff_flow, ScopedTimer *sor_timer); + void exec(GLuint diff_flow_tex, GLuint equation_tex, GLuint diffusivity_tex, int level_width, int level_height, int num_iterations, bool zero_diff_flow, ScopedTimer *sor_timer); private: PersistentFBOSet<1> fbos; @@ -769,7 +759,7 @@ private: GLuint uniform_diff_flow_tex; GLuint uniform_equation_tex; - GLuint uniform_smoothness_x_tex, uniform_smoothness_y_tex; + GLuint uniform_diffusivity_tex; GLuint uniform_phase, uniform_zero_diff_flow; }; @@ -781,20 +771,18 @@ SOR::SOR() uniform_diff_flow_tex = glGetUniformLocation(sor_program, "diff_flow_tex"); uniform_equation_tex = glGetUniformLocation(sor_program, "equation_tex"); - uniform_smoothness_x_tex = glGetUniformLocation(sor_program, "smoothness_x_tex"); - uniform_smoothness_y_tex = glGetUniformLocation(sor_program, "smoothness_y_tex"); + uniform_diffusivity_tex = glGetUniformLocation(sor_program, "diffusivity_tex"); uniform_phase = glGetUniformLocation(sor_program, "phase"); uniform_zero_diff_flow = glGetUniformLocation(sor_program, "zero_diff_flow"); } -void SOR::exec(GLuint diff_flow_tex, GLuint equation_tex, GLuint smoothness_x_tex, GLuint smoothness_y_tex, int level_width, int level_height, int num_iterations, bool zero_diff_flow, ScopedTimer *sor_timer) +void SOR::exec(GLuint diff_flow_tex, GLuint equation_tex, GLuint diffusivity_tex, int level_width, int level_height, int num_iterations, bool zero_diff_flow, ScopedTimer *sor_timer) { glUseProgram(sor_program); bind_sampler(sor_program, uniform_diff_flow_tex, 0, diff_flow_tex, nearest_sampler); - bind_sampler(sor_program, uniform_smoothness_x_tex, 1, smoothness_x_tex, zero_border_sampler); - bind_sampler(sor_program, uniform_smoothness_y_tex, 2, smoothness_y_tex, zero_border_sampler); - bind_sampler(sor_program, uniform_equation_tex, 3, equation_tex, nearest_sampler); + bind_sampler(sor_program, uniform_diffusivity_tex, 1, diffusivity_tex, zero_border_sampler); + bind_sampler(sor_program, uniform_equation_tex, 2, equation_tex, nearest_sampler); glProgramUniform1i(sor_program, uniform_zero_diff_flow, zero_diff_flow); @@ -954,7 +942,7 @@ private: Densify densify; Prewarp prewarp; Derivatives derivatives; - ComputeSmoothness compute_smoothness; + ComputeDiffusivity compute_diffusivity; SetupEquations setup_equations; SOR sor; AddBaseFlow add_base_flow; @@ -982,11 +970,11 @@ DISComputeFlow::DISComputeFlow(int width, int height) // Similarly, gradients are zero outside the border, since the edge is taken // to be constant. glCreateSamplers(1, &zero_border_sampler); - glSamplerParameteri(zero_border_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(zero_border_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(zero_border_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(zero_border_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(zero_border_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glSamplerParameteri(zero_border_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - float zero[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float zero[] = { 0.0f, 0.0f, 0.0f, 0.0f }; // Note that zero alpha means we can also see whether we sampled outside the border or not. glSamplerParameterfv(zero_border_sampler, GL_TEXTURE_BORDER_COLOR, zero); // Initial flow is zero, 1x1. @@ -1122,41 +1110,38 @@ GLuint DISComputeFlow::exec(GLuint tex0, GLuint tex1, ResizeStrategy resize_stra // but not read until we've written something sane to it. GLuint du_dv_tex = pool.get_texture(GL_RG16F, level_width, level_height); - // And for smoothness. - GLuint smoothness_x_tex = pool.get_texture(GL_R16F, level_width, level_height); - GLuint smoothness_y_tex = pool.get_texture(GL_R16F, level_width, level_height); + // And for diffusivity. + GLuint diffusivity_tex = pool.get_texture(GL_R16F, level_width, level_height); // And finally for the equation set. See SetupEquations for // the storage format. GLuint equation_tex = pool.get_texture(GL_RGBA32UI, level_width, level_height); for (int outer_idx = 0; outer_idx < level + 1; ++outer_idx) { - // Calculate the smoothness terms between the neighboring pixels, - // both in x and y direction. + // Calculate the diffusivity term for each pixel. { - ScopedTimer timer("Compute smoothness", &varref_timer); - compute_smoothness.exec(base_flow_tex, du_dv_tex, smoothness_x_tex, smoothness_y_tex, level_width, level_height, outer_idx == 0); + ScopedTimer timer("Compute diffusivity", &varref_timer); + compute_diffusivity.exec(base_flow_tex, du_dv_tex, diffusivity_tex, level_width, level_height, outer_idx == 0); } // Set up the 2x2 equation system for each pixel. { ScopedTimer timer("Set up equations", &varref_timer); - setup_equations.exec(I_x_y_tex, I_t_tex, du_dv_tex, base_flow_tex, beta_0_tex, smoothness_x_tex, smoothness_y_tex, equation_tex, level_width, level_height, outer_idx == 0); + setup_equations.exec(I_x_y_tex, I_t_tex, du_dv_tex, base_flow_tex, beta_0_tex, diffusivity_tex, equation_tex, level_width, level_height, outer_idx == 0); } // Run a few SOR (or quasi-SOR, since we're not really Jacobi) iterations. // Note that these are to/from the same texture. { ScopedTimer timer("SOR", &varref_timer); - sor.exec(du_dv_tex, equation_tex, smoothness_x_tex, smoothness_y_tex, level_width, level_height, 5, outer_idx == 0, &timer); + sor.exec(du_dv_tex, equation_tex, diffusivity_tex, level_width, level_height, 5, outer_idx == 0, &timer); } } pool.release_texture(I_t_tex); pool.release_texture(I_x_y_tex); pool.release_texture(beta_0_tex); - pool.release_texture(smoothness_x_tex); - pool.release_texture(smoothness_y_tex); + pool.release_texture(diffusivity_tex); pool.release_texture(equation_tex); // Add the differential flow found by the variational refinement to the base flow, diff --git a/smoothness.frag b/smoothness.frag deleted file mode 100644 index 218d6df..0000000 --- a/smoothness.frag +++ /dev/null @@ -1,85 +0,0 @@ -#version 450 core - -in vec2 tc; -out float smoothness_x, smoothness_y; -const float eps_sq = 0.001 * 0.001; - -uniform sampler2D flow_tex, diff_flow_tex; - -// Relative weighting of smoothness term. -uniform float alpha; - -uniform bool zero_diff_flow; - -// This must be a macro, since the offset needs to be a constant expression. -#define get_flow(x_offs, y_offs) \ - (textureOffset(flow_tex, tc, ivec2((x_offs), (y_offs))).xy + \ - textureOffset(diff_flow_tex, tc, ivec2((x_offs), (y_offs))).xy) - -#define get_flow_no_diff(x_offs, y_offs) \ - textureOffset(flow_tex, tc, ivec2((x_offs), (y_offs))).xy - -float diffusivity(float u_x, float u_y, float v_x, float v_y) -{ - return alpha * inversesqrt(u_x * u_x + u_y * u_y + v_x * v_x + v_y * v_y + eps_sq); -} - -void main() -{ - float g, g_right, g_up; - - if (zero_diff_flow) { - // These are shared between some of the diffusivities. - vec2 flow_0_0 = get_flow_no_diff(0, 0); - vec2 flow_1_1 = get_flow_no_diff(1, 1); - - // Find diffusivity (g) for this pixel, using central differences. - { - vec2 uv_x = get_flow_no_diff(1, 0) - get_flow_no_diff(-1, 0); - vec2 uv_y = get_flow_no_diff(0, 1) - get_flow_no_diff( 0, -1); - g = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - - // Now find diffusivity for the pixel to the right. - { - vec2 uv_x = get_flow_no_diff(2, 0) - flow_0_0; - vec2 uv_y = flow_1_1 - get_flow_no_diff( 1, -1); - g_right = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - - // And up. - { - vec2 uv_x = flow_1_1 - get_flow_no_diff(-1, 1); - vec2 uv_y = get_flow_no_diff(0, 2) - flow_0_0; - g_up = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - } else { - // These are shared between some of the diffusivities. - vec2 flow_0_0 = get_flow(0, 0); - vec2 flow_1_1 = get_flow(1, 1); - - // Find diffusivity (g) for this pixel, using central differences. - { - vec2 uv_x = get_flow(1, 0) - get_flow(-1, 0); - vec2 uv_y = get_flow(0, 1) - get_flow( 0, -1); - g = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - - // Now find diffusivity for the pixel to the right. - { - vec2 uv_x = get_flow(2, 0) - flow_0_0; - vec2 uv_y = flow_1_1 - get_flow( 1, -1); - g_right = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - - // And up. - { - vec2 uv_x = flow_1_1 - get_flow(-1, 1); - vec2 uv_y = get_flow(0, 2) - flow_0_0; - g_up = diffusivity(uv_x.x, uv_y.x, uv_x.y, uv_y.y); - } - } - - smoothness_x = 0.5 * (g + g_right); - smoothness_y = 0.5 * (g + g_up); -} diff --git a/sor.frag b/sor.frag index 2b68597..91bf831 100644 --- a/sor.frag +++ b/sor.frag @@ -1,10 +1,10 @@ #version 450 core -in vec2 tc; +in vec2 tc, tc_left, tc_down; in float element_sum_idx; out vec2 diff_flow; -uniform sampler2D diff_flow_tex, smoothness_x_tex, smoothness_y_tex; +uniform sampler2D diff_flow_tex, diffusivity_tex; uniform usampler2D equation_tex; uniform int phase; @@ -27,6 +27,16 @@ vec2 unpack_floats_shared(uint c) return vec2(a, b); } +float zero_if_outside_border(vec4 val) +{ + if (val.w < 1.0f) { + // We hit the border (or more like half-way to it), so zero smoothness. + return 0.0f; + } else { + return val.x; + } +} + void main() { // Red-black SOR: Every other pass, we update every other element in a @@ -52,10 +62,10 @@ void main() // (it couldn't be done earlier, because we didn't know // the values of the neighboring pixels; they change for // each SOR iteration). - float smooth_l = textureOffset(smoothness_x_tex, tc, ivec2(-1, 0)).x; - float smooth_r = texture(smoothness_x_tex, tc).x; - float smooth_d = textureOffset(smoothness_y_tex, tc, ivec2( 0, -1)).x; - float smooth_u = texture(smoothness_y_tex, tc).x; + float smooth_l = zero_if_outside_border(texture(diffusivity_tex, tc_left)); + float smooth_r = zero_if_outside_border(textureOffset(diffusivity_tex, tc_left, ivec2(1, 0))); + float smooth_d = zero_if_outside_border(texture(diffusivity_tex, tc_down)); + float smooth_u = zero_if_outside_border(textureOffset(diffusivity_tex, tc_down, ivec2(0, 1))); b += smooth_l * textureOffset(diff_flow_tex, tc, ivec2(-1, 0)).xy; b += smooth_r * textureOffset(diff_flow_tex, tc, ivec2( 1, 0)).xy; b += smooth_d * textureOffset(diff_flow_tex, tc, ivec2( 0, -1)).xy; diff --git a/sor.vert b/sor.vert index b102442..55d1a90 100644 --- a/sor.vert +++ b/sor.vert @@ -1,10 +1,10 @@ #version 450 core layout(location=0) in vec2 position; -out vec2 tc; +out vec2 tc, tc_left, tc_down; out float element_sum_idx; -uniform sampler2D diff_flow_tex; +uniform sampler2D diff_flow_tex, diffusivity_tex; void main() { @@ -16,6 +16,8 @@ void main() // 0.000 0.000 0.000 1.000 gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); tc = position; + tc_left = vec2(tc.x - 0.5f / textureSize(diffusivity_tex, 0).x, tc.y); + tc_down = vec2(tc.x, tc.y - 0.5f / textureSize(diffusivity_tex, 0).y); vec2 element_idx = position * textureSize(diff_flow_tex, 0) - 0.5; element_sum_idx = element_idx.x + element_idx.y;