2012-11-20 141 views
8

我有一个实现GLSurfaceView.Renderer接口的呈现器; GLSurfaceView的子类和一些代表我想要绘制的对象的类。我有http://developer.android.com/training/graphics/opengl/motion.html 的代码我想扩展它,并添加一些沿轴移动,但无法管理它。该对象只能旋转。 这里是我的代码:OpenGL ES Android矩阵转换

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); 
    } 
} 

我的期望是每个重绘对象将通过裂伤旋转和1F沿Y轴traslated。虽然我只能看到旋转(也有点投影)。 我其实有一些问题: 如何应用我的翻译矩阵和 分割opengl功能的最佳做法是什么?模型矩阵不应该存储在对象本身而不是渲染器中?矩阵操作是否应该在渲染器类中执行? 我将它们分组在一起,因为我猜它们都是相关的。

+0

嗯。仍然没有解释如何初始化mProjMatrix。 –

+0

下面是最后的提示:尝试从http://learningwebgl.com/blog/?page_id=1217逐步复制课程。它只包含javascript,但差异很小。 API是相同的,矩阵数学是相同的。祝你好运! –

+0

@AkiSuihkonen在另一个[线程](http://stackoverflow.com/questions/11925647/is-googles-android-opengl-tutorial-teaching-incorrect-linear-algebra)人们建议(对于相同的教程相同的代码)使用'gl_Position = uMVPMatrix * vPosition;'而不是'gl_Position = vPosition * uMVPMatrix;'。如果我遵循这个建议,我完全看不到我的三角形 –

回答

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

    “的右侧和左侧的同一矩阵乘以MM“(见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); 
    

谢谢大家,我可以从这个主题中得到所有有用的输入。

+1

这很好用 - 我遇到过的唯一一个帮助我的教程。谢谢您的回答! – Antinous

+1

万一它帮助其他人遇到了这个答案,对我而言不明显的部分是Matrix.multiplyMM修改目标矩阵_during_计算,而不是之后。因此,如果您想通过旋转乘以mvp,并将结果放入mvp,则Matrix.multiplyMM(mMVPMatrix,0,mMVPMatrix,0,mModelMatrix,0)将在运行中突变mMVPMatrix,导致奇怪的计算结果。这就是上述克隆工作的原因。 出于我的目的,我能够通过在两个不同的“划痕”矩阵之间翻转进行“链接”计算,例如:http://pastebin.com/h7c9Ktg9 –

2

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

请注意Matrix.setIdentityM(mModelMatrix,0);将所有积累的旋转和平移恢复为“零”或实际上恢复到标识矩阵... 同样的惯例适用于btw全部设置函数。 为了积累所有的转化,人们必须

  • setIdentity(模型);
  • translate(trans); //获取旋转的原点
  • rotate(rotmatrix); //积累旋转
  • translate(t2); //再次转化为一些更好的位置...

还应该保持每个调用之间的对象转换矢量[牛,OY,盎司]的值,并喂它们Matrix.translateM(mModelMatrix,牛, 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)的顺序乘以 。

+0

我忘了提及绘图方法是由我的EventListener触发的,所以我猜,我不需要时间函数。我的三角形按预期旋转。它只是不会沿着轴移动。 –

+0

这是因为有* setRotate *而不是Matrix.rotateM。 (或任何它在Android GLES API中) –

+0

我现在有 'Matrix.setIdentityM(mModelMatrix,0); Matrix.setIdentityM(mMVPMatrix,0); Matrix.translateM(mModelMatrix,0,1f,0f,0); Matrix.translateM(mModelMatrix,0,1f,0f,0); Matrix.translateM Matrix.rotateM(mModelMatrix,0,mTriangle.Angle,0,0,-1.0f); Matrix.multiplyMM(tempMatrix,0,mVMatrix,0,mModelMatrix,0); Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,tempMatrix,0);'仍然只能看到围绕Z轴的旋转,没有任何其他运动。感谢提供将对象翻译为原点的提示。在我管理它将对象从原点移开后,我会解决这个问题。 –

0

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

大概应该是:

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

第一行不应该是'Matrix.multiplyMM(mVMatrix,0,mVMatrix,0,mModelMatrix,0)'?如果是,我仍然只能看到旋转。没有翻译。 –

+1

AFAIK multiplyMM的右侧和左侧不能有相同的矩阵:*但是,如果结果元素与lhs或rhs元素重叠,则结果元素值未定义。我在那里定义了一个新的矩阵,'ModelView'矩阵,以保存视图*模型乘法的临时结果。 – Tim

+0

和你一样 - 定义了一个临时矩阵。与预期的一样,问题仍然存在。 –