2010-11-09 3 views
3

J'utilise SDL avec OpenGL et jusqu'à maintenant, je l'ai fait tout en 2D (avec glOrtho())En utilisant gluUnProject() pour dessiner un quad à la position du curseur

Maintenant, je veux essayer de dessiner les choses en 3D mais bien sûr, puisque j'ai maintenant jeté une troisième dimension dans le mélange, les choses deviennent plus compliquées. Ce que je veux faire est de prendre les coordonnées du curseur à l'écran, de les traduire en (?) Coordonnées du monde (coordonnées que je peux utiliser dans OpenGL puisque j'ai maintenant la perspective etc.), et dessiner un quad à cette position (le curseur de la souris étant au centre du quad)

J'ai lu quelques tutoriels sur gluUnProject() et je comprends en quelque sorte ce que je suis censé faire, mais puisque j'apprends par moi-même, il est très facile d'être confus et de ne pas bien comprendre ce que je fais. En tant que tel, j'ai principalement copié à partir d'exemples que j'ai trouvés.

Ci-dessous mon code (j'ai pris le contrôle d'erreur, etc. pour tenter de le couper un peu) Comme vous pouvez le voir

, j'ai des variables mouseX, mouseY et mouseZ, dont mouseX et mouseY obtiennent leur valeurs de SDL.

J'ai essayé d'utiliser glReadPixel() pour obtenir mouseZ mais je ne suis pas sûr de le faire correctement. Le problème est que quand je clique, le quad n'est pas dessiné dans la position correcte (je suppose en partie du fait que je ne sais pas comment obtenir mouseZ correctement, donc je l'ai juste remplacé dans gluUnProject() avec 1.0?)

J'utilise les nouvelles coordonnées (wx, wy, wz) dans la fonction glTranslatef() mais encore une fois parce que je ne sais pas comment obtenir mouseZ correctement, je suppose que c'est la raison ça ne fonctionne pas correctement. Si je remplace wz avec -499 cela semble fonctionner, mais je dois savoir comment obtenir des résultats précis sans trouver manuellement les numéros corrects (ou presque)

Si quelqu'un peut me dire ce que je fais mal, ou donnez-moi des conseils ce serait grandement apprécié.

#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; 
} 

Répondre

1

Je trouve que si j'ajouté ce qui suit:

GLfloat depth[2]; 

alors changé les glReadPixels() de:

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

à:

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

je viens de changer gluUnProject () de:

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); 

alors je pourrais obtenir la valeur Z que je voulais.

Ensuite, je viens d'ajouter une petite valeur à wz, par exemple: wz += 1; pour m'assurer que le quad est apparu au-dessus de l'endroit où j'ai cliqué et il semble fonctionner comme je l'ai prévu maintenant.

0

Pour deviner Z vous devez avoir un sens pour cette z:

Habituellement, le sens est que vous voulez couper la ligne correspondant à (origine de la caméra, pixel) avec un objet 3D est affiché. Vous pouvez utiliser le tampon Z pour cela.

Sinon (vous voulez coller un polygone au curseur sans relation 3D), utilisez simplement les fonctions 2D, vous pouvez simplement alterner entre les projections 3D et 2D tout en dessinant dans le même cadre (soit avec la matrice de projection ou avec des fonctions spécifiques 2D), vous n'avez donc pas besoin d'un z.

La définition d'une valeur par défaut pour Z est une mauvaise idée si elle n'a pas de logique dans votre conception.

Il n'y a qu'une seule valeur de Z qui vous donnera les coordonnées de pixels correctes. Le lien entre les coordonnées 2D et 3D dans OpenGL est qu'OpenGl utilise un plan de projection à Z = 1. Et puis échelles les coordonnées de pixels de [-1,1] aux coordonnées de pixels.

+0

Donc, juste pour vérifier ma compréhension, si je voulais trouver la valeur Z correcte, j'aurais d'abord besoin d'une surface sur laquelle je veux placer le quad? –

+0

pour la première option oui si vous voulez que ce quad vive dans l'espace 3D. Si vous n'avez aucun objet tel qu'il semble, vous pouvez utiliser un plan de projection orthogonal à la direction de la caméra. C'est ce que vous faites en utilisant un Z fixe comme vous l'avez dit. Mais vous devez trouver le bon Z pour faire correspondre les coordonnées des pixels. Cela dépend de votre matrice de projection. Donc, je pense qu'il est plus facile de simplement passer la matrice de projection en 2D pour dessiner votre quad. –

Questions connexes