Multiple textures in one shader with ZBuffer and alpha blending in 2D

I have a few sprite sheets and on the scene I have to render multiple pictures coming from different textures. Each object on the sprite sheet can have a different Z value (it can be beneath or above other objects). Z values of objects from distinct textures often overlap and I am also using alpha blending for transparency.

All these factors force me to sort all objects sent for rendering by their Z value ( the farthest objects are drawn first). And here the problem arises. Doing 1 render call per each texture enables to properly sort and draw just the objects from one texture at a time. Objects from 2nd texture could probably be drawn before some objects from the 1st texture dependning on their Z value. In such case I can't sort properly the objects before drawing becouse drawing would require more than textures amount render calls which is unacceptable I guess.

The only solution which came to my mind so far was to create such a fragment shader (changing sampler depending on the varying passed):

public static final String fs_Image =
        "precision mediump float;" +
        "varying vec2 v_texCoord;" +
        "varying float v_texInd;" +
        "uniform sampler2D u_tex0;" +
        "uniform sampler2D u_tex1;" +
        "void main() {" +
        "   if(v_texInd == 0.0)" +
        "       gl_FragColor = texture2D( u_tex0, v_texCoord );" +
        "   else" +
        "       gl_FragColor = texture2D( u_tex1, v_texCoord );" +
        "   if(gl_FragColor.a == 0.0)" +
        "       discard;" +
        "}";

I don't quite like this solution but it enables me to draw all the objects even in 1 render call. In case there would be more than 2 textures I doubt this could be efficient solution.

The other alternative would be to create Z value constraints for all objects from distinct sprite sheets and then z values from different textures wouldn't overlap and I could properly sort and draw objects from multiple textures in a few render calls.

I'm wondering which of these approaches is better? Or maybe there's some better solution? I would be very grateful for any help!


As you did, first, z-order your objects. Then, let's say your pixel can come from 4 different textures and you want a one pass rendering :

  • Add a vec4 uniform to you fragment shader, and use its components to multiply each vec4 resulting from texture lookups
  • Attach a texture index to each object
  • Before drawing an object, bind the uniform such as all values are set at 0.0f except the value corresponding to the texture to use, set at 1.0f
  • The frag shader would be like this:

    precision mediump float;
    
    varying vec2 v_texCoord;
    
    uniform vec4 u_SelectedTexture;
    
    uniform sampler2D u_tex0;
    uniform sampler2D u_tex1;
    uniform sampler2D u_tex2;
    uniform sampler2D u_tex3;
    
    void main() {
       glFragColor = texture2D(u_tex0, v_texCoord) * uSelectedTexture.x
           + texture2D(u_tex1, v_texCoord) * uSelectedTexture.y +
           texture2D(u_tex2, v_texCoord) * uSelectedTexture.z +
           texture2D(u_tex3, v_texCoord) * uSelectedTexture.w;
    }
    

    Where u_SelectedTexture is the uniform I propose you to add.

    In your rendering pipeline, if you want to use u_tex1 for example, you should use something like before drawing :

    glUniform4f(uniformLocation, 0.0f, 1.0f, 0.0f, 0.0f);
    

    These are non-dependent texture reads that should not dramatically impact your rendering time.

    Hope it answers to your question.

    Regards !

    链接地址: http://www.djcxy.com/p/37172.html

    上一篇: 为访问体素的多个线程获取唯一的缓冲区索引

    下一篇: 使用ZBuffer和2D中的alpha混合在一个着色器中创建多个纹理