简体   繁体   中英

Additive blending of positive and negative color fragments in a single render pass

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM