ウィンドウにレンダリングされた単純な赤い四角形があり、それを任意の方向に回転させるためにアークボールを作成しました。NeHe の Arcball Rotation tutorial のコードに従っていました 。
問題は、長方形がレンダリングされてマウスの左ボタンがクリックされると、ウィンドウ内でコマのように回転することです。マウスのクリック、ドラッグ、ストップの更新は、マウスが移動するたびに発生します。これが、マウスがそのように回転する理由です。クリック、ドラッグ、ストップの間だけ回転を制限する方法がわかりません。回転を制限するにはどうすればよいですか? 私はこれを約4〜5日間デバッグしようとしていますが、うまくいきません。
元の Arcball.h ファイルと Arcball.cpp ファイルをプロジェクトに追加し、ヘッダー ファイルに 1 つの変更を加えました。この行で 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;
}
}
編集:ルーチンのcase WM_MOUSEMOVE:
ハンドラー内にチェックを挿入することで、シーンの回転を制御できない問題を修正しました。WndProc()
チェックは:if(isClicked == true) { //code }
で、これでうまくいったようです。こまのように回転しなくなりました。ただし、回転を細かく制御することはまだできません。クリックしてドラッグして離す間、コマのように回転します。