OpenGL ES 2.0 – Applying rotation to only specific quads within a batch

| | August 8, 2015

This problem seems fairly simple on the face of it: How, when drawing a batch of quads using a triangle strip, can I apply a rotation to only one or some of the quads.

I’ve been looking at this problem for ages and have looked at various similar questions on SE and the wider internet (I’ve also asked this before). I’m still at a loss as to how to achieve this.

I’ve included the code that I use to draw my sprites (my project is a 2D game). As well as my rotation method and shaders.

Needless to say, I can draw many objects (currently, my largest batch contains over 200 objects) – I use a spritesheet, so drawing my sprites with different parts of a larger texture, isn’t a problem. Obviously, when I apply a rotation, it rotates the batch as a whole.

Draw Batch Method

public void drawBatch(int[] coOrdinates, float[] mvpMatrix, int numOfSprites, int totalFrames, float[] whichFrame){

   x= 0;
   coOrdinateCount = 0;

    //Populate the array based on the number of sprites
    for (int count = 0;count<numOfSprites;count+=1){

    //NOTE - textureLeft, TextureRight, textureTop, textureBottom, xPlotTop, xPlotBottom, xPlotLeft & xPlotRight ARE valid.  I've removed the code working them out for readability as it's not relevant to this question

        vertices[x] = xPlotLeft;
        vertices[(x+1)] = yPlotTop;
        vertices[(x+2)] = 0;
        vertices[(x+3)] = textureLeft;
        vertices[(x+4)] = textureTop;

        vertices[(x+5)] = xPlotRight;
        vertices[(x+6)] = yPlotTop;
        vertices[(x+7)] = 0;
        vertices[(x+8)] = textureRight;
        vertices[x+9] = textureTop;

        vertices[x+10] = xPlotLeft;
        vertices[x+11] = yPlotBottom;
        vertices[x+12] = 0;
        vertices[x+13] = textureLeft;
        vertices[x+14] = textureBottom;

        vertices[x+15] = xPlotRight;
        vertices[x+16] = yPlotTop;
        vertices[x+17] = 0;
        vertices[x+18] = textureRight;
        vertices[x+19] = textureTop;

        vertices[x+20] = xPlotLeft;
        vertices[x+21] = yPlotBottom;
        vertices[x+22] = 0;
        vertices[x+23] = textureLeft;
        vertices[x+24] = textureBottom;

        vertices[x+25] = xPlotRight;
        vertices[x+26] = yPlotBottom;
        vertices[x+27] = 0;
        vertices[x+28] = textureRight;
        vertices[x+29] = textureBottom;

        x+=30;
        coOrdinateCount+=2;
    }

    vertexBuf.rewind();
    vertexBuf.put(vertices).position(0);

    GLES20.glUseProgram(iProgId);

    // Combine the rotation matrix
    Matrix.multiplyMM(mvpMatrix2, 0, mvpMatrix, 0,  mRotationMatrix, 0);

    mMVPMatrixHandle = GLES20.glGetUniformLocation(iProgId, "uMVPMatrix");

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix2, 0);

    //Set starting position
    vertexBuf.position(0);
    //Specify attributes
    GLES20.glVertexAttribPointer(iPosition, 3, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
    //Enable attribute
    GLES20.glEnableVertexAttribArray(iPosition);
    //Set starting position (texture)
    vertexBuf.position(3);
    //Specify attributes (textures)
    GLES20.glVertexAttribPointer(iTexCoords, 2, GLES20.GL_FLOAT, false, 5 * 4, vertexBuf);
    //Enable attribute for texture
    GLES20.glEnableVertexAttribArray(iTexCoords);

    //Enable Alpha blending 
    GLES20.glEnable(GLES20.GL_BLEND); 
    GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);

    //Draw
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0,  6 * numOfSprites);

    //Disable Alpha blending
    GLES20.glDisable(GLES20.GL_BLEND);

}

Rotation Method(only works for single quads)

public void rotate(float x, float y, int angle){

    //Note centreX, centreY are valid.  The code that works them out has been removed for readability as they are not relevant to this question.

    Matrix.setIdentityM(mRotationMatrix, 0);
    Matrix.translateM(mRotationMatrix, 0, centreX, centreY, 0f);
    Matrix.rotateM(mRotationMatrix, 0, angle, 0, 0, 0.1f);
    Matrix.translateM(mRotationMatrix, 0, -centreX, -centreY, 0f);

}

Vertex Shader

    String strVShader =  
        "uniform mat4 uMVPMatrix;" +
        "attribute vec4 a_position;n"+
        "attribute vec2 a_texCoords;" +
        "varying vec2 v_texCoords;" +
        "void main()n" +
        "{n" +
        "gl_Position = uMVPMatrix * a_position;n"+  
        "v_texCoords = a_texCoords;" +
        "}";

Fragment Shader

    String strFShader =
        "precision mediump float;" +
        "uniform float opValue;"+
        "varying vec2 v_texCoords;" +
        "uniform sampler2D u_baseMap;" +
        "void main()" +
        "{" +
        "gl_FragColor = texture2D(u_baseMap, v_texCoords);" +
        "gl_FragColor *= opValue;"+
        "}";

Please could someone explain any methods that are available to achieve this with some code examples, so I can try to understand how this is supposed to work? Or indeed if this is actually possible….?

Leave a Reply