Android OpenGL ES 绘图 -- 缩放、平移、旋转

OpenGL的缩放、平移、旋转

注: 参考:http://wiki.jikexueyuan.com/project/opengl-es-basics/coordinate-transformation.html

Coordinate System坐标系

OpenGL 使用了右手坐标系统,右手坐标系判断方法:在空间直角坐标系中,让右手拇指指向x轴的正方向,食指指向y轴的正方向,如果中指能指向z轴的正方向,则称这个坐标系为右手直角坐标系。

Translate 平移变换

方法 public abstract void glTranslatef (float x, float y, float z) 用于坐标平移变换。

Rotate 旋转

方法public abstract void glRotatef(float angle, float x, float y, float z) 用来实现选择坐标变换,单位为角度。
比如你选择一个骰子,首先按下列顺序选择3次:

gl.glRotatef(90f, 1.0f, 0.0f, 0.0f);
gl.glRotatef(90f, 0.0f, 1.0f, 0.0f);
gl.glRotatef(90f, 0.0f, 0.0f, 1.0f);  


然后打算逆向旋转回原先的初始状态,需要有如下旋转:

gl.glRotatef(90f, -1.0f, 0.0f, 0.0f);
gl.glRotatef(90f, 0.0f, -1.0f, 0.0f);
gl.glRotatef(90f, 0.0f, 0.0f, -1.0f);  


或者如下旋转:

gl.glRotatef(90f, 0.0f, 0.0f, -1.0f);
gl.glRotatef(90f, 0.0f, -1.0f, 0.0f);
gl.glRotatef(90f, -1.0f, 0.0f, 0.0f);  

旋转变换 glRotatef(angle, -x, -y, -z) 和 glRotatef(-angle, x, y, z) 是等价的,但选择变换的顺序直接影响最终坐标变换的结果。 角度为正时表示逆时针方向。

Translate & Rotate (平移和旋转组合变换)

在对 Mesh(网格,构成三维形体的基本单位)同时进行平移和选择变换时,坐标变换的顺序也直接影响最终的结果。
比如:先平移后旋转,旋转的中心为平移后的坐标。

先选择后平移: 平移在则相对于旋转后的坐标系:

Scale(缩放)

方法public abstract void glScalef (float x, float y, float z)用于缩放变换。
比如使用 gl.glScalef(2f, 2f, 2f) 变换后的基本,相当于把每个坐标刻度值都乘以2.

Translate & Scale(平移和缩放组合变换)

同样当需要平移和缩放时,变换的顺序也会影响最终结果。
比如先平移后缩放:

gl.glTranslatef(2, 0, 0);
gl.glScalef(0.5f, 0.5f, 0.5f);  


如果调换一下顺序:

gl.glScalef(0.5f, 0.5f, 0.5f);
gl.glTranslatef(2, 0, 0);  

结果就有所不同:

注:以上所有操作都是针对矩阵,对于已经绘制的图形无影响

矩阵操作,单位矩阵

在进行平移,旋转,缩放变换时,所有的变换都是针对当前的矩阵(与当前矩阵相乘),如果需要将当前矩阵回复最初的无变换的矩阵,可以使用单位矩阵(无平移,缩放,旋转

public abstract void glLoadIdentity()。

在栈中保存当前矩阵和从栈中恢复所存矩阵,可以使用

public abstract void glPushMatrix()

public abstract void glPopMatrix()。

在进行坐标变换的一个好习惯是在变换前使用 glPushMatrix 保存当前矩阵,完成坐标变换操作后,再调用 glPopMatrix 恢复原先的矩阵设置。

Demo

利用上面介绍的坐标变换知识,来绘制 3 个正方形 A,B,C。进行缩放变换,使的 B 比 A 小 50%,C 比 B 小 50%。 然后以屏幕中心逆时针旋转 A,B 以 A 为中心顺时针旋转,C 以 B 为中心顺时针旋转同时以自己中心高速逆时针旋转。

本次示例使用透视投影
在onSurfaceChanged中设置

        // Sets the current view port to the new size.
        gl.glViewport(0, 0, width, height);
        // Select the projection matrix
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // Reset the projection matrix
        gl.glLoadIdentity();// OpenGL docs.
        //设置透视投影,参数作用请看之前的文章
        GLU.gluPerspective(gl,45.f,(float) width/height,10f,100f);
        // Select the modelview matrix
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // Reset the modelview matrix
        gl.glLoadIdentity();

所画图形为之前的矩形(因设置透视投影,各轴刻度值相等,所画矩形为正方形),封装成drawREC绘制方法

 private void drawREC(GL10 gl) {

        float vertices[] = {
                -0.5f,  0.5f, 0.0f,  // 0, Top Left
                -0.5f, -0.5f, 0.0f,  // 1, Bottom Left
                0.5f, -0.5f, 0.0f,  // 2, Bottom Right
                0.5f,  0.5f, 0.0f,  // 3, Top Right
        };
        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
        vbb.order(ByteOrder.nativeOrder());
        FloatBuffer vertexBuffer = vbb.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        short[] indices = { 0, 1,
                            2, 0,
                            2, 3 };
        ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
        ibb.order(ByteOrder.nativeOrder());
        ShortBuffer indexBuffer = ibb.asShortBuffer();
        indexBuffer.put(indices);
        indexBuffer.position(0);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
                GL10.GL_UNSIGNED_SHORT, indexBuffer);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    }

在onDrawFrame开始绘制

    float angle =0f;
    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glFrontFace(GL10.GL_CCW);
        gl.glEnable(GL10.GL_CULL_FACE);
        //重置视角矩阵
        gl.glLoadIdentity();
        gl.glTranslatef(0,0,-10f);
        // 清除屏幕和深度缓存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
                GL10.GL_DEPTH_BUFFER_BIT);
        //REC A
        // Save the current matrix.
        gl.glPushMatrix();
        // Rotate square A counter-clockwise.
        gl.glRotatef(angle, 0, 0, 1);
        // Draw REC A.
        drawREC(gl);
        // Restore the last matrix.
        gl.glPopMatrix();
        // SQUARE B
        //making it rotate around A.
        gl.glRotatef(-angle, 0, 0, 1);
        // Move square B.
        gl.glTranslatef(2, 0, 0);
        // Scale it to 50% of REC A
        gl.glScalef(0.5f, 0.5f, 0.5f);
        // Draw REC B.
        drawREC(gl);
        // REC C
        // Make the rotation around B
        gl.glRotatef(-angle, 0, 0, 1);
        gl.glTranslatef(2, 0, 0);
        // Scale it to 50% of REC B
        gl.glScalef(0.5f, .5f, 0.5f);
        // Rotate around it's own center.
        gl.glRotatef(angle*10, 0, 0, 1);
        // Draw REC C.
        drawREC(gl);
        // Increse the angle.
        angle++;
    }

你可能感兴趣的:(Android)