約2日前に、Model-View-Projection( "MVP")マトリックスを明示的に計算して、その動作を理解するためのコードを作成することにしました。それ以来、私が使用している射影行列のせいで、問題が発生しただけです。
iPhoneディスプレイを使用して、次の4つの角の頂点で表される画面中心の正方形を作成します。
const CGFloat cy = screenHeight/2.0f;
const CGFloat z = -1.0f;
const CGFloat dim = 50.0f;
vxData[0] = cx-dim;
vxData[1] = cy-dim;
vxData[2] = z;
vxData[3] = cx-dim;
vxData[4] = cy+dim;
vxData[5] = z;
vxData[6] = cx+dim;
vxData[7] = cy+dim;
vxData[8] = z;
vxData[9] = cx+dim;
vxData[10] = cy-dim;
vxData[11] = z;
OGLES 2.0を使用しているので、MVPをユニフォームとして頂点シェーダーに渡し、次に変換を現在の頂点位置に適用します。
uniform mat4 mvp;
attribute vec3 vpos;
void main()
{
gl_Position = mvp * vec4(vpos, 1.0);
}
今のところ、MVPを単純化してP行列にしました。以下に示すコードには、2つの射影行列がリストされています。1つ目は標準のパースペクティブ射影行列で、2つ目はオンラインで見つけた明示値射影行列です。
CGRect screenBounds = [[UIScreen mainScreen] bounds];
const CGFloat screenWidth = screenBounds.size.width;
const CGFloat screenHeight = screenBounds.size.height;
const GLfloat n = 0.01f;
const GLfloat f = 100.0f;
const GLfloat fov = 60.0f * 2.0f * M_PI / 360.0f;
const GLfloat a = screenWidth/screenHeight;
const GLfloat d = 1.0f / tanf(fov/2.0f);
// Standard perspective projection.
GLKMatrix4 projectionMx = GLKMatrix4Make(d/a, 0.0f, 0.0f, 0.0f,
0.0f, d, 0.0f, 0.0f,
0.0f, 0.0f, (n+f)/(n-f), -1.0f,
0.0f, 0.0f, (2*n*f)/(n-f), 0.0f);
// The one I found online.
GLKMatrix4 projectionMx = GLKMatrix4Make(2.0f/screenWidth,0.0f,0.0f,0.0f,
0.0f,2.0f/-screenHeight,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
-1.0f,1.0f,0.0f,1.0f);
明示的な値マトリックスを使用する場合、正方形は画面の中央に正確な寸法で正確にレンダリングされます。透視投影行列を使用する場合、画面には何も表示されません。透視投影行列によって画面の中心に生成された位置の値を印刷しましたが(screenWidth/2, screenHeight/2, 0)
、それらは膨大です。明示的な値の行列は正しくゼロを生成します。
明示的な値行列は正射影行列だと思います-そうですか?私のフラストレーションは、パースペクティブプロジェクションマトリックスが機能しない理由を理解できないことです。
誰かがこの問題で私を助けてくれたら、私は非常に感謝しています。どうもありがとう。
クリスチャンラウの更新:
#define Zn 0.0f
#define Zf 100.0f
#define PRIMITIVE_Z 1.0f
//...
CGRect screenBounds = [[UIScreen mainScreen] bounds];
const CGFloat screenWidth = screenBounds.size.width;
const CGFloat screenHeight = screenBounds.size.height;
//...
glUseProgram(program);
//...
glViewport(0.0f, 0.0f, screenBounds.size.width, screenBounds.size.height);
//...
const CGFloat cx = screenWidth/2.0f;
const CGFloat cy = screenHeight/2.0f;
const CGFloat z = PRIMITIVE_Z;
const CGFloat dim = 50.0f;
vxData[0] = cx-dim;
vxData[1] = cy-dim;
vxData[2] = z;
vxData[3] = cx-dim;
vxData[4] = cy+dim;
vxData[5] = z;
vxData[6] = cx+dim;
vxData[7] = cy+dim;
vxData[8] = z;
vxData[9] = cx+dim;
vxData[10] = cy-dim;
vxData[11] = z;
//...
const GLfloat n = Zn;
const GLfloat f = Zf;
const GLfloat fov = 60.0f * 2.0f * M_PI / 360.0f;
const GLfloat a = screenWidth/screenHeight;
const GLfloat d = 1.0f / tanf(fov/2.0f);
GLKMatrix4 projectionMx = GLKMatrix4Make(d/a, 0.0f, 0.0f, 0.0f,
0.0f, d, 0.0f, 0.0f,
0.0f, 0.0f, (n+f)/(n-f), -1.0f,
0.0f, 0.0f, (2*n*f)/(n-f), 0.0f);
//...
// ** Here is the matrix you recommended, Christian:
GLKMatrix4 ts = GLKMatrix4Make(2.0f/screenWidth, 0.0f, 0.0f, -1.0f,
0.0f, 2.0f/screenHeight, 0.0f, -1.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
GLKMatrix4 mvp = GLKMatrix4Multiply(projectionMx, ts);
更新2
新しいMVPコード:
GLKMatrix4 ts = GLKMatrix4Make(2.0f/screenWidth, 0.0f, 0.0f, -1.0f,
0.0f, 2.0f/-screenHeight, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
// Using Apple perspective, view matrix generators
// (I can solve bugs in my own implementation later..!)
GLKMatrix4 _p = GLKMatrix4MakePerspective(60.0f * 2.0f * M_PI / 360.0f,
screenWidth / screenHeight,
Zn, Zf);
GLKMatrix4 _mv = GLKMatrix4MakeLookAt(0.0f, 0.0f, 1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 1.0f, 0.0f);
GLKMatrix4 _mvp = GLKMatrix4Multiply(_p, _mv);
GLKMatrix4 mvp = GLKMatrix4Multiply(_mvp, ts);
それでも画面の中心には何も表示されず、画面の中心の変換されたx、y座標はゼロではありません。
更新3
ts
上記のコードで代わりにの転置を使用すると機能します!しかし、正方形はもはや正方形に見えません。アスペクト比が設定されているように見えます。screenHeight/screenWidth
つまり、(短い)画面の幅に平行な長い寸法と、(長い)画面の高さに平行な短い寸法があります。
transpose(ts)
(a)転置が必要な理由と、それが有効な修正であるかどうか、(b)非正方形の次元を正しく修正する方法、および(c)使用するこの追加の行列がどのように適合するかを知りたいです。ビューポート*プロジェクション*ビュー*モデル*ポイントの変換チェーン。
(c)の場合:マトリックスが何をするか、つまり、範囲[-1、1]にどのように変換するかについてのChristianRauによる説明を理解しています。しかし、この追加の作業を別個の変換行列として含めるのは正しいですか、それともMVPチェーンの一部が代わりにこの作業を行う必要がありますか?
これまでの貴重な貢献をしてくれたChristianRauに心から感謝します。
更新4
「tsがどのように適合するか」についての私の質問はばかげていますね。要点は、頂点に画面座標を使用することを選択しているため、マトリックスが必要なだけです。最初から世界空間の座標を使用する場合、この作業は必要ありません。
すべてのあなたの助けをクリスチャンに感謝します、それはかけがえのないものでした:)問題は解決しました。