0

この種の質問は以前にここで見たことがありますが、完全な答えが得られたものはなかったので、コードを投稿して、誰かが私に洞察を与えることができるかどうかを確認します。基本的に、このコードは機能しますが、(高さ* 1.205)[幅に関係なく]の魔法のzオフセットがあり、その理由がわかりません。

サイズの設定と配置ベクトルの作成:

gl.viewportWidth = gl.canvas.width;
gl.viewportHeight = gl.canvas.height;
gl.viewportHalfWidth = gl.viewportWidth / 2;
gl.viewportHalfHeight = gl.viewportHeight / 2;
gl.viewportAspect = gl.viewportWidth / gl.viewportHeight;
gl.viewportZoom = -gl.viewportHeight * 1.205;
if (gl.alignmentTest) {
    gl.alignmentVertices = (new Buffer(    // TL, TM, BM, BR, TR, BL, TL
       [    1.0,                        -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5,     -1.0,                    0.0,
        gl.viewportHalfWidth - 0.5, -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,     -(gl.viewportHeight - 1.0),  0.0,
        gl.viewportWidth - 1.0,         -1.0,                    0.0,
            1.0,                    -(gl.viewportHeight - 1.0),  0.0,
            1.0,                        -1.0,                    0.0], 3)).post();
}

配置ベクトルの描画:

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
mat4.perspective(45, gl.viewportAspect, 0.1, 1000.0, gl.perspective.current);
gl.perspective.post();    // ^ writes directly to current perspective buffer

gl.modelView.resetToIdentity();

gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

// Translate to pixel resolution
gl.modelView.push();
gl.modelView.translate([-gl.viewportHalfWidth, gl.viewportHalfHeight, gl.viewportZoom]);
gl.modelView.post();

// Alignment test?
if (gl.alignmentTest && gl.alignmentVertices) {
    gl.red.useAsAttribute(gl.shaderProg.vertexColour);
    gl.zero.vec2.useAsAttribute(gl.shaderProg.vertexTextureCoord);
    gl.alignmentVertices.drawAsPrimitives(gl.shaderProg.vertexPosition, gl.LINE_STRIP);
}

gl.disable(gl.BLEND);

問題の行は次のとおりです。

gl.viewportZoom = -gl.viewportHeight * 1.205;

と:

gl.modelView.translate([-gl.viewportHalfWidth, gl.viewportHalfHeight, gl.viewportZoom]);

このコードはどのサイズでも機能します。

これが700x300のスクリーンショットです:http://oi49.tinypic.com/2my9ir7.jpg

そして別の400x600:http: //oi46.tinypic.com/i2irh3.jpg

したがって、問題は次のとおりです。なぜこの魔法のスケーリング係数1.205が存在するのでしょうか。または、それを必要とするために私が間違っていることは何でしょうか?

4

1 に答える 1

3

計算はしていませんが、その要因は、透視投影マトリックスのFOVと平面に近いものから生じると推測しています。1:1 ピクセルを取得しようとするほとんどのアプリケーションは、透視投影も使用しません。

遠近法を使用する理由がある場合は、FOV ベースの遠近法の計算を使用せず、代わりに錐台ベース ( glFrustum-alike) を使用することをお勧めします。投影錐台の効果を実際に導出する方がはるかに簡単であり、その補正を行うことができます。手動で調整するのではなく、第一原理から考慮します。


これは基本的に三角関数の問題です。ビュー フラスタム、またはむしろビュー ピラミッドを想像してください (つまり、ニア プレーンとファー プレーンによって切り離されていません)。「カメラ位置」に先端があり、4 つの傾斜面があります。従来定義されているFOVは、上面と底面の間の角度に等しいです(これが、あなたが言及したように、幅が影響を及ぼさない理由です)。ただし、この目的のためには、気にするパラメーターは角度ではなく、勾配(Z と X または Y の動きの比率) です。これが、任意の図形の由来です。

古き良きのドキュメントgluPerspectiveを見ると(これは、パースペクティブ操作で使用しているものと同じ数学を使用していると想定しています)、次のように書かれています f = cotangent(fovy/2)。これはまさに私たちが気にかけている計算です。(これを再現しようとする場合、数学ライブラリのほとんどの三角関数は度ではなくラジアンで角度を取ることに注意してください。)

係数 2 が発生するのは、FOV が通常全視野角として測定されるためですが、対象となる値はその半分、つまり「真っ直ぐ前」と「ビューのちょうど端」の間の角度です。

ご存じのとおり、コタンジェント (またはタンジェント) 関数の値は勾配として解釈できます。上記の傾きfは、Z の動きと X または Y の動きの比率を正確に示しています。たとえば、ある値dでオブジェクトを拡大縮小し、Z 軸に沿って で移動しても、f*dサイズが変化しているようには見えません。これはまさにあなたviewportZoomがすでに行っていることかもしれません:

f / 2 = cot(45° / 2) / 2 ≈ 1.207106

これは 1.205 にかなり近いです。これが実際に当てはまる場合、2 の因数がどこから来ているのかわかりません。

あなたがする必要があるのは、一度計算するだけです(または、最終的にどちらがより便利であるかに応じて、fおそらくその逆数)、両方を使用して「ズーム」距離と投影行列を計算します。tan(fovy/2)


(ちなみに、あなたのコードにはBufferpostdrawAsPrimitives、 など、WebGL ではない多くのものが含まれています。使用しているライブラリについて言及すると、役立つ可能性があります。)

于 2012-12-11T05:34:09.177 に答える