Fix winding fill blending

(Using somewhat of a hack)
This commit is contained in:
Grant Sanderson 2023-01-26 15:27:48 -08:00
parent 3f5df432ce
commit 37f0bf8c11
4 changed files with 29 additions and 12 deletions

View file

@ -289,10 +289,9 @@ class FillShaderWrapper(ShaderWrapper):
texture_fbo.clear()
texture_fbo.use()
self.ctx.blend_func = (moderngl.ONE, moderngl.ONE)
vao.render(self.render_primitive)
vao.render()
self.ctx.blend_func = (moderngl.ONE, moderngl.ONE_MINUS_SRC_ALPHA)
original_fbo.use()
self.ctx.blend_func = (moderngl.ONE, moderngl.ONE_MINUS_SRC_ALPHA)
texture_vao.render(moderngl.TRIANGLE_STRIP)
self.ctx.blend_func = moderngl.DEFAULT_BLENDING
self.ctx.blend_func = (moderngl.DEFAULT_BLENDING)

View file

@ -13,12 +13,26 @@ void main() {
if (color.a == 0) discard;
frag_color = color;
// Pre-multiply alphas
if(winding) frag_color *= frag_color.a;
/*
We want negatively oriented triangles to be canceled with positively
oriented ones. The easiest way to do this is to give them negative alpha,
and change the blend function to just add them. However, this messes with
usual blending, so instead the following line is meant to let this canceling
work even for the normal blending equation:
// Give a sign based on orientation so that
// additive blending cancels as needed
if(winding && orientation < 0) frag_color *= -1;
(1 - alpha) * dst + alpha * src
We want the effect of blending with a positively oriented triangle followed
by a negatively oriented one to return to whatever the original frag value
was. You can work out this will work if the alpha for negative orientations
is changed to -alpha / (1 - alpha). This has a singularity at alpha = 1,
so we cap it at a value very close to 1. Effectively, the purpose of this
cap is to make sure the original fragment color can be recovered even after
blending with an alpha = 1 color.
*/
float a = 0.999 * frag_color.a;
if(winding && orientation < 0) a = -a / (1 - a);
frag_color.a = a;
if (bool(fill_all)) return;

View file

@ -36,6 +36,11 @@ void emit_triangle(vec3 points[3], vec4 v_color[3]){
for(int i = 0; i < 3; i++){
uv_coords = SIMPLE_QUADRATIC[i];
color = finalize_color(v_color[i], points[i], unit_normal);
if(winding){
// Pure black will be used to discard fragments later
if(color.rgb == vec3(0.0)) color.rgb += vec3(0.01);
// color.a = sqrt(color.a);
}
gl_Position = get_gl_Position(points[i]);
EmitVertex();
}

View file

@ -110,7 +110,7 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
size = (2 * DEFAULT_PIXEL_WIDTH, 2 * DEFAULT_PIXEL_HEIGHT)
# Important to make sure dtype is floating point (not fixed point)
# so that alpha values can be negative and are not clipped
texture = ctx.texture(size=size, components=4, dtype='f2')
texture = ctx.texture(size=size, components=4, dtype='f4')
depth_buffer = ctx.depth_renderbuffer(size) # TODO, currently not used
texture_fbo = ctx.framebuffer(texture, depth_buffer)
@ -147,8 +147,7 @@ def get_fill_palette(ctx) -> Tuple[Framebuffer, VertexArray]:
0.25 * texture(Texture, tc1) +
0.25 * texture(Texture, tc2) +
0.25 * texture(Texture, tc3);
if(frag_color.a == 0) discard;
frag_color = abs(frag_color);
if(distance(frag_color.rgb, vec3(0.0)) < 1e-3) discard;
//TODO, set gl_FragDepth;
}
''',