简体   繁体   中英

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 !

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