Использование gluUnProject () для рисования четырехугольника в позиции курсора - PullRequest
3 голосов
/ 09 ноября 2010

Я использую SDL с OpenGL, и до сих пор я все делал в 2d (Использование glOrtho ())

Теперь я хочу попробовать нарисовать вещи в 3D, но, конечно, так как я бросил 3-йизмерение в смеси, вещи становятся все более сложными.

Что я хочу сделать, это взять координаты курсора на экране, перевести их в (?) мировые координаты (координаты, которые я могуиспользовать в OpenGL, так как у меня теперь есть перспектива и т. д.), и нарисовать четырехугольник в этой позиции (курсор мыши находится в центре четырехугольника)

Я прочитал несколько руководств по gluUnProject () и сортируюЯ понимаю, что я должен делать, но так как я учусь сам, очень легко запутаться и неправильно понять, что я делаю.

Таким образом, я в основном скопировал примеры, которые нашел.

Ниже приведен мой код (я попытался проверить ошибки и т. Д., Чтобы немного его урезать)

Как видите, у меня есть переменные mouseX, mouseY и mouseZ, из которыхсмертноеeX и mouseY получают свои значения из SDL.

Я пытался использовать glReadPixel () для получения mouseZ, но я не уверен, правильно ли я это делаю.

Проблема в том, что когда я нажимаюквад не прорисован в правильном положении (наверное, отчасти из-за того, что я не знаю, как правильно получить mouseZ, поэтому я просто заменил его в gluUnProject () на 1.0?)

IЯ использую новые координаты (wx, wy, wz) в функции glTranslatef (), но еще раз, потому что я не знаю, как правильно получить 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;
}

Ответы [ 2 ]

1 голос
/ 10 ноября 2010

Я обнаружил, что если я добавлю следующее:

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;, чтобы убедиться, что квад появился над местом, где я щелкнул, и, кажется, он работает так, как я планировал.

0 голосов
/ 09 ноября 2010

Чтобы угадать Z, вам нужно иметь значение для этого z:

Обычно это означает, что вы хотите пересечь линию, соответствующую (исходная точка камеры, пиксель), отображаемому трехмерному объекту. Для этого вы можете использовать Z-буфер.

Если нет (вы хотите прикрепить многоугольник к курсору без 3D-отношения), просто используйте 2D-функции, вы можете просто чередовать 3D и 2D-проекции при рисовании в одном кадре (либо с помощью матрицы проекции, либо 2D-функции), поэтому вам не нужно z.

Установка значения по умолчанию для Z - плохая идея, если она не имеет смысла в вашем дизайне.

Существует только одно значение Z, которое даст вам правильные координаты пикселей.

Связь между 2D и 3D координатами в openGL заключается в том, что OpenGl использует плоскость проекции при Z = 1. А затем масштабирует координаты пикселей от [-1,1] до координат пикселей.

...