I've been trying to get openGLES2 to work on my Android device and this is starting to drive me insane. I've spent well over ten hours now trying to get this to work. I just don't understand anymore. What I want is the ordinary GL3.0/ES1.0 behaviour, there's a stack of modelview matrices and when I call a 'push' function, I get a duplicate to work with and any subsequent matrix operations happen in the local coordinate space.

Here's my MatrixStack class:

public class MatrixStack {
private String TAG = "MatrixStack"; 

public float[] mMatrix = new float[16];
public float[] vMatrix = new float[16];
public float[] pMatrix = new float[16];

public float[] mvMatrix = new float[16];
public float[] mvpMatrix = new float[16];

private Stack stack = new Stack();

public MatrixStack() {

public void push() {
/*if(stackM.empty() || stackV.empty()) {
    Log.d(TAG, "say wha? I'm empty.... ERROR ERROR");
} else {
    //mMatrixPrev = (float[]) stackM.peek();
    //vMatrixPrev = (float[]) stackV.peek();

float[] mvMatrixDupe = mvMatrix.clone();


public void pop() {
if(stack.empty()) {
    Log.d(TAG, "Can't pop this empty stack...");
} else {
    mvMatrix = (float[]) stack.pop();

public void loadIdentity() {
Matrix.setIdentityM(mvMatrix, 0);


public void setProjection(float[] pMatrix) {
this.pMatrix = pMatrix;

public void translate(float x, float y, float z) {
Matrix.translateM(mvMatrix, 0, x, y, z);

public float[] getM() {
return mMatrix;

public float[] getV() {
return vMatrix;

public float[] getMV() {
return mvMatrix;

public float[] getMVP() {
Matrix.multiplyMM(mvpMatrix, 0, pMatrix, 0, mvMatrix, 0);

return mvpMatrix;


Here's the renderer:

public class MyGLRenderer implements GLSurfaceView.Renderer {
public static final String TAG = "MyGLRenderer";

private MatrixStack matrixStack = new MatrixStack();
private World world;
private float[] mVMatrix = new float[16];
private float[] mMVPMatrix = new float[16];
private float[] mProjMatrix = new float[16];
private float[] mMMatrix= new float[16];
private float[] mMVMatrix = new float[16];
private float[] mRotationMatrix = new float[16];

private volatile double dt;
private volatile double endTime; //for working out the dt

public void sendWorld(World targetworld) {
world = targetworld;
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);


public void onDrawFrame(GL10 unused) {
if(world != null) {
    dt = System.currentTimeMillis() - endTime;

    world.update( (float) dt);




    matrixStack.translate(0.f, 0.f, -3.f);

        endTime = System.currentTimeMillis();
} else {
    Log.d("Quad", "There is no world....");

public void onSurfaceChanged(GL10 unused, int width, int height) {
    GLES20.glViewport(0, 0, width, height);

float ratio = (float) width / height;

Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 4);

//Matrix.orthoM(mProjMatrix, 0, 0, width, 0, height, -1.f, 1.f);

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

int shader = GLES20.glCreateShader(type);

GLES20.glShaderSource(shader, shaderCode);

return shader; 


And here's the quad class (with embedded shaders):

class Quad {
private String TAG = "Quad";

private FloatBuffer vertexBuffer;
private ShortBuffer indicesBuffer;
private float height;
private float width;
public float xPos = 0;
public float yPos = 0;
public float zPos = 0;
private float xVel = 0;
private float yVel = 0;
private float xAcc = 0;
private float yAcc = 0;
private int mProgram;
private int posAttr;
private int texAttr;
private int mMVMatrixHandle;
private int mPMatrixHandle;

private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 uMVMatrix;" +
"uniform mat4 uPMatrix;" +
"void main() {" +
"  gl_Position = uPMatrix * uMVMatrix * vPosition;" +

private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
"  gl_FragColor = vColor;" +

static final int COORDS_PER_VERTEX = 3;

private final int vertexCount = quadCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex

static float quadCoords[] = {
-0.5f,  0.5f, 0.0f,   // top left
-0.5f, -0.5f, 0.0f,   // bottom left
 0.5f, -0.5f, 0.0f,   // bottom right
 0.5f,  0.5f, 0.0f  // top right

private short indices[] = {1, 0, 2, 3};

float color[] = {
0.0f, 0.0f, 1.0f, 1.0f

public Quad() {
ByteBuffer vbb = ByteBuffer.allocateDirect(quadCoords.length * 4); //each float is four bytes
vertexBuffer = vbb.asFloatBuffer();

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); //shorts are just two bytes!!!
indicesBuffer = ibb.asShortBuffer();

int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

mProgram = GLES20.glCreateProgram();             // create empty OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram);                  // creates OpenGL ES program executables

public void setXVel(float xVel) {
this.xVel = xVel;

public void setYVel(float yVel) {
this.yVel = yVel;

public void setXAcc(float xAcc) {
this.xAcc = xAcc;

public void setYAcc(float yAcc) {
this.yAcc = yAcc;

public void update(float dt) {
xVel += xAcc * dt;
yVel += yAcc * dt;

xPos += xVel;
yPos += yVel;

public void draw(MatrixStack stack) {


stack.translate(xPos, yPos, zPos);


posAttr = GLES20.glGetAttribLocation(mProgram, "vPosition");
texAttr = GLES20.glGetUniformLocation(mProgram, "vColor");

GLES20.glVertexAttribPointer(posAttr, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);


GLES20.glUniform4f(texAttr, 0.0f, 0.0f, 1.0f, 1.0f);

mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
mPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uPMatrix");

GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, stack.getMV(), 0);
GLES20.glUniformMatrix4fv(mPMatrixHandle, 1, false, stack.pMatrix, 0);

GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, 4, GLES20.GL_UNSIGNED_SHORT, indicesBuffer);




When I render, whatever the hell I do, that Matrix.translateM resets the mv matrix and draws to world coordinates, not a local system, regardless of what it pops back to.

How is this supposed to work? I've everything I can find on the web, every tutorial and even trawled open game engine source code, to no avail. Could anyone help? Just some pseudocode on how that MatrixStack is supposed to work to replicate the one in openGL3+ES1.



1 Answer 1


Don't try to replicate stacks of matrices, you're wasting 10 hours on debugging a matrix stack class rather than learning the 'new' way ;-) Find a decent matrix & vector library that supports useful functions (dot product, cross product, translation, rotation, etc) - the Internet is full of them, Google will give you loads.

Then, consider splitting your world/whatever into objects and give each object its own matrix. This will define the object's local transformations.

Make a simple tree so that objects can have children. Give each one a way to pass its object matrix into its children. Have a 'head' node that defines the overall transformation.

The gradual multiplication of these matrices through the tree builds the modelview matrices for each object automatically. No messy pushing or popping required.

Every object's position and orientation will be defined in relation to its parent object (so make children as appropriate).

In short, forget the matrix stack idea and find some tutorials that lead you through GLES2. It's quite difficult to understand, so find as many different tutorials as you can (include ones related to iOS OpenGL ES, it's the same GL).

  • \$\begingroup\$ +1; trying to beat the new way into the same shape as the old way is a surefire way to create a mess. Work with it the way it's supposed to work instead. \$\endgroup\$ Commented Aug 5, 2012 at 22:14

Not the answer you're looking for? Browse other questions tagged .