I'm trying to figure a way to recreate or at least have a similar result to the max clamp blend equation in OpenGl es 2.0 on Android devices.
Unfortunately, glBlendEquation(GL_MAX_EXT) is not supported on Android. GL_MAX enum is defined in the gl header in Android but when executing, the result is a GL_INVALID_ENUM​, 0x0500 error.
I have a solution using shaders and off screen textures where each render ping-pongs back and forth between textures using the shader to calculate the max pixel value.
However, this solution isn't fast enough for any real time execution on most Android devices.
So given this limitation, is there any way to recreate a similar result using just different blend equations and blend factors?
I have tried many blend function combinations, the closest have been:
glBlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_ALPHA) : This comes close but textures become too transparent. Textures with low alpha values are difficult to see.
glBlendFunction(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA) : This also comes some what close but the alpha accumulates too much and the colors become darker than intended.
If you could do GL_MAX blending without needing a special blend function... OpenGL would never have added it in the first place. So your options are to do without or to use your shader method.
Related
I'm trying to implement deferred rendering on an Android phone using OPENGL ES 3.0. I've gotten this to work ok but only very slowly, which rather defeats the whole point. What really slows things up is the multiple calls to the shaders. Here, briefly, is what my code does:
Geometry Pass:
Render scene - output position, normal and colour to off-screen buffers.
For each light:
a) Stencil Pass:
Render a sphere at the current light position, sized according to the lights intensity. Mark these pixels as influenced by current light. No actual output.
b) Light Pass:
Render a sphere again, this time using the data from the geometry pass to apply lighting equations to pixels marked in the previous step. Add this to off-screen buffer
Blit to screen
It's this restarting the shaders for each light causing the bottleneck. For example, with 25 lights the above steps run at about 5 fps. If instead I do: Geometry Pass / Stencil Pass - draw 25 lights / Light Pass - draw 25 lights it runs at around 30 fps. So, does anybody know how I can avoid having to re-initialize the shaders? Or, in fact, just explain what's taking up the time? Would it help or even be possible (and I'm sorry if this sounds daft) to keep the shader 'open' and overwrite the previous data rather than doing whatever it is that takes so much time restarting the shader? Or should I give this up as a method for having multiple lights, on a mobile devise anyway.
Well, I solved the problem of having to swap shaders for each light by using an integer texture as a stencil map, where a certain bit is set to represent each light. (So, limited to 32 lights.) This means step 2a (above) can be looped, then a single change of shader, and looping step 2b. However, (ahahaha!) it turns out that this didn't really speed things up as it's not, after all, swapping shaders that's the problem but changing write destination. That is, multiple calls to glDrawBuffers. As I had two such calls in the stencil creation loop - one to draw nowhere when drawing a sphere to calculate which pixels are influenced and one to draw to the integer texture used as the stencil map. I finally realized that as I use blending (each write with a colour where a singe bit is on) it doesn't matter if I write at the pixel calculation stage, so long as it's with all zeros. Getting rid of the unnecessary calls to glDrawBuffers takes the FPS from single figures to the high twenties.
In summary, this method of deferred rendering is certainly faster than forward rendering but limited to 32 lights.
I'd like to say that me code was written just to see if this was a viable method and many small optimizations could be made. Incidentally, as I was limited to 4 draw buffers, I had to scratch the position map and instead recover this from gl_FragCoord.xyz. I don't have proper benchmarking tools so I'd be interested to hear from anyone who can tell me what difference this makes, speedwise.
I am developping a game on android using opengl and am having a little performance problem.
Let's say for example I want to draw a background partially filled with grass "bushes". Bushes have different x,y,z, different sizes and so on (each bush is a 2D sprite), and potentially partially hide each other (I use a perspective camera). I am having a big performance problem if those sprites are big (i.e. the quad sizes, not the texture size/resolution) :
If I use a classical front to back draw (to avoid overdraw), I find myself having problems because of (I think) alpha testing. Even if the bushes have only opaque and fully transparent pixels (no partial transparency), and if I use the proper alpha testing comparison (GL_EQUAL 1) the performances are bad because a lot of pixels have to be alpha tested (If I understand right).
If I use a back to front display with alpha testing disabled, I lose a lot of performance too (but this time because of overdraw problems), even when disabling depth buffer writing (not sure if it does anything if depth test is disabled by the way).
I am having good performances if using front to back without alpha testing, but of course sprite cutout is completely gone, which is really really bad.
All the bushes have the same texture, I use 16 bit colors, mip mapping, geometry batching, cull faces, no shaders, etc. All what I can think of to improve performances (which are not bad in other cases), except texture compression. I even filter the sprites to avoid "displaying" the ones out the screen. I have also tried some "violent optimizations" for test purposes, such as making the textures fully opaque, lowering the texture resolution a lot, disabling blending, etc, but nothing was fantastic performance-wise except the alpha testing removal.
I was wondering if I was forgetting something here to help with the performance. Back to front creates overdraw, front to back is slow because of alpha testing (and I do not want my bushes to be "square" images so I cannot disable alpha testing). If I create smaller sprites performances are far better (even with a lot more sprites), but this is only a workaround.
To summarize, how can you display overlapping big quads needing cutout, without losing performance?
PS : I am testing on a nexus one.
PS2 : Some optimizations suggest to not create quads but geometries more "fitting" the texture, but it seems to be a really tedious process, and would not help me a lot I think.
Drawing front-to-back is normally a benefit because of early-z: the hardware can do the depth test right after rasterization, before doing the texture fetch or shading. With front-to-back sorting, most fragments fail the depth test, and you save a lot of texture bandwidth, shading throughput, and zbuffer-write bandwidth.
But alpha test breaks that. If a fragment passes the depth test, it might still be killed by alpha test, so zwrite can't happen until after texturing/shading. Most hardware that can do early-z still has to do the depth test at the same point in the pipeline as it does zwrite, so with alpha test you end up doing ztest + zwrite after texturing and shading. As a result, front-to-back sorting only saves you zwrite bandwidth, nothing else.
I think you have two options, if you really want large sprites that overlap significantly:
(a) Only use two or three distinct Z values for your sprites. Draw them back-to-front with blending (and alpha-test, if it helps). No overlap within a layer: you can pre-render each layer either in the original assets or once at runtime, then just shift it left and right.
(b) If your sprites have large opaque regions surrounded by a semi-transparent border, you can draw the opaque regions in a first pass with no alpha test, then draw borders as a separate pass. This will cut down on the number of alpha-tested fragments.
I am working on an Android app, based on the LibGDX framework (Though I don't think that should affect this problem too much), and I am having trouble finding a way to get the results I want when drawing using transparent sprites. The problem is that the sprites visibly layer on top of each other where they overlap, similar to what is displayed in this image :
This is pretty unsightly for some of what I want to do, and even completely breaks other parts. What I would like them to do is merge together seamlessly, like so:
The only success I have had thus far is to draw the entire sequence of sprites on a separate texture at full opacity, and then draw that texture back with the desired opacity. I had this working moderately well, and I could likely make it work for most of what I need it to, but the large problem right now is that these things are dynamically drawn onto the screen, and the process of modifying a fairly large texture and sending it back are pretty taxing on mobile devices, and causes an unacceptable level of performance.
I've spent a good chunk of time looking for more ideal solutions, including experimenting with blend modes and coming up with quirky formulas that balanced out alpha and color values in ways to even things out, but nothing was particularly successful. My guess is that the only viable route for this is the previously mentioned way of creating a texture and applying the alpha difference to that, but I am unsure of the best way to make that work with lower powered mobile devices.
There might be a few other ways to do this: The most straight forward would be to attach a stencil buffer and draw circles to stencil first and then draw a full screen rect with desired color+alpha with the stencil, this should be much faster then some FBO with a separate texture.
Another thing might work is drawing those circles first with disabled blend and then your whole scene over it with inverted "blendFunc" but do note it might be impossible if other elements also need blending.
3rd instead of using stencil you could just use the alpha channel of your render buffer. Just use a color mask to draw only to alpha and draw the circles, then reenable RGB on color mask and draw the fullscreen rect using appropriate "blendFunc" also note here that if previous shapes have used blend you will need to clear the alpha to 1.0 before doing this (color mask to alpha only, disabled blend, draw full screen rect with color that has alpha set to 1.0)
I've search around and seems that glBlendEquation has some issues in Android, -GL_MAX/MIN is not even listed in the opengles specs
I need to find a workaround to GL_MIN blendEquation mode. Is that possible? I want to write to a color buffer only if the alpha there is greater than the pixel's alpha i'm trying to write. Is it possible to do it without any extension or using more than 1 texture?
The dirty solution I was trying to avoid is this. Using Frame Buffer objects and shaders to emulate the color buffer and the blending mode:
Modify existing shaders to blend the scene with an FBO_1, into FBO_2.
Render FBO_2 to the screen.
The next drawing call swap FBO_1 with FBO_2, as FBO_2 equals the color buffer.
An "unintrusive" and more inefficient alternative is to use 3 FBOs and a shader, and make an additional pass.
Render scene to FBO_1 //without any modification to existing shaders
Blend FBO_1 with FBO_2 into FBO_3 //with new shader.
Render FBO_3 to the screen.
The next drawing call swap FBO_2 with FBO_3. The only advantage of this alternative is that i dont have to modify the existing drawing logic.
I really don't like any of this ideas. I'll gladly accept better answers!
I'm trying to get specular highlight over objetcs that are texture mapped. As far as I know, the only direct way for OpenGL to not compute the final color over the texture color (this is, as for example plain white) is with the call glLightModelf(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR), but that is not supported in OpenGL ES.
So, how can I do this? Do I have to use another texture for the specluar highlight, of is there another easier way?
Than you!
P.S. I'm using OpenGL ES 1.x
One workaround would be to run in two passes: first pass renders the texture with ambient & diffuse lighting, the second pass renders the specular highlights on top of that (without texturing enabled).
Thanks for the great suggestions, they saved my day. The only problem was a flicker. I first thought there was a problem with a depth buffer and limited depth resolution but it was not the case. I had to use gl.glDepthFunc(GL10.GL_ALWAYS); for perfect blending. However for complex primitives you will be able to see through the object.
After playing for another week I figured that one simply has to disable depth test when doing blending and simply take care of the order in which you render objects on each pass. Typically you want to finish all rendering passes for far object before drawing a closer one.
This takes care for flicker problem that I had completely.