web-dev-qa-db-ja.com

OpenGLMath-スクリーンスペースをワールドスペース座標に投影する

一日の終わりに少し数学の時間。

ウィンドウサイズの4ポイントを投影する必要があります

<0,0> <1024,768>

ワールドスペース座標にしたがって、後で地形カリングに使用される四角形の形状を形成します-GluUnprojectなし

テストのみのために、私はマウスの座標を使用します-そしてそれらを世界の座標に投影しようとします

16
PeeS

[〜#〜]解決済み[〜#〜]

これを正確に行う方法を段階的に説明します。

  1. クライアントエリア内のマウス座標を取得します
  2. モデル行列が必要ない場合は、射影行列と表示行列を取得します。
  3. 乗算投影*表示
  4. 乗算の結果を逆にする
  5. で構成されるvector4を構築します

    x = mouseposition.xウィンドウxの範囲内

    • -1から1の間の値に変換します

    y = mouseposition.yウィンドウyの範囲内

    • -1から1の間の値に変換します
    • 必要に応じてmouseposition.yを反転することを忘れないでください

    z = the depth value(これはglReadPixelで取得できます)

    • 手動で-1から1に移動できます(zNear、zFar)

    w = 1.0

  6. 前に作成した逆行列をベクトルに乗算します

  7. 行列の乗算後、結果ベクトルをそのw成分で除算します(透視除算)

        POINT mousePos;
        GetCursorPos(&mousePos);
        ScreenToClient( this->GetWindowHWND(), &mousePos );         
    
        CMatrix4x4 matProjection = m_pCamera->getViewMatrix() *  m_pCamera->getProjectionMatrix() ;
    
        CMatrix4x4 matInverse =  matProjection.inverse();
    
    
        float in[4];
        float winZ = 1.0;
    
    
        in[0]=(2.0f*((float)(mousePos.x-0)/(this->GetResolution().x-0)))-1.0f,
        in[1]=1.0f-(2.0f*((float)(mousePos.y-0)/(this->GetResolution().y-0)));
        in[2]=2.0* winZ -1.0;
        in[3]=1.0;          
    
        CVector4 vIn = CVector4(in[0],in[1],in[2],in[3]);
        pos = vIn * matInverse;
    
        pos.w = 1.0 / pos.w;
    
        pos.x *= pos.w;
        pos.y *= pos.w;
        pos.z *= pos.w;
    
        sprintf(strTitle,"%f %f %f / %f,%f,%f ",m_pCamera->m_vPosition.x,m_pCamera->m_vPosition.y,m_pCamera->m_vPosition.z,pos.x,pos.y,pos.z);
    
        SetWindowText(this->GetWindowHWND(),strTitle);
    
32
PeeS

すべての行列を乗算します。次に、結果を反転します。投影後のポイントは常に-1,1になります。したがって、4つのコーナースクリーンポイントは-1、-1です。 -1,1; 1、-1; 1,1。ただし、z値を選択する必要があります。 OpenGLを使用している場合、zは-1から1の間です。directxの場合、範囲は0から1です。最後にポイントを取得し、マトリックスで変換します。

7
crazyjul

Gluライブラリにアクセスできる場合は、 gluUnProject (winX、winY、winZ、model、projection、viewport、&objX、&objY、&objZ);を使用します。

winXwinYは、画面の隅にピクセル単位で表示されます。 winZは[0,1]の数値で、zNearzFar(クリッピング平面)の間のどこに点を置くかを指定します。 objX-Z結果を保持します。真ん中の変数は関連する行列です。必要に応じてクエリを実行できます。

3
JCooper

ここで提供される回答にいくつかの調整を加える必要がありました。しかし、これが私が最終的に得たコードです(GLMを使用していることに注意してください。乗算順序に影響を与える可能性があります)。 nearResultは近平面上の投影点であり、farResultは遠平面上の投影点です。レイキャストを実行して、マウスが何にカーソルを合わせているかを確認したいので、それらを方向ベクトルに変換します。方向ベクトルは、カメラの位置から発生します。

vec3 getRayFromScreenSpace(const vec2 & pos)
{
    mat4 invMat= inverse(m_glData.getPerspective()*m_glData.getView());
    vec4 near = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, -1, 1.0);
    vec4 far = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, 1, 1.0);
    vec4 nearResult = invMat*near;
    vec4 farResult = invMat*far;
    nearResult /= nearResult.w;
    farResult /= farResult.w;
    vec3 dir = vec3(farResult - nearResult );
    return normalize(dir);
}
1
JHall