提问人:izzy and simple 提问时间:11/6/2022 更新时间:11/6/2022 访问量:84
如何实现3D模型按不同指标渲染?[复制]
how to implement 3D model rendering By different indexes? [duplicate]
问:
我在 OpenGL 中渲染 3D 模型时遇到问题 - 问题是我无法通过单个索引缓冲区实现渲染
(我的意思是渲染:顶点的顶点索引,法线的正常索引,texcoord 的 texcoord 索引)
因此,目前我的程序不使用索引渲染 因为 glDrawElements - 意味着对于 VertexArrayObject 中的所有 VertexBufferObject,一个 ElementBufferObject 用于渲染 (实际上,创建了一个索引缓冲区,但它始终等于 0,1,2,3,4,...)
尽管此方法有效,但与使用多个索引缓冲区相比,它会花费大量视频卡内存
我附上了一张具有所需结果的图片 以及问题所在
问题 - 如何确保在绘制模型时使用不同的索引?
我尝试了很多方法,但没有得到想要的结果😥
答:
1赞
robthebloke
11/6/2022
#1
您有 3 种选择。
- 展平所有 3 个数组,并使用 glDrawArrays。这通常是最简单的选择。
struct Vertex {
float v[3];
float n[3];
float t[2];
};
std::vector<Vertex> flatten(
float V[], float N[], float T[],
uint32_t VI[], uint32_t NI[], uint32_t TI[],
uint32_t num_triangles)
{
std::vector<Vertex> combined(num_triangles * 3);
for(uint32_t i = 0; i < num_triangles * 3; ++i) {
combined[i].v[0] = V[ 3* VI[i] ];
combined[i].v[1] = V[ 3* VI[i] + 1 ];
combined[i].v[2] = V[ 3* VI[i] + 2 ];
combined[I].n[0] = N[ 3* NI[i] ];
combined[I].n[1] = N[ 3* NI[i] + 1 ];
combined[I].n[2] = N[ 3* NI[i] + 2 ];
combined[I].t[0] = N[ 2* TI[i] ];
combined[I].t[1] = N[ 2* TI[i] + 1 ];
}
return combined;
}
void draw(const std::vector<Vertex>& verts) {
glVertexAttribPointer(VERTS_IDX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), verts[0].v);
glVertexAttribPointer(NORMS_IDX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), verts[0].n);
glVertexAttribPointer(UVS_IDX, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), verts[0].t);
glDrawArrays(GL_TRIANGLES, 0, verts.size());
}
- 通过对现有索引进行哈希处理来生成一组新的索引。
struct Vertex {
float v[3];
float n[3];
float t[2];
};
struct IndexedMesh {
std::vector<Vertex> verts;
std::vector<uint32_t> indices;
};
// just going to use 21bits for each index.
uint64_t make_index_hash(uint32_t vi, uint32_t ni, uint32_t ti) {
assert(vi < 0x1FFFFF);
assert(ni < 0x1FFFFF);
assert(ti < 0x1FFFFF);
return ((uint64_t)vi) |
((uint64_t)vi) << 21 |
((uint64_t)vi) << 42;
}
IndexedMesh flatten(
float V[], float N[], float T[],
uint32_t VI[], uint32_t NI[], uint32_t TI[],
uint32_t num_triangles)
{
std::map<uint64_t, uint62_t> index_remap;
std::vector<Vertex> combined;
std::vector<uint32_t> combined_indices(num_triangles * 3);
for(uint32_t i = 0; i < num_triangles * 3; ++i) {
uint64_t hash = make_index_hash(VI[i], NI[i], TI[I]);
// check to see if this set of indices has been sued before
auto iter = index_remap.find(hash);
if(iter != index_remap.end() {
combined_indices[i] = iter->second;
} else {
index_remap.emplace(hash, combined.size());
Vertex v = {
{ V[ 3* VI[i] ], V[ 3* VI[i] + 1 ], V[ 3* VI[I] + 2 ] },
{ N[ 3* NI[i] ], N[ 3* NI[i] + 1 ], N[ 3* NI[I] + 2 ] },
{ T[ 2* TI[i] ], T[ 2* TI[i] + 1 ] }
};
combined.push_back(v);
}
}
return { combined, combined_indices };
}
void draw(const IndexedMesh& mesh) {
glVertexAttribPointer(VERTS_IDX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), mesh.verts[0].v);
glVertexAttribPointer(NORMS_IDX, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), mesh.verts[0].n);
glVertexAttribPointer(UVS_IDX, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), mesh.verts[0].t);
glDrawElements(GL_TRIANGLES, verts.size(), GL_UNSIGNED_INT, mesh.indices.data());
}
- 最后一个选项是使用着色器存储缓冲区在着色器中执行此操作。基本思想是将顶点/法线/uv 数组加载到着色器存储缓冲区中,并将索引集加载到传统的每个顶点参数中。
在着色器中,您可以直接为这些数组编制索引。(我已经有一段时间没有使用 glsl 了,所以这更像是一个一般提示,而不是可行的代码)。
我以前使用过这种方法,但无法确定性能影响是什么/是否(我认为选项 2 是性能最高的 tbh)
layout(std430, binding = 0) buffer VertsSSBO
{
vec3 verts[];
};
layout(std430, binding = 1) buffer NormsSSBO
{
vec3 norms[];
};
layout(std430, binding = 2) buffer UVsSSBO
{
vec2 uvcoords[];
};
// the indices are stored in vertex buffers,
// and bound with glVertexAttribPointer
in uint vs_vertex_index;
in uint vs_normal_index;
in uint vs_uv_index;
// outputs to fragment shader
out vec4 fs_normal;
out vec2 fs_uv;
uniform mat4 vs_mvp; ///< the modelview-projection matrix
void main() {
// grab the elements from the shader storage buffers
vec4 v = vec4(verts[vs_vertex_index], 1.0);
vec4 n = vec4(norms[vs_normal_index], 0.0);
vec2 t = uvcoords[vs_normal_index];
// now transform and output as you would usually.
gl_Position = vs_mvp * v;
fs_normal = vs_mvp * n;
fs_uv = t;
}
评论