So I'm trying to render two moving quads, each at different locations. My shaders are as simple as possible (vertices are only transformed by the modelview-projection matrix, there's only one color).

Whenever I try and render something, I only end up with slivers of color! I've only done work with 3D rendering in OpenGL before so I'm having issues with 2D stuff.

Here's my basic rendering loop, simplified a bit (I'm using the Matrix manipulation methods provided by android.opengl.Matrix and program is a custom class I created that just calls GLES20.glUniformMatrix4fv()):

Matrix.orthoM(projection, 0, 0, windowWidth, 0, windowHeight, -1, 1);
program.setUniformMatrix4f("Projection", projection);

At this point, I render the quads (this is repeated for each quad):

Matrix.setIdentityM(modelview, 0);
Matrix.translateM(modelview, 0, quadX, quadY, 0);
program.setUniformMatrix4f("ModelView", modelview);
quad.render(); // calls glDrawArrays

and all I see is a sliver of the color each quad is! I'm at my wits end here, I've tried everything I can think of and I'm at the point where I'm screaming at my computer and tossing phones across the room. Anybody got any pointers? Am I using ortho wrong? I'm 100% sure I'm rendering everything at a Z value of 0. I tried using frustumM instead of orthoM, which made it so that I could see the quads but they would get totally skewed whenever they got moved, which makes sense if I correctly understand the way frustum works (it's more for 3D rendering, anyway).

If it makes any difference, I defined my viewport with

 GLES20.glViewport(0, 0, windowWidth, windowHeight);

Where windowWidth and windowHeight are the same values that are pased to orthoM

It might be worth noting that the android.opengl.Matrix methods take in an offset as the second parameter so that multiple matrices can be shoved into one array, so that'w what the first 0 is for

For reference, here's my vertex shader code:

uniform mat4 ModelView;
uniform mat4 Projection;

attribute vec4 vPosition;

void main() {
    mat4 mvp = Projection * ModelView; 
    gl_Position = vPosition * mvp;

I tried swapping Projection * ModelView with ModelView * Projection but now I just get some really funky looking shapes...


Well first of all

void main() {
    mat4 mvp = Projection * ModelView; 
    gl_Position = vPosition * mvp;

is incorrect, doesn't matter that it looks less wrong.

There are two ways you can multiply vectors and matrices. If your vector is represented as a row and your matrix is constructed apropriately, then the order you're multiplying in should go as follows.

new_vector = vector * matrix;

However, if you represent the vector as a column and construct the matrices apropriately (i'm fairly sure that all of the built-in matrix functions do exactly this, it's kind of a standard), then your equation should go as follows.

new_vector = matrix * vector;

So, in the end, if everything else was done correctly, swapping your vertex shader main function to

void main() {
    mat4 mvp = Projection * ModelView; 
    gl_Position = mvp * vPosition;

should fix the problem. If it doesn't fix the issue then we can go from here, but so far this is definetly incorrect and won't produce proper resaults even if everything else is correct.

  • \$\begingroup\$ That would make sense, that vector * matrix != matrix * vector. However, after changing it to mvp * vPosition I just get a blank screen :/ \$\endgroup\$ – TranquilMarmot Jul 7 '12 at 4:29
  • \$\begingroup\$ I got rid of the orthoM() call (so my projection matrix is just the identity matrix) and now I can see the quads just fine. Am I using ortho wrong or should I really just be using the identity matrix for my projection (which doesn't seem right at all...)? \$\endgroup\$ – TranquilMarmot Jul 7 '12 at 5:25
  • \$\begingroup\$ Ok, I see now. Getting rid of the orthographic projection makes it so that everything gets stretched with the screen (i.e. in portrait mode everything is stretched vertically and in landscape mode everything is stretched horizontally). \$\endgroup\$ – TranquilMarmot Jul 7 '12 at 5:41
  • \$\begingroup\$ @TranquilMarmot public static void orthoM (float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far) you're using this function, right? the thing you wanna do is make sure that left/right and top/bottom are halfs of your screen width/height, you have to make them go from -half to + half, not form 0 to whole \$\endgroup\$ – dreta Jul 7 '12 at 5:42
  • \$\begingroup\$ @TranquilMarmot other than that, it may be that the matrix math is done with vectors as rows in the android library, so just swap the ordering to the one you had, just make sure that you call it as vector = vector * view * projection, because the way you were doing it was vector = vector * projection * view \$\endgroup\$ – dreta Jul 7 '12 at 5:46

I wasted quite some time trying to find out how to form a 2d projection matrix because I couldn't find an explanation what this matrix really is. I'm talking about the 4x4 matrix M that you pass to the veretex shader and use like

gl_Position = M * vPosition

Finally I figured out. Here is an explanation before I forget, and sory for my math language.

This matrix is an operator that makes a point in OpenGL coordinates from a point in model coordinates. OpenGL coordinates map an area on the screen that OpenGL controls into the [-1,1]x[-1,1] square. What I call the model coordinates are the coordinates that you think in when you build your scene. The third coordinate should be 0 since we are in 2d. These are projective coordinates. The fourth coordinate is such that Euclidian coordinates are obtained by dividing the first three projective coordinates by the fourth coordinate.

Assuming you don't need a rotation, here is how to build this matrix:

float[] mMVPMatrix = {a,0f,0f,0f,0f,b,0f,0f,0f,0f,-1f,0f,-a*cx,-b*xy,0f,zoom};

to show an 2*a*zoom x 2*b*zoom rectangle with a center in in cx,cy. Parameters a and b should be proportional to the dimmensions of the area that OpenGL controls (what you get as arguments in the onSurfaceChanged method). So forget about all these functions that build matrices while hiding information and don't use the expensive matrix multiplication for something as simple as this. It is much easier to debug something you understand.


Okay, I finally figured it out!

I changed

Matrix.orthoM(projection, 0, 0, windowWidth, 0, windowHeight, -1, 1);


float ratio = static_cast<float>(windowWidth) / 
Matrix.orthoM(projection, 0, 0, ratio, 0, 1, -1, 1);

I then had to scale my projection matrix to make it a lot smaller with Matrix.scaleM(projection, 0, 0.05f, 0.05f, 1.0f);.

I then added an offset to the modelview translations to simulate a camera so that I could center on the action (so Matrix.translateM(modelview, 0, quadX, quadY, 0); was changed to Matrix.translateM(modelview, 0, quadX + camX, quadY + camY, 0);)

Thanks for the help, all!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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