我在窗口中渲染了一个简单的红色矩形,我创建了一个弧形球,以便在任何方向上旋转它。我遵循了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();
尽管如此,根据你提供的代码,我认为你的图像根本不应该旋转,因为你在之后应用旋转。我认为可能需要更多的代码来找到您的问题。