最近在用OpenGL做三维程序,其中用到了用鼠标使物体旋转的功能,于是欣然将其总结一下,做成另一个完整的程序,下面将给出整个程序的源代码。
一,所需支持
程序使用了GLUT库,需要下载库文件,执行时需要相应的动态链接库。在Windows平台下的下载地址:http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip。如果找不到就在http://www.opengl.org/主页找一下吧。
Windows环境下安装GLUT的步骤:
1、将下载的压缩包解开,将得到5个文件
2、假设C盘是系统盘,Microsoft Visual Studio安装在c:\Program Files\
(1)glut.h 放在“c:\Program Files\Microsoft Visual Studio\VC98\include\GL”;
(2)glut.lib和glut32.lib放在“c:\Program Files\Microsoft Visual Studio\VC98\lib”;
(3)glut.dll和glut32.dll放到“C:\Windows\System32”
二,原理
x = r * sin(φ) * cos(α)
z = r * sin(φ) * sin(α)
y = r * cos(φ)
鼠标的水平移动导致α改变,鼠标的垂直移动导致φ改变
三,源程序
(将此代码保存为file.c,然后编译链接即可执行了)
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glut.h> /*OpenGL Utility Toolkit*//*该文件已包含了GL.h 和Glu.h*/
#define DEG_TO_RAD 0.017453
#define TRUE 1
#define FALSE 0
struct POINT /*用于记录鼠标位置*/
{
int x;
int y;
};
struct CAMERA /*用于摄像机定位*/
{
GLfloat xeye;
GLfloat yeye;
GLfloat zeye;
};
struct POLAR /*球坐标*/
{
float r; /*距离r*/
float alpha; /*水平偏角α*/
float fy; /*竖直偏角φ(单位均用角度)*/
};
struct POLAR polar={ 3.0f, 60.0f, 45.0f}; /*初始化球坐标*/
struct CAMERA camera; /*这个摄像机的位置就是球坐标的位置*/
struct POINT oldpt={ -1, -1}; /*记录鼠标的前一个位置*/
int l_button_down=FALSE; /*记录鼠标左键按下的状态*/
void Init() /*初始化场景*/
{
glClearColor( 1.0, 1.0, 1.0, 1.0); /*将背静设为白色*/
glColor3f( 0.0, 0.0, 0.5); /*物体用蓝色*/
}
void Reshape(int w, int h) /*使随窗口大小改变而改变*/
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-6.0, 6.0,-6.0, 6.0,-6.0, 6.0); /*定义剪裁区*/
}
void Keyboard(unsigned char key, int x, int y) /*当有键盘消息时会回调该函数*/
{
switch (key) {
case 27: /*按ESCAPE时退出窗口*/
exit(0);
break;
}
}
void Display() /*在这里绘制图形*/
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(camera.xeye,camera.yeye,camera.zeye, /*设定摄像机位置,*/
/*你所看到的景物将根据摄像机的位置改变而改变,*/
/*这就是鼠标调整摄像机位置的结果*/
0.0 , 0.0, 0.0,/*这三个参数是摄像机观察的点*/
0.0, 1.0, 0.0);/*这三个参数指定了视图的上方向*/
glBegin(GL_QUADS); /*画一个彩色的正方体*/
/*front*/
glColor3f( 0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
/*back*/
glColor3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
/*top*/
glColor3f( 1.0f, 0.0f, 0.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
/*bottom*/
glColor3f( 0.0f, 1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
/*right*/
glColor3f( 1.0f, 0.0f, 1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
/*left*/
glColor3f( 1.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glEnd();
glutSwapBuffers(); /*交换前后台缓冲区*/
}
/*将球坐标转化为直角坐标,并设定为摄像机的位置*/
void SetCamera(GLfloat x, GLfloat y) /*x,y 是水平方向和竖直方向的改变量*/
{
GLfloat alpha,fy; /*和它的名字一样,不过是单位是弧度*/
if((polar.fy+y)>5.0f && (polar.fy+y)<175.0f)
{ /*定义竖直偏角只能在5°到175°之间*/
polar.alpha += x; /*根据鼠标移动的方向设置新的球坐标*/
polar.fy += y;
if(polar.alpha>360.0f) polar.alpha-=360.0f;
if(polar.alpha<0.0f) polar.alpha+=360.0f; /*将水平偏角锁定在0°到360°之间*/
alpha=polar.alpha*DEG_TO_RAD;
fy=polar.fy*DEG_TO_RAD; /*角度转弧度*/
camera.xeye = polar.r * sin(fy) * cos(alpha); /*极坐标转直角坐标*/
camera.zeye = polar.r * sin(fy) * sin(alpha);
camera.yeye = polar.r * cos(fy); /*注意:竖直方向的是y轴*/
Display(); /*每次改变相机位置时重绘*/
/*当然,我画的是静态的,若景物是动态的,你必须将重绘放在空闲回调函数中*/
}
}
void Mouse(int button, int state, int x, int y) /*当鼠标按下或拿起时会回调该函数*/
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
l_button_down = TRUE; /*当l_button_down为true时才可改变相机位置*/
oldpt.x=x; /*记录旧坐标,以便移动发生时计算鼠标移动方向*/
oldpt.y=y;
}
if(button == GLUT_LEFT_BUTTON && state == GLUT_UP)
{
l_button_down = FALSE; /*拿起时不能改变摄像机位置*/
}
}
void OnMouseMove(int x, int y) /*当鼠标移动时会回调该函数*/
{
if(l_button_down) /*如果鼠标没有按下则不改变摄像机位置*/
{
SetCamera(float(x-oldpt.x),float(oldpt.y-y)); /*根据增量重新设定摄像机位置*/
oldpt.x=x; /*将当前坐标置为旧坐标*/
oldpt.y=y;
}
}
/*若景物是动态的,则使用该函数调用重绘
void Idle()
{
Display();
}
*/
int main(int argc, char** argv)
{
glutInit(&argc, argv); /*初始化GLUT*/
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); /*设置显示模式(双缓冲)*/
glutInitWindowSize(400, 400); /*设定窗口大小*/
glutInitWindowPosition(100, 100); /*左上角坐标*/
glutCreateWindow(argv[0]); /*创建窗口*/
Init();
SetCamera(0.0f,0.0f);
glutReshapeFunc(Reshape);
glutDisplayFunc(Display);
glutKeyboardFunc(Keyboard);
glutMouseFunc(Mouse);
glutMotionFunc(OnMouseMove); /*设置各种消息处理函数*/
/* glutIdleFunc(Idle);*/ /*设置空闲回调函数*/
glutMainLoop(); /*进入消息循环*/
return 0;
}
评论