测试发现,还是NEHE的鼠标旋转物体效果好啊,但NEHE是在基于Windows 的程序框架下编写的,不少代码融入到了windows编程中,感觉比较混乱,所以就想提取出来,在基于控制台的框架下实现出来,在此框架下代码结构比较简单,便于以后再使用这些代码,也就是便于代码复用。主程序代码如下
#include <stdlib.h>
#include <GL/glut.h>
#include <stdio.h>
#include "math.h"
#include "ArcBall.h"
// object
GLfloat vertices[] = {-1.0,-1.0,-1.0,1.0,-1.0,-1.0,
1.0,1.0,-1.0, -1.0,1.0,-1.0, -1.0,-1.0,1.0,
1.0,-1.0,1.0, 1.0,1.0,1.0, -1.0,1.0,1.0};
GLfloat colors[] = {0.0,0.0,0.0,1.0,0.0,0.0,
1.0,1.0,0.0, 0.0,1.0,0.0, 0.0,0.0,1.0,
1.0,0.0,1.0, 1.0,1.0,1.0, 0.0,1.0,1.0};
GLubyte cubeIndices[]={0,3,2,1,2,3,7,6,0,4,7,3,1,2,6,5,4,5,6,7,0,1,5,4};
// mouse control
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 };
ArcBallT ArcBall(640.0f, 480.0f); // NEW: ArcBall Instance
Point2fT MousePt; // NEW: Current Mouse Point
bool isClicked = false; // NEW: Clicking The Mouse?
bool isDragging = false; // NEW: Dragging The Mouse?
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix(); // NEW: Prepare Dynamic Transform
glMultMatrixf(Transform.M); // NEW: Apply Dynamic Transform
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, cubeIndices);
glPopMatrix();
glutSwapBuffers();
}
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_LEFT_BUTTON)
{
switch(state)
{
case GLUT_DOWN:
isClicked = true;
printf_s("startmotion: x = %d, y = %d\n",x,y);
break;
case GLUT_UP:
isClicked = false;
isDragging = false;
printf_s("stopmotion: x = %d, y = %d\n",x,y);
break;
}
}
if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
Matrix3fSetIdentity(&LastRot); // Reset Rotation
Matrix3fSetIdentity(&ThisRot); // Reset Rotation
Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Reset Rotation
glutPostRedisplay();
}
}
void mouseMotion(int x, int y)
{
MousePt.s.X = x;
MousePt.s.Y = y;
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
}
}
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27: // VK_ESCAPE
exit(0);
break;
}
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("colorcube");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutKeyboardFunc(keyboard);
glEnable(GL_DEPTH_TEST);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glColorPointer(3,GL_FLOAT, 0, colors);
glClearColor(0.0,0.0,0.0,1.0);
glColor3f(1.0,1.0,1.0);
glutMainLoop();
}
,另外再包含NEHE教程中的ArcBall.h和ArcBall.cpp程序。
ArcBall.cpp中包含的头文件还要做如下修改
//#include <gl\gl.h> // 注释掉
//#include <gl\glu.h> // 注释掉
#include <gl\glut.h> // 做修改
可以尝试一下,与之前的鼠标跟踪球程序对比,哪个效果好,感觉还是NEHE这个功能完善。