本文介绍如何使用矩阵堆栈原理实现简单的行星运行系统。

原理

有时我们需要在一个场景中绘制不同的模型,如果这些模型彼此间没有联系,即各模型的位置不会相互影响,那我们只需要单独为每个模型创建合适的变换矩阵,并经过渲染管线将其渲染即可。而对于一个位置会相互影响的系统而言,例如行星运行系统,地球围绕太阳公转,而月球围绕地球公转。处理这样问题的关键在于如何确定各物体变换矩阵,准确来说是模型-视图矩阵。而矩阵堆栈可以很好地将这问题简化。
所谓矩阵堆栈,就一个用来存储变换矩阵的堆栈结构,栈顶矩阵为栈底矩阵乘上另一个矩阵变换而来,由此,栈底到栈顶形成一个逐步复杂的结构。通常来说,栈底的矩阵为视图矩阵,因为对于一个场景中的每个物体,它们都要经过视图矩阵的变换。逐步往上,由父物体的变换矩阵先入栈,利用栈顶矩阵作为该物体的模型-视图矩阵绘制物体后,再进入其子物体的管线,依次逐步进行。同时,对于不希望由父物体继承给子物体的变换矩阵可以在绘制完父物体后将其出栈。

实现

代码实现

对于本文所要研究的行星运行系统,共有三个物体:太阳、地球、月球,它们的依赖关系是:地球围绕太阳公转,而月球围绕地球公转。矩阵堆栈的变换情况如下:

  1. 将视图矩阵压入栈中。

    vMat = glm::translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
    mvStack.push(vMat);
    
  2. 构造太阳的模型矩阵,将其与栈顶矩阵相乘后。

  3. 将旋转矩阵与栈顶矩阵相乘并入栈以实现太阳的自转效果,将栈顶矩阵作为太阳的模型-视图矩阵,渲染太阳后将栈顶矩阵出栈,移除太阳的旋转变换。

    /// <summary>
    /// 绘制太阳
    /// </summary>
    mMat = glm::translate(glm::mat4(1.0f), glm::vec3(sunLocX, sunLocY, sunLocZ));
    mvStack.top() *= mMat;
    mvStack.push(mvStack.top());
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), (float)currentTime, glm::vec3(0.0f, 1.0f, 0.0f)); // 太阳自转drawSphere(sunTexture);
    mvStack.pop(); // 矩阵堆栈中移除太阳自转
    
  4. 将平移矩阵与栈顶矩阵相乘并入栈以实现地球的公转效果,其中平移的坐标的计算利用程序运行时间的三角函数值得到。

  5. 将旋转矩阵与缩放矩阵与栈顶矩阵相乘后入栈,实现地球的自转效果并将地球的尺寸缩小,将栈顶矩阵作为地球的模型-视图矩阵,渲染地球后将栈顶矩阵出栈,移除地球的旋转和缩放变换。

    /// <summary>
    /// 绘制地球
    /// </summary>
    mvStack.push(mvStack.top());
    mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3(sin((float)currentTime) * 4.0f, 0.0f, cos((float)currentTime) * 4.0f)); // 地球公转
    mvStack.push(mvStack.top());
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), (float)currentTime, glm::vec3(0.0f, 1.0f, 0.0f)); // 地球自转
    mvStack.top() *= glm::scale(glm::mat4(1.0f), glm::vec3(0.3f, 0.3f, 0.3f)); // 地球缩放drawSphere(earthTexture);
    mvStack.pop(); // 矩阵堆栈中移除地球自转和缩放
    
  6. 与地球类似,将平移矩阵与栈顶矩阵相乘并入栈以实现月球的公转效果。由于月球已经没有子物体,因此无需继续创建新的矩阵,只需要在栈顶矩阵的基础上乘以月球的自转和缩放矩阵,渲染完成后,将矩阵堆栈清空。

    /// <summary>
    /// 绘制月球
    /// </summary>
    mvStack.push(mvStack.top());
    mvStack.top() *= glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, sin((float)currentTime) * 0.8f, cos((float)currentTime) * 0.8f)); // 月球公转
    mvStack.top() *= glm::rotate(glm::mat4(1.0f), (float)currentTime, glm::vec3(0.0f, 0.0f, 1.0f)); // 月球自转
    mvStack.top() *= glm::scale(glm::mat4(1.0f), glm::vec3(0.1f, 0.1f, 0.1f)); // 月球缩放drawSphere(moonTexture);
    mvStack.pop(); mvStack.pop(); mvStack.pop(); // 清空矩阵堆栈
    

运行效果

项目链接

本项目已上传 github 仓库,如果想要查看项目的完整代码,可以自行访问。

项目链接

OpenGL入门 矩阵堆栈实现简单行星系统相关推荐

  1. OpenGL/C++实战——C++实现太阳系行星系统

    注:本教程版权归实验楼所有,有兴趣的同学也可点进官网蓝桥网课:C++实现太阳系行星系统学习(免费课程) 文章目录 框架设计 认识 OpenGL 和 GLUT 类设计 stars.hpp solarsy ...

  2. OpenGL使用矩阵堆栈glpushMatrix的原因

    http://anony3721.blog.163.com/blog/static/511974201133095555708/ 题外话:学习OpenGL有两个礼拜了,总结下才发现仅仅明白了其基本概念 ...

  3. OpenGL入门学习[二] 绘制简单的几何图形

    OpenGL入门学习[二] 本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念. 一.点.直线和多边形 我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念 ...

  4. OpenGL之矩阵堆栈绘制立体图元

    绘制流程 一.main函数 初始化双缓冲窗口:glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); 设置w ...

  5. 视频教程-OpenGL入门2019版-其他

    OpenGL入门2019版 在大学期间系统的学习了opengl.计算机图形学.计算机视觉的算法,与2013年加入4399,任职暗黑战神项目组主程,2015年3月底离职创业,创办了战火信息科技有限公司, ...

  6. OpenGL太阳系行星系统简单实现

    一.项目简介 使用OpenGL(glfw, glad)模拟太阳系(地球.月球.太阳)系统,涉及三维图形变换.坐标系统,光照模型(待添加).键盘鼠标事件处理等内容,在main函数中封装了绝大部分的Ope ...

  7. C++ 实现太阳系行星系统(OpenGL)

    基本框架设计 一.介绍 本次实验将使用 OpenGL GLUT 编写一个简单的太阳系运行系统. 实验涉及的知识点 C++ 语言基础 基本的 Makefile 基本的 OOP 编程思想 OpenGL G ...

  8. OpenGL学习笔记:模型变换、视图变换、投影变换 、视口变换、操作矩阵堆栈

    1. 模型变换和视图变换  从"相对移动"的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性.在OpenGL中,实现这两种功能甚至使用的是同样的函数. 由于模型 ...

  9. 基于C++和OpenGL (GLUT) 实现太阳系行星系统

    基于C++和OpenGL (GLUT) 实现太阳系行星系统 效果图: 分析与设计 OpenGL 包含了很多渲染函数,但是他们的设计目的是独立于任何窗口系统或操作系统的.因此,它自身并没有包含创建打开窗 ...

最新文章

  1. 秒杀商品超卖事故:Redis分布式锁请慎用!
  2. 不能打游戏的汽车不是好电影院!特斯拉面向国内推送V10.0系统,能辅助变道还能看爱奇艺...
  3. 无需Root也能Hook?——Depoxsed框架演示
  4. spark 写tidb_优秀的数据工程师,怎么用Spark在TiDB上做OLAP分析
  5. oracle 怎么读取模板,获取、部署和管理Oracle VM模板
  6. GPU代码修改成TPU代码
  7. arcgis超级工具密码_浏览器的自动保存密码是如何将我们的密码泄露的?
  8. FTP连接时出现“227 Entering Passive Mode”的解决方法
  9. 自然语言处理理论与实战
  10. 基于气象站点气象数据的空间插值
  11. 【上汽零束SOA】云管端一体化SOA软件平台系列介绍之四:车云一体架构篇
  12. SPSS 工作空间不足的解决办法
  13. iOS开发中对音效和音乐播放的简单实现
  14. czy的后宫5 召集妹子
  15. python tkinter界面可视化工具
  16. UltraEdit编辑器无法使用快捷键全选ctrl+a功能失效解决办法
  17. linux查看服务器网络延迟,ECS Linux下的qperf测量网络带宽和延迟的具体步骤
  18. 23,verilog之参数parameter介绍
  19. Java 之父:找Bug最浪费时间,现在不是开源的黄金时代!
  20. 如何利用字符串格式化漏洞

热门文章

  1. 如何让一个停不下来的shell脚本在规定时间内停下来?
  2. 性能架构师看IT之家的性能问题及解法
  3. 浪潮服务器光驱安装操作系统,浪潮服务器安装
  4. 基于Python+Django的项目申报审核平台系统
  5. linux 渗透工具_适用于Linux的十大最佳渗透测试工具
  6. UnityShader——屏幕空间反射(一)
  7. jmeter-阶梯式性能指标监听
  8. L2级ADAS前装搭载量1月同比增超6成,国产供应商“崭露头角”
  9. 盖雅招聘联合Moka开启招聘新模式
  10. Unity背景音乐控制