OpenGL-限制Arcball旋转



我在窗口中渲染了一个简单的红色矩形,我创建了一个弧形球,以便在任何方向上旋转它。我遵循了NeHe的Arcball Rotation教程中的代码。

问题是,一旦渲染矩形并单击鼠标左键,它就会像窗口中的顶部一样旋转。每次移动鼠标时都会发生鼠标点击-拖动-停止更新,这就是它以这种方式旋转的原因。我想不出一种方法来限制旋转只在点击-拖动停止的持续时间。如何限制旋转?我已经试着调试了大约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;
    }

}

编辑:我通过在WndProc()例程的case WM_MOUSEMOVE:处理程序中插入一个检查,解决了无法控制的场景旋转问题。支票是:if(isClicked == true) { //code },这似乎奏效了。它不再像陀螺一样旋转。然而,我仍然不能很好地控制旋转;在点击-拖动释放持续时间内,它仍然像陀螺一样旋转。

假设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();

尽管如此,根据你提供的代码,我认为你的图像根本不应该旋转,因为你在之后应用旋转。我认为可能需要更多的代码来找到您的问题。

相关内容

  • 没有找到相关文章

最新更新