GL_ALPHA_TEST replacement in OpenGL ES 1.1 (no shaders)
So it seems like the performance of GL_ALPHA_TEST on iOS is very poor. To quote Apple:
Graphics hardware often performs depth testing early in the graphics pipeline, before calculating the fragment’s color v开发者_StackOverflow社区alue. If your application uses an alpha test in OpenGL ES 1.1 or the
discard
instruction in an OpenGL ES 2.0 fragment shader, some hardware depth-buffer optimizations must be disabled. In particular, this may require a fragment’s color to be completely calculated only to be discarded because the fragment is not visible.An alternative to using alpha test or discard to kill pixels is to use alpha blending with alpha forced to zero. This effectively eliminates any contribution to the framebuffer color while retaining the Z-buffer optimizations. This does change the value stored in the depth buffer and so may require back-to-front sorting of the transparent primitives.
If you need to use alpha testing or a
discard
instruction, draw these objects separately in the scene after processing any primitives that do not require it. Place thediscard
instruction early in the fragment shader to avoid performing calculations whose results are unused.
I am wondering: what exactly do they mean by "use alpha blending with alpha forced to zero". How can you accomplish this? Alternatively, is there any other way to omit/hide pixels based on their alpha value?
I have considered using texture combiners or various blend modes (including glBlendFuncSeparateOES
). However, nothing seems right for the job. I suppose having a separate alpha texture and using texture combiners could work. I would really prefer having only one texture, though.
The issue is profound and linked to the depth buffer. You can set alpha to zero in shader code, but you will still output a depth fragment, so it's only a partial workaround depending on your reason for using alpha test. So you could bias alpha and scale by a large number (to avoid the shader branch) then clamp and you'll get a sharp delineated alpha test edge, but transparent pixels will still fill the zbuffer which if that's your reason for using alpha test you're still no better off. You cannot really get around the core problem in a shader. You could adjust your content to minimize this and perhaps draw opaque untested z and do alpha tested transprency last. The details of how this affects z can very from platform to platform. On some platforms zbuffer optimizations like early z and coarse z might be disabled permanently from then until your next clear, so in delaying alpha test you could gain performance, but it really is down to the details of the implementation.
Adjust the art to minimize transparent fragments and use alpha test as late as possible when rendering if it cannot be avoided.
Also if you have a discard function, use it at the end of your shader against a constant alpha test, it may be counterintuitive but some implementations optimize this alpha test discard to use fixed function hardware which is better than a shader branch (on some platforms). Again it really depends on how sophisticated the GPU thread flow control is. Future platforms with efficient branching will probably benefit from doing this earlier, you're basically trying to navigate your way to exploit hidden implementation optimizations that vary across platforms and will change in future.
精彩评论