3

私はOpenGLでSDLを使用しており、これまで2Dですべてを実行してきました(glOrtho()を使用)

今は3Dで描いてみたいのですが、もちろん3次元を混ぜ合わせたので、どんどん複雑になっていきます。

私がやりたいのは、カーソルの画面座標を取得し、それらを(?)世界座標(遠近法などがあるのでOpenGLで使用できる座標)に変換し、でクワッドを描画することです。その位置(マウスカーソルはクワッドの中心にあります)

gluUnProject()に関するチュートリアルをいくつか読んだことがあり、自分が何をすべきかをある程度理解していますが、自分で学習しているため、混乱しやすく、自分が何をしているかを正しく理解できません。

そのため、私は主に私が見つけた例からコピーしました。

以下は私のコードです(少し削減するためにエラーチェックなどを削除しました)

ご覧のとおり、mouseX、mouseY、mouseZ変数があり、そのうちのmouseXとmouseYはSDLから値を取得します。

glReadPixel()を使用してmouseZを取得しようとしましたが、正しく実行されているかどうかわかりません。

問題は、クリックしたときにクワッドが正しい位置に描画されないことです(mouseZを正しく取得する方法がわからないためか、gluUnProject()で1.0に置き換えただけですか?)

glTranslatef()関数で新しい座標(wx、wy、wz)を使用していますが、mouseZを正しく取得する方法がわからないため、これが正しく機能しない理由だと思います。wzを-499に置き換えると、問題なく動作するように見えますが、正しい(またはほぼ正しい)数値を手動で見つけずに正確な結果を得る方法を知る必要があります

誰かが私が間違っていることを教えてくれたり、アドバイスをくれたら大歓迎です。

#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>

SDL_Surface* screen = 0;
SDL_Event event;
bool isRunning = true;

int mouseX, mouseY, mouseZ = 0;

GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realY; /* OpenGL y coordinate position */
GLdouble wx, wy, wz; /* returned world x, y, z coords */

int main(int argc, char **argv) {
    SDL_Init(SDL_INIT_EVERYTHING);

    screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);

    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);

    glViewport(0, 0, 800, 600);

    glClearDepth(1.f);
    glClearColor(0, 0, 0, 0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(90.f, 1.f, 1.f, 500.f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    while(isRunning) {
        while(SDL_PollEvent(&event)) {
            if(event.type == SDL_QUIT) {
                isRunning = false;
            }

            if(event.type == SDL_MOUSEBUTTONDOWN) {
                if(event.button.button == SDL_BUTTON_LEFT) {
                    SDL_GetMouseState(&mouseX, &mouseY);

                    glGetIntegerv(GL_VIEWPORT, viewport);
                    glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
                    glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
                    realY = viewport[3] - (GLint) mouseY - 1;
                    glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);

                    gluUnProject((GLdouble)mouseX, (GLdouble)realY, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
                }
            }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glPushMatrix();

        glTranslatef(wx, wy, wz);

        glBegin(GL_QUADS);
            glColor4f(1.f, 0.f, 0.f, 1.f);
            glVertex3f(-20.f, -20.f, 0.f);

            glColor4f(0.f, 1.f, 0.f, 1.f);
            glVertex3f(-20.f, 20.f, 0.f);

            glColor4f(0.f, 0.f, 1.f, 1.f);
            glVertex3f(20.f, 20.f, 0.f);

            glColor4f(1.f, 0.f, 1.f, 1.f);
            glVertex3f(20.f, -20.f, 0.f);
        glEnd();

        glPopMatrix();

        SDL_GL_SwapBuffers();
    }

    SDL_FreeSurface(screen);

    return 0;
}
4

2 に答える 2

1

以下を追加すると、次のことがわかりました。

GLfloat depth[2];

次に、glReadPixels() を次のように変更しました。

glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);

に:

glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth);

次に、gluUnProject() を次のように変更しました。

gluUnProject((GLdouble)mouseX, (GLdouble)realY, mouseZ, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

に:

gluUnProject((GLdouble) mouseX, (GLdouble) realY, depth[0], mvmatrix, projmatrix, viewport, &wx, &wy, &wz);

その後、必要な Z 値を取得できました。

次に、wz に小さな値を追加しました。たとえばwz += 1;、クワッドがクリックした場所の上に表示され、意図したとおりに動作するようにします。

于 2010-11-10T09:44:38.280 に答える
0

Z を推測するには、この z に意味が必要です。

通常は (camera origin,pixel) に対応する線を で表示された 3d オブジェクトと交差させたいという意味です。これには Z バッファを使用できます。

そうでない場合 (ポリゴンを 3D 関係なしでカーソルに貼り付けたい場合)、2D 関数を使用するだけで、同じフレームで描画中に 3D と 2D の投影を切り替えることができます (投影マトリックスまたは 2D 固有の関数を使用) )、したがって、z は必要ありません。

設計に根拠がない場合、Z のデフォルト値を設定することはお勧めできません。

正しいピクセル座標を与える Z の値は 1 つだけです。

OpenGL の 2D 座標と 3D 座標の間のリンクは、OpenGl が Z = 1 で投影面を使用することです。次に、ピクセル座標を [-1,1] からピクセル座標にスケーリングします。

于 2010-11-09T14:45:04.267 に答える