I'm working on a WebGL project that resembles a particle system. For aesthetic purposes, my single rendering pass is configured to blend additively , and I've disabled depth testing. I'm also clearing my viewport buffer to 50% gray , for the sake of argument.
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE);
gl.disable(gl.DEPTH_TEST);
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
I've uploaded a vertex buffer and index buffer to the GPU representing two partially overlapping triangles . Their vertices have a vec3 color attribute . I've assigned each vertex a color of 50% gray (0.5, 0.5, 0.5) .
When I draw the triangles with my shaders, I'm relieved to report that my viewport buffer now looks 50% gray with two overlapping triangular regions that are white . The triangles are white because their fragments' color values were additively blended with those already in the color buffer.
Now, I re-upload the vertex buffer with the following change: the color of the vertices of the second triangle are now -50% gray (-0.5, -0.5, -0.5) .
What I hope to accomplish is that my viewport buffer would look 50% gray with two overlapping triangular regions– one white , one black – which intersect, and produce 50% gray at their intersection. After all, adding a negative number should be the same as subtracting a positive number of the same magnitude.
What I see instead is a 50% gray viewport with only one triangular region – the white one.
I assume that this is because the output of my fragment shader is being clamped to a range whose lower bound is zero, before it's blended with the color buffer. I would like to know how to circumvent this clamping– ideally in WebGL, without requiring multiple render passes.
I'll be testing solutions in the source of the page at this URL: http://rezmason.net/scourge/issues/positive_negative_fragments.html
UPDATE
As an investigation, I've experimented with performing my additive blending in a frame buffer, and then drawing the frame buffer to the viewport buffer by texturing it to a unit quad– that's two separate draw calls, of course, which ideally I'd like to avoid.
That said, because I can explicitly set the format of the frame buffer to floating point, no clamping occurs with any value while I perform operations within that buffer. When I draw the buffer to the viewport, I assume that clamping finally occurs, but by then all the blending is already done.
My question is now substantially simpler: is there any way to initialize a WebGL or OpenGL context, so that its viewport is formatted as a floating point buffer?
Use gl.blendEquation( gl.FUNC_SUBTRACT )
. Then use positive values in your shader.
If you want do something in the middle, you can make some hacky things:
gl.enable(gl.BLEND);
gl.blendFuncSeparate(gl.ONE_MINUS_SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
gl.blendEquation(gl.FUNC_ADD);
It will give you this equation:
You can now draw white triangle if you set color to (0.5, 0.5, 0.5, 0) and black triangle with color (0.5, 0.5, 0.5, 1).
If you want different colors I hope you get the point. You can compare different blending functions here: http://www.andersriggelsen.dk/glblendfunc.php
Edit: Sorry, my mistake. You should change
gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.ONE_MINUS_DST_ALPHA, gl.ONE, gl.ONE);
to
gl.blendFuncSeparate(gl.ONE_MINUS_SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
I've forgotten which one is source and which one is destination. I've updated my answer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.