2013-06-06 4 views
0

OpenGL과 함께 큐브를 렌더링하는 장면이 있습니다 (프로그램 구조는 GLUT를 사용하지 않고 win32 프로그램 구조이지만 단지 큐브를 glutSolidCube으로 그립니다) now 나는 이들 큐브를 마우스로 선택하여 선택하려고합니다. (I 큐브에서 만든 해골, 아무것도 더있다 templateSkeletons) 사용자가 내가 마우스 위치를 얻을 현장에 마우스 버튼을 클릭 첫째 때 을하고 장면 좌표의 좌표를 찾기 위해 노력 : 이것은 내가 뭐하는 거지입니다마우스가`gluUnProject`를 사용하여 OpenGL에서 마우스를 가져옴

if (mouse.buttonPressed(Mouse::BUTTON_LEFT)) 
     { 
      mouse.update(); 
      templateSkeletons[0].selectionMode = true; 
      Vector3* points; 
      points = GetOGLPos(); 
      templateSkeletons[0].setIntersectionPoints(points[0],points[1]); 
     }else 
      templateSkeletons[0].selectionMode = false; 

이 난 그냥 glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);를 호출하여 (장면에서 나는이 기능 여기에 투영 행렬을 가져 오는하고 내 자신의 camrea 자체 투영 행렬을 가지고 있지만 통지를 좌표를 검색하고있는 GerOGLPos 기능입니다 것은이 잘못하고 난 내 자신의 camrea의 투영 행렬을 얻어야한다) :

Vector3* GetOGLPos() 
    {Vector3 pointsOnLine[2]; 
double mvmatrix[16]; 
double projmatrix[16]; 
int viewport[4]; 
double dX, dY, dZ, dClickY,zz; 
glGetIntegerv(GL_VIEWPORT, viewport); 
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); 
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); 
dClickY = double (viewport[3] - mouse.yPos()); 
// OpenGL renders with (0,0) on bottom, mouse reports with (0,0) on top 
//glReadPixels(mouse.xPos(), int(dClickY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &zz); 
gluUnProject ((double) mouse.xPos(), dClickY, 0.0, mvmatrix, projmatrix, viewport, &dX, &dY, &dZ); 
pointsOnLine[0] = Vector3((float) dX, (float) dY, (float) dZ); 
gluUnProject ((double) mouse.xPos(), dClickY, 1.0, mvmatrix, projmatrix, viewport, &dX, &dY, &dZ); 
pointsOnLine[1] = Vector3((float) dX, (float) dY, (float) dZ); 

    return pointsOnLine; 
     } 

이제 장면에서 피킹 레이를 나타내는 두 점이 있다고 가정합니다. 나는 레이와 큐브에 의해 생성 된 라인의 거리를 계산하려고하고,이 값보다 작은 경우 내가 큐브의 색상은 내가 고른 것을 알고 변경 큐브를 렌더링 할 때 지금 (jointsOfSkeleton 각 큐브를 나타냅니다 내가) 배열에 바로 큐브 숫자 6을 테스트하고 여기에 더 많은 골격 아무것도 생성되지 않습니다 : 내가 큐브 변화의 색상을 볼 수있는 창에 무관 한 위치를 클릭하면

if(selectionMode) 
     { 

      distToLine = Vector3::PointToLineDistance3D(rayPoints[0],rayPoints[1],Vector3::Vector3(jointsOfSkeleton[6].x, 
       jointsOfSkeleton[6].y,jointsOfSkeleton[6].z)); 
      //distToLine = sqrt(distToLine); 
      if(distToLine < 0.5) 
       glColor3f(1.0,0.0,0.0); 

      else 
       glColor3f(1.0,1.0,1.0); 
     } 

, 그것은 작동하지 않습니다 맞아, 나는 디버거에서 거리를보고 거리가 옳지 않은 것 같다. 이것은 내가 선 포인트 거리의 검색에 사용 기능입니다 :

static float PointToLineDistance3D(Vector3 a, Vector3 b, Vector3 point) 
{ 

    Vector3 lineDirection = b - a; 
    float t = (Vector3::dot(point,lineDirection) - Vector3::dot(lineDirection,a))/(Vector3::dot(lineDirection,lineDirection)); 
    Vector3 direction; 
    direction.x = a.x + (lineDirection.x *t) - point.x; 
    direction.y = a.y + (lineDirection.y *t) - point.y; 
    direction.z = a.z + (lineDirection.z *t) - point.z; 

    float ShortestDistance = sqrtf((direction.x*direction.x)+(direction.y*direction.y)+(direction.z*direction.z)); 

    return ShortestDistance; 

} 

답변

2

이 내가 작성합니다 어떻게는 PointToLineDistance3D : 나는 가정을 만들어

static float PointToLineDistance3D(const Vector3 &a, const Vector3 &b, const Vector3 &point){ 
    Vector3 lineDirection = Vector3::normalize(b - a), pointDirection = point - a; 
    float t = Vector3::dot(pointDirection,lineDirection); 
    Vector3 projection = a + (lineDirection * t); 

    float ShortestDistance = (projection - point).length(); 
    return ShortestDistance; 
} 

그 :

  • Vector3 클래스는
  • * 오페라있어, 명백한 의미와 더불어, length 방법이있다 토르
  • 반환 ... 정규화 된 벡터 (이 또한 별도의 객체를 구성하지 않도록하는 방법을 만들 수있는)뿐만 아니라 normalize 기능이있다, 벡터의 크기를 조절합니다.

아이디어는 레이 point의 투영을 계산하고 projectionpoint과 사이의 거리를 계산하는 것이다. 알 수 있듯이 알고리즘은 구현과 약간 다르며, 특히 계산은 t입니다. 아마도 이것은 당신의 문제가있는 곳입니다. 케이스를 I 위에서 제공된 코드를 테스트하기 위해

는, I는 XY 평면 상에 큐브의 3 × 3 벽을 구축을 사용하는 작은 프로그램, 벽의 중심 <0,0,0>되는 썼다. 나는 카메라를 움직일 때조차도 문제없이 작동시킬 수 있었다. 유일한 문제는 자연스러운 OpenGL Y 축의 대칭 인 위에서 아래로 이동하는 마우스 좌표계 (즉, Y 마우스 좌표가 아래쪽으로 증가 _)와 관련되어있었습니다. 그것은 컴파일하고 실행하기 위해 SDL 라이브러리가 필요합니다.

#include <iostream> 

#include <GL/gl.h> 
#include <GL/glu.h> 
#include <SDL/SDL.h> 
#include <unistd.h> 

#include <Vector3.h> 

#define WIDTH 800 
#define HEIGHT 600 

GLuint box; 
int highlight[2]; // position of the cube in the wall 
const float cube_width = 5.0; 

Vector3 position(0,0,-25); // camera position 

// build the cube display list 
void setup_cube(){ 

    const float w = cube_width; 

    float w0 = -w, h0 = -w, w1 = w, h1 = w; 

    box = glGenLists(1); 
    glNewList(box, GL_COMPILE); 
    glBegin(GL_QUAD_STRIP); 
     glVertex3f(w0, h1, w0); 
     glVertex3f(w0, h0, w0); 
     glVertex3f(w1, h1, w0); 
     glVertex3f(w1, h0, w0); 
     glVertex3f(w1, h1, w1); 
     glVertex3f(w1, h0, w1); 
     glVertex3f(w0, h1, w1); 
     glVertex3f(w0, h0, w1); 
    glEnd(); 
    glBegin(GL_QUAD_STRIP); 
     glVertex3f(w1, h1, w0); 
     glVertex3f(w1, h1, w1); 
     glVertex3f(w0, h1, w0); 
     glVertex3f(w0, h1, w1); 
     glVertex3f(w0, h0, w0); 
     glVertex3f(w0, h0, w1); 
     glVertex3f(w1, h0, w0); 
     glVertex3f(w1, h0, w1); 
    glEnd(); 
    glEndList(); 
} 

void setup_scene(){ 

    float r = WIDTH/HEIGHT; 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glFrustum(-r, r, -1, 1, 1, 1024); 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 

    glTranslatef(position[0],position[1],position[2]); 

    glEnable(GL_CULL_FACE); 
    glEnable(GL_DEPTH_TEST); 
} 

void draw_scene(){ 

    const float w = cube_width; 
    int i = 0, j = 0; 

    for (int i = -1; i < 2; i++) { 
    for (int j = -1; j < 2; j++) { 
     float x = w * 2 * i, y = w * 2 * j; 

     if (highlight[0] == i && highlight[1] == j) 
     glColor3f(0.0, 1.0, 0.0); 
     else 
     glColor3f(1.0, 0.0, 0.0); 

     glPushMatrix(); 
     glTranslatef(x,y,0); 
     glCallList(box); 
     glPopMatrix(); 
    } 
    } 
} 

void aim(float xm, float ym_){ 

    const float w = cube_width; 
    float ym = HEIGHT - ym_; 

    GLdouble model[16]; 
    GLdouble proj[16]; 
    GLint view[16]; 

    glGetDoublev(GL_MODELVIEW_MATRIX, model); 
    glGetDoublev(GL_PROJECTION_MATRIX, proj); 
    glGetIntegerv(GL_VIEWPORT, view); 
    highlight[0] = -5; 
    highlight[1] = -5; 

    for (int i = -1; i < 2; i++) { 
    for (int j = -1; j < 2; j++) { 
     float x = w * 2 * i, y = w * 2 * j; 
     double ox, oy, oz; 
     Vector3 centre(x,y,0); 
     gluUnProject(xm, ym, 0, model, proj, view, &ox, &oy, &oz); 
     Vector3 p0(ox,oy,oz); 
     gluUnProject(xm, ym, 1, model, proj, view, &ox, &oy, &oz); 
     Vector3 p1(ox,oy,oz); 
     float d = PointToLineDistance(p0,p1,centre); 
     if (d < w) { 
     highlight[0] = i; 
     highlight[1] = j; 
     return; 
     } 
    } 
    } 
} 

int main(){ 

    SDL_Surface *screen; 

    SDL_Init(SDL_INIT_VIDEO); 

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 

    if ((screen=SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_OPENGL)) == NULL) { 
    SDL_Quit(); 
    return -1; 
    } 

    setup_cube(); 

    while (1) { 
    SDL_Event event; 
    setup_scene(); 

    while(SDL_PollEvent(&event)){ 
     switch(event.type){ 
     case SDL_MOUSEMOTION: 
     aim(event.motion.x, event.motion.y); 
     break; 
     case SDL_KEYDOWN: 
     { 
      switch (event.key.keysym.sym){ 
      case SDLK_ESCAPE: 
      SDL_Quit(); 
      exit(1); 
      case SDLK_LEFT: 
      position.add(Vector3(1,0,0)); 
      break; 
      case SDLK_RIGHT: 
      position.sub(Vector3(1,0,0)); 
      break; 
      case SDLK_UP: 
      position.add(Vector3(0,0,1)); 
      break; 
      case SDLK_DOWN: 
      position.sub(Vector3(0,0,1)); 
      break; 
      case SDLK_PAGEDOWN: 
      position.add(Vector3(0,1,0)); 
      break; 
      case SDLK_PAGEUP: 
      position.sub(Vector3(0,1,0)); 
      break; 
      } 
     } 
     default: 
     break; 
     } 
    } 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    draw_scene(); 
    SDL_GL_SwapBuffers(); 
    usleep(10); 
    } 

    return 0; 
} 

올바르게 위에 마우스 포인터가 목표로 큐브를 나열 소스입니다. 화살표와 페이지 위/아래 키를 사용하여 이동할 수 있습니다.

+0

시험해 보겠습니다. 바로 돌아올 것입니다. – user667222

+1

내'Vector3' 클래스에 가정이 있습니다. 그러나이 코드 수정으로 문제가 해결되지 않았습니다. 내가 말했듯이 기본 투영 행렬을 사용하고 있습니다. 내가 문제의 원인이라고 생각하지 않니? 'GLGetDoublev (GL_PROJECTION_MATRIX, projmatrix); 대신' – user667222

+1

'대신 사용할 수 있습니다. 좋은 통찰력 : 독자적인 매트릭스를 사용하는 코드는 보이지 않지만'glLoadMatrix'를 사용하여 OpenGL 변환 파이프 라인에 설치할 수 있습니다. 이 경우,'glGetDouble'을 사용하는 대신에 동일한 행렬을'gluUnproject'에 제공하기 만하면됩니다 : 렌더링과 사용자 사이의 작업에 따라 같은 행렬이 될 수도 있고 그렇지 않을 수도 있습니다 상호 작용 코드. 나는 그것을 검증하기 위해 함수를 다시 구현했다. 그리고 어쩌면 코드가 어떻게 든 최적화 되었기 때문에 나는 내 것과 비슷한 점을 볼 수 없었다. – didierc

관련 문제