呈现多个对象的最佳方式

我有一个场景,包括一个玩家对象,一个平台,一个敌人,一个背景。 目前,这是我的渲染function的样子:

void Sprite::Render() { glUseProgram(m_Program); glActiveTexture(GL_TEXTURE0); // Background glBindVertexArray(BackgroundVAO); glBindTexture(GL_TEXTURE_2D, m_Textures[1]); glUniform1i(glGetUniformLocation(m_Program, "Texture1"), 0); m_ProjectionMatrix = m_Camera.ViewToWorldMatrix(); m_TransformationMatrix = m_ProjectionMatrix; m_TransformationMatrixLoc = glGetUniformLocation(m_Program, "TransformationMatrix"); glUniformMatrix4fv(m_TransformationMatrixLoc, 1, GL_FALSE, &m_TransformationMatrix[0][0]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); // Enemy glBindVertexArray(EnemyVAO); glBindTexture(GL_TEXTURE_2D, m_Textures[2]); glUniform1i(glGetUniformLocation(m_Program, "Texture3"), 0); m_ProjectionMatrix = glm::translate(glm::mat4(), glm::vec3(EnemyX, EnemyY, 0.0f)) * m_Camera.ViewToWorldMatrix(); m_TransformationMatrix = m_ProjectionMatrix; m_TransformationMatrixLoc = glGetUniformLocation(m_Program, "TransformationMatrix"); glUniformMatrix4fv(m_TransformationMatrixLoc, 1, GL_FALSE, &m_TransformationMatrix[0][0]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); // Platform One glBindVertexArray(PlatformVAO); glBindTexture(GL_TEXTURE_2D, m_Textures[3]); glUniform1i(glGetUniformLocation(m_Program, "Texture4"), 0); m_ProjectionMatrix = glm::translate(glm::mat4(), glm::vec3(0.0f, -0.5f, 0.0f)) * m_Camera.ViewToWorldMatrix(); m_TransformationMatrix = m_ProjectionMatrix; m_TransformationMatrixLoc = glGetUniformLocation(m_Program, "TransformationMatrix"); glUniformMatrix4fv(m_TransformationMatrixLoc, 1, GL_FALSE, &m_TransformationMatrix[0][0]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); // Player glBindVertexArray(PlayerVAO); glBindTexture(GL_TEXTURE_2D, m_Textures[0]); glUniform1i(glGetUniformLocation(m_Program, "Texture2"), 0); m_ProjectionMatrix = glm::translate(glm::mat4(), glm::vec3(PlayerX, PlayerY, 0.0f)) * m_Camera.ViewToWorldMatrix(); m_TransformationMatrix = m_ProjectionMatrix; m_TransformationMatrixLoc = glGetUniformLocation(m_Program, "TransformationMatrix"); glUniformMatrix4fv(m_TransformationMatrixLoc, 1, GL_FALSE, &m_TransformationMatrix[0][0]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindVertexArray(0); } 

正如你所看到的,这是不必要的复杂。 如果我想画两个或更多的敌人,或者四个或更多的平台,那么它会变得非常大! 我的问题是,我怎样才能使这个更小? 我更喜欢能够在我的main.cpp中做这样的事情:Sprite.Render(Player); Sprite.Render(EnemyOne); 等等…

期待阅读您的提示,谢谢!

这个archtypal解决scheme是一个场景图 。 对于5到10个对象来说可能有点复杂,但对于像第一人称射击游戏这样的复杂游戏来说,它基本上是事实上的标准。

场景图的基本目标是将描述应该做什么的数据与执行该操作的代码分开。 在包含描述场景的数据的graphics中创建一组“节点”,然后您有访问者“遍历”graphics以执行openGL绘图命令。 从历史上看,由场景图提供的分区被发现对许多许多游戏来说是非常理想的。 像Unity这样的工具包很大程度上依赖于它。

在这样的场景图中,可以有一个描述如何渲染玩家的节点。 将变换matrix与对象分离也是很典型的,所以你可能有一个变换节点(玩家位置),你的玩家几何graphics和纹理作为一个子节点。

场景图显然比这更复杂(我还是不完全了解OGL的场景图),但是它运行得很好,几乎每个人都这样做。

你的代码非常具体,并且过于明确。 这也不灵活。

考虑重构你的代码:

  1. 可重用。
  2. 更通用。
  3. 尽可能重复使用数据。

让我解释:

我们可以说如何呈现给定的游戏实体?

为了呈现每个实体(在你的情况),你需要:

  1. 投影matrix(每个实体独有)
  2. 转换(每个实体都是唯一的)
  3. 着色器程序(可重用,但可能是唯一的)
  4. 表示精灵的纹理(可能是唯一的)
  5. 统一的变换位置(如果重复使用相同的着色器,则可重用)
  6. 您的四边形的顶点数量和网格手柄,将被纹理化(可重复使用,但不能保证在将来是唯一的)

为了解决这个问题,我们可以使用面向对象的原则封装graphics数据:

  • 处理所有着色器函数的ShaderProgram类。
  • 存储网格句柄和顶点数的网格类
  • 一个Texture类,它存储纹理句柄。
  • 最后,一个外观类,其中存储的其他人。

你的代码会变成这样:

 void renderAll() { for (auto entity: m_entities) { entity->getAppearance()->getShader()->activate(); entity->getAppearance()->getShader()->setTransform("TransformationMatrix",entity->getAppearance()->getTransform() ); entity->getAppearance()->getTexture()->Bind(); entity->getAppearance()->getMesh()->Bind(); entity->getAppearance()->getMesh()->Draw(); } } 

你现在所有的代码现在隐藏在这些类中。 这样做将允许您从文件数据中提供新的网格,并使您的渲染引擎更加灵活。 用这种方法,你只需要编写一段代码,然后根据需要重复使用代码。