如何在 OpenGL 中加载和渲染可能包含三角形、四边形或 N-Gons 的 OBJ 文件?
Posted
技术标签:
【中文标题】如何在 OpenGL 中加载和渲染可能包含三角形、四边形或 N-Gons 的 OBJ 文件?【英文标题】:How can I load and render an OBJ file that may include Triangles, Quads, or N-Gons in OpenGL? 【发布时间】:2020-06-24 21:28:30 【问题描述】:我有以下 c++ 代码来加载目标文件,至少是顶点和顶点索引。
bool ObjMeshImporter::from_file(const std::string& filepath, nelems::Mesh* pMesh)
std::ifstream in(filepath, std::ios::in);
if (!in)
return false;
std::vector<glm::vec3> t_vert;
std::string line;
while (std::getline(in, line))
if (line.substr(0, 2) == "v ")
// read vertices
std::istringstream s(line.substr(2));
glm::vec3 v; s >> v.x; s >> v.y; s >> v.z;
// Add to temporary vertices before indexing
t_vert.push_back(v);
else if (line.substr(0, 2) == "f ")
// TODO: Store UVs and Normals
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
int count_found = sscanf_s(line.substr(2).c_str(),
"%d/%d/%d %d/%d/%d %d/%d/%d\n",
&vertexIndex[0], &uvIndex[0], &normalIndex[0],
&vertexIndex[1], &uvIndex[1], &normalIndex[1],
&vertexIndex[2], &uvIndex[2], &normalIndex[2]);
if (count_found != 9)
return false;
pMesh->add_vertex_index(vertexIndex[0]-1);
pMesh->add_vertex_index(vertexIndex[1]-1);
pMesh->add_vertex_index(vertexIndex[2]-1);
// Now use the indices to create the concrete vertices for the mesh
for (auto v_idx : pMesh->GetVertexIndices())
glm::vec3 vertex = t_vert[v_idx];
pMesh->add_vertex(vertex);
return true;
它对于像这样的对象(Blender icosphere)非常有效:
这个模型是由三角形组成的。
但是当我加载一个有四边形的时,它不起作用:
当然,因为这是我的面部渲染方法:
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)mVertexIndices.size());
所以我知道,我必须扩展解析器,并为“f”中的每一行检查我有多少索引,最好存储一个 VFace 类,它知道一个面由多少个顶点组成 - 好的.
所以我会将带有 tris 的面渲染为 GL_TRIANGLE,将带有四边形的面渲染为 GL_QUADS...但是 NGONS 呢?以及如何渲染线条?
编辑:我看到有 GL_POLYGON。但是我必须为这些创建单独的顶点缓冲区吗?
【问题讨论】:
这能回答你的问题吗? How can I parse a simple .obj file into triangles? 不,我想用三角形、四边形或 ngons 渲染面。 不熟悉 c++,但我注意到您调用 (GLsizei)mVertexIndices.size() 但使用 glDrawArrays。那么它不应该是一个 glDrawElements 调用吗?或者 GLsize 应该指向顶点索引的大小而不是索引。 @Kempie :我不这么认为,因为那样我需要一个 GL_ELEMENT_ARRAY 缓冲区 【参考方案1】:不,我想用三角形、四边形或 ngons 渲染面。
我认为这个问题没有合理的解决方案。 现代图形硬件仅渲染 3 种类型的图元:点、线段和三角形。所以直接的答案是你必须从任何非三角形几何体(quads、n-polygons、B-Spline > 曲面、分析曲面等)。这可以通过您自己的代码或使用现有库来完成(后者是首选,因为分割多边形并不是那么简单——我已经看到几个实现通常工作,但在某些 OBJ 文件的一个或另一个用例中失败)。
现代硬件仅在三角形上运行是有充分理由的 - 它们可用于渲染任何其他几何图形,它们完全并行化(与元素中节点数量可变的几何图形相比),这使得硬件更简单。
以下是在 OpenGL 中使用 cmets 渲染非三角形的一些方法:
GL_QUADS
。 已弃用,自 OpenGL 3.0 起。不过应该注意的是,根据various publications 和讨论,至少 NVIDIA 和可能的 AMD 硬件实际上仍然对这些原语提供硬件加速支持。您将需要两个不同的绘制通道来渲染与四边形混合的三角形(例如,每种基本类型的拆分索引,尽管您可能仍然共享公共顶点缓冲区)。如果您曾经在应用程序中使用过GL_QUADS
,您可能还会注意到传递给图形硬件的非平面四边形被拆分为三角形,并且不同的 GPU 供应商以不同的顺序执行此操作(例如生成不同的三角形对)。
GL_POLYGON
。自 OpenGL 3.0 起也已弃用。这个原语在 OpenGL 中存在,当时顶点处理不是由图形硬件完成,而是由 CPU 完成。所以这个可能从来没有任何真正的硬件加速——OpenGL驱动程序只是以一种缓慢而低效的方式将多边形分割成三角形。 GL_POLYGON
对 OBJ 文件几乎无用还有另一个原因 - GL_POLYGON
仅适用于 凸 多边形(可以简单地拆分为三角形),而 OBJ 文件通常包含 concave强>多边形。您可能会在 Internet 上找到一些要求多边形凸面的 OBJ 规范,而另一些则根本不指定多边形细节 - 但实际上您不能忽略这一点,因为现实世界的 OBJ 文件确实具有复杂的多边形(只要您关心读取任意文件) .
GL_PATCHES
代表 Tessellation Shaders。这些是为固定大小的补丁的硬件加速三角测量而设计的,这是一种用于显示平滑表面的强大机制。然而,这些与 OBJ 文件中的 n 多边形无关,因为为曲面细分着色器定义几何图形需要遵循非常不同的模式。
Geometry Shaders 的邻接原语。像GL_TRIANGLES_ADJACENCY
这样的基元提供了关于三角形周围的附加信息,但它们也与 OBJ 文件中的 n 多边形没有直接关系。与镶嵌着色器不同,几何着色器允许激发具有任意指定节点位置的可变数量的新三角形。这在技术上允许在几何着色器中生成任意 n 多边形分割成三角形。尽管要实现这一点,几何数据必须不是在主顶点数据中提供,而是通过附加结构(如 TBO 或类似结构)提供。实际上,这种方法实施起来毫无意义(只要您不进行一些研究),因为几何着色器被证明对于类似曲面细分的任务非常低效,导致非常性能非常差。
计算着色器。这些可以用于任意任务,包括使用自定义数据结构将多边形分割成三角形和/或渲染它们,但这不太可能是渲染多边形的可靠方法 - 也是研究主题而不是实际解决方案。
李>【讨论】:
好的,但是 Blender 是怎么做到的呢?它使用四边形、NGons、Tris 渲染对象......一切 我不知道 Blender 是如何渲染的,但我相信它会分离逻辑几何定义并通过专用处理将所有内容渲染为三角形。数据模型可能支持多边形、双浮点精度、具有相同位置但不同法线的共享顶点 - 一切对数据处理有意义,但图形硬件不支持直接渲染。 是的,我想就是这样......但是如何在不显示三角形的情况下进行渲染?以上是关于如何在 OpenGL 中加载和渲染可能包含三角形、四边形或 N-Gons 的 OBJ 文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何以与 OpenGL 中的点精灵相同的方式渲染屏幕对齐的矩形