NeHe OpenGL教程 第四十八课:轨迹球
前言
声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。
NeHe OpenGL第四十八课:轨迹球

轨迹球实现的鼠标旋转
使用鼠标旋转物体,很简单也有很多实现方法,这里我们教会你模拟轨迹球来实现它.
轨迹球控制
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(); // 弹出保存的矩阵
原文及其个版本源代码下载:
NeHe OpenGL教程 第四十八课:轨迹球的更多相关文章
- NeHe OpenGL教程 第三十八课:资源文件
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十五课:顶点缓存
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十六课:全屏反走样
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十二课:多重视口
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十四课:3D光晕
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十课:绳子的模拟
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第三十六课:从渲染到纹理
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第三十五课:播放AVI
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第三十二课:拾取游戏
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
随机推荐
- loading
<!doctype html> <html> <head> <title>实惠福利</title> <meta charset=&qu ...
- Android 《第一行代码》 第二章练习代码 ActivityTest
FirstActivity.java package com.example.activitytest; import android.app.Activity; import android.con ...
- 回车键转tab键解决方案二
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- linux 下mysql 字段插入的值超过 预设大小报错
其原因 是 STRICT_TRANS_TABLES 决定了 如果超出字段大小,则不会截取 ,直接报错. 到/etc/my.cnf 删除 STRICT_TRANS_TABLES 就可以了 sq ...
- JSON认识
阅读目录 JSON的两种结构 认识JSON字符串 在JS中如何使用JSON 在.NET中如何使用JSON 总结 JSON的全称是”JavaScript Object Notation”,意思是Java ...
- 收藏的牛人的Backbone分享教程
http://yujianshenbing.iteye.com/category/256978 感谢御剑神兵,目前正在看,为源码分析做准备. 今天是2015年4月13号,看了前两篇,
- 在Eclipse上建立hadoop2.2.0/hadoop2.4.0源代码阅读环境
1.安装依赖的包: yum install gcc-c++ g++ autoconf automake libtool cmake zlib1g-dev pkg-config libssl-dev 2 ...
- 系统不支持curl
解决安装pinphp时出现的“系统不支持curl!” 今天在本机安装phppin开源程序时,提示“系统不支持curl!”错误. 由于我本机是UBUNTU系统,所以直接通过apt-get进行安装. ...
- MxNet下训练alexnet(一)
1.图像经过工具包中的 make_lsit im2rec 转换为可调用各式.rec,.bin都可以 2.然后使用train_imageXXXX进行训练,参数需要对应 3.利用保存的模型进行估计,测试 ...
- 网络编程-socket
本节内容: 一:TCP/IP:Transmission Control Protocol/Internet Protocol 传输控制协议/因特网互联协议.即通讯协议.是主机接入互联网以及互联网中两台 ...