[译]GLUT教程 - 移动镜头1
Lighthouse3d.com >> GLUT Tutorial >> Input >> Move the Camera I
下面来看一个更有趣的GLUT应用.本节我们会绘制一个雪人世界,并直接用按键移动镜头.向左和向右键会在XZ切面围绕Y轴旋转镜头.反之,向上和向下键会在当前方向向前向后移动镜头.
实现代码已经在适当地方标上注释.首先我们要一些全局变量来保存镜头参数.这些变量会保存了镜头位置和目标方向的向量.我们还需要保存角度.由于y是常量,所以不用保存.
angle: y轴上旋转的角度.该变量是旋转镜头用
x,z: XZ平面的镜头位置
lx, lz: 定义我们视线的向量
以上变量的赋值如下:
// angle of rotation for the camera direction
float angle=0.0;
// actual vector representing the camera's direction
float lx=0.0f,lz=-1.0f;
// XZ position of the camera
float x=0.0f,z=5.0f;
画雪人的代码下面给出,运行结果如下图:

void drawSnowMan() {
glColor3f(1.0f, 1.0f, 1.0f);
// Draw Body
glTranslatef(0.0f ,0.75f, 0.0f);
glutSolidSphere(0.75f,,);
// Draw Head
glTranslatef(0.0f, 1.0f, 0.0f);
glutSolidSphere(0.25f,,);
// Draw Eyes
glPushMatrix();
glColor3f(0.0f,0.0f,0.0f);
glTranslatef(0.05f, 0.10f, 0.18f);
glutSolidSphere(0.05f,,);
glTranslatef(-0.1f, 0.0f, 0.0f);
glutSolidSphere(0.05f,,);
glPopMatrix();
// Draw Nose
glColor3f(1.0f, 0.5f , 0.5f);
glRotatef(0.0f,1.0f, 0.0f, 0.0f);
glutSolidCone(0.08f,0.5f,,);
}
接下来我们得到新的渲染函数.它包含所有的绘制雪人世界的命令.另一个改变是gluLookAt函数.gluLookAt函数的参数从默认值变成了传入变量.你可能不熟悉这个函数,下面来解释一下.gluLookAt函数提供一个简单直观的方式来设置镜头位置和方向.一般而言它有三组参数,每组由三个浮点型值组成.第一组是标示了镜头位置.第二组是定义我们视线的点,它可以是我们视线上的任意点.最后一组是标示了向上的向量,一般设置为(0.0, 1.0, 0.0),意思是镜头是没有倾斜的.如果你希望镜头倾斜你可以更改这组值.例如,改成倒视视觉是(0.0, -1.0, 0.0).
如前文所述, x,y,z表示了镜头的位置,所以它们的值和gluLookAt的第一个向量一致.第二组参数,目侧点,是通过视觉和镜头位置的向量相加所得.
目视点 = 视线 + 镜头位置
下面是渲染函数的实现代码:
void renderScene(void) {
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt( x, 1.0f, z,
x+lx, 1.0f, z+lz,
0.0f, 1.0f, 0.0f);
// Draw ground
glColor3f(0.9f, 0.9f, 0.9f);
glBegin(GL_QUADS);
glVertex3f(-100.0f, 0.0f, -100.0f);
glVertex3f(-100.0f, 0.0f, 100.0f);
glVertex3f( 100.0f, 0.0f, 100.0f);
glVertex3f( 100.0f, 0.0f, -100.0f);
glEnd();
// Draw 36 SnowMen
for(int i = -; i < ; i++)
for(int j=-; j < ; j++) {
glPushMatrix();
glTranslatef(i*10.0,,j * 10.0);
drawSnowMan();
glPopMatrix();
}
glutSwapBuffers();
}
现在开始处理箭头键(上下左右).我们用左右箭头键来旋转镜头,例如更改向量来定义视线.上下键用来移动当前方向的视线向前向后.
当用户按左右键时,角度变量也会跟着改变.随着角度值的改变,程序会重新计算出视线向量的lx和lz组件相应的合适的值..留意到我们现在只是在XZ平面移动,所以我们不用改变视觉向量的ly坐标.新的lx和lz值会映射到单一的XZ平面的圆圈上.于是,下面得出了计算角度ang和新的lx,lz值的公式:
lx = sin(ang)
lz = -cos(ang)
跟我们把极坐标转换成平面坐标一样.lz是负值,因为初始值为-1.
注意,当更新lx和lz时镜头是不移动的,镜头位置不变,只有目视点改变.
我们还想沿着视线移动镜头,例如下一个镜头位置需要沿着视线向量.为了达到这个效果我们需要分别在按上/下键的时候加/减一个粒度的视觉向量到当前位置.例如,移动镜头向前时,x和z的计算公式如下:
x = x + lx * 粒度
z = z + lz * 粒度
这里的粒度是指一个合适的速率.我们知道lx和lz是一个单一向量(前面提及,它是一个单位周期中的点),因此如果粒度值保持在一个常量,速率便会维持在一个常量变化的感觉.增加粒度我们就移动得快一点,也就是说,我们会在每一帧移动得更远.
void processSpecialKeys(int key, int xx, int yy) {
float fraction = 0.1f;
switch (key) {
case GLUT_KEY_LEFT :
angle -= 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_RIGHT :
angle += 0.01f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_UP :
x += lx * fraction;
z += lz * fraction;
break;
case GLUT_KEY_DOWN :
x -= lx * fraction;
z -= lz * fraction;
break;
}
}
配合着以上代码的更改,main函数里面也增加一些代码.唯一的变化是开启了深度测试特性.
int main(int argc, char **argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(,);
glutInitWindowSize(,);
glutCreateWindow("Lighthouse3D - GLUT Tutorial");
// register callbacks
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderScene);
glutKeyboardFunc(processNormalKeys);
glutSpecialFunc(processSpecialKeys);
// OpenGL init
glEnable(GL_DEPTH_TEST);
// enter GLUT event processing cycle
glutMainLoop();
return ;
}
[译]GLUT教程 - 移动镜头1的更多相关文章
- [译]GLUT教程 - 移动镜头3
Lighthouse3d.com >> GLUT Tutorial >> Input >> Moving the Camera III 上一节的示例中我们用键盘更改 ...
- [译]GLUT教程 - 移动镜头2
Lighthouse3d.com >> GLUT Tutorial >> Input >> Move the Camera II 本节的最后一个示例是回顾.现在我们 ...
- [译]GLUT教程(目录)
http://www.lighthouse3d.com/tutorials/glut-tutorial/ GLUT是OpenGL Utility Toolkit的意思.作者Mark J. Kilgar ...
- [译]GLUT教程 - glutPostRedisplay函数
Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> glutPostRedisplay 直 ...
- [译]GLUT教程 - 游戏模式
Lighthouse3d.com >> GLUT Tutorial >> Extras >> Game Mode 根据GLUT官网的说明,GLUT的游戏模式是为开启 ...
- [译]GLUT教程 - 位图和正交投影视图
Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Bitmap Fonts and Orthogonal Projecti ...
- [译]GLUT教程 - 安装
Lighthouse3d.com >> GLUT Tutorial >> Basics >> Setup 你需要什么 要用GLUT库开发程序,你可以下载最新版本3. ...
- [译]GLUT教程 - 整合代码8
Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> The Code So Far VII ...
- [译]GLUT教程 - 整合代码7
Lighthouse3d.com >> GLUT Tutorial >> Extras >> The Code So Far VII 以下是子窗体的最终版本代码. ...
随机推荐
- [给自己扫盲]Node.js 究竟是什么?
Node.js 究竟是什么? 一个 “编码就绪” 服务器 Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用程序,编写能 ...
- 设置并删除Dreamweaver自动生成的_notes文件夹
在使用Dreamweaver做项目时站点下面的每个文件夹里面都会自动生成一个_notes文件夹,删除之后马上又会再次生成.最近做项目时,有童鞋一不小心把所有的_notes文件夹全部存回到SVN上面了, ...
- Tomcat服务器多域名配置(转载)
Tomcat服务器多域名配置 我们来讲解下如何在Tomcat服务器上进行多域名配置: 也就是一个Tomcat跑多网站,这里用真实案例举例,比如我这个云主机需要运行两个网站: pan.java1234. ...
- Android Handler 消息循环机制
前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定 ...
- 【Linux】CentOS7上安装搜狗输入法
找到一篇资料,提供安装搜狗输入法的方法,在http://www.cnblogs.com/Yiutto/p/6204085.html[也是本文的参考原地址] 请大家自行下载fcitx.tar.gz 1. ...
- Windows环境下,用netstat命令查看某个端口号是否占用
目标:在Windows环境下,用netstat命令查看某个端口号是否占用,为哪个进程所占用. 操作:操作分为两步:(1)查看该端口被那个PID所占用;方法一:有针对性的查看端口,使用命令 Netsta ...
- Uri详解之——Uri结构与代码提取
目录(?)[+] 前言:依然没有前言…… 相关博客:1.<Uri详解之——Uri结构与代码提取>2.<Uri详解之二——通过自定义Uri外部启动APP与Notification启动& ...
- [置顶]
kubernetes资源类型--ingress
Ingress在K8S1.1之前还没有. 概念 Ingress是一种HTTP方式的路由转发机制,为K8S服务配置HTTP负载均衡器,通常会将服务暴露给K8S群集外的客户端. Ingress是一个允许入 ...
- 以lstm+ctc对汉字识别为例对tensorflow 中的lstm,ctc loss的调试
#-*-coding:utf8-*- __author = "buyizhiyou" __date = "2017-11-21" ''' 单步调试,结合汉字的识 ...
- Flume推送数据到SparkStreaming案例实战和内幕源码解密
本期内容: 1. Flume on HDFS案例回顾 2. Flume推送数据到Spark Streaming实战 3. 原理绘图剖析 1. Flume on HDFS案例回顾 上节课要求大家自己安装 ...