gpt4 book ai didi

opengl - 使用纹理缓冲区对象 (OpenGL) 在图形应用程序中管理矩阵的有效方法

转载 作者:行者123 更新时间:2023-12-02 08:58:25 24 4
gpt4 key购买 nike

我正在使用 OpenGL 和 GLSL 开发一个小型 3D 引擎。我目前使用纹理缓冲区对象 (TBO) 来存储我的所有矩阵(项目、 View 、模型和阴影矩阵)。但我对图形引擎中处理矩阵的最佳方法(我的意思是最有效的方法)进行了一些研究,但没有成功。目标是将最多的矩阵存储到最少数量的 TBO 中,并发生最少的状态更改以及 GPU 和客户端代码 (glBufferSubData) 之间的最少交换。

我提出了两种不同的方法(各有优缺点):

这是一个场景示例:

1 个摄像头(1 个 ProjMatrix、1 个 ViewMatrix)5个盒子(5个ModelMatrix)

这是我使用的简单顶点着色器的示例:

#version 400

/*
** Vertex attributes.
*/
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec2 VertexTexture;

/*
** Uniform matrix buffer.
*/
uniform samplerBuffer matrixBuffer;

/*
** Matrix buffer offset.
*/
uniform int MatrixBufferOffset;

/*
** Output variables.
*/
out vec2 TexCoords;

/*
** Returns matrix4x4 from texture cache.
*/
mat4 Get_Matrix(int offset)
{
return (mat4(texelFetch(
matrixBuffer, offset), texelFetch(
matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2),
texelFetch(matrixBuffer, offset + 3)));
}

/*
** Vertex shader entry point.
*/
void main(void)
{
TexCoords = VertexTexture;
{
mat4 ModelViewProjMatrix = Get_Matrix(
MatrixBufferOffset);
gl_Position = ModelViewProjMatrix * VertexPosition;
}
}

1)我目前使用的方法:在我的顶点着色器中,我使用ModelViewProjMatrix(光栅化(gl_Position)所需)、ModelViewMatrix(用于照明计算)和ModelMatrix。因此,为了避免顶点着色器中无用的计算,我决定存储 ModelViewProjMatrix、ModelViewMatrix 和 TBO 中内联的每个网格节点的 ModelMatrix,如下所示:

TBO = {[ModelViewProj_Box1][ModelView_Box1][Model_Box1]|[ModelViewProj_Box2]...}

优点:我不需要为每个顶点着色器计算乘积 Proj * View * Model(例如 ModelViewProj)(矩阵是预先计算好的)。

缺点:如果移动相机,我需要更新所有 ModelViewProj 和 ModelView 矩阵。因此,有很多信息需要更新。

2)我想到了另一种方式,我认为更有效:存储一次投影矩阵,一次 View 矩阵,最后再次存储每个盒子场景节点模型矩阵:

TBO = {[ProjMatrix][ViewMatrix][ModelMatrix_Box1][ModelMatrix_Box2]...}

所以我的顶点着色器将如下所示:

#version 400

/*
** Vertex attributes.
*/
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec2 VertexTexture;

/*
** Uniform matrix buffer.
*/
uniform samplerBuffer matrixBuffer;

/*
** Matrix buffer offset.
*/
uniform int MatrixBufferOffset;

/*
** Output variables.
*/
out vec2 TexCoords;

/*
** Returns matrix4x4 from texture cache.
*/
mat4 Get_Matrix(int offset)
{
return (mat4(texelFetch(
matrixBuffer, offset), texelFetch(
matrixBuffer, offset + 1), texelFetch(matrixBuffer, offset + 2),
texelFetch(matrixBuffer, offset + 3)));
}

/*
** Vertex shader entry point.
*/
void main(void)
{
TexCoords = VertexTexture;
{
mat4 ProjMatrix = Get_Matrix(MatrixBufferOffset);
mat4 ViewMatrix = Get_Matrix(MatrixBufferOffset + 4);
mat4 ModelMatrix = Get_Matrix(MatrixBufferOffset + 8);

gl_Position = ProjMatrix * ViewMatrix * ModelMatrix * VertexPosition;
}
}

优点:TBO 包含所用矩阵的确切数量。更新具有很强的针对性(如果我移动相机,我只会更新 View 矩阵,如果我调整窗口大小,我只会更新投影矩阵,最后,如果对象正在移动,则只会更新其模型矩阵)。

缺点:我需要计算顶点着色器 ModelViewProjMatrix 中的每个顶点。另外,如果场景由大量对象组成,每个对象都拥有不同的模型矩阵,我可能需要创建一个新的 TBO。因此,我将丢失项目/ View 矩阵信息,因为我将无法连接到正确的 TBO,这将我们带到我的第三种方法。

3) 将投影和 View 矩阵存储在 TBO 中,并将所有其他模型矩阵存储在另一个或其他 TBO 中,如下所示:

TBO_0 = {[ProjMatrix][ViewMatrix]}TBO_1 = {[ModelMatrix_Box1][ModelMatrix_Box2]...}

您觉得我的 3 种方法怎么样?哪一个最适合您?

预先非常感谢您的帮助!

最佳答案

解决方案 3 是大多数引擎所做的,只不过它们使用统一缓冲区(常量缓冲区)而不是纹理缓冲区。此外,它们通常不会将所有模型矩阵分组在同一个缓冲区中,它们通常按对象类型分组(因为相同的对象通过实例化一次绘制),有时按更新频率分组(对象从不移动的都在同一个缓冲区中,因此永远不需要更新)。

glBufferSubData 也可能非常慢;更新缓冲区通常比绑定(bind)不同的缓冲区慢,因为所有同步都发生在驱动程序内部。关于这一点,有一个很好的书籍章节,可以在 Internet 上免费获得,名为“OpenGL Insights:异步缓冲区传输”(Google 即可找到它)。

编辑:nvidia article您在评论中链接的内容非常有趣。他们建议使用 glMultiDrawElements 一次进行多次绘制调用(这是主要技巧,其他一切都是因为这个决定)。这可以大大减少驱动程序中的 CPU 工作,但这也意味着提供绘制对象所需的所有数据要复杂得多:您必须为矩阵/ Material 值构建/更新更大的缓冲区,并且,您还需要使用诸如无绑定(bind)纹理之类的东西才能为每个对象提供不同的纹理。所以,有趣,但更复杂。

只有当您想要绘制许多不同对象时,glMultiDrawElements才重要。他们的示例有 68000-98000 个不同的网格,这确实很多。例如,在游戏中,通常有许多相同对象的实例,但只有几百个不同的对象(最多)。最终,这取决于您的 3D 引擎需要渲染什么。

关于opengl - 使用纹理缓冲区对象 (OpenGL) 在图形应用程序中管理矩阵的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29672810/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com