NeHe 系列教程之十:在3D空间中漫游

英文教程地址:lesson10

本课演示了从外部文件中加载数据构建3D模型的实例,代码基于第一课。

首先是3D模型的数据结构定义:

namespace {bool fp;         // F pressed?const float piover180 = 0.0174532925f;float heading;float xpos;float zpos;GLfloat yrot;                   // Y RotationGLfloat walkbias = 0;GLfloat walkbiasangle = 0;GLfloat lookupdown = 0.0f;GLuint filter;         // Which filter to useGLuint texture[3];        // Storage for 3 texturestypedef struct tagVERTEX{float x, y, z;float u, v;} VERTEX;typedef struct tagTRIANGLE{VERTEX vertex[3];} TRIANGLE;typedef struct tagSECTOR{int numtriangles;TRIANGLE* triangle;} SECTOR;SECTOR sector1;         // Our model goes here:

接着是读取外部数据文件,构建3D模型:

const char* readstr(QFile &f){QByteArray line = f.readLine();while (line.at(0) == '/' || line.at(0) == '\n') {line = f.readLine();}return line.constData();}void SetupWorld(){float x, y, z, u, v;int numtriangles;const char *oneline;QFile filein(":/World.txt");if (!filein.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug("failed to open file");} else {qDebug("open file successfully");}oneline = readstr(filein);sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);sector1.triangle = new TRIANGLE[numtriangles];sector1.numtriangles = numtriangles;for (int loop = 0; loop < numtriangles; loop++){for (int vert = 0; vert < 3; vert++){oneline = readstr(filein);sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);sector1.triangle[loop].vertex[vert].x = x;sector1.triangle[loop].vertex[vert].y = y;sector1.triangle[loop].vertex[vert].z = z;sector1.triangle[loop].vertex[vert].u = u;sector1.triangle[loop].vertex[vert].v = v;}}filein.close();return;}
}

采用了三种不同的纹理过滤方式, 加载纹理代码如下:

void MyGLWidget::loadTextures()
{QImage image;if (image.load(":/Mud.bmp")) {image =  convertToGLFormat(image);glGenTextures(3, texture);// Create Nearest Filtered TextureglBindTexture(GL_TEXTURE_2D, texture[0]);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());// Create Linear Filtered TextureglBindTexture(GL_TEXTURE_2D, texture[1]);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());// Create MipMapped TextureglBindTexture(GL_TEXTURE_2D, texture[2]);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits());}
}

在初始化代码中,调用构建3D模型函数,即:

void MyGLWidget::initializeGL()
{...SetupWorld();}

然后是绘制代码,将3D场景显示出来:

void MyGLWidget::paintGL()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     // Clear the screen and the depth bufferglLoadIdentity();                  // Reset the viewGLfloat x_m, y_m, z_m, u_m, v_m;GLfloat xtrans = -xpos;GLfloat ztrans = -zpos;GLfloat ytrans = -walkbias-0.25f;GLfloat sceneroty = 360.0f - yrot;int numtriangles;glRotatef(lookupdown,1.0f,0,0);glRotatef(sceneroty,0,1.0f,0);glTranslatef(xtrans, ytrans, ztrans);glBindTexture(GL_TEXTURE_2D, texture[filter]);numtriangles = sector1.numtriangles;// Process each trianglefor (int loop_m = 0; loop_m < numtriangles; loop_m++){glBegin(GL_TRIANGLES);glNormal3f( 0.0f, 0.0f, 1.0f);x_m = sector1.triangle[loop_m].vertex[0].x;y_m = sector1.triangle[loop_m].vertex[0].y;z_m = sector1.triangle[loop_m].vertex[0].z;u_m = sector1.triangle[loop_m].vertex[0].u;v_m = sector1.triangle[loop_m].vertex[0].v;glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);x_m = sector1.triangle[loop_m].vertex[1].x;y_m = sector1.triangle[loop_m].vertex[1].y;z_m = sector1.triangle[loop_m].vertex[1].z;u_m = sector1.triangle[loop_m].vertex[1].u;v_m = sector1.triangle[loop_m].vertex[1].v;glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);x_m = sector1.triangle[loop_m].vertex[2].x;y_m = sector1.triangle[loop_m].vertex[2].y;z_m = sector1.triangle[loop_m].vertex[2].z;u_m = sector1.triangle[loop_m].vertex[2].u;v_m = sector1.triangle[loop_m].vertex[2].v;glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m);glEnd();}
}

最后是键盘控制处理:

void MyGLWidget::keyReleaseEvent(QKeyEvent *e)
{switch (e->key()) {case Qt::Key_I:fp = false;break;default:QGLWidget::keyReleaseEvent(e);}
}void MyGLWidget::keyPressEvent(QKeyEvent *e)
{switch (e->key()) {case Qt::Key_I:fp = true;filter += 1;if (filter > 2)filter = 0;break;case Qt::Key_F:fullscreen = !fullscreen;if (fullscreen) {showFullScreen();} else {resize(640, 480);showNormal();}break;case Qt::Key_Right:yrot -= 1.5f;break;case Qt::Key_Left:yrot += 1.5f;break;case Qt::Key_Up:xpos -= (float)sin(heading*piover180) * 0.05f;          // Move On The X-Plane Based On Player Directionzpos -= (float)cos(heading*piover180) * 0.05f;          // Move On The Z-Plane Based On Player Directionif (walkbiasangle >= 359.0f)                 // Is walkbiasangle>=359?{walkbiasangle = 0.0f;                   // Make walkbiasangle Equal 0}else                                // Otherwise{walkbiasangle+= 10;                    // If walkbiasangle < 359 Increase It By 10}walkbias = (float)sin(walkbiasangle * piover180)/20.0f;     // Causes The Player To Bouncebreak;case Qt::Key_Down:xpos += (float)sin(heading*piover180) * 0.05f;          // Move On The X-Plane Based On Player Directionzpos += (float)cos(heading*piover180) * 0.05f;          // Move On The Z-Plane Based On Player Directionif (walkbiasangle <= 1.0f)                   // Is walkbiasangle<=1?{walkbiasangle = 359.0f;                 // Make walkbiasangle Equal 359}else                                // Otherwise{walkbiasangle-= 10;                 // If walkbiasangle > 1 Decrease It By 10}walkbias = (float)sin(walkbiasangle * piover180)/20.0f;     // Causes The Player To Bouncebreak;case Qt::Key_Escape:QMessageBox::StandardButton reply;reply = QMessageBox::question(NULL, "NeHe","Do you want to exit?",QMessageBox::Yes | QMessageBox::No,QMessageBox::Yes);if (reply == QMessageBox::Yes) {qApp->quit();}break;default:QGLWidget::keyPressEvent(e);break;}
}

最后运行效果如下所示:

转载于:https://my.oschina.net/fuyajun1983cn/blog/263866

NeHe教程Qt实现——lesson10相关推荐

  1. NeHe教程Qt实现——lesson01

    NeHe 系列教程之一: 创建一个OpenGL 窗口 英文教程地址: lesson01 在Qt的实现中, 我们主要依赖QGLWidget类, 我们主要重载三个重要方法 :     void initi ...

  2. NeHe教程Qt实现——lesson07

    NeHe 系列教程之七: 光照及纹理过滤 英文教程地址:lesson07 本课将以第一课的代码为基础, 实现光照效果. 首先是对象定义与纹理加载的代码: namespace { bool light; ...

  3. NeHe教程Qt实现——lesson08

    NeHe 系列教程之八: 混合 英文教程地址:lesson08 本课将在第七课的基础上添加颜色混合的代码: namespace { ... bool blend; // Blending OFF/ON ...

  4. NeHe教程Qt实现——lesson09

    NeHe 系列教程之九: 在3D空间中移动位图 英文教程地址:lesson09 本课基于第一课的代码, 利用颜色混合的方法,将一个黑白纹理与随机颜色进行混合,产生绚丽的效果. 首先是定义相关变量和数据 ...

  5. NeHe教程Qt实现——lesson16

    NeHe 系列教程之十四:雾 英文教程地址:lesson16 本课展示产生雾. 相关变量和函数定义: namespace { bool gp; GLuint fogMode[] = { GL_EXP, ...

  6. NeHe教程Qt实现——lesson06

    NeHe 系列教程之六: 纹理映射 英文教程地址:lesson06 本课以第一课的代码为基础,演示了加载纹理的过程. 首先给出的是绘制几何对象和加载纹理坐标的代码 namespace {GLfloat ...

  7. NeHe教程Qt实现——lesson15

    NeHe 系列教程之十四:纹理 轮廓字体 英文教程地址:lesson15 本课展示如何创建和显示纹理轮廓字体, 代码基于第一课. 首先是字体库的创建: namespace {#define USE_D ...

  8. NeHe教程Qt实现——lesson13

    NeHe 系列教程之十三: 位图字体 英文教程地址:lesson13 本课将展示位图字体的创建和显示, 代码基于第一课. 首先是字休库的创建,如下所示: namespace {#define USE_ ...

  9. NeHe教程Qt实现——lesson14

    NeHe 系列教程之十四: 轮廓字体 英文教程地址:lesson14 本课展示如何创建和显示轮廓字体,即带有尝试的字体,可沿Z轴旋转和移动, 代码基于第一课. 同前一课类似,首先也是要创建字体库以及对 ...

最新文章

  1. CS131专题-6:图像特征(Blob检测、LoG算子、Harris-Laplacian)
  2. 互联网元年:如何提升自己?
  3. 家电换新就现在 国美发放“年中惠民消费大补贴”
  4. Java面试题系列之Java基础类库(一)
  5. CentOS 下安装 Node.js 8.11.3 LTS Version
  6. “iexplorer.exe遇到问题需要关闭”问题的处理
  7. c++ mysql 写库 乱码 ??_mysql c++ 乱码 解决方法
  8. 【干货笔记】CS224n-2019 学习笔记 Lecture 01 Introduction and Word Vectors
  9. latex 伪代码 return怎么写 不换行怎么办
  10. ImageView显示图像控件
  11. android 正五边形图表,Android自定义View-蜘蛛网属性图(五边形图)
  12. 用虚表和虚表指针实现动态绑定
  13. 生物信息学中的机器学习:使用K-Means和PCA进行基因组序列分析 COVID-19接下来如何突变?
  14. 【笔记】scp如何复制文件到带空格路径的server目录
  15. 笨人学php好学吗_经典学经:笨人学数学的方法
  16. silverlight文件下载方法
  17. 七天学会php,十天学会PHP之第六天
  18. php 教育类,php教育培训网站是哪个
  19. asp毕业设计——基于asp+sqlserver的人力资源管理系统设计与实现(毕业论文+程序源码)——人力资源管理系统
  20. python 页眉页脚_python自动化办公:玩转word之页眉页脚秘笈-阿里云开发者社区

热门文章

  1. Viewpager的创建和使用——————————不懂的大家可以问,欢迎提问
  2. 约瑟夫环(约瑟夫问题)求最后出列的人数
  3. 高通按手机售价收专利费不合理?too 幼稚!
  4. SQL SERVER使用ODBC 驱动建立的链接服务器调用存储过程时参数不能为NULL值
  5. 一些实用的mysql语句(不断积累更新)
  6. 自学篇之-----纯css做的漂亮的单选框复选框样式
  7. 笔记-【6】-JS中JSON的基础理解!
  8. nyoj983 首尾相连数组的最大子数组和
  9. 多线程同步之 WaitableTimer (等待定时器对象)[续三]
  10. linux 路由跟踪表满错误 nf_conntrack: table full, dropping packet 原理解决方法