我有一个提供3D网格的现有系统。提供的数据是具有3个分量(x,y,z)和索引列表的顶点坐标数组。 问题是索引列表是四元组的连续数组 我知道所有的四边形都有相同的绕线顺序(逆时针),但我没有关于四边形的更多信息。我对他们的关系或邻接并不了解。
由于我想使用核心配置文件进行渲染,因此我无法使用GL_QUAD
原始类型。我必须将四边形转换为tringles。
当然,四元索引数组可以很容易地转换为三角形索引数组:
std::vector<unsigned int> triangles;
triangles.reserve( no_of_indices * 6 / 4 );
for ( int i = 0; i < no_of_indices; i += 4 )
{
int tri[] = { quad[i], quad[i+1], quad[i+2], quad[i], quad[i+2], quad[i+3] };
triangles.insert(triangles.end(), tri, tri+6 );
}
如果必须只做一次,那就是解决方案。但是,meash数据并不是静态的。数据可以动态变化。 数据不会每次都连续变化,但数据会不可预测地随机变化。
另一个简单的解决方案是创建一个顶点数组对象,该对象直接引用带有四边形的元素数组缓冲区,并在具有GL_TRIANGLE_FAN
基元类型的循环中绘制它们:
for ( int i = 0; i < no_of_indices; i += 4 )
glDrawElements( GL_TRIANGLE_FAN, 4, GL_UNSIGNED_INT, (void*)(sizeof(unsigned int) * 4) );
但我希望有更好的解决方案。我正在寻找一种可能用一次绘制调用绘制四边形,或者将四边形转换为GPU上的三角形。
答案 0 :(得分:5)
如果该操作仅需执行一次,则可以解决。但是网格数据不是静态的。
网格数据可能是动态的,但该列表的拓扑相同。每4个顶点是一个四边形,因此每4个顶点代表三角形(0,1,2)和(0,2,3)。
因此,您可以构建任意大的 static 索引缓冲区,其中包含这些数字不断增加的系列(0、1、2、0、2、3、4、5、6、4、6 ,7等)。您甚至可以use baseVertex
rendering使它们偏移以使用相同的索引缓冲区渲染不同的四边形序列。
我的建议是使索引缓冲区使用GLushort
作为索引类型。这样,您的索引数据每象限仅占用12个字节。使用短裤可以在一个绘图命令中提供16384个四边形的限制,但是您可以重用相同的索引缓冲区以baseVertex
渲染来绘制多个四边形:
constexpr GLushort batchSize = 16384;
constexpr unsigned int vertsPerQuad = 6;
void drawQuads(GLuint quadCount)
{
//Assume VAO is set up.
int baseVertex = 0;
while(quadCount > batchSize)
{
glDrawElementsBaseVertex(GL_TRIANGLES, batchSize * vertsPerQuad, GL_UNSIGNED_SHORT, 0, baseVertex * 4);
baseVertex += batchSize;
quadCount -= batchSize;
}
glDrawElementsBaseVertex(GL_TRIANGLES, quadCount * vertsPerQuad, GL_UNSIGNED_SHORT, 0, baseVertex * 4);
}
如果您希望索引数据少一点,可以使用primitive restart indices。这使您可以指定一个索引来表示“重新启动原语”。这样,您就可以使用GL_TRIANGLE_STRIP
基元并将基元分解为多个片段,而同时仍然只有一个draw调用。因此,您有5个索引,而不是每个四边形6个索引,第5个是重新启动索引。因此,现在您的GLushort
索引每象限仅占用10个字节。但是,batchSize
现在必须为16383,因为保留索引0xFFFF以便重新启动。并且vertsPerQuad
必须为5。
当然,baseVertex渲染在原始重启时也可以正常工作,因此上述代码也可以工作。
答案 1 :(得分:0)
首先,我想提一下,这是不这个我想自己回答的问题,但我想提供我目前解决这个问题的方法。 这意味着,我仍在寻找&#34;&#34;&#34;解决方案,完全可以接受的解决方案。
在我的解决方案中,我决定使用Te I绘制大小为4的补丁:
glPatchParameteri( GL_PATCH_VERTICES, self.__patch_vertices )
glDrawElements( GL_PATCHES, no_of_indices, GL_UNSIGNED_INT, 0 )
Tessellation Control Shader有默认行为。补丁数据直接从顶点着色器调用传递到曲面细分基元生成。因此可以完全省略。
Tessellation Evaluation Shader使用四边形补丁(quads
)创建2个三角形:
#version 450
layout(quads, ccw) in;
in TInOut
{
vec3 pos;
} inData[];
out TInOut
{
vec3 pos;
} outData;
uniform mat4 u_projectionMat44;
void main()
{
const int inx_map[4] = int[4](0, 1, 3, 2);
float i_quad = dot( vec2(1.0, 2.0), gl_TessCoord.xy );
int inx = inx_map[int(round(i_quad))];
outData.pos = inData[inx].pos;
gl_Position = u_projectionMat44 * vec4( outData.pos, 1.0 );
}
另一种灵魂就是使用Geometry Shader。输入的原始类型lines_adjacency
提供了4个顶点,可以映射到2个三角形(triangle_strip
)。当然这似乎是一个黑客,因为lines adjacency
与四元组完全不同,但无论如何都可以。
glDrawElements( GL_LINES_ADJACENCY, no_of_indices, GL_UNSIGNED_INT, 0 );
几何着色器:
#version 450
layout( lines_adjacency ) in;
layout( triangle_strip, max_vertices = 4 ) out;
in TInOut
{
vec3 pos;
} inData[];
out TInOut
{
vec3 col;
} outData;
uniform mat4 u_projectionMat44;
void main()
{
const int inx_map[4] = int[4](0, 1, 3, 2);
for ( int i=0; i < 4; ++i )
{
outData.pos = inData[inx_map[i]].pos;
gl_Position = u_projectionMat44 * vec4( outData.pos, 1.0 );
EmitVertex();
}
EndPrimitive();
}