12

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 は、レンダラーではなくオブジェクト自体に格納するべきではありませんか? マトリックス操作はレンダラー クラスで実行する必要がありますか? それらはすべて関連していると思われるので、それらをグループ化しました。

4

3 に答える 3

19

私は Android トレーニングの例を使用してきましたが、次のアプローチが最終的に機能します。( Android トレーニング > OpenGL ES を使用したグラフィックスの表示 > モーションの追加に基づく)

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

このスレッドから得られるすべての有用な情報に感謝します。

于 2013-06-25T08:47:13.170 に答える
2

動きを見たい場合は、フレームごとに mTriangle.mAngle を更新する必要があります (できれば、速度の違いや他のプロセスによって引き起こされる遅延に対処するための時間の関数として...)。

Matrix.setIdentityM(mModelMatrix, 0); に注意してください。蓄積されたすべての回転と平行移動を「ゼロ」または実際には恒等行列に復元します...ところで、同じ規則がすべてのセット関数に適用されます。すべての変換を蓄積するには、

  • setIdentity(モデル);
  • 翻訳(トランス); // 回転の原点を取得する
  • 回転 (rotmatrix); // 回転を累積する
  • 翻訳(t2); // より適切な位置に再度変換します...

また、各呼び出し間でオブジェクト変換ベクトル [ox,oy,oz] の値を保持し、それらを Matrix.translateM(mModelMatrix, ox, oy, oz, 0); にフィードする必要があります。

通常、すべての「変換、回転、スケーリング」などのマトリックスをできるだけ早く連結し、オブジェクトごとに、または複数のオブジェクトとバウンディング ボックスを持つ複雑なコンテナーごとに階層的にキャッシュします。カメラ(または通常は視錐台の外側)。

また、通常、移動するカメラを 1 つの行列に保持し、フレームごとに投影行列を乗算します。

次のようなものから始めることができます:

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

ティムが気付いたように、射影行列が含まれていません。つまり、x と y の値を変更すると違いが生じる場合でも、すべての z 値がこのコードで正確に動作します。

MVP 行列は、M * V * P = (M*V) * P = M * (V*P) の順に乗算することを意味すると言いたくなるでしょう。

于 2012-11-20T18:59:58.283 に答える