6

私は OpenGL を使用してシーンの軸外投影を行おうとしています。Robert Kooima の軸外投影のドキュメントを読んで、実際に何をしなければならないかについてより良いアイデアが得られましたが、まだいくつかの部分があります。私はここでトリッキーだと思っています。OpenGL の軸外投影コードが次のようになることを知りました。

コード 1:

glMatrixMode(GL_PROJECTION);  
    glLoadIdentity();            
    glFrustum(fNear*(-fFov * ratio + headX),  
              fNear*(fFov * ratio + headX),  
              fNear*(-fFov + headY),  
              fNear*(fFov + headY),  
              fNear, fFar);  
          
    glMatrixMode(GL_MODELVIEW);  
    glLoadIdentity();  
    gluLookAt(headX*headZ, headY*headZ, 0, headX*headZ, headY*headZ, -1, 0, 1, 0);
    glTranslatef(0.0,0.0,headZ);

これが、ユーザーが画面の中央にいる通常の透視投影であった場合、私が理解しているように、かなり簡単に理解できます。

               Screen  
                   |
                   |  h = H/2
                   |  
x----- n -----------
                   |
                   |  h = H/2
                   |

ユーザーが x にいて、画面からの距離が n の場合、 glFrustumの上下の座標は次のように計算されます (theta は視野 (fov)であり、 30 度と仮定します)

h = n * tan (theta/2);
tanValue = DEG_TO_RAD * theta/2;
[EDIT Line additon here>>]: fFov = tan(tanValue);
h = n * tan (tanValue);

したがって、トップとボトム (トップの値を否定) は両方ともglFrustum引数に対して取得されます。左のものは今のところ左右です。

Now, Aspect Ratio, r = ofGetWidth()/ofGetHeight();
Right = n * (fFov * r); , where r is the aspect ratio [Edit1>> Was written tanValue*r earlier here]

質問1) 上記の (tanValue*r) は水平視野角を取得し、それを適用して左右の値を取得していますか?

   double msX = (double)ofGetMouseX();
   double msY = (double)ofGetMouseY();
   double scrWidth = (double)ofGetWidth();
   double scrHeight = (double)ofGetHeight();

   headX = (msX / scrWidth) - 0.5;
   headY = ((scrHeight - msY) / scrHeight) - 0.5;
   headZ = -2.0;

ここで、軸外の投影を考えて、headXheadYの位置を計算します (実際のユーザーの頭の代わりにここではマウスを使用します)。

質問2) headX と y はどのように計算され、上記から -0.5 を差し引くのは何に使用されますか? msX と msY が変化すると、x 値が (-0.5 から 0.5) になり、y 値が (0.5 から -0.5) になることがわかりました。

質問3) 上記のコード (コード 1) で、headY は計算された tan(fov/2) 値にどのように追加されますか?

-fFov + headY
fFov + headY

この価値は私たちに何をもたらしますか?-fFov は theta/2 の計算された tan ですが、headY を直接追加するにはどうすればよいですか?

-fFov * ratio + headX
-fFov * ratio + headX

abvoe は、軸外投影の非対称 glFrustum 呼び出しの左と右を与える n (近い値) を掛けた値をどのように与えるのでしょうか?

質問4) View Point で錐台の頂点をユーザーの目の位置 (この場合はマウスの位置) に移動するには、glLookAt を実行する必要があることを理解しています。上記のコードの次の行に注意してください。

gluLookAt(headX*headZ, headY*headZ, 0, headX*headZ, headY*headZ, -1, 0, 1, 0);

ここで使用できる目の xPosition、headX*headZ目の yPosition はどのようにして得られるのでしょうか?headY*headZgluLookAt()

編集:ここに完全な問題の説明が追加されました: pastebin.com/BiSHXspb

4

1 に答える 1

6

アスキーアートの素​​敵な絵を作ってくださいました

               Screen  
                   B
                   |  h = H/2
                   |  
x----- n ----------A
                   |
                   |  h = H/2
                   B'

視野はfov = angle((x,B), (x,B'))、スクリーン「線」の 2 つの先端 B、B' と点 x との間で形成される角度として定義されます。三角関数Tangens (tan) は次のように定義されます。

h/n = tan( angle((x,A), (x,B)) )

そして、length(A, B) == length(A, B') == h == H/2私たちはそれを知っているので、

H/(2·n) == tan( fov ) == tan( angle((x,B), (x,B')) ) == tan( 2·angle((x,A), (x,B)) )

三角法では角度はラジアンで与えられますが、ほとんどの人は度からラジアンに変換する必要があるかもしれません。

つまり、スクリーン スパン (= h ) の半分だけに関心があるので、角度を半分にする必要があります。また、度数を受け入れたい場合は、それをラジアンに変換します。それがこの表現の意味です。

tanValue = DEG_TO_RAD * theta/2;

それを使用して、次のようにhを計算します

h = tan(tanValue) * n

FOV が画面の水平スパンまたは垂直スパンの場合は、フィールド スパンHがアスペクト比でどのようにスケーリングされるかによって異なります。

headX と y はどのように計算され、上記から -0.5 を差し引くのは何ですか? msX と msY が変化すると、x 値が (-0.5 から 0.5) になり、y 値が (0.5 から -0.5) になることがわかりました。

あなたが与えた計算は、スクリーン空間座標が [0, screenWidth] × [0, screenHeight] の範囲にあると仮定しています。ただし、正規化された範囲 [-1, 1]² で錐台の計算を行っているため、デバイスの絶対マウス座標を正規化された中心の相対座標に合わせたいと考えています。これにより、正規化された近平面サイズに対する軸オフセットを指定できます。オフセットが 0 の場合は次のようになります (この図では、グリッドの距離は 0.1 単位です)。

錐台中心投影

-0.5 の X オフセットを適用すると、次のようになります (オレンジ色のアウトライン)。ニア プレーンの左端が -0.5 にシフトされていることがわかります。

フラスタム シフト プロジェクション

ここで、グリッドがスクリーンであり、マウス ポインターが平面境界近くの投影錐台をドラッグすると想像してください。

この価値は私たちに何をもたらしますか?-fFov は theta/2 の計算された tan ですが、headY を直接追加するにはどうすればよいですか?

fFov は角度ではなく、ASCII アート画像のスパンH/2 = hであるためです。また、headXheadYは、正規化された近投影面での相対的なシフトです。

headX headZ はどのようにして目の xPosition を与え、headY headZ は目の yPosition を与えるのでしょうか? ここで gluLookAt() で使用できますか?

あなたが引用しているコードは、その効果を強調するためのその場限りの解決策のようです。実際のヘッド トラッキング ステレオスコピック システムでは、わずかに異なる操作を行います。技術的には、 headZを使用してニア プレーン距離を計算するか、そこから導出する必要があります。

とにかく、主なアイデアは、頭が投影面からある距離に配置され、中心点が投影の相対単位でシフトされるということです。したがって、頂点補正を機能させるには、投影面までの実際の頭の距離で相対的なheadX、headYをスケーリングする必要があります。

コメント/リクエストによる更新

ここまでは、視野 (fov) をスクリーン スパンに変換する際に 1 つの次元だけを見てきました。画像が歪まないようにするには、ニア クリッピング プレーンの [左、右] / [下、上] 範囲の縦横比が、ビューポートの幅/高さの縦横比と一致する必要があります。

FoV 角度を垂直 FoV として定義することを選択した場合、ニア クリッピング プレーン範囲の水平サイズは、with/height アスペクト比でスケーリングされた垂直ニア クリッピング プレーン範囲のサイズになります。

これは、軸外投影について特別なことではありませんが、すべての透視投影ヘルパー関数で見られます。参照用に gluPerspective のソース コードを比較します。

void GLAPIENTRY
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
   GLdouble xmin, xmax, ymin, ymax;

   ymax = zNear * tan(fovy * M_PI / 360.0); // M_PI / 360.0 == DEG_TO_RAD
   ymin = -ymax;

   xmin = ymin * aspect;
   xmax = ymax * aspect;

   glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
}

そして、ニア クリッピング プレーンの範囲を [-aspect、aspect]×[-1, 1] と考えると、もちろんheadXの位置は正規化された範囲 [-1, 1] ではなく、範囲 [ -側面、側面]も同様です。

リンクした論文を見ると、トラッカーによって報告された各画面の頭の位置が、画面に対する絶対座標に変換されていることがわかります。


2 週間前、私は「Z スペース」と呼ばれるディスプレイ システムをテストする機会がありました。このシステムでは、偏光ステレオ ディスプレイがヘッド トラッカーと組み合わされ、軸外のフラスタムとルックアットの組み合わせが作成され、ディスプレイの前の物理的な頭の位置に一致しました。画面。また、目の前の 3D シーンを操作するための「ペン」も提供します。これは、私がここ数年で見た中で最も印象的なものの 1 つであり、現在、上司に購入を懇願しています :)

于 2013-05-08T19:16:15.783 に答える