Making an object/shape rotate in place with OpenGL ES on Android

I started learning OpenGL on android, and now I'm trying to mess around with a simple triangle. What I'm trying to do is make it rotate in place (the rotation pivot being the shape's center), although I only managed to make it rotate around an axis (By that I mean it makes a circular motion in the axis specified).

Here's my code:

@Override
public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -10, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    long time = SystemClock.uptimeMillis() % 4000L;
    float angle = 0.090f * ((int) time);

    Matrix.setIdentityM(mModelMatrix, 0); // initialize to identity matrix
    Matrix.rotateM(mModelMatrix, 0, angle, 0, 1.0f, 0);

    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);

    mPlayerCharacter.draw(mMVPMatrix);
}

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

    float ratio = (float) width / height;
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    mPlayerCharacter = new PlayerCharacter();
}

----- PlayerCharacter.draw() -----

public void draw(float[] mvpMatrix) {
    // Add program to OpenGL ES environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader's vPosition member
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

    // Enable a handle to the triangle vertices
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    // Prepare the triangle coordinate data
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

    // get handle to fragment shader's vColor member
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

    // Set color for drawing the triangle
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

    // get handle to shape's transformation matrix
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

The triangles coordinates are top (0, 0.622, 0), bottom left ( -0.5, -0.311, 0), and bottom right (0.5, -0.311, 0).

I tried looking for similar questions or related guides, but none of the answers I found worked for me.

If so, what is the right way to achieve the result I'm looking for?

Answers


Assume you have your object transformation matrix:

    protected final float[] mTransformMatrix = new float[16];

When you create object you just use Matrix.setIdentityM(mTransformMatrix, 0);

To rotate you need:

Matrix.rotateM(mTransformMatrix, 0, angle, 0, 0, 1.0f);

Here are some methods for object positioning, sizeing and rotating:

    public Sprite setSize(float sizeX, float sizeY) {
    setCenterSizeRotation(this.mPositionX, this.mPositionY, sizeX, sizeY,
            this.mAngle);
    this.mSpriteWidth = sizeX;
    this.mSpriteHeight = sizeY;

    return this;
}

public Sprite setCenter(float posX, float posY) {
    setCenterSizeRotation(posX, posY, this.mSpriteWidth,
            this.mSpriteHeight, this.mAngle);
    this.mPositionX = posX;
    this.mPositionY = posY;

    return this;
}

public Sprite setRotation(float angle) {
    setCenterSizeRotation(this.mPositionX, this.mPositionY,
            this.mSpriteWidth, this.mSpriteHeight, angle);
    this.mAngle = angle;

    return this;
}

public Sprite setCenterSizeRotation(float posX, float posY, float sizeX,
        float sizeY, float angle) {

    reset();
    float oX = UtilsGL.getStepX() * posX - 1.0f;
    float oY = UtilsGL.getStepY() * posY - 1.0f;
    float scaleX = sizeX / (UtilsGL.getSurfaceWidth());
    float scaleY = sizeY / (UtilsGL.getSurfaceHeight());

    translate(oX, oY);
    scale(scaleX, scaleY);
    rotate(angle);

    this.mSpriteWidth = sizeX;
    this.mSpriteHeight = sizeY;
    this.mPositionX = posX;
    this.mPositionY = posY;
    this.mAngle = angle;

    return this;
}

public Sprite translate(float x, float y) {
    Matrix.translateM(mTransformMatrix, 0, x, y, 0);
    return this;
}

public Sprite scale(float x, float y) {
    Matrix.scaleM(mTransformMatrix, 0, x, y, 1.0f);
    return this;
}

public Sprite rotate(float d) {
    Matrix.rotateM(mTransformMatrix, 0, d, 0, 0, 1.0f);
    return this;
}

public Sprite reset() {
    Matrix.setIdentityM(mTransformMatrix, 0);
    return this;
}

Don't be afraid of returns, that's just a bit of code from my Sprite class

UtilsGL part:

    private static int mSurfaceWidth;
private static int mSurfaceHeight;
private static float mStepX;
private static float mStepY;

    public static void setSurfaceWH(int width, int height) {
    mSurfaceWidth = width;
    mSurfaceHeight = height;
    mStepX = 2.0f / (float) mSurfaceWidth;
    mStepY = 2.0f / (float) mSurfaceHeight;
}

public static int getSurfaceWidth() {
    return mSurfaceWidth;
}

public static int getSurfaceHeight() {
    return mSurfaceHeight;
}

public static float getStepX() {
    return mStepX;
}

public static float getStepY() {
    return mStepY;
}

A lot of code down here but it's all useful. Why static? I'm not a OOP geek) I chose to make it simple but functional


Problem solved! I can't believe it was something so small!

The problem was this line: gl_Position = vPosition * uMVPMatrix;

I can't quite explain why (so if someone could - that'd be great!) but when I changed it to: gl_Position = uMVPMatrix * vPosition; it worked as expected!

If someone can further explain why this works instead of the first option, that'd be awesome! I will of course mark the answer as accepted.

Thanks.


Need Your Help

Is there a way to use a dictionary or xml in the Application Settings?

xml vb.net dictionary linq-to-xml application-settings

I have to store a complex type in the application settings. I thought that storing it as XML would work best.

How to spec operations that rely on Memcached?

ruby-on-rails rspec memcached rspec-rails

We have a Rails application that we test with RSpec. We want to spec operations that rely on Memcached. What is the best practice to do so?