用opengl实现轨迹圆|经典程序

来源:互联网 发布:淘宝扣12分有什么影响 编辑:程序博客网 时间:2024/05/24 01:36

在你的图形工程中添加轨迹球的功能,可以更好的对模型进行查看。

之前写过一个.ply模型的读取程序,加入了下面轨迹球的功能。

下面是一个比较经典的轨迹球实现程序。

ArcBall.h

#pragma once///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ArcBall.h///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#ifndef _ArcBall_h#define _ArcBall_h// 仅在Debug模式下,启用断言#ifdef _DEBUG# include "assert.h"#else# define assert(x) { }#endif//2维点typedef union Tuple2f_t{    struct    {        GLfloat X, Y;    } s;    GLfloat T[2];} Tuple2fT;//3维点typedef union Tuple3f_t{    struct    {        GLfloat X, Y, Z;    } s;    GLfloat T[3];} Tuple3fT;//4维点typedef union Tuple4f_t{    struct    {        GLfloat X, Y, Z, W;    } s;    GLfloat T[4];} Tuple4fT;//3x3矩阵typedef union Matrix3f_t{    struct    {        //column major        union { GLfloat M00; GLfloat XX; GLfloat SX; };        union { GLfloat M10; GLfloat XY; };        union { GLfloat M20; GLfloat XZ; };        union { GLfloat M01; GLfloat YX; };        union { GLfloat M11; GLfloat YY; GLfloat SY; };        union { GLfloat M21; GLfloat YZ; };        union { GLfloat M02; GLfloat ZX; };        union { GLfloat M12; GLfloat ZY; };        union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };    } s;    GLfloat M[9];} Matrix3fT;//4x4矩阵typedef union Matrix4f_t{    struct    {        //column major        union { GLfloat M00; GLfloat XX; GLfloat SX; };        union { GLfloat M10; GLfloat XY; };        union { GLfloat M20; GLfloat XZ; };        union { GLfloat M30; GLfloat XW; };        union { GLfloat M01; GLfloat YX; };        union { GLfloat M11; GLfloat YY; GLfloat SY; };        union { GLfloat M21; GLfloat YZ; };        union { GLfloat M31; GLfloat YW; };        union { GLfloat M02; GLfloat ZX; };        union { GLfloat M12; GLfloat ZY; };        union { GLfloat M22; GLfloat ZZ; GLfloat SZ; };        union { GLfloat M32; GLfloat ZW; };        union { GLfloat M03; GLfloat TX; };        union { GLfloat M13; GLfloat TY; };        union { GLfloat M23; GLfloat TZ; };        union { GLfloat M33; GLfloat TW; GLfloat SW; };    } s;    GLfloat M[16];} Matrix4fT;//定义类型的别名#define Point2fT    Tuple2fT   #define Quat4fT     Tuple4fT   #define Vector2fT   Tuple2fT   #define Vector3fT   Tuple3fT   #define FuncSqrt    sqrtf# define Epsilon 1.0e-5//2维点相加inlinestatic void Point2fAdd(Point2fT* NewObj, const Tuple2fT* t1){    assert(NewObj && t1);    NewObj->s.X += t1->s.X;    NewObj->s.Y += t1->s.Y;}//2维点相减inlinestatic void Point2fSub(Point2fT* NewObj, const Tuple2fT* t1){    assert(NewObj && t1);    NewObj->s.X -= t1->s.X;    NewObj->s.Y -= t1->s.Y;}//3维点矢积inlinestatic void Vector3fCross(Vector3fT* NewObj, const Vector3fT* v1, const Vector3fT* v2){    Vector3fT Result;    assert(NewObj && v1 && v2);    Result.s.X = (v1->s.Y * v2->s.Z) - (v1->s.Z * v2->s.Y);    Result.s.Y = (v1->s.Z * v2->s.X) - (v1->s.X * v2->s.Z);    Result.s.Z = (v1->s.X * v2->s.Y) - (v1->s.Y * v2->s.X);    *NewObj = Result;}//3维点点积inlinestatic GLfloat Vector3fDot(const Vector3fT* NewObj, const Vector3fT* v1){    assert(NewObj && v1);    return  (NewObj->s.X * v1->s.X) +        (NewObj->s.Y * v1->s.Y) +        (NewObj->s.Z * v1->s.Z);}//3维点的长度的平方inlinestatic GLfloat Vector3fLengthSquared(const Vector3fT* NewObj){    assert(NewObj);    return  (NewObj->s.X * NewObj->s.X) +        (NewObj->s.Y * NewObj->s.Y) +        (NewObj->s.Z * NewObj->s.Z);}//3维点的长度inlinestatic GLfloat Vector3fLength(const Vector3fT* NewObj){    assert(NewObj);    return FuncSqrt(Vector3fLengthSquared(NewObj));}//设置3x3矩阵为0矩阵inlinestatic void Matrix3fSetZero(Matrix3fT* NewObj){    NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 =        NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 =        NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 = 0.0f;}//设置4x4矩阵为0矩阵inlinestatic void Matrix4fSetZero(Matrix4fT* NewObj){    NewObj->s.M00 = NewObj->s.M01 = NewObj->s.M02 =        NewObj->s.M10 = NewObj->s.M11 = NewObj->s.M12 =        NewObj->s.M20 = NewObj->s.M21 = NewObj->s.M22 =        NewObj->s.M30 = NewObj->s.M31 = NewObj->s.M32 = 0.0f;}//设置3x3矩阵为单位矩阵inlinestatic void Matrix3fSetIdentity(Matrix3fT* NewObj){    Matrix3fSetZero(NewObj);    NewObj->s.M00 =        NewObj->s.M11 =        NewObj->s.M22 = 1.0f;}//设置4x4矩阵为单位矩阵inlinestatic void Matrix4fSetIdentity(Matrix4fT* NewObj){    Matrix4fSetZero(NewObj);    NewObj->s.M00 = 1.0f;    NewObj->s.M11 = 1.0f;    NewObj->s.M22 = 1.0f;    NewObj->s.M33 = 1.0f;}//从四元数设置旋转矩阵inlinestatic void Matrix3fSetRotationFromQuat4f(Matrix3fT* NewObj, const Quat4fT* q1){    GLfloat n, s;    GLfloat xs, ys, zs;    GLfloat wx, wy, wz;    GLfloat xx, xy, xz;    GLfloat yy, yz, zz;    assert(NewObj && q1);    n = (q1->s.X * q1->s.X) + (q1->s.Y * q1->s.Y) + (q1->s.Z * q1->s.Z) + (q1->s.W * q1->s.W);    s = (n > 0.0f) ? (2.0f / n) : 0.0f;    xs = q1->s.X * s;  ys = q1->s.Y * s;  zs = q1->s.Z * s;    wx = q1->s.W * xs; wy = q1->s.W * ys; wz = q1->s.W * zs;    xx = q1->s.X * xs; xy = q1->s.X * ys; xz = q1->s.X * zs;    yy = q1->s.Y * ys; yz = q1->s.Y * zs; zz = q1->s.Z * zs;    NewObj->s.XX = 1.0f - (yy + zz); NewObj->s.YX = xy - wz;  NewObj->s.ZX = xz + wy;    NewObj->s.XY = xy + wz;  NewObj->s.YY = 1.0f - (xx + zz); NewObj->s.ZY = yz - wx;    NewObj->s.XZ = xz - wy;  NewObj->s.YZ = yz + wx;  NewObj->s.ZZ = 1.0f - (xx + yy);}//3x3矩阵相乘inlinestatic void Matrix3fMulMatrix3f(Matrix3fT* NewObj, const Matrix3fT* m1){    Matrix3fT Result;    assert(NewObj && m1);    Result.s.M00 = (NewObj->s.M00 * m1->s.M00) + (NewObj->s.M01 * m1->s.M10) + (NewObj->s.M02 * m1->s.M20);    Result.s.M01 = (NewObj->s.M00 * m1->s.M01) + (NewObj->s.M01 * m1->s.M11) + (NewObj->s.M02 * m1->s.M21);    Result.s.M02 = (NewObj->s.M00 * m1->s.M02) + (NewObj->s.M01 * m1->s.M12) + (NewObj->s.M02 * m1->s.M22);    Result.s.M10 = (NewObj->s.M10 * m1->s.M00) + (NewObj->s.M11 * m1->s.M10) + (NewObj->s.M12 * m1->s.M20);    Result.s.M11 = (NewObj->s.M10 * m1->s.M01) + (NewObj->s.M11 * m1->s.M11) + (NewObj->s.M12 * m1->s.M21);    Result.s.M12 = (NewObj->s.M10 * m1->s.M02) + (NewObj->s.M11 * m1->s.M12) + (NewObj->s.M12 * m1->s.M22);    Result.s.M20 = (NewObj->s.M20 * m1->s.M00) + (NewObj->s.M21 * m1->s.M10) + (NewObj->s.M22 * m1->s.M20);    Result.s.M21 = (NewObj->s.M20 * m1->s.M01) + (NewObj->s.M21 * m1->s.M11) + (NewObj->s.M22 * m1->s.M21);    Result.s.M22 = (NewObj->s.M20 * m1->s.M02) + (NewObj->s.M21 * m1->s.M12) + (NewObj->s.M22 * m1->s.M22);    *NewObj = Result;}//4x4矩阵相乘inlinestatic void Matrix4fSetRotationScaleFromMatrix4f(Matrix4fT* NewObj, const Matrix4fT* m1){    assert(NewObj && m1);    NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;    NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;    NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;}//进行矩阵的奇异值分解,旋转矩阵被保存到rot3和rot4中,返回矩阵的缩放因子inlinestatic GLfloat Matrix4fSVD(const Matrix4fT* NewObj, Matrix3fT* rot3, Matrix4fT* rot4){    GLfloat s, n;    assert(NewObj);    s = FuncSqrt(        ((NewObj->s.XX * NewObj->s.XX) + (NewObj->s.XY * NewObj->s.XY) + (NewObj->s.XZ * NewObj->s.XZ) +            (NewObj->s.YX * NewObj->s.YX) + (NewObj->s.YY * NewObj->s.YY) + (NewObj->s.YZ * NewObj->s.YZ) +            (NewObj->s.ZX * NewObj->s.ZX) + (NewObj->s.ZY * NewObj->s.ZY) + (NewObj->s.ZZ * NewObj->s.ZZ)) / 3.0f);    if (rot3)    {        rot3->s.XX = NewObj->s.XX; rot3->s.XY = NewObj->s.XY; rot3->s.XZ = NewObj->s.XZ;        rot3->s.YX = NewObj->s.YX; rot3->s.YY = NewObj->s.YY; rot3->s.YZ = NewObj->s.YZ;        rot3->s.ZX = NewObj->s.ZX; rot3->s.ZY = NewObj->s.ZY; rot3->s.ZZ = NewObj->s.ZZ;        n = 1.0f / FuncSqrt((NewObj->s.XX * NewObj->s.XX) +            (NewObj->s.XY * NewObj->s.XY) +            (NewObj->s.XZ * NewObj->s.XZ));        rot3->s.XX *= n;        rot3->s.XY *= n;        rot3->s.XZ *= n;        n = 1.0f / FuncSqrt((NewObj->s.YX * NewObj->s.YX) +            (NewObj->s.YY * NewObj->s.YY) +            (NewObj->s.YZ * NewObj->s.YZ));        rot3->s.YX *= n;        rot3->s.YY *= n;        rot3->s.YZ *= n;        n = 1.0f / FuncSqrt((NewObj->s.ZX * NewObj->s.ZX) +            (NewObj->s.ZY * NewObj->s.ZY) +            (NewObj->s.ZZ * NewObj->s.ZZ));        rot3->s.ZX *= n;        rot3->s.ZY *= n;        rot3->s.ZZ *= n;    }    if (rot4)    {        if (rot4 != NewObj)        {            Matrix4fSetRotationScaleFromMatrix4f(rot4, NewObj);        }        n = 1.0f / FuncSqrt((NewObj->s.XX * NewObj->s.XX) +            (NewObj->s.XY * NewObj->s.XY) +            (NewObj->s.XZ * NewObj->s.XZ));        rot4->s.XX *= n;        rot4->s.XY *= n;        rot4->s.XZ *= n;        n = 1.0f / FuncSqrt((NewObj->s.YX * NewObj->s.YX) +            (NewObj->s.YY * NewObj->s.YY) +            (NewObj->s.YZ * NewObj->s.YZ));        rot4->s.YX *= n;        rot4->s.YY *= n;        rot4->s.YZ *= n;        n = 1.0f / FuncSqrt((NewObj->s.ZX * NewObj->s.ZX) +            (NewObj->s.ZY * NewObj->s.ZY) +            (NewObj->s.ZZ * NewObj->s.ZZ));        rot4->s.ZX *= n;        rot4->s.ZY *= n;        rot4->s.ZZ *= n;    }    return s;}//从3x3矩阵变为4x4的旋转矩阵inlinestatic void Matrix4fSetRotationScaleFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1){    assert(NewObj && m1);    NewObj->s.XX = m1->s.XX; NewObj->s.YX = m1->s.YX; NewObj->s.ZX = m1->s.ZX;    NewObj->s.XY = m1->s.XY; NewObj->s.YY = m1->s.YY; NewObj->s.ZY = m1->s.ZY;    NewObj->s.XZ = m1->s.XZ; NewObj->s.YZ = m1->s.YZ; NewObj->s.ZZ = m1->s.ZZ;}//4x4矩阵的与标量的乘积inlinestatic void Matrix4fMulRotationScale(Matrix4fT* NewObj, GLfloat scale){    assert(NewObj);    NewObj->s.XX *= scale; NewObj->s.YX *= scale; NewObj->s.ZX *= scale;    NewObj->s.XY *= scale; NewObj->s.YY *= scale; NewObj->s.ZY *= scale;    NewObj->s.XZ *= scale; NewObj->s.YZ *= scale; NewObj->s.ZZ *= scale;}//设置旋转矩阵inlinestatic void Matrix4fSetRotationFromMatrix3f(Matrix4fT* NewObj, const Matrix3fT* m1){    GLfloat scale;    assert(NewObj && m1);    scale = Matrix4fSVD(NewObj, NULL, NULL);    Matrix4fSetRotationScaleFromMatrix3f(NewObj, m1);    Matrix4fMulRotationScale(NewObj, scale);}typedef class ArcBall_t{protected:    //把二维点映射到三维点    inline        void _mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const;public:    //构造/析构函数    ArcBall_t(GLfloat NewWidth, GLfloat NewHeight);    ~ArcBall_t() { };    //设置边界    inline        void    setBounds(GLfloat NewWidth, GLfloat NewHeight)    {        assert((NewWidth > 1.0f) && (NewHeight > 1.0f));        //设置长宽的调整因子        this->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);        this->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);    }    //鼠标点击    void    click(const Point2fT* NewPt);    //鼠标拖动计算旋转    void    drag(const Point2fT* NewPt, Quat4fT* NewRot);    //更新鼠标状态    void    upstate();    //void    mousemove(WPARAM wParam,LPARAM lParam);protected:    Vector3fT   StVec;          //保存鼠标点击的坐标    Vector3fT   EnVec;          //保存鼠标拖动的坐标    GLfloat     AdjustWidth;    //宽度的调整因子    GLfloat     AdjustHeight;   //长度的调整因子public:    Matrix4fT   Transform;      //计算变换                Matrix3fT   LastRot;        //上一次的旋转     Matrix3fT   ThisRot;        //这次的旋转    float zoomRate;    float lastZoomRate;    bool        isDragging;     // 是否拖动    bool        isRClicked;     // 是否右击鼠标    bool        isClicked;      // 是否点击鼠标    bool        isZooming;    //是否正在缩放    Point2fT    LastPt;    Matrix4fT origTransform;    Point2fT    MousePt;        // 当前的鼠标位置} ArcBallT;#endif

ArcBall.cpp

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ArcBall.cpp////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                         #include <glut.h>        #include <math.h>                                    #include "ArcBall.h"                                 //轨迹球参数://直径                    2.0f//半径                    1.0f//半径平方                1.0fvoid ArcBall_t::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const{    Point2fT TempPt;    GLfloat length;    //复制到临时变量    TempPt = *NewPt;    //把长宽调整到[-1 ... 1]区间    TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f;    TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight);    //计算长度的平方    length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y);    //如果点映射到球的外面    if (length > 1.0f)    {        GLfloat norm;        //缩放到球上        norm = 1.0f / FuncSqrt(length);        //设置z坐标为0        NewVec->s.X = TempPt.s.X * norm;        NewVec->s.Y = TempPt.s.Y * norm;        NewVec->s.Z = 0.0f;    }    //如果在球内    else    {        //利用半径的平方为1,求出z坐标        NewVec->s.X = TempPt.s.X;        NewVec->s.Y = TempPt.s.Y;        NewVec->s.Z = FuncSqrt(1.0f - length);    }}ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight){    this->StVec.s.X = 0.0f;    this->StVec.s.Y = 0.0f;    this->StVec.s.Z = 0.0f;    this->EnVec.s.X = 0.0f;    this->EnVec.s.Y = 0.0f;    this->EnVec.s.Z = 0.0f;    Matrix4fSetIdentity(&Transform);    Matrix3fSetIdentity(&LastRot);    Matrix3fSetIdentity(&ThisRot);    this->isDragging = false;    this->isClicked = false;    this->isRClicked = false;    this->isZooming = false;    this->zoomRate = 1;    this->setBounds(NewWidth, NewHeight);}void ArcBall_t::upstate(){    if (!this->isZooming && this->isRClicked) {                    // 开始拖动        this->isZooming = true;                                        // 设置拖动为变量为true                this->LastPt = this->MousePt;        this->lastZoomRate = this->zoomRate;    }    else if (this->isZooming) {//正在拖动        if (this->isRClicked) {                //拖动                    Point2fSub(&this->MousePt, &this->LastPt);            this->zoomRate = this->lastZoomRate + this->MousePt.s.X * this->AdjustWidth * 2;        }        else {                                            //停止拖动            this->isZooming = false;        }    }    else if (!this->isDragging && this->isClicked) {                                                // 如果没有拖动        this->isDragging = true;                                        // 设置拖动为变量为true        this->LastRot = this->ThisRot;        this->click(&this->MousePt);    }    else if (this->isDragging) {        if (this->isClicked) {                                            //如果按住拖动            Quat4fT     ThisQuat;            this->drag(&this->MousePt, &ThisQuat);                        // 更新轨迹球的变量            Matrix3fSetRotationFromQuat4f(&this->ThisRot, &ThisQuat);        // 计算旋转量            Matrix3fMulMatrix3f(&this->ThisRot, &this->LastRot);            Matrix4fSetRotationFromMatrix3f(&this->Transform, &this->ThisRot);        }        else                                                        // 如果放开鼠标,设置拖动为false            this->isDragging = false;    }}//按下鼠标,记录当前对应的轨迹球的位置void    ArcBall_t::click(const Point2fT* NewPt){    this->_mapToSphere(NewPt, &this->StVec);}//鼠标拖动,计算旋转四元数void    ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot){    //新的位置    this->_mapToSphere(NewPt, &this->EnVec);    //计算旋转    if (NewRot)    {        Vector3fT  Perp;        //计算旋转轴        Vector3fCross(&Perp, &this->StVec, &this->EnVec);        //如果不为0        if (Vector3fLength(&Perp) > Epsilon)        {            //记录旋转轴            NewRot->s.X = Perp.s.X;            NewRot->s.Y = Perp.s.Y;            NewRot->s.Z = Perp.s.Z;            //在四元数中,w=cos(a/2),a为旋转的角度            NewRot->s.W = Vector3fDot(&this->StVec, &this->EnVec);        }        //是0,说明没有旋转        else        {            NewRot->s.X =                NewRot->s.Y =                NewRot->s.Z =                NewRot->s.W = 0.0f;        }    }}

sample.cpp

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////sample.cpp////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#include <glut.h>#include <math.h>                                                #include "ArcBall.h"                                                                                                                            //初始化,必须用全局变量的方式,不能用newArcBallT arcBall(600.0f, 400.0f);ArcBallT*    ArcBall = &arcBall;// new ArcBallT(600.0f,400.0f);//&arcBall;void reshape(int w, int h) {    glViewport(0, 0, w, h);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    glFrustum(-1, 1, -1, 1, 1.5, 20);    glMatrixMode(GL_MODELVIEW);    ////ball    ArcBall->setBounds((GLfloat)w, (GLfloat)h);//1. 设置窗口边界}void init() {    glClearColor(0, 0, 0, 0);    glShadeModel(GL_FLAT);}void display(void){    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glColor3f(1.0, 1.0, 1.0);    glLoadIdentity();    gluLookAt(0.0, 0.0, 5.0,        0.0, 0.0, 0.0,        0.0, 1.0, 0.0);    glScalef(1.0, 2.0, 1.0);    //glPushMatrix();                    glTranslatef(0, 0, -3);    glScalef(ArcBall->zoomRate, ArcBall->zoomRate, ArcBall->zoomRate);//2. 缩放    glMultMatrixf(ArcBall->Transform.M);                        //3. 旋转    glutWireCube(1.0);    //glPopMatrix();                                                        glFlush();}//移动void move(int x, int y){    ArcBall->MousePt.s.X = x;    ArcBall->MousePt.s.Y = y;    ArcBall->upstate();    glutPostRedisplay();}//点击void mouse(int button, int state, int x, int y){    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {        ArcBall->isClicked = true;        move(x, y);    }    else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)        ArcBall->isClicked = false;    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {        ArcBall->isRClicked = true;        move(x, y);    }    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)        ArcBall->isRClicked = false;    ArcBall->upstate();    glutPostRedisplay();}int main(int argc, char** argv) {    glutInit(&argc, argv);    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);    glutInitWindowSize(640, 480);    glutCreateWindow("HI");    init();    glutDisplayFunc(display);    glutReshapeFunc(reshape);    glutMouseFunc(mouse);        //registered the mouse event.    glutMotionFunc(move);        //registered the move event    glutMainLoop();    return 0;}

转载自 http://blog.sina.com.cn/s/blog_8d8425f30100ywap.html

1 0