新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 29408 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客楼主
    发贴心情 


    第四十八课

    按此在新窗口浏览图片轨迹球实现的鼠标旋转

    使用鼠标旋转物体,很简单也有很多实现方法,这里我们教会你模拟轨迹球来实现它.

      
       
       
    轨迹球控制
    By Terence J. Grant (tjgrant@tatewake.com)
    如果只用鼠标来控制你的模型是不是很酷?轨迹球可以帮你做到这一点,我将告诉你我的实现,你可以把它应用在你的工程里。

    我的实现是基于Bretton Wade’s,它是基于Ken Shoemake’s 实现的,最初的版本,你可以从游戏编程指南这本图上找到。但我还是修正了一些错误,并优化了它。

    轨迹球实现的内容就是把二维的鼠标点映射到三维的轨迹球,并基于它完成旋转变化。

    为了完成这个设想,首先我们把鼠标坐标映射到[-1,1]之间,它很简单:



      
       

    MousePt.X  =  ((MousePt.X / ((Width  -1) / 2)) -1);MousePt.Y  = -((MousePt.Y / ((Height -1) / 2))-1);

       
    这只是为了数学上的简化,下面我们计算这个长度,如果它大于轨迹球的边界,我们将简单的把z轴设为0,否则我们把z轴设置为这个二维点映射到球面上对应的z值。
    一旦我们有了两个点,就可以计算它的法向量了和旋转角了。

    下面我们从构造函数开始,完整的讲解这个类:


      
       

    ArcBall_t::ArcBall_t(GLfloat NewWidth, GLfloat NewHeight)

       
    当点击鼠标时,记录点击的位置   
       

    void    ArcBall_t::click(const Point2fT* NewPt)
       
    当拖动鼠标时,记录当前鼠标的位置,并计算出旋转的量。   
       

    void ArcBall_t::drag(const Point2fT* NewPt, Quat4fT* NewRot)


       
    如果窗口大小改变,设置鼠标移动的范围  
       

    void    ArcBall_t::setBounds(GLfloat NewWidth, GLfloat NewHeight)
       
    下面是完成计算所要用到的数据结果,都是一些矩阵和向量  
       

    Matrix4fT Transform = {  1.0f,  0.0f,  0.0f,  0.0f,          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,
    0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 1.0f };

    Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 1.0f };

    ArcBallT ArcBall(640.0f, 480.0f);
    Point2fT MousePt;
    bool isClicked = false; // 是否点击鼠标
    bool isRClicked = false; // 是否右击鼠标
    bool isDragging = false; // 是否拖动


       
    在上面定义的变量中,transform是我们获得的最终的变换矩阵,lastRot是上一次鼠标拖动得到的旋转矩阵,thisRot为这次鼠标拖动得到的旋转矩阵。
    当我们点击鼠标时,创建一个单位旋转矩阵,当我们拖动鼠标时,这个矩阵跟踪鼠标的变化。

    为了更新鼠标的移动范围,我们在函数ReshapeGL中加入下面一行:


      
       

    void ReshapeGL (int width, int height){ . . . ArcBall.setBounds((GLfloat)width, (GLfloat)height);    // 更新鼠标的移动范围}
    // 处理鼠标的按键操作
    LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    . . .
    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;
    break;

    case WM_LBUTTONUP: isClicked = false; break;
    case WM_RBUTTONUP: isRClicked = false; break;
    case WM_LBUTTONDOWN: isClicked = true; break;
    case WM_RBUTTONDOWN: isRClicked = true; break;
    . . .
    }


       
    为了随着输入更新我们的的状态,在Update函数中需要处理更新参数  
       

    if (isRClicked)          // 如果右键按下,这重置所有的变量{ Matrix3fSetIdentity(&LastRot);
      Matrix3fSetIdentity(&ThisRot);
      Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot);
      }
    if (!isDragging) // 如果没有拖动
    {
    if (isClicked) // 第一次按下
    {
    isDragging = true; // 设置拖动为变量为true
    LastRot = ThisRot;
    ArcBall.click(&MousePt);
    }
    }
    else
    {
    if (isClicked) //如果按住拖动
    {
    Quat4fT ThisQuat;

    ArcBall.drag(&MousePt, &ThisQuat); // 更新轨迹球的变量
    Matrix3fSetRotationFromQuat4f(&ThisRot, &ThisQuat); // 计算旋转量
    Matrix3fMulMatrix3f(&ThisRot, &LastRot);
    Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot);
    }
    else // 如果放开鼠标,设置拖动为false
    isDragging = false;
    }


       
    好了,完成了上面的内容。我们到了绘制的阶段。
    记住在绘制前,把我们得到的矩阵乘以当前的模型变换矩阵。  
       

    glPushMatrix();         // 保存当前的矩阵 glMultMatrixf(Transform.M);       // 应用我们的变换矩阵
    glBegin(GL_TRIANGLES); // 绘制模型
    . . .
    glEnd();

    glPopMatrix(); // 弹出保存的矩阵

       
    我已经在上面给掩饰了所有的技巧,你可以不使用我告诉你的数学技巧,因为我想你会有更好的。现在你已经看到了,这是多么的简单,你完全可以按你的风格创造出更好的轨迹球。

    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/11/1 11:52:00
     
     GoogleAdSense射手座1984-11-30
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/5/10 20:47:53

    本主题贴数6,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 4..(7311字) - 一分之千,2007年11月1日
        回复:  这些都学会 差不多就入门了 谢谢楼主了!!(40字) - emc2010,2011年12月16日
        回复:  谢谢你!没了吗?(18字) - 长风万里,2007年11月1日
        回复:  Lesson: 48 ArcBall Rotation Control, Revisi..(8041字) - 一分之千,2007年11月1日
        回复:  第四十八课[IMG]http://www.owlei.com/DancingWind/P..(4302字) - 一分之千,2007年11月1日
        回复:  Lesson: 47 Using vertex and fragment (or pi..(20272字) - 一分之千,2007年11月1日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms