How to work with matrices in OpenGL ES 2.0

satya - Mon Aug 06 2012 13:34:07 GMT-0400 (Eastern Daylight Time)

Here is how you arrive at a model-view-projection matrix


protected void setupMatrices()
    {
       Matrix.setIdentityM(mMMatrix, 0);
       
       //world coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
        
        //Project it: screen coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    }

satya - Mon Aug 06 2012 13:36:03 GMT-0400 (Eastern Daylight Time)

matrix api

matrix api

satya - Tue Aug 07 2012 10:03:01 GMT-0400 (Eastern Daylight Time)

what is known: The order of matrix multiplication matters

what is known: The order of matrix multiplication matters

satya - Tue Aug 07 2012 10:03:49 GMT-0400 (Eastern Daylight Time)

Make sure you apply the model coordinate transformation first

and then the view matrix (eye coordinates) transformation and then the projection matrix transformation.

satya - Tue Aug 07 2012 10:04:41 GMT-0400 (Eastern Daylight Time)

Here is the right order example


    private void initializeMatrices()
    {
       Matrix.setIdentityM(mTranslateMatrix, 0);
    }
    public void trnslate(float x, float y, float z)
    {
       Matrix.translateM(this.mTranslateMatrix,0,this.mTranslateMatrix,0,x,y,z);
    }
    public void rotate(float angle, float x, float y, float z)
    {
       Matrix.rotateM(this.mTranslateMatrix,0,this.mTranslateMatrix,0,angle,x,y,z);
       //Matrix.rotateM(this.mRotationMatrix,0,x,y,z);
    }
    protected void setupMatrices()
    {
       Matrix.setIdentityM(mMMatrix, 0);
       
       //translate model coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, this.mTranslateMatrix, 0, mMMatrix, 0);
        
       //world coordinates: viewmatrix * model matrix
        Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMVPMatrix, 0);
        
        //Project it: screen coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    }

satya - Tue Aug 07 2012 10:05:46 GMT-0400 (Eastern Daylight Time)

You will get weird results if you apply the eye coordinate transformation first

including the right behavior sometimes.

satya - Tue Aug 07 2012 16:27:36 GMT-0400 (Eastern Daylight Time)

Bummer...source and target matrices for rotateM(Target, Source...)

Pay real attention!!! Don't give the same matrix for both. they seem to get completely confused. Use different variables!!

satya - Fri Aug 10 2012 15:15:58 GMT-0400 (Eastern Daylight Time)

May be not, don't take my word for it...

I was reading the opengl super bible yesterday and saw the recommendation that one should use eye coordinate transformation first, followed by the concatenated model transformations next.

umm...not entirely sure why, but it seem to work as well!!

Nope!! My intuition was right

Do the model transformations first and then do the eye coordinates next yielding a joint MV (Model View) Matrix. Perhaps the book is right as well if the focus had been when to apply the projection matrix which clearly comes after the eye coordinates.

satya - Fri Aug 10 2012 15:22:08 GMT-0400 (Eastern Daylight Time)

Transformation in OpenGL applies to a single 'POINT'

It will come as a surprise to you in opengl if you are doing it the first time. we may see things as 3 dimensional objects such as cubes and spheres.

however realize all of the matrix transformations ACT on a SINGLE POINT. Each point is individually transformed and it has no memory of its adjacent vertices!! Ha! It is right before my eyes but I refuse to abandon my "whole" object view of the world.

why is this important?

it is so when you apply a series of transformations such as translate, rotate, scale etc. You may think that you are concatenating these transformations through matrix multiplication.

whats wrong with that?

well in your mind you are only thinking of starting object and the ending object. So you tend to give your coordinates at those two distinct points in time. There lies the problem.

After each transformation the point that is transformed is at a different location. Now the new transformation applies to this NEW point not to the OLD my friend.

satya - Sat Aug 11 2012 13:37:32 GMT-0400 (Eastern Daylight Time)

Here is the right way to multiply the matrices


protected void setupMatrices()
    {
       Matrix.setIdentityM(mMMatrix, 0);
       
        //translate the model combo next
        Matrix.multiplyMM(mMVPMatrix, 0, this.mCurrentModelMatrix, 0, mMMatrix, 0);
       
       //translate eye coordinates first
        Matrix.multiplyMM(mMVPMatrix, 0, this.mVMatrix, 0, mMVPMatrix, 0);
        
        //Project it: screen coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    }

satya - Sat Aug 11 2012 13:37:56 GMT-0400 (Eastern Daylight Time)

Here is the wrong way to do it


protected void setupMatrices1()
    {
       Matrix.setIdentityM(mMMatrix, 0);
       
       //translate eye coordinates first
        Matrix.multiplyMM(mMVPMatrix, 0, this.mVMatrix, 0, mMMatrix, 0);
       
        //translate the model combo next
        Matrix.multiplyMM(mMVPMatrix, 0, this.mCurrentModelMatrix, 0, mMVPMatrix, 0);
        
        //Project it: screen coordinates
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    }

satya - Sat Aug 11 2012 13:41:46 GMT-0400 (Eastern Daylight Time)

Key driver code


protected void draw(GL10 gl, int positionHandle)
    {
        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false,
                0, mFVertexBuffer);
        checkGlError("glVertexAttribPointer maPosition");
        //mFVertexBuffer.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
        GLES20.glEnableVertexAttribArray(positionHandle);
        checkGlError("glEnableVertexAttribArray maPositionHandle");

        long time = SystemClock.uptimeMillis() % 4000L;
        //Break time into 4000 parts
        //each part is .090 so that in 4000 parts it will be 360
        float angle = 0.090f * ((int) time);
        
        this.initializeMatrices();
        //Center the cube
        this.trnslate(0,0,-1);
        
        //Rotate it around y axis
        this.rotate(angle, 0,-1,0);
        
        //Decenter it to where ever you want
        this.trnslate(0,-2,2);
        
        this.setupMatrices();
        int vertexCount = mTriangleVerticesData.length/3;
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        checkGlError("glDrawArrays");
    }