2016-03-22 10 views
0

私はモデル、ビュー、および投影行列を使って3D空間を作成するために4 * 4浮動行列クラスを作成しようとしています。現在の状態では、ビューマトリックスを回転しようとすると、平行移動も適用されているように見え、スペースは歪んでしまいます。投影、ビュー、およびモデルの行列乗算は、頂点シェーダで行われます。OpenGL Java Matrix4fの実装

Edit5:変換関数の非機能状態は以下の発見された次のよう

public class Mat4f { 
public float m00, m10, m20, m30, 
      m01, m11, m21, m31, 
      m02, m12, m22, m32, 
      m03, m13, m23, m33; 

public Mat4f() { 
    loadIdentity(); 
} 

public Mat4f loadIdentity() { 
    m00 = 1.0f; m10 = 0.0f; m20 = 0.0f; m30 = 0.0f; 
    m01 = 0.0f; m11 = 1.0f; m21 = 0.0f; m31 = 0.0f; 
    m02 = 0.0f; m12 = 0.0f; m22 = 1.0f; m32 = 0.0f; 
    m03 = 0.0f; m13 = 0.0f; m23 = 0.0f; m33 = 1.0f; 
    return this; 
} 

public Mat4f store(FloatBuffer buffer) { 
    buffer.put(m00); 
    buffer.put(m01); 
    buffer.put(m02); 
    buffer.put(m03); 

    buffer.put(m10); 
    buffer.put(m11); 
    buffer.put(m12); 
    buffer.put(m13); 

    buffer.put(m20); 
    buffer.put(m21); 
    buffer.put(m22); 
    buffer.put(m23); 

    buffer.put(m30); 
    buffer.put(m31); 
    buffer.put(m32); 
    buffer.put(m33); 

    buffer.flip(); 

    return this; 
} 

public Mat4f loadPerspective(float fov, float ratio, float near, float far) { 
    m11 = (float) (1.0f/(Math.tan(fov/2.0f))); 
    m00 = m11/ratio; 
    m22 = -(far + near)/(far - near); 
    m23 = -1.0f; 
    m32 = -2.0f * far * near/(far - near); 
    m33 = 0.0f; 
    return this; 
} 

public Mat4f translate(float x, float y, float z) { 
    m30 = x; 
    m31 = y; 
    m32 = z; 
    return this; 
} 

public Mat4f scale(float x, float y, float z) { 
    m00 = x; 
    m11 = y; 
    m22 = z; 
    return this; 
} 

public Mat4f rotateX(float x) { 
    m11 = (float) Math.cos(x); 
    m12 = (float) Math.sin(x); 
    m21 = (float) -(Math.sin(x)); 
    m22 = (float) Math.cos(x); 
    return this; 
} 

public Mat4f rotateY(float y) { 
    m00 = (float) Math.cos(y); 
    m02 = (float) -(Math.sin(y)); 
    m20 = (float) Math.sin(y); 
    m22 = (float) Math.cos(y); 
    return this; 
} 

public Mat4f rotateZ(float z) { 
    m00 = (float) Math.cos(z); 
    m01 = (float) Math.sin(z); 
    m10 = (float) -(Math.sin(z)); 
    m11 = (float) Math.cos(z); 
    return this; 
} 
} 

そして、それらを行うための適切な方法は次のとおりです。

public Mat4f translate(float x, float y, float z, Mat4f dest) { 
    dest.m00 = m00; 
    dest.m01 = m01; 
    dest.m02 = m02; 
    dest.m03 = m03; 
    dest.m10 = m10; 
    dest.m11 = m11; 
    dest.m12 = m12; 
    dest.m13 = m13; 
    dest.m20 = m20; 
    dest.m21 = m21; 
    dest.m22 = m22; 
    dest.m23 = m23; 
    dest.m30 = m00 * x + m10 * y + m20 * z + m30; 
    dest.m31 = m01 * x + m11 * y + m21 * z + m31; 
    dest.m32 = m02 * x + m12 * y + m22 * z + m32; 
    dest.m33 = m03 * x + m13 * y + m23 * z + m33; 
    return this; 
} 

public Mat4f translate(float x, float y, float z) { 
    return translate(x, y, z, this); 
} 

public Mat4f scale(float x, float y, float z, Mat4f dest) { 
    dest.m00 = m00 * x; 
    dest.m01 = m01 * x; 
    dest.m02 = m02 * x; 
    dest.m03 = m03 * x; 
    dest.m10 = m10 * y; 
    dest.m11 = m11 * y; 
    dest.m12 = m12 * y; 
    dest.m13 = m13 * y; 
    dest.m20 = m20 * z; 
    dest.m21 = m21 * z; 
    dest.m22 = m22 * z; 
    dest.m23 = m23 * z; 
    dest.m30 = m30; 
    dest.m31 = m31; 
    dest.m32 = m32; 
    dest.m33 = m33; 
    return this; 
} 

public Mat4f scale(float x, float y, float z) { 
    return scale(x, y, z, this); 
} 

public Mat4f rotateX(float x, Mat4f dest) { 
    float cos = (float) Math.cos(x); 
    float sin = (float) Math.sin(x); 
    float rm11 = cos; 
    float rm12 = sin; 
    float rm21 = -sin; 
    float rm22 = cos; 

    float nm10 = m10 * rm11 + m20 * rm12; 
    float nm11 = m11 * rm11 + m21 * rm12; 
    float nm12 = m12 * rm11 + m22 * rm12; 
    float nm13 = m13 * rm11 + m23 * rm12; 

    dest. m20 = m10 * rm21 + m20 * rm22; 
    dest.m21 = m11 * rm21 + m21 * rm22; 
    dest.m22 = m12 * rm21 + m22 * rm22; 
    dest. m23 = m13 * rm21 + m23 * rm22; 

    dest.m10 = nm10; 
    dest.m11 = nm11; 
    dest.m12 = nm12; 
    dest.m13 = nm13; 

    return this; 
} 

public Mat4f rotateX(float x) { 
    return rotateX(x, this); 
} 

public Mat4f rotateY(float y, Mat4f dest) { 
    float cos = (float) Math.cos(y); 
    float sin = (float) Math.sin(y); 
    float rm00 = cos; 
    float rm02 = -sin; 
    float rm20 = sin; 
    float rm22 = cos; 

    float nm00 = m00 * rm00 + m20 * rm02; 
    float nm01 = m01 * rm00 + m21 * rm02; 
    float nm02 = m02 * rm00 + m22 * rm02; 
    float nm03 = m03 * rm00 + m23 * rm02; 

    dest.m20 = m00 * rm20 + m20 * rm22; 
    dest.m21 = m01 * rm20 + m21 * rm22; 
    dest.m22 = m02 * rm20 + m22 * rm22; 
    dest.m23 = m03 * rm20 + m23 * rm22; 

    dest.m00 = nm00; 
    dest.m01 = nm01; 
    dest.m02 = nm02; 
    dest.m03 = nm03; 

    return this; 
} 

public Mat4f rotateY(float y) { 
    return rotateY(y, this); 
} 

public Mat4f rotateZ(float z, Mat4f dest) { 
    float cos = (float) Math.cos(z); 
    float sin = (float) Math.sin(z); 
    float rm00 = cos; 
    float rm01 = sin; 
    float rm10 = -sin; 
    float rm11 = cos; 

    float nm00 = m00 * rm00 + m10 * rm01; 
    float nm01 = m01 * rm00 + m11 * rm01; 
    float nm02 = m02 * rm00 + m12 * rm01; 
    float nm03 = m03 * rm00 + m13 * rm01; 

    dest.m10 = m00 * rm10 + m10 * rm11; 
    dest.m11 = m01 * rm10 + m11 * rm11; 
    dest.m12 = m02 * rm10 + m12 * rm11; 
    dest.m13 = m03 * rm10 + m13 * rm11; 

    dest.m00 = nm00; 
    dest.m01 = nm01; 
    dest.m02 = nm02; 
    dest.m03 = nm03; 

    return this; 
} 

public Mat4f rotateZ(float z) { 
    return rotateZ(z, this); 
} 

私が使用した行列を変更するには次の変換の順番:

public void transform() { 
    mMat.loadIdentity(); 
    mMat.translate(position.x, position.y, position.z); 
    mMat.rotateX((float) Math.toRadians(orientation.x)); 
    mMat.rotateY((float) Math.toRadians(orientation.y)); 
    mMat.rotateZ((float) Math.toRadians(orientation.z)); 
    mMat.scale(scale.x, scale.y, scale.z); 
} 

public void updateCamera() { 
    Vec3f position = World.camera.getPosition(); 
    vMat.loadIdentity(); 
    vMat.rotateX((float) Math.toRadians(World.camera.getPitch())); 
    vMat.rotateY((float) Math.toRadians(World.camera.getYaw())); 
    vMat.translate(-position.x, -position.y, position.z); 
} 

編集:透視投影は問題ありません。変換もそうですが、モデル行列をMat4fに格納すると、モデルの回転がカメラの回転に従います。

Edit2:Mat4fをモデル行列として使用すると、モデルの向きがカメラの回転に追従しなくなりました。投影行列、平行移動、スケーリングはうまく機能します。

Edit3:コードを編集しました。適用された回転は完全な円の回転ではなく、モデルは左右に振ります。

Edit4:私は

答えて

0

あなたの行列クラスは、変換の合成を実装していない行列の乗算で回転をして試みてきました。それぞれの行列方法は、は、特定の要素をで上書きします。例えば

は、以下の動作sequenc見:

translate(1,1,1); 
rotateX(45); 
translate(1,1,1); 

このような配列は、数学的に行列乗算のT *のR T及びRは、基本的な回転/並進マトリックスである* T(によって表されるべきですそれぞれのパラメータで)。

しかし、あなたのコードが行うことは、T(最初は行列が同一性であるため)を作成し、回転の一部を上書きし、最後に翻訳部分を再度上書きすることです。

コードを修正するには、適切な行列乗算方法を実装する必要があります。実際には、行列にさらなる変換を適用する場合はいつでも使用してください。基本変換行列のいくつかのメソッドを作成すると便利です。

しかし、これはまだ私にとっては、通常の行メジャーと列メジャーマトリックスのストレージレイアウトのようです。

mXYメンバーのレイアウトは、m12が2番目の行、3番目の列になる数学的な規則を使用することをお勧めします。 storeメソッドは、マトリックスをカラムのメジャーレイアウトのバッファに入れます。このようなバッファは、従来のGLの行列関数(glLoadMatrixまたはglMultMatrixなど)によって直接使用できます。 transposeパラメータがGL_FALSEに設定されている場合、マトリックスユニフォームの「標準」レイアウトになります。

しかし、あなたのtranslate方法を見て:

public Mat4f translate(float x, float y, float z) { 
    m30 = x; 
    m31 = y; 
    m32 = z; 
    return this; 
} 

これが最後の、ない最後のに並進ベクトルを設定します。 (他のすべての機能も、転置レイアウトを使用しているように見えます)。

現在、従来のGLでは、matrix * vectorの規約が使用されています(D3Dが好むvector * matrixではなく)。その場合、あなたの行列はGLが期待するものに転置されます。シェーダを使用する場合は、どの乗算命令を使用するかはあなた次第ですが、マトリックスに使用している規則と一致する必要があります。M * v == v^T * M^T

+0

私の質問に答える時間をとってくれてありがとう! loadPerspectiveメソッド、変換、スケーリングは正常に動作しているため、発注の問題にはなりません。私はストアの機能を行のメジャー(私のインデックスをm03、m13、m23に変更するのと同じだと思います)と変えれば、すべてが黒になります。頂点シェーダ。 –

+0

私は自分の答えを更新しました。 – derhass

+0

オブジェクトの位置、方向、およびスケールフィールドはデルタではなく、絶対値を保持しています。マトリックスを変換する前に、毎回単位行列を呼び出します。私が働くことができない唯一のことは、回転です。私は回転だけで指数をトランスポントしようとしましたが、それはどちらも失敗しました。また、関数に依存値を追加しようとしましたが(編集を参照)、常に同じ種類の誤動作が発生します。 –

0

実際問題は、これまでの変換を考慮しなかったことです。私は行列の乗算を使用しないで終わった。私はJOMLから関連する部品をコピーしました。これはhttps://github.com/JOML-CI/JOMLに届きます。 問題の内容とクラスの最終状態を反映するために質問を編集します。 JOMLの貢献者に感謝し、Derhassの助けに感謝します!