Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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();

stack.push(mvMatrixDupe);
}

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);
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glDepthMask(false);

world.init();
}

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

    world.update( (float) dt);

    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    matrixStack.setProjection(mProjMatrix);

    matrixStack.loadIdentity();

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

    world.draw(matrixStack);
        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);
GLES20.glCompileShader(shader);

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
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(quadCoords);
vertexBuffer.position(0);

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); //shorts are just two bytes!!!
ibb.order(ByteOrder.nativeOrder());
indicesBuffer = ibb.asShortBuffer();
indicesBuffer.put(indices);
indicesBuffer.position(0);

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.push();

stack.loadIdentity();

stack.translate(xPos, yPos, zPos);

GLES20.glUseProgram(mProgram);

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

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

GLES20.glEnableVertexAttribArray(posAttr);

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);

GLES20.glDisableVertexAttribArray(posAttr);

stack.pop();
}

}

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.

Thanks.

share|improve this question

closed as too localized by Jari Komppa, Jonathan Hobbs, Trevor Powell, jco, Josh Petrie Oct 4 '12 at 16:00

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.If this question can be reworded to fit the rules in the help center, please edit the question.

add comment

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).

share|improve this answer
    
+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. –  Jimmy Shelter Aug 5 '12 at 22:14
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.