一个鼠标实现跟踪球的简单类

来源:互联网 发布:ubuntu您不是所有者 编辑:程序博客网 时间:2024/06/06 08:38

三维空间中,每个物体有一个包围球 ,跟踪球思想有点类似拨动地球仪,就是拨动物体的包围球,物体也随之旋转,这样子可以更好的,更全面的观察物体。

主要思想就是鼠标单击屏幕,并执行拖动:画出一段弧线,起点v0,终点v1。这两点都是二维的,必须投影到三维空间中,分别记为:p0,p1, 也就是两个向量:p0,p1,进行单位化以后,二者进行差乘求出向量axis,则axis就是物体旋转轴。angle成员变量是控制球体转动速度的。

代码如下:

#include <math.h>
#include 
<GL/glut.h>

class CTrackBall
{
public:
    
#define M_PI 3.1415926
    CTrackBall()
        :angle(
0.0),
        trackingMouse(
false), trackBallMove(false),reDrawContinue(false)
    
{
        
for(int i=0; i<3; i++)    axis[i]=lastPos[i]=0.0F;
    }
;
    
~CTrackBall(){};

    
void SetWinWidth(int w) { winWidth=w; }
    
void SetWinHeight(int h){ winHeight=h; }

    
void MakeRotate()
    
{
        glRotatef(angle, axis[
0], axis[1], axis[2]);
    }

    
//根据二维的坐标x,y产生一组三维的坐标,单位化后存放到v中
    void trackball_Prov(int x, int y, float v[3])
    
{
        GLfloat    d, a;

        
/*Project x,y to a hemi-sphere centered within width,height*/
        v[
0]=(2.0F*x-winWidth) / winWidth;
        v[
1]=(winHeight-2.0F*x) / winHeight;

        d
=(float)sqrt(v[0]*v[0]+v[1]*v[1]);
        v[
2]=(float)cos ( (M_PI/2.0F)* ( (d<1.0? d : 1.0F ) );
        
//make identity  单位化
        a=1.0F / (float)sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
        v[
0*=a;
        v[
1*=a;
        v[
2*=a;
    }


    
//GUI的接口函数
    void onMouseMotion(int x, int y)
    
{
        
float curPos[3], dx, dy, dz;

        trackball_Prov(x, y, curPos);
        
if(trackingMouse)
        
{
            dx
=curPos[0]-lastPos[0];
            dy
=curPos[1]-lastPos[1];
            dz
=curPos[2]-lastPos[2];

            
if(dx || dy || dz)
            
{
                angle
=90.0F*sqrt(dx*dx+dy*dy+dz*dz);

                
//vector Cross:lastPos×curPos;
                axis[0= lastPos[1]*curPos[2- lastPos[2]*curPos[1];
                axis[
1= lastPos[2]*curPos[0- lastPos[0]*curPos[2];
                axis[
2= lastPos[0]*curPos[1- lastPos[1]*curPos[0];

                
//refresh the lastPos
                lastPos[0= curPos[0];
                lastPos[
1= curPos[1];
                lastPos[
2= curPos[2];
            }

        }


        glutPostRedisplay();
    }

    //交互方式可以修改的,
    
void onMouseButton(int button, int state, int x, int y)
    
{
        
if(button==GLUT_RIGHT_BUTTON)
            exit(
0);
        
if(button==GLUT_LEFT_BUTTON)
            
switch(state)
        
{
            
case GLUT_DOWN:
                y
=winHeight-y;
                startMotion(x, y);
                
break;
            
case GLUT_UP:
                stopMotion(x, y);
                
break;
        }

    }


    
void startMotion(int x, int y)
    
{
        trackingMouse 
= true;
        reDrawContinue 
= false;
        startX 
= x;    startY = y;
        curX 
= x;    curY = y;

        trackball_Prov(x, y, lastPos);
        trackBallMove 
= true;
    }


    
void stopMotion(int x, int y)
    
{
        trackingMouse 
= false;
        
if(startX != x || startY!= y)
            reDrawContinue
=true;
        
else
        
{
            angle
=0.0
            reDrawContinue
=false;    trackBallMove = false;
        }

    }

    
    
//control switch variable:
    bool trackingMouse;
    
bool trackBallMove;
    
bool reDrawContinue;
private:
    
int winWidth, winHeight;

    
float angle;
    
float axis[3];
    
float lastPos[3];
    
//for the use of mouse
    int curX, curY;
    
int startX, startY;
}
;

类接口的使用:

void Display()
{
    glClear(GL_COLOR_BUFFER_BIT 
| GL_DEPTH_BUFFER_BIT);
    
/*view transform*/
    
if(trackBall.trackBallMove)
    
{
        
//printf("%f ", angle);
        trackBall.MakeRotate();
    }

  //  colorCube();  绘制物体函数调用;

    glutSwapBuffers();
}


void myReshape(int w, int h)
{
    glViewport(
0,0,w,h);
    
    trackBall.SetWinWidth(w);
    trackBall.SetWinHeight(h);
}


void spinCube()   //
{
    
if(trackBall.reDrawContinue)    
        glutPostRedisplay();
}

void onMouseMotion(int x, int y)
{
    trackBall.onMouseMotion(x, y);
}

void onMouseButton(int button, int state, int x, int y)
{
    trackBall.onMouseButton(button, state, x, y);
}

main里面除了一般的创建窗口,视图矩阵,和投影矩阵的设置等之外,加上交互函数调用:

 glutDisplayFunc(Display);
 glutIdleFunc(spinCube);
 glutMouseFunc( onMouseButton );
 glutMotionFunc( onMouseMotion );
就可以了。

原创粉丝点击