2014-10-14 2 views
0

У меня есть простой красный прямоугольник, который отображается в окне, и я создал аркад, чтобы повернуть его в любом направлении. Я следил за кодом от NeHe's Arcball Rotation tutorial.OpenGL - ограничение вращения Arcball

Проблема заключается в том, что после рендеринга прямоугольника и нажатия левой кнопки мыши он вращается как верх в окне. Обновление щелчка мыши-перетаскивания происходит каждый раз, когда мышь перемещается, и именно по этой причине он вращается таким образом. Я не могу определить способ ограничить вращение только в течение продолжительности нажатия-перетаскивания. Как ограничить вращение? Я пытался отладить это примерно 4-5 дней без везения.

Я добавил исходные файлы Arcball.h и Arcball.cpp в свой проект с одним изменением на заголовочный файл; Я просто создал конструктор по умолчанию для класса Arcball_t с этой линией -

ArcBall_t() {};

Единственные другие изменения от первоначального проекта, что я бросил вызов на Update() функцию в мой код:

// ========================================================================================== 
// function declarations 

#define GET_PROC_ADDRESS(str) wglGetProcAddress(str) 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

void DrawOpenGLScene(HDC hDC); 
void Update(); 

HGLRC SetUpOpenGLContext(HWND hWnd); 

// ==========================================================================================  
// Trackball declarations 

const float PI2 = 2.0*3.1415926535f;        // PI Squared 

GLUquadricObj *quadratic; 


Point2fT MousePt;            // NEW: Current Mouse Point 
bool  isClicked = false;          // NEW: Clicking The Mouse? 
bool  isRClicked = false;          // NEW: Clicking The Right Mouse Button? 
bool  isDragging = false;          // NEW: Dragging The Mouse? 



Matrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f,    // NEW: Final Transform 
          0.0f, 1.0f, 0.0f, 0.0f, 
          0.0f, 0.0f, 1.0f, 0.0f, 
          0.0f, 0.0f, 0.0f, 1.0f }; 

Matrix3fT LastRot  = { 1.0f, 0.0f, 0.0f,     // NEW: Last Rotation 
          0.0f, 1.0f, 0.0f, 
          0.0f, 0.0f, 1.0f }; 

Matrix3fT ThisRot  = { 1.0f, 0.0f, 0.0f,     // NEW: This Rotation 
          0.0f, 1.0f, 0.0f, 
          0.0f, 0.0f, 1.0f }; 

// ========================================================================================== 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
        LPSTR lpszCmdLine, int nCmdShow) 
{ 
    static char szClassName[] = "Myclass"; 
    static char szTitle[]="A Simple Win32 API OpenGL Program"; 
    WNDCLASS wc; 
    MSG  msg; 
    HWND  hWnd; 

    wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = (WNDPROC)WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance = hInstance; 
    wc.hIcon = NULL; 
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH); 
    wc.lpszMenuName = NULL; 
    wc.lpszClassName = szClassName; 
    if (!RegisterClass (&wc)) 
     return 0; 

    hWnd = CreateWindow(szClassName, szTitle, 
         WS_OVERLAPPEDWINDOW | 
          // NEED THESE for OpenGL calls to work! 
       WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 
           0, 0, 1024, 256, 
       NULL, NULL, hInstance, NULL); 

    ArcBall_t ArcBall(1024.0f, 256.0f);        // NEW: ArcBall Instance 

    ShowWindow(hWnd, nCmdShow); 
    UpdateWindow(hWnd); 
    while (GetMessage(&msg, NULL, 0, 0)) 
     { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
     } 

    return(msg.wParam); 
} 

// ========================================================================================== 

//******************************************************* 
// This is the brain of the loop 
// Checks for a new key press or mouse movement 
// renders when something is detected 
//******************************************************* 


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, 
        WPARAM wParam, LPARAM lParam) 
{ 
    HDC hDC; 
    static HGLRC hRC; // Note this is STATIC! 
    PAINTSTRUCT ps; 

    switch (msg) 
     { 
     case WM_CREATE: 
      // Select a pixel format and create a rendering context 
      hRC = SetUpOpenGLContext(hWnd); 
      break;  

     case WM_PAINT: 
      // Draw the scene 
      // Get a DC, make RC current & associate it with this DC 
      hDC = BeginPaint(hWnd, &ps); 
      wglMakeCurrent(hDC, hRC); 

      DrawOpenGLScene(hDC); // Draw     

      // We're done with the RC, so deselect it 
      wglMakeCurrent(NULL, NULL); 
      EndPaint(hWnd, &ps); 
      break; 

     //*NEW* Mouse based messages for arcball 

     case WM_LBUTTONUP: 
      isClicked = false; 

     break; 

     case WM_RBUTTONUP: 
      isRClicked = false; 

     break; 

     case WM_LBUTTONDOWN: 
      isClicked = true; 

     break; 

     case WM_RBUTTONDOWN: 
      isRClicked = true; 

     break; 

     case WM_MOUSEMOVE: 
      MousePt.s.X = (GLfloat)LOWORD(lParam); 
      MousePt.s.Y = (GLfloat)HIWORD(lParam); 
      isClicked = (LOWORD(wParam) & MK_LBUTTON) ? true : false; 
      isRClicked = (LOWORD(wParam) & MK_RBUTTON) ? true : false; 

      Update(); 
      RedrawWindow(hWnd, NULL, NULL, RDW_INTERNALPAINT); 

     break; 


     case WM_DESTROY: 

      // Clean up and terminate 
      wglDeleteContext(hRC); 

      PostQuitMessage(0); 
      break; 

     default: 
       return DefWindowProc(hWnd, msg, wParam, lParam); 
     } 

     return (0); 
} 

// ========================================================================================== 

//******************************************************* 
// SetUpOpenGL sets the pixel format and a rendering 
// context then returns the RC 
//******************************************************* 

HGLRC SetUpOpenGLContext(HWND hWnd) 
{ 
    static PIXELFORMATDESCRIPTOR pfd = { 
     sizeof (PIXELFORMATDESCRIPTOR), // strcut size 
     1,        // Version number 
     PFD_DRAW_TO_WINDOW |  // Flags, draw to a window, 
      PFD_SUPPORT_OPENGL | // use OpenGL 
      PFD_DOUBLEBUFFER, // Use a double buffer 
     PFD_TYPE_RGBA,   // RGBA pixel values 
     32,      // 24-bit color 
     0, 0, 0,    // RGB bits & shift sizes. 
     0, 0, 0,    // Don't care about them 
     0, 0,     // No alpha buffer info 
     0, 0, 0, 0, 0,   // No accumulation buffer 
     32,      // 32-bit depth buffer 
     8,      // No stencil buffer 
     0,      // No auxiliary buffers 
     PFD_MAIN_PLANE,   // Layer type 
     0,      // Reserved (must be 0) 
     0,      // No layer mask 
     0,      // No visible mask 
     0      // No damage mask 
    }; 

    int nMyPixelFormatID; 
    HDC hDC; 
    HGLRC hRC; 

    hDC = GetDC(hWnd); 
    nMyPixelFormatID = ChoosePixelFormat(hDC, &pfd); 
    SetPixelFormat(hDC, nMyPixelFormatID, &pfd); 
    hRC = wglCreateContext(hDC); 
    ReleaseDC(hWnd, hDC); 

    quadratic=gluNewQuadric();          // Create A Pointer To The Quadric Object 
    gluQuadricNormals(quadratic, GLU_SMOOTH);      // Create Smooth Normals 
    gluQuadricTexture(quadratic, GL_TRUE);       // Create Texture Coords 

    return hRC; 
} 

// ========================================================================================== 
// simple test code - rectangle/triangle 

void DrawOpenGLScene(HDC hDC) 
{ 


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW); 

    glTranslatef(0.0f, 0.0f, 0.0f); 

    glColor3f(1.0, 0.0, 0.0); // drawing color 
    glBegin(GL_POLYGON);  // define the rectangle 
      glVertex2f(-0.5,-0.5); 
      glVertex2f(-0.5,0.5); 
      glVertex2f(0.5,0.5); 
      glVertex2f(0.5,-0.5); 
    glEnd(); 

    glMultMatrixf(Transform.M); 

    glFlush(); // force execution 
    SwapBuffers(hDC); 
} 

// ========================================================================================== 

void Update()         // Perform Motion Updates Here 
{ 

    ArcBall_t ArcBall; 

    if (isRClicked)             // If Right Mouse Clicked, Reset All Rotations 
    { 
     Matrix3fSetIdentity(&LastRot);        // Reset Rotation 
     Matrix3fSetIdentity(&ThisRot);        // Reset Rotation 
     Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot);  // Reset Rotation 
    } 

    if (!isDragging)            // Not Dragging 
    { 
     if (isClicked)            // First Click 
     { 
      isDragging = true;          // Prepare For Dragging 
      LastRot = ThisRot;          // Set Last Static Rotation To Last Dynamic One 
      ArcBall.click(&MousePt);        // Update Start Vector And Prepare For Dragging 
     } 

    } 
    else 
    { 
     if (isClicked)            // Still Clicked, So Still Dragging 
     { 
      Quat4fT  ThisQuat; 

      ArcBall.drag(&MousePt, &ThisQuat);      // Update End Vector And Get Rotation As Quaternion 
      Matrix3fSetRotationFromQuat4f(&ThisRot, &ThisQuat);  // Convert Quaternion Into Matrix3fT 
      Matrix3fMulMatrix3f(&ThisRot, &LastRot);    // Accumulate Last Rotation Into This One 
      Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Set Our Final Transform's Rotation From This One 
     } 
     else              // No Longer Dragging 
      isDragging = false; 
    } 


} 

EDIT: Я исправил проблему с неконтролируемым поворотом сцены, вставив чек в обработчик case WM_MOUSEMOVE: подпрограммы WndProc(). Счет: if(isClicked == true) { //code }, и это похоже на трюк. Он больше не вращается, как верх. Тем не менее, у меня до сих пор нет прекрасного контроля над поворотом; он по-прежнему вращается как верхняя часть продолжительности выталкивания клика.

+0

Я все еще смотрю на ваш код, но вы просто умножаете Pi на два, а не на квадрат (на случай, если вы не знаете). – TheBlindSpring

ответ

1

Предполагая, что ваши функции arcball.drag и arcball.click верны, единственная проблема с вашим кодом заключается в том, что вы применяете поворот после рисования, и вам нужно сделать это раньше. Ваш код:

glTranslatef(0.0f, 0.0f, 0.0f); 

glColor3f(1.0, 0.0, 0.0); // drawing color 
glBegin(GL_POLYGON);  // define the rectangle 
     glVertex2f(-0.5,-0.5); 
     glVertex2f(-0.5,0.5); 
     glVertex2f(0.5,0.5); 
     glVertex2f(0.5,-0.5); 
glEnd(); 

glMultMatrixf(Transform.M); 

Попробуйте изменить его:

glTranslatef(0.0f, 0.0f, 0.0f); 
glMultMatrixf(Transform.M); 
glColor3f(1.0, 0.0, 0.0); // drawing color 
glBegin(GL_POLYGON);  // define the rectangle 
     glVertex2f(-0.5,-0.5); 
     glVertex2f(-0.5,0.5); 
     glVertex2f(0.5,0.5); 
     glVertex2f(0.5,-0.5); 
glEnd(); 

Хотя, на основе кода, которую вы предоставили, я не думаю, что ваше изображение должно вращаться на все, потому что вы подаете вращение после. Я думаю, вам понадобится больше кода, чтобы найти вашу проблему.

+0

Да, я подумал об этом, и я положил вызов 'glMultMatrixf' перед' glBegin() .. glEnd() '. Однако это не проблема. Мне пришлось настроить мою функцию «WndProc()»; в частности, «случай WM_MOUSEMOVE:». Я вставил чек: 'if (isClicked == true) {// code}', и это, казалось, сработало. Сцена больше не вращается неуправляемо, и она позволяет вращаться только во время перетаскивания клика. Но у меня все еще нет прекрасного контроля над моей сценой. Он по-прежнему вращается, как верхняя часть продолжительности выталкивания кликов. Я напишу еще один вопрос с дополнительной информацией. – Eagle

+0

Я не использую 'PI2' в любом месте своего кода. Я только что скопировал это из заголовка учебника NeHe Arcball. Кроме того, единственными файлами, которые я использовал в этом учебнике, были Arcball.cpp и Arcball.h. Предполагая, что они правильно запрограммированы (как это, надеюсь, должно быть), все еще есть ошибка в моем коде, который я пытаюсь найти. – Eagle

+0

Если ничего не изменилось. LOT, я бы не рекомендовал создать новый вопрос, я бы просто отредактировал/обновил этот вопрос. Я не знаю, насколько вы знакомы с Stack Overflow, но люди придирчивы к тем вопросам, и если они видят, что вы задали почти одинаковый вопрос дважды, они часто будут решать один из вопросов. В любом случае, дайте мне знать, когда вы разместите еще какой-нибудь код, и я могу попытаться помочь. – TheBlindSpring

Смежные вопросы