Mehrere 2D-Bilder in OpenGL-ES 2.0 rendern

Ich bin neu in OpenGL und versuche, ES 2.0 zu lernen.

Zu Beginn arbeite ich an einem Kartenspiel, bei dem ich mehrere Kartenbilder rendern muss. Ich folgte diesemhttp: //www.learnopengles.com/android-lesson-four-introducing-basic-texturing

ch habe einige Klassen erstellt, um mit den Daten und Aktionen umzugehe

MySprite enthält die Texturinformationen, einschließlich Position und Skalierungsfaktoren.Batcher zeichnet alle Sprites auf einmal. Es ist eine grobe Umsetzung.
ShaderHelper verwaltet die Erstellung von Shadern und die Verknüpfung mit einem Programm.GLRenderer ist der Ort, an dem das Rendering durchgeführt wird (es implementiert `Renderer`.) Q1

Mein Programm rendert ein Bild korrekt. Das Problem ist, dass beim Rendern von 2 Bildern das erste durch das spätere ersetzt wird, das zweite wird also zweimal gerendert.

Ich vermute, es hängt damit zusammen, wie ich Texturen in @ erstellMySprite Klasse. Ich bin mir aber nicht sicher warum. Kannst du helfen

Q2

Ich habe gelesen, dass ich @ verwenden muss, wenn ich 2 Bilder rendern musGL_TEXTURE0 undGL_TEXTURE1, anstatt nur @ zu verwendGL_TEXTURE0.

_GLES20.glActiveTexture(GLES20.GL_TEXTURE0);

Aber da diese Konstanten begrenzt sind (0 bis 31), gibt es eine bessere Möglichkeit, mehr als 32 kleine Bilder zu rendern, ohne die Eindeutigkeit der Bilder zu verlieren?

Bitte weise mich in die richtige Richtung.

Der Cod

GLRenderer:

public class GLRenderer implements Renderer {
    ArrayList<MySprite> images = new ArrayList<MySprite>();
    Batcher batch;
    int x = 0;
...
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        batch = new Batcher();
        MySprite s = MySprite.createGLSprite(mContext.getAssets(), "menu/back.png");
        images.add(s);
        s.XScale = 2;
        s.YScale = 3;

        images.add(MySprite.createGLSprite(mContext.getAssets(), "menu/play.png"));

        // Set the clear color to black
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1);

        ShaderHelper.initGlProgram();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        mScreenWidth = width;
        mScreenHeight = height;

        // Redo the Viewport, making it fullscreen.
        GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight);

        batch.setScreenDimension(width, height);

        // Set our shader programm
        GLES20.glUseProgram(ShaderHelper.programTexture);
    }

    @Override
    public void onDrawFrame(GL10 unused) {
        // clear Screen and Depth Buffer, we have set the clear color as black.
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        batch.begin();
        int y = 0;
        for (MySprite s : images) {
            s.X = x;
            s.Y = y;
            batch.draw(s);

            y += 200;
        }
        batch.end();

        x += 1;
    }
}

Batcher:

public class Batcher {
    // Store the model matrix. This matrix is used to move models from object space (where each model can be thought
    // of being located at the center of the universe) to world space.
    private final float[] mtrxModel = new float[16];
    // Store the projection matrix. This is used to project the scene onto a 2D viewport.
    private static final float[] mtrxProjection = new float[16];
    // Allocate storage for the final combined matrix. This will be passed into the shader program.
    private final float[] mtrxMVP = new float[16];

    // Create our UV coordinates.
    static float[] uvArray = new float[]{
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f
    };
    static FloatBuffer uvBuffer;
    static FloatBuffer vertexBuffer;
    static boolean staticInitialized = false;
    static short[] indices = new short[]{0, 1, 2, 0, 2, 3}; // The order of vertexrendering.
    static ShortBuffer indicesBuffer;

    ArrayList<MySprite> sprites = new ArrayList<MySprite>();

    public Batcher() {
        if (!staticInitialized) {
            // The texture buffer
            uvBuffer = ByteBuffer.allocateDirect(uvArray.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            uvBuffer.put(uvArray)
                    .position(0);

            // initialize byte buffer for the draw list
            indicesBuffer = ByteBuffer.allocateDirect(indices.length * 2)
                    .order(ByteOrder.nativeOrder())
                    .asShortBuffer();
            indicesBuffer.put(indices)
                    .position(0);

            float[] vertices = new float[] {
                    0, 0, 0,
                    0, 1, 0,
                    1, 1, 0,
                    1, 0, 0
            };

            // The vertex buffer.
            vertexBuffer = ByteBuffer.allocateDirect(vertices.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer();
            vertexBuffer.put(vertices)
                    .position(0);

            staticInitialized = true;
        }
    }

    public void setScreenDimension(int screenWidth, int screenHeight) {
        Matrix.setIdentityM(mtrxProjection, 0);
        // (0,0)--->
        //   |
        //   v
        //I want it to be more natural like desktop screen
        Matrix.orthoM(mtrxProjection, 0,
                -1f, screenWidth,
                screenHeight, -1f,
                -1f, 1f);
    }

    public void begin() {
        sprites.clear();
    }

    public void draw(MySprite sprite) {
        sprites.add(sprite);
    }

    public void end() {
        // Get handle to shape's transformation matrix
        int u_MVPMatrix = GLES20.glGetUniformLocation(ShaderHelper.programTexture, "u_MVPMatrix");
        int a_Position = GLES20.glGetAttribLocation(ShaderHelper.programTexture, "a_Position");
        int a_texCoord = GLES20.glGetAttribLocation(ShaderHelper.programTexture, "a_texCoord");
        int u_texture = GLES20.glGetUniformLocation(ShaderHelper.programTexture, "u_texture");

        GLES20.glEnableVertexAttribArray(a_Position);
        GLES20.glEnableVertexAttribArray(a_texCoord);

        //loop all sprites
        for (int i = 0; i < sprites.size(); i++) {
            MySprite ms = sprites.get(i);

            // Matrix op - start
                Matrix.setIdentityM(mtrxMVP, 0);
                Matrix.setIdentityM(mtrxModel, 0);

                Matrix.translateM(mtrxModel, 0, ms.X, ms.Y, 0f);
                Matrix.scaleM(mtrxModel, 0, ms.getWidth() * ms.XScale, ms.getHeight() * ms.YScale, 0f);

                Matrix.multiplyMM(mtrxMVP, 0, mtrxModel, 0, mtrxMVP, 0);
                Matrix.multiplyMM(mtrxMVP, 0, mtrxProjection, 0, mtrxMVP, 0);
            // Matrix op - end

            // Pass the data to shaders - start
                // Prepare the triangle coordinate data
                GLES20.glVertexAttribPointer(a_Position, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);

                // Prepare the texturecoordinates
                GLES20.glVertexAttribPointer(a_texCoord, 2, GLES20.GL_FLOAT, false, 0, uvBuffer);

                GLES20.glUniformMatrix4fv(u_MVPMatrix, 1, false, mtrxMVP, 0);

                // Set the sampler texture unit to where we have saved the texture.
                GLES20.glUniform1i(u_texture, ms.getTextureId());
            // Pass the data to shaders - end

            // Draw the triangles
            GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);
        }
    }
}

ShaderHelper

public class ShaderHelper {
    static final String vs_Image =
        "uniform mat4 u_MVPMatrix;" +
        "attribute vec4 a_Position;" +
        "attribute vec2 a_texCoord;" +
        "varying vec2 v_texCoord;" +
        "void main() {" +
        "  gl_Position = u_MVPMatrix * a_Position;" +
        "  v_texCoord = a_texCoord;" +
        "}";

    static final String fs_Image =
        "precision mediump float;" +
        "uniform sampler2D u_texture;" +
        "varying vec2 v_texCoord;" +
        "void main() {" +
        "  gl_FragColor = texture2D(u_texture, v_texCoord);" +
        "}";

    // Program variables
    public static int programTexture;
    public static int vertexShaderImage, fragmentShaderImage;

    public static int loadShader(int type, String shaderCode){

        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // add the source code to the shader and compile it
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        // return the shader
        return shader;
    }

    public static void initGlProgram() {
        // Create the shaders, images
        vertexShaderImage = ShaderHelper.loadShader(GLES20.GL_VERTEX_SHADER, ShaderHelper.vs_Image);
        fragmentShaderImage = ShaderHelper.loadShader(GLES20.GL_FRAGMENT_SHADER, ShaderHelper.fs_Image);

        ShaderHelper.programTexture = GLES20.glCreateProgram();             // create empty OpenGL ES Program
        GLES20.glAttachShader(ShaderHelper.programTexture, vertexShaderImage);   // add the vertex shader to program
        GLES20.glAttachShader(ShaderHelper.programTexture, fragmentShaderImage); // add the fragment shader to program
        GLES20.glLinkProgram(ShaderHelper.programTexture);                  // creates OpenGL ES program executables
    }

    public static void dispose() {
        GLES20.glDetachShader(ShaderHelper.programTexture, ShaderHelper.vertexShaderImage);
        GLES20.glDetachShader(ShaderHelper.programTexture, ShaderHelper.fragmentShaderImage);

        GLES20.glDeleteShader(ShaderHelper.fragmentShaderImage);
        GLES20.glDeleteShader(ShaderHelper.vertexShaderImage);

        GLES20.glDeleteProgram(ShaderHelper.programTexture);
    }
}

MySprite

public class MySprite {
    public int X, Y;
    public float XScale, YScale;
    private int w, h;

    int textureId = -1;

    private MySprite(Bitmap bmp, int textureId) {
        this.w = bmp.getWidth();
        this.h = bmp.getHeight();
        this.textureId = textureId;
        this.XScale = this.YScale = 1f;
    }

    public static MySprite createGLSprite(final AssetManager assets, final String assetImagePath) {
        Bitmap bmp = TextureHelper.getBitmapFromAsset(assets, assetImagePath);
        if (bmp == null) return null;

        MySprite ms = new MySprite(bmp, createGlTexture());
        Log.d("G1", "image id = " + ms.getTextureId());

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

        // Load the bitmap into the bound texture.
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);

        bmp.recycle();
        return ms;
    }

    private static int createGlTexture() {
        // Generate Textures, if more needed, alter these numbers.
        final int[] textureHandles = new int[1];
        GLES20.glGenTextures(1, textureHandles, 0);

        if (textureHandles[0] != 0) {
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandles[0]);
            return textureHandles[0];
        } else {
            throw new RuntimeException("Error loading texture.");
        }
    }
...
}

Antworten auf die Frage(4)

Ihre Antwort auf die Frage