2

頂点シェーダーは次のとおりです。

uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;

void main(void)
{
    gl_Position = projection * view * model * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;
}

私の理解では、さまざまな変換を使用して、モデル空間は最終的にクリップ空間に変わります。これは、ビューポートに直接描画される各軸の各ユニットによって囲まれたボックスです。つまり、(-1, 1,0) の何かが一番上にあります。ビューポートの左側。シェーダーからすべてのマトリックス変換を削除すると、

gl_Position = gl_Vertex;

モデルとして単純なクワッドを渡します

public Vector3[] verts = new Vector3[] {
    new Vector3(-1f, -1f, 0),
    new Vector3(1f, -1f, 0),
    new Vector3(1f, 1f, 0),
    new Vector3(-1f, 1f, 0),
};

public Vector2[] coords = new Vector2[] {
    new Vector2(0, 1f),
    new Vector2(1f, 1f),
    new Vector2(1f, 0f),
    new Vector2(0f, 0f),
};

public uint[] indices = new uint[] {
    0,1,2,
    0,2,3,
};

期待されるフルスクリーン画像を取得します。変換を適用すると、予想どおり、画像が画面の中央に小さな正方形として表示されます。CPU 上のクリップ座標でモデルの頂点の位置を計算しようとすると、問題が発生します。

public Vector4 testMult(Vector4 v, Matrix4 m)
{
    return new Vector4(
        m.M11 * v.X + m.M12 * v.Y + m.M13 * v.Z + m.M14 * v.W,
        m.M21 * v.X + m.M22 * v.Y + m.M23 * v.Z + m.M24 * v.W,
        m.M31 * v.X + m.M32 * v.Y + m.M33 * v.Z + m.M34 * v.W,
        m.M41 * v.X + m.M42 * v.Y + m.M43 * v.Z + m.M44 * v.W);
}

Matrix4 test = (GlobalDrawer.projectionMatrix * GlobalDrawer.viewMatrix) * modelMatrix;

Vector4 testv = (new Vector4(1f, 1f, 0, 1));
Console.WriteLine("Test Input: " + testv);
Console.WriteLine("Test Output: " + Vector4.Transform(testv, test));
Vector4 testv2 = testMult(testv, test);
Console.WriteLine("Test Output: " + testv2);
Console.WriteLine("Test Output division: " + testv2 / testv2.W);

(渡された行列は、シェーダーに渡されたものと同じです)

次に、プログラムはクリップ スペースの外側に出力を提供し、W による除算は 0 による除算につながります。

Test Input: (1, 1, 0, 1)
Test Output: (0.9053301, 1.207107, -2.031746, 0)
Test Output: (0.9053301, 1.207107, -1, 0)
Test Output division: (Infinity, Infinity, -Infinity, NaN)

マトリックスは次のように作成されます。

projectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, window.Width / (float)window.Height, 1.0f, 64.0f);
projectionMatrix =
(1.81066, 0, 0, 0)
(0, 2.414213, 0, 0)
(0, 0, -1.031746, -1)
(0, 0, -2.031746, 0)

viewMatrix = Matrix4.LookAt(new Vector3(0,0,4), -Vector3.UnitZ, Vector3.UnitY);
viewMatrix = 
(1, 0, 0, 0)
(0, 1, 0, 0)
(0, 0, 1, 0)
(0, 0, -4, 1)

modelMatrix = 
(0.5, 0  , 0  , 0)
(0  , 0.5, 0  , 0)
(0  , 0  , 1  , 0)
(0  , 0  , 0  , 1)

では、問題はその理由です。私は何を間違っていますか?

4

1 に答える 1

3

編集(コメントから実際の回答を追加)

OpenTK 行列はデフォルトで転置されます。列ベクトルの代わりに行ベクトルを使用しているようです。したがって、(proj * view * model) ではなく、(model * view * proj) として乗算を行う必要があります。それか、アップロードする前にすべての行列を転置します。


実際には、クリップ スペースは -1 から 1 までではなく、-W から W までです。ここで、W はクリップ スペース ベクトルの 4 番目のコンポーネントです。

おそらくあなたが考えているのは、正規化されたデバイス座標と呼ばれ、各軸で -1 から 1 の範囲です。この値は、クリップ スペース ベクトルの X、Y、および Z 座標をクリップ スペースの W コンポーネントで割ることによって得られます。この 分割 を透視 分割と 呼 ぶ。

これは、クリップ スペース座標を gl_Position に渡した後、舞台裏で行われます。

ただし、クリップ空間の座標は 0 ですが、これは正しくないようです。

詳細については、OpenGL FAQ : Transformationsを参照してください。

于 2012-07-12T16:46:10.700 に答える