I want to implement a fragment/blending operation using OpenGL ES 3.1 that fulfills the following requirements:
If the pixel produced by the fragment shader fulfills a certain condition (that can be determined as early as in the vertex shader) then its color value should be added to the one in the framebuffer.
If the pixel doesn't fulfill the condition, then the color should completely replace the one in the framebuffer.
Can this be done via the usual blending functions, alpha tricks etc.?
I think you could just use standard premultiplied alpha blending:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
If you want to replace, then you output an alpha value of 1 from your fragment shader. If you want to do additive then you output an alpha value of 0 from your fragment shader.
That assumes you're only really interested in the RGB values that end up in your framebuffer.
If you know this at vertex shading time I presume that whole triangles are either one blend or another. This is an ideal thing for stencil testing provided that you don't have too much geometry.
Clear stencil to zero.
Draw shape with color writes disabled, and stencil being set to one for regions which match one of the two blend rules.
Set blend rule one.
Draw shape with stencil testing enabled and passing when stencil == 0.
Set blend rule two.
Draw shape with stencil testing enabled and passing when stencil == 1.
How much this costs depends on your geometry, as you need to pass it in to rendering multiple times, but the stencil testing part of this is normally close to "free".
Related
I have created a shape in my stencil buffer (black in the picture below). Now I would like to render to the backbuffer. I would like one texture on the outer pixels (say 4 pixels) of my stencil (red), and an other texture on the remaining pixels (red).
I have read several solutions that involve scaling, but that will not work when there is no obvious center of the shape.
How do I acquire the desired effect?
The stencil buffer works great for doing operations on the specific fragments being overlaid onto them. However, it's not so great for doing operations that require looking at pixels other than the one corresponding to the fragment being rendered. In order to do outlining, you have to ask about the values of neighboring pixels, which stencil operations don't allow.
So, if it is possible to put the stencil data you want to test against in a non-stencil format image (ie: a color image, maybe with an integer texture format), that would make things much simpler. You can do the effect of stencil discarding by using discard directly in the fragment shader. Since you can fetch arbitrarily from the texture (as long as you're not trying to modify it), you can fetch neighboring pixels and test their values. You can use that to identify when a fragment is near a border.
However, if you're relying on specialized stencil operations to build the stencil data itself (like bitwise operations), then that's more complicated. You will have to employ stencil texturing operations, so you're going to have to render to an FBO texture that has a depth/stencil format. And you'll have to set it up to allow you to read from the stencil aspect of the texture. This is an OpenGL 4.3 feature.
This effectively converts it into an 8-bit unsigned integer texture. That allows you to play whatever games you need to. But if you want to use stencil tests to discard fragments, you will also need texture barrier functionality to allow you to read from an image that's attached to the current FBO. But you don't need to actually use the barrier, since you should mask off stencil writing. You just need GL 4.5 or the NV/ARB_texture_barrier extension to be available, which they widely are.
Either way this happens, the biggest difficulty is going to be varying the size of the border. It is easy to just test the neighboring 9 pixels to see if it is at a border. But the larger the border size, the larger the area of pixels each fragment has to test. At that point, I would suggest trying to look for a different solution, one that is based on some knowledge of what pattern is being written into the stencil buffer.
That is, if the rendering operation that lays down the stencil has some knowledge of the shape, then it could compute a distance to the edge of the shape in some way. This might require constructing the geometry in a way that it has distance information in it.
I have fragment shader that writes to framebuffer's texture. I have 2 shaders that use the framebuffer's output texture. First uses just alpha and Second just RGB. When framebuffer's shader return fragmentColor.a = 0 the RGB component completely dissapear when used in Second shader even when I set fragmentColor.a to 1 manually. Is it possible to prevent this "RGB dissapear" or am I getting some bug? Yes I can generate different textures for each shader but it costs huge amount of perfomance because even with only one "draw" it's very costly. But if I could output to two textures at same time that would also solve whole problem. Anyone has any advice/solution?
You probably have blending enabled and set glBlendFunc to something like glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), which will also affect the destination alpha values. To overcome this there's separable blending, set it up with glBlendFuncSeparate[i] and choose the source and destination equations so that the RGB values are passed through as needed for your application. Use the "i" variant to set different blending functions for each fragment shader output target (if you have a single fragment shader with multiple outputs), or call the non-"i" version multiple times, before each render pass to set it up for your individual fragment shaders.
I am trying to experiment with different alpha blending equations for transparent objects using OpenGL but it looks like fragment shaders operate on the color of fragments on single objects and cant take into account the scene behind the object.
On the other hand there doesn't seem to be a way to intercept the blending stage with arbitrary GLSL code, for example I can't think of a way to reproduce soft light blend mode with the current OpenGL primitives.
Is there a way to reconcile these?
There are a couple relatively well-supported extensions:
KHR_blend_equation_advanced - implements common blending modes (including soft light).
EXT_shader_framebuffer_fetch - provides destination color from the framebuffer for fully custom blending in the shader.
Blending is still one of those few parts of the fragment pipeline that's a hardwired circuit on the GPU. Hence it's not programmable. Your best bet is rendering to a texture and do a blending postprocessing pass.
copy render target, and draw your object with it as texture.
if there is many small object, you can only copy part of your render target.
first pass: draw object with render target as texture to texture_2;
second pass: draw object to render target with texture_2;
I'm trying to render a model in OpenGL. I'm on Day 4 of C++ and OpenGL (Yes, I have learned this quickly) and I'm at a bit of a stop with textures.
I'm having a bit of trouble making my texture alpha work. In this image, I have this character from Spiral Knights. As you can see on the top of his head, there's those white portions.
I've got Blending enabled and my blend function set to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
What I'm assuming here, and this is why I ask this question, is that the texture transparency is working, but the triangles behind the texture are still showing.
How do I make those triangles invisible but still show my texture?
Thanks.
There are two important things to be done when using blending:
You must sort primitives back to front and render in that order (order independent transparency in depth buffer based renderers is still an ongoing research topic).
When using textures to control the alpha channel you must either write a shader that somehow gets the texture's alpha values passed down to the resulting fragment color, or – if you're using the fixed function pipeline – you have to use GL_MODULATE texture env mode, or GL_DECAL with the primitive color alpha value set to 0, or use GL_REPLACE.
There is some method to access the background pixel in a fragment shader in order to change the alpha blending function?
I try to implement the fragment shader from page 5 of Weighted Blended Order-Independent Transparency but I don't know how to get Ci.
In standard OpenGL, you can't read the current value in the color buffer in your fragment shader. As far as I'm aware, the only place this functionality is available is as an extension in OpenGL ES (EXT_shader_framebuffer_fetch).
I didn't study the paper you linked, but there are two main options to blend your current rendering with previously rendered content:
Fixed function blending
If the blending functionality you need is covered by the blending functions/equations supported by OpenGL, this is the easiest and likely most efficient option. You set up the blending with glBlendFunc() and glBlendEquation() (or there more flexible variations glBlendFuncSeparate() and glBlendEquationSeparate()), enable blending with glEnable(GL_BLEND), and you're ready to draw.
There are also extensions that enable more variations, like KHR_blend_equation_advanced. Of course, like with all extensions, you can't count on them being supported on all platforms.
Multiple Passes
If you really do need programmable control over the blending, you can always do that with more rendering passes.
Say you render two passes that need to be blended together, and want the result in framebuffer C. The conventional sequence would be:
set current framebuffer to C
render pass 1
set up and enable blending
render pass 2
Now if this is not enough, you can render pass 1 and pass 2 into separate framebuffers, and then combine them:
set current framebuffer to A
render pass 1
set current framebuffer to B
render pass 2
set current framebuffer to C
bind color buffers from framebuffer A and B as textures
draw screen size quad, and sample/combine A and B in fragment shader
A and B in this sequence are FBOs with texture attachments. So you end up with the result of each rendering pass in a texture. You can then bind both of the textures for a final pass, sample them both in your fragment shader, and combine the colors in a fully programmable fashion to produce the final output.