OpenGL ES Android矩阵转换

时间:2012-11-20 18:49:47

标签: android opengl-es opengl-es-2.0

我有一个实现GLSurfaceView.Renderer接口的渲染器; GLSurfaceView的子类和一些表示我想要绘制的对象的类。我有来自http://developer.android.com/training/graphics/opengl/motion.html的代码 我想扩展它并添加一些沿轴移动而无法管理它。该对象仅旋转。 这是我的代码:

public class NotMyCoolRenderer implements GLSurfaceView.Renderer {

public GLShip mTriangle;
private GLBackgroundStar   mSquare;

private final float[] mMVPMatrix = new float[16];
private final float[] mProjMatrix = new float[16];
private final float[] mVMatrix = new float[16];
private final float[] mModelMatrix = new float[16];
private final float[] tempMatrix = new float[16];

public void onDrawFrame(GL10 unused) {
    // Draw background color
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    // Set the camera position (View matrix)
    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    // Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
    // Draw square
    mSquare.draw(mMVPMatrix);
    // Now moving on to triangle aka ship
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.translateM(mModelMatrix, 0, 0.1f, 0f, 0);
    Matrix.rotateM(mModelMatrix, 0, mTriangle.mAngle, 0, 0, -1.0f);
    Matrix.multiplyMM(tempMatrix, 0, mVMatrix, 0, mProjMatrix, 0); 
    Matrix.multiplyMM(mMVPMatrix, 0, mModelMatrix , 0, tempMatrix , 0);  

    // Draw triangle
    mTriangle.draw(mMVPMatrix);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
    // Adjust the viewport based on geometry changes,
    // such as screen rotation
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;

    // this projection matrix is applied to object coordinates
    // in the onDrawFrame() method
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

}

public class GLShip {
    public volatile float mAngle;
    private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +

        "attribute vec4 vPosition;" +
        "void main() {" +
        // the matrix must be included as a modifier of gl_Position
        "  gl_Position = uMVPMatrix * vPosition;" +
        "}";


    public void draw(float[] mvpMatrix) {
        // Add program to OpenGL 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");
        NotMyCoolRenderer.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        NotMyCoolRenderer.checkGlError("glUniformMatrix4fv");

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

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

我的期望是,在每次重绘时,对象将通过mAngle旋转并沿Y轴移动1f。我只能看到旋转(有点投射)。 我实际上有一些问题: 我如何应用我的翻译矩阵和 划分opengl功能的最佳做法是什么? modelMatrix不应该存储在对象本身而不是存储在渲染器中吗?矩阵运算应该在渲染器类中执行吗? 我将它们组合在一起,因为我猜它们都是相关的。

3 个答案:

答案 0 :(得分:17)

我一直在使用Android培训中的示例,以下方法最终适用于我。 (基于Android Training > Displaying Graphics with OpenGL ES > Adding Motion

  1. 使用正确的顶点着色器:

    private final String vertexShaderCode =
    // This matrix member variable provides a hook to manipulate
    // the coordinates of the objects that use this vertex shader
    "uniform mat4 uMVPMatrix;" +
    "attribute vec4 vPosition;" +
    "void main() {" +
    // the matrix must be included as a modifier of gl_Position
    "  gl_Position = uMVPMatrix * vPosition;" +
    "}";
    
  2. 在渲染器类中:

    public class MyGL20Renderer implements GLSurfaceView.Renderer {
    [...]
    // create a model matrix for the triangle
    private final float[] mModelMatrix = new float[16];
    // create a temporary matrix for calculation purposes,
    // to avoid the same matrix on the right and left side of multiplyMM later
    // see https://stackoverflow.com/questions/13480043/opengl-es-android-matrix-transformations#comment18443759_13480364
    private float[] mTempMatrix = new float[16];
    [...]
    
  3. onDrawFrame 中应用转换,以翻译开头:

    public void onDrawFrame(GL10 unused) {
    [...]
    Matrix.setIdentityM(mModelMatrix, 0); // initialize to identity matrix
    Matrix.translateM(mModelMatrix, 0, -0.5f, 0, 0); // translation to the left
    
  4. 然后轮换

    // Create a rotation transformation for the triangle
    long time = SystemClock.uptimeMillis() % 4000L;
    float mAngle = 0.090f * ((int) time);
    Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
    
  5. 合并轮播和翻译,避免使用 mModelMatrix

      

    “作为multiplyMM右侧和左侧的相同矩阵”(见2

    // Combine Rotation and Translation matrices 
    mTempMatrix = mModelMatrix.clone();
    Matrix.multiplyMM(mModelMatrix, 0, mTempMatrix, 0, mRotationMatrix, 0);
    
  6. 将模型矩阵与投影和摄像机视图相结合; 再次避免使用 mModelMatrix

      

    “作为multiplyMM右侧和左侧的相同矩阵”(见2

    // Combine the model matrix with the projection and camera view
    mTempMatrix = mMVPMatrix.clone();
    Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mModelMatrix, 0);
    
  7. 绘制形状

    // Draw shape
    mTriangle.draw(mMVPMatrix);
    
  8. 谢谢大家,我可以从这个帖子中得到所有有用的输入。

答案 1 :(得分:2)

如果你想看到移动,你应该每帧更新mTriangle.mAngle(最好是时间的函数来对抗由其他进程引起的速度差异或延迟......)。

注意Matrix.setIdentityM(mModelMatrix,0);将所有累积的旋转和翻译恢复为“零”或实际上恢复到身份矩阵...... 相同的约定将btw应用于所有 set 函数。 为了积累所有的变换,必须

  • setIdentity(模型);
  • 翻译(反式); //获取旋转原点
  • 旋转(rotmatrix); //积累轮换
  • 翻译(T2); //再次翻译到更好的位置...

还应该在每个调用之间保留对象转换向量[ox,oy,oz]的值,并将它们提供给Matrix.translateM(mModelMatrix,ox,oy,oz,0);

通常,尽可能早地连接所有“翻译,旋转,缩放”等矩阵,并按每个对象缓存它们,或者按照具有多个对象并具有边界框的复杂容器进行分层,以便可以剔除多个对象当在相机后面(或通常在观看视锥体外)时。

通常一个人将一个移动的摄像机保持在一个矩阵中,每帧将它与投影矩阵相乘。

您可以从以下内容开始:

float Time = System.currentTimeMillis() * 0.01f;  // 10 radians / second == fast!
Matrix.translateM(mModelMatrix, Math.sin(Time)*2.0f, 0, 1f, 0);
...

正如蒂姆所注意到的那样,没有涉及投影矩阵,这意味着所有z值都在这个代码中完全表现,即使改变x& y值会产生影响。

我很想说,MVP矩阵意味着成倍增加 按顺序M * V * P =(M * V)* P = M *(V * P)。

答案 2 :(得分:0)

请注意,您没有将投影矩阵应用于您正在绘制的三角形,这可能会导致问题。

应该是:

Matrix.multiplyMM(mMVMatrix, 0, mVMatrix, 0, mModelMatrix, 0);  
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVMatrix, 0);