应用转换时,OpenGL 是不是会更改内存中的顶点?

Posted

技术标签:

【中文标题】应用转换时,OpenGL 是不是会更改内存中的顶点?【英文标题】:Does OpenGL change vertices in memory when you apply transformations?应用转换时,OpenGL 是否会更改内存中的顶点? 【发布时间】:2015-09-26 02:18:32 【问题描述】:

假设我的程序中有一个顶点(为了方便起见),(0, 0, 0)。就在原点。我使用简单的平移矩阵渲染单个帧,将顶点沿 x 轴向下移动两个单位。相应地渲染顶点。现在 VRAM 中显示的顶点是否与 (2, 0, 0)?我已经读过,每次渲染帧时在 OpenGL 中加载所有相应的单位矩阵很重要——我认为这是因为一切都会越来越远地不断移动、旋转等,这意味着应用转换确实会修改实际数据,而不仅仅是屏幕上的外观。

【问题讨论】:

带有固定管线的 OpenGL 2.0 还是带有自定义着色器的 OpenGL 4/ES? IE 你曾经调用 glVertex 吗? 带有自定义着色器的现代 OpenGL。 如果没记错的话,我认为您不必在现代 opengl 中加载所有身份矩阵,因为现代 opengl 没有状态机。 如果你有兴趣学习 OpenGL,我强烈推荐这个网站marekknows.com,你可以购买下载点数来观看他的视频教程。我从 2007-08 年开始成为会员,我从他那里学到了很多;不仅要学习 OpenGL 或游戏引擎开发,还要学习许多不同的算法和方法来完成各种编程任务。我还学习了优雅的应用程序设计,它增强了我的 C++ 技能。 【参考方案1】:

严格来说,OpenGL 只是一个 API 定义。只要符合规范,实现就可以为所欲为。

话虽如此,您的问题的答案通常是:。很难想象将转换后的顶点存储回还包含原始顶点的内存中会有什么意义。

原始顶点位置被传递到顶点着色器,在那里它们被处理,其中可以包括变换。一旦它们退出顶点着色器,转换后的位置很可能会存储在某种缓存或专用的片上 GPU 内存中,直到它们被管道的下一步处理,包括透视分割、视口变换的应用,和光栅化。一旦完成这些顶点处理步骤,就可以丢弃转换后的顶点。它们可能会在缓存中停留更长时间,以便在再次使用相同的原始顶点时可能重用已处理的顶点。但它们不会以任何持久的方式存储。

按照我的解释,您听说必须为每一帧重置矩阵可能是一种误解。如果你想在下一帧中应用相同的矩阵,你根本不需要做任何事情。

他们最有可能谈论的是旧版 OpenGL 中矩阵堆栈的工作方式。大多数修改当前矩阵的调用,如glTranslatef()glRotatef() 等,都以增量方式应用于当前矩阵。例如,如果您调用glRotatef(),则旋转与矩阵堆栈上已经存在的变换相结合。结果是您新指定的旋转首先应用于顶点,然后是已经在矩阵堆栈上的变换。

基于此,如果您想在每帧开始时从头开始指定转换,您将调用glLoadIdentity() 以在开始指定新转换之前重置矩阵堆栈上的当前转换。或者您可以使用glPushMatrix()/glPopMatrix() 来保存和恢复矩阵堆栈的所需状态。

如果您使用许多人所说的“现代 OpenGL”,这意味着您不使用传统的固定管道功能,您不必担心任何这些。矩阵堆栈永远消失了,您可以计算自己的转换矩阵,并将它们传递给您的着色器代码。

【讨论】:

@Sam Claus 使用此反馈也可让 Reto Koradi 获得出色的分数!我没有涉及堆栈、gpu 和缓存内存,但他说的是硬件内发生的事情以及所有事情都在 CPU 上完成的传统 OpenGL 与在 GPU 上使用着色器的新版本 OpenGL 之间的区别。 谢谢!抱歉,如果我的问题设计不当——在我遵循的教程中,使用了一点旧版 OpenGL,然后是现代的。现在我有两个版本的答案!虽然我打算从现在开始使用严格的现代 OpenGL。但是,如果您不介意的话,这些答案又给我留下了一个问题。我想几乎完全避免将 CPU 用于物理、模型移动、碰撞检测等。使用现代 OpenGL,我可以实际编辑 VRAM 中的数据 - 还是 CPU 必须跟踪事物? 就像我在 A 点有我的头像,并且我使用 GPU 在视觉上将它移动到 B 点,头像通常仍然在物理上位于 A 点,直到我更新它在 RAM 中的位置,使用CPU。【参考方案2】:

这是 wiki 上关于变换矩阵所涉及的数学的链接。 https://en.wikipedia.org/wiki/Transformation_matrix 这将使您了解幕后的数学。另一种看待这一点的方法也是线性或向量代数。因此,当您渲染场景时,幕后发生的事情是所有顶点(像素)数据都从 CPU 发送到 GPU 以进行光栅化并绘制到屏幕上。这是您的批处理或渲染调用,现在您还有一个帧函数,它将每秒发生 x 次,这将为您提供每秒帧数。因此,如果您以 60 FPS 的速度进行渲染,那么这些像素、顶点、三角形等将每秒绘制 60 次。当你对这组顶点应用变换时,这里发生的是你有一个变换矩阵,它被乘以你的模型视图投影矩阵。 MVP * T 这将被保存回您现有的 MVP 矩阵,如果这是您设置计算的方式。从 OpenGL v1.0 Pure CPU 调用到 v4.5,您使用的 OpenGL 版本之间存在一些差异。据我所知,在 3.2 或 3.3 版本之后,我不记得您必须自己实现 MVP 的哪个版本,其中第一次引入着色器的大于 v1.5 的版本已经为您处理了。这是关于 OpenGL https://www.opengl.org/ 的文档,在主页上会有一个主题说文档从那里您可以选择 OpenGL Registry 或您想要查看的任何特定版本。从这里您可以阅读他们关于 OpenGL API 的文档,因为该站点涵盖了他们 API 中可用的所有内容。因此,当您开始了解此过程时,是的,这些顶点的实际坐标数据确实会发生变化,但是除非您将静态类型变量增加一个时间因子,否则它不会连续变化,从而为您提供某种运动或动画模拟.如果您只应用一个变换,那么这些像素、顶点、三角形等将根据您应用的变换进行旋转、平移、缩放或剪切。我会告诉你这些操作的顺序确实很重要,但我不会告诉你它们是什么顺序,这将由你阅读并弄清楚。之所以重要,是因为并非每个矩阵乘法都有一个有效的逆矩阵。 Identity 用于舍入误差和浮点精度等原因,因此如果您碰巧在大约 10 秒内应用了 1,000 次转换,则不会出现天文错误。这应该足以为您指明正确的方向,也可以作为 OpenGL API 如何工作的指南。

【讨论】:

谢谢!我从您的回答中学到了很多东西,但我仍然不明白为什么即使您不重置矩阵,顶点数据也不会继续变化。我不记得我头顶上的不同矩阵布局 - 但假设您设置了一个平移矩阵以在正 x 轴下移动 2 个单位,就像我的问题一样。每次渲染帧而不重置该矩阵时,为什么顶点不沿 x 轴进一步向下移动两个单位?矩阵使用一次后会自动重置吗? 正如我所说,当您对一组数据进行变换矩阵运算时,会发生矩阵乘法并将其存储回您开始使用的原始矩阵中。这不是一个连续的操作。您有一个像素顶点 A,并且您将其向任意方向平移 2 个单位,您将看到绘制到屏幕上的原始像素(顶点)的平移结果。

以上是关于应用转换时,OpenGL 是不是会更改内存中的顶点?的主要内容,如果未能解决你的问题,请参考以下文章

openGL中的坐标系

Android OpenGL 1.1 FBO 和 VBO 支持

opengl vbo 纹理

窗口调整大小后将鼠标位置转换为 2D openGL 中的世界坐标

将 OpenGL 绘制列表转换为顶点数组或 VBO

OpenGL 顶点缓冲