C++ OpenGL 网格渲染
C++ OpenGL mesh rendering
我知道互联网上有很多关于此的资源,但它们似乎对我帮助不大。
我想达到的效果:
我正在从数据中烘焙一个网格,该数据将顶点存储在 vector<Vector3>
.
中
(Vector3
是一个 sctruct
包含 float x, y, z
)
它将三角形存储在 map<int, vector<int>>
(地图的关键是子网格和 vector<int>
三角形)
vector<Vector2>
内的紫外线
(Vector2
是包含 float x, y
的 struct
)
vector<Color>
中的颜色值
(颜色值像 uv 一样应用于顶点)
现在我想编写一个代码来读取该数据并将其以最高性能绘制到屏幕上
我得到了什么:
static void renderMesh(Mesh mesh, float x, float y, float z) {
if (mesh.triangles.empty()) return;
if (mesh.vertices.empty()) return;
if (mesh.uvs.empty()) return;
glColor3f(1, 1, 1);
typedef std::map<int, std::vector<int>>::iterator it_type;
for (it_type iterator = mesh.triangles.begin(); iterator != mesh.triangles.end(); iterator++) {
int submesh = iterator->first;
if (submesh < mesh.textures.size()) glBindTexture(GL_TEXTURE_2D, mesh.textures[submesh].id);
else glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < iterator->second.size(); i += 3) {
int t0 = iterator->second[i + 0];
int t1 = iterator->second[i + 1];
int t2 = iterator->second[i + 2];
Vector3 v0 = mesh.vertices[t0];
Vector3 v1 = mesh.vertices[t1];
Vector3 v2 = mesh.vertices[t2];
Color c0 = mesh.vertexColors[t0];
Color c1 = mesh.vertexColors[t1];
Color c2 = mesh.vertexColors[t2];
Vector2 u0 = mesh.uvs[t0];
Vector2 u1 = mesh.uvs[t1];
Vector2 u2 = mesh.uvs[t2];
glBegin(GL_TRIANGLES);
glColor4f(c0.r / 255.0f, c0.g / 255.0f, c0.b / 255.0f, c0.a / 255.0f); glTexCoord2d(u0.x, u0.y); glVertex3f(v0.x + x, v0.y + y, v0.z + z);
glColor4f(c1.r / 255.0f, c1.g / 255.0f, c1.b / 255.0f, c1.a / 255.0f); glTexCoord2d(u1.x, u1.y); glVertex3f(v1.x + x, v1.y + y, v1.z + z);
glColor4f(c2.r / 255.0f, c2.g / 255.0f, c2.b / 255.0f, c2.a / 255.0f); glTexCoord2d(u2.x, u2.y); glVertex3f(v2.x + x, v2.y + y, v2.z + z);
glEnd();
glColor3f(1, 1, 1);
}
}
}
问题:
我发现我渲染的方式不是最好的方式,你可以使用 glDrawArrays
获得更高的性能(我认为它被称为)。
你能帮我重写我的代码以适应 glDrawArrays 吗,因为到目前为止我在互联网上找到的东西对我帮助不大。
谢谢,如果需要更多信息,请询问。
不推荐使用 glBegin
和 glEnd
等函数。像glDrawArrays这样的函数有更好的性能,但使用起来稍微复杂一些。
glBegin
渲染技术的问题是每次你想画东西的时候你必须一个一个地传达每个顶点。如今,显卡可以非常快速地渲染数千个顶点,但是如果您一个一个地渲染,无论您的显卡性能如何,渲染都会变得卡顿。
glDrawArrays
的主要优点是您只需初始化一次数组,然后一次调用即可绘制它。所以首先,您需要在程序开始时为每个属性填充一个数组。在您的情况下:位置、颜色和纹理坐标。它必须是浮点数组,像这样:
std::vector<float> vertices;
std::vector<float> colors;
std::vector<float> textureCoords;
for (int i = 0; i < iterator->second.size(); i += 3) {
int t0 = iterator->second[i + 0];
int t1 = iterator->second[i + 1];
int t2 = iterator->second[i + 2];
vertices.push_back(mesh.vertices[t0].x);
vertices.push_back(mesh.vertices[t0].y);
vertices.push_back(mesh.vertices[t0].z);
vertices.push_back(mesh.vertices[t1].x);
vertices.push_back(mesh.vertices[t1].y);
vertices.push_back(mesh.vertices[t1].z);
vertices.push_back(mesh.vertices[t2].x);
vertices.push_back(mesh.vertices[t2].y);
vertices.push_back(mesh.vertices[t2].z);
// [...] Same for colors and texture coords.
}
然后,在另一个设置为显示的函数中,你可以使用这些数组来绘制它:
// Enable everything you need
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Set your used arrays
glVertexPointer(3, GL_FLOAT, 0, vertices.data());
glColorPointer(4, GL_FLOAT, 0, colors.data());
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords.data());
// Draw your mesh
glDrawArrays(GL_TRIANGLES, 0, size); // 'size' is the number of your vertices.
// Reset initial state
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
当然,您必须启用您想要使用的其他属性,例如纹理或混合。
注意:
如果您想了解性能,还有其他函数使用索引来减少所用数据的大小,例如 glDrawElements。
还有其他更高级的 OpenGL 技术,可让您通过将数据直接保存在显卡内存上来提高性能,例如 Vertex Buffer Objects。
我知道互联网上有很多关于此的资源,但它们似乎对我帮助不大。
我想达到的效果:
我正在从数据中烘焙一个网格,该数据将顶点存储在 vector<Vector3>
.
中
(Vector3
是一个 sctruct
包含 float x, y, z
)
它将三角形存储在 map<int, vector<int>>
(地图的关键是子网格和 vector<int>
三角形)
vector<Vector2>
内的紫外线
(Vector2
是包含 float x, y
的 struct
)
vector<Color>
中的颜色值
(颜色值像 uv 一样应用于顶点)
现在我想编写一个代码来读取该数据并将其以最高性能绘制到屏幕上
我得到了什么:
static void renderMesh(Mesh mesh, float x, float y, float z) {
if (mesh.triangles.empty()) return;
if (mesh.vertices.empty()) return;
if (mesh.uvs.empty()) return;
glColor3f(1, 1, 1);
typedef std::map<int, std::vector<int>>::iterator it_type;
for (it_type iterator = mesh.triangles.begin(); iterator != mesh.triangles.end(); iterator++) {
int submesh = iterator->first;
if (submesh < mesh.textures.size()) glBindTexture(GL_TEXTURE_2D, mesh.textures[submesh].id);
else glBindTexture(GL_TEXTURE_2D, 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (int i = 0; i < iterator->second.size(); i += 3) {
int t0 = iterator->second[i + 0];
int t1 = iterator->second[i + 1];
int t2 = iterator->second[i + 2];
Vector3 v0 = mesh.vertices[t0];
Vector3 v1 = mesh.vertices[t1];
Vector3 v2 = mesh.vertices[t2];
Color c0 = mesh.vertexColors[t0];
Color c1 = mesh.vertexColors[t1];
Color c2 = mesh.vertexColors[t2];
Vector2 u0 = mesh.uvs[t0];
Vector2 u1 = mesh.uvs[t1];
Vector2 u2 = mesh.uvs[t2];
glBegin(GL_TRIANGLES);
glColor4f(c0.r / 255.0f, c0.g / 255.0f, c0.b / 255.0f, c0.a / 255.0f); glTexCoord2d(u0.x, u0.y); glVertex3f(v0.x + x, v0.y + y, v0.z + z);
glColor4f(c1.r / 255.0f, c1.g / 255.0f, c1.b / 255.0f, c1.a / 255.0f); glTexCoord2d(u1.x, u1.y); glVertex3f(v1.x + x, v1.y + y, v1.z + z);
glColor4f(c2.r / 255.0f, c2.g / 255.0f, c2.b / 255.0f, c2.a / 255.0f); glTexCoord2d(u2.x, u2.y); glVertex3f(v2.x + x, v2.y + y, v2.z + z);
glEnd();
glColor3f(1, 1, 1);
}
}
}
问题:
我发现我渲染的方式不是最好的方式,你可以使用 glDrawArrays
获得更高的性能(我认为它被称为)。
你能帮我重写我的代码以适应 glDrawArrays 吗,因为到目前为止我在互联网上找到的东西对我帮助不大。
谢谢,如果需要更多信息,请询问。
不推荐使用 glBegin
和 glEnd
等函数。像glDrawArrays这样的函数有更好的性能,但使用起来稍微复杂一些。
glBegin
渲染技术的问题是每次你想画东西的时候你必须一个一个地传达每个顶点。如今,显卡可以非常快速地渲染数千个顶点,但是如果您一个一个地渲染,无论您的显卡性能如何,渲染都会变得卡顿。
glDrawArrays
的主要优点是您只需初始化一次数组,然后一次调用即可绘制它。所以首先,您需要在程序开始时为每个属性填充一个数组。在您的情况下:位置、颜色和纹理坐标。它必须是浮点数组,像这样:
std::vector<float> vertices;
std::vector<float> colors;
std::vector<float> textureCoords;
for (int i = 0; i < iterator->second.size(); i += 3) {
int t0 = iterator->second[i + 0];
int t1 = iterator->second[i + 1];
int t2 = iterator->second[i + 2];
vertices.push_back(mesh.vertices[t0].x);
vertices.push_back(mesh.vertices[t0].y);
vertices.push_back(mesh.vertices[t0].z);
vertices.push_back(mesh.vertices[t1].x);
vertices.push_back(mesh.vertices[t1].y);
vertices.push_back(mesh.vertices[t1].z);
vertices.push_back(mesh.vertices[t2].x);
vertices.push_back(mesh.vertices[t2].y);
vertices.push_back(mesh.vertices[t2].z);
// [...] Same for colors and texture coords.
}
然后,在另一个设置为显示的函数中,你可以使用这些数组来绘制它:
// Enable everything you need
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Set your used arrays
glVertexPointer(3, GL_FLOAT, 0, vertices.data());
glColorPointer(4, GL_FLOAT, 0, colors.data());
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords.data());
// Draw your mesh
glDrawArrays(GL_TRIANGLES, 0, size); // 'size' is the number of your vertices.
// Reset initial state
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
当然,您必须启用您想要使用的其他属性,例如纹理或混合。
注意:
如果您想了解性能,还有其他函数使用索引来减少所用数据的大小,例如 glDrawElements。
还有其他更高级的 OpenGL 技术,可让您通过将数据直接保存在显卡内存上来提高性能,例如 Vertex Buffer Objects。