【问题标题】:How to Draw OpenMesh using OpenGL如何使用 OpenGL 绘制 OpenMesh
【发布时间】:2020-07-22 22:13:17
【问题描述】:

我正在做一个项目,我正在使用 OpenMesh 读取 stlobj 文件并使用openGL。 我一直在做以下事情,

#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/IO/MeshIO.hh>

OpenMesh::TriMesh_ArrayKernelT<> mesh;

std::vector<point> vertices;
std::vector<point> normals;

void readMesh(std::string file)
{
    OpenMesh::IO::read_mesh(mesh, file);

    mesh.requestFaceNormals();
    mesh.request_vertex_normals();
    mesh.updateNormals();

    vertices.clear();
    normals.clear();

    for (auto face : mesh.faces())
    {
        for (auto vertex : mesh.fv_range(face))
        {
            auto point = mesh.point(vertex);
            auto normal = mesh.normal(face);

            vertices.push_back(point);
            normals.push_back(normal);
        }
    }

    mesh.releaseFaceNormals();
    mesh.releaseVertexNormals();
}

在绘制时,我只需像这样将verticesnormals 向量传递给顶点着色器

void paint()
{
    glSetAttributeArray(0, vertices.data());
    glSetAttributeArray(1, normals.data());
    glDrawArrays(GL_TRIANGLES, 0, vertices.length());
}

顶点着色器如下所示:

attribute vec3 position;
attribute vec3 normal;

uniform mat4 modelViewMatrix;

void main(void)
{
    vec4 color = vec4(0.25, 0.25, 0.25, 0.0);

    vec4 P = vec4(position, 0);
    vec4 N = vec4(normal, 0);

    vec3 L = vec3(20, 20, 20) - position;
    vec3 V = -position;
    N = normalize(N);
    L = normalize(L);
    V = normalize(V);
    vec3 R = reflect(-L, vec3(N));
    vec3 diffuse = max(dot(vec3(N), L), 0.0) * color.rgb;
    vec3 specular = pow(max(dot(R, V), 0.0), 0.2) * vec3(0.1, 0.1, 0.1);
    color = vec4(color.a * (ambient + diffuse + specular), color.a);
    color = clamp(color, 0.0, 1.0);

    gl_Color = color;
    gl_Position = modelViewMatrix * P;
}

片段着色器是:

void main(void)
{
    gl_FragColor = gl_Color;
}

这会产生非常好的结果,但是将顶点和法线的另一个副本存储在另一个位置(normalsvertices)以便能够绘制网格的想法看起来非常违反直觉。

我想知道是否可以使用 openGL 缓冲区和 openMesh 来优化它。我一直在搜索有关此主题的任何内容,但一无所获。

【问题讨论】:

  • 换句话说,我怎样才能消除对verticesnormal 向量的需求?

标签: c++ opengl openmesh


【解决方案1】:

Vertex Specification。您可以为顶点坐标和正常顶点创建 2 个Vertex Buffer Object

GLuint vbos[2];
glGenBuffers(2, vbos);
glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(normals[0]), normals.data(), GL_STATIC_DRAW);

如果您使用 OpenGL 3.0 或更高版本,则可以指定 Vertex Array Object 并声明顶点规范:

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

当你想绘制网格时,绑定VAO就足够了:

glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, vertices.length());

如果您使用 OpenGL 2.0,则无法创建 VAO,因此您必须在绘制网格之前指定通用顶点属性数据的数组:

glBindBuffer(GL_ARRAY_BUFFER, vbos[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, vbos[1]);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, vertices.length());

另外请注意,属性索引不保证为 0 和 1。属性索引可以是任意数字。

如果您使用 GLSL 3.30 版,则可以通过 Layout Qualifier 在着色器代码中设置属性索引。
无论如何,您可以在链接程序之前通过glBindAttribLocation 定义属性索引,或者在链接程序之后通过glGetAttribLocation 检索属性索引。

【讨论】:

  • 可能我无法正确解决这个问题,但我想说的是:我怎样才能消除对 verticesnormals 向量的需求?据我从这个解决方案中可以看出,它们仍在使用中。这个想法是我想减少每个网格的内存消耗。
  • @MostafaMahmoud 你的意思是要把顶点坐标和法向量组合成一个有6个分量的属性元组?
  • 不完全是,我只是想直接使用存储在网格结构中的顶点和法线数据来消除readMesh()函数中对两个嵌套for循环的需要
  • @MostafaMahmoud 所以这个问题与OpenGL或GLSL无关,只是一个c++编码问题?
  • @MostafaMahmoud 问题既不是关于 OpenGL 指令也不是关于着色器代码。无论如何,您想要实现的目标是不可能的,因为法线向量是每个面的,但是您必须指定每个顶点的法线向量。
猜你喜欢
  • 2012-03-28
  • 1970-01-01
  • 2019-04-29
  • 2014-09-25
  • 2019-01-13
  • 1970-01-01
  • 2021-01-16
  • 1970-01-01
  • 2017-09-28
相关资源
最近更新 更多