【问题标题】:opengl - triangle adjacency to triangle stripopengl - 三角形邻接三角形条
【发布时间】:2018-02-11 13:40:58
【问题描述】:

假设我有我的几何图形并创建了一个包含三角形邻接信息的索引缓冲区。然后,将绘图模式从GL_TRIANGLES 更改为GL_TRIANGLE_ADJACENCY。 问题是,我可以使用几何着色器将几何从三角形邻接转换为三角形带吗?

类似这样的:

layout(triangles_adjacency) in;
layout(triangle_strip, max_vertices = 3) out;

in Vertex
{
    vec3 normal;
} vertex[];

out FragmentVertexData
{
  vec3 normal;
  vec3 fragpos;
} VertexOut;


void main()
{
    for(int i = 0 ; i < gl_in.length(); i+=2)
    {
        gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * gl_in[i].gl_Position;
        VertexOut.normal = vertex[i].normal;
        VertexOut.fragpos =  vec3(ModelMatrix * gl_in[i].gl_Position);
        VertexOut.fragpos = gl_Position; 
        EmitVertex();
    }
    EndPrimitive();
}

我已经尝试过,实际上它会绘制几何图形,但法线有问题。我也必须索引它们吗?我错过了一步吗?

这就是我在片段着色器中使用 fragpos 和 normal 的方式

vec3 normal = normalize(VertexOut.normal);
  vec3 lightDir = normalize(light.position - VertexOut.fragpos);

这是我编写三角形邻接索引缓冲区的算法:

void Loader::FindAdjacencies(const aiMesh * paiMesh, vector<int>& indices)
{
    // Step 1 - find the two triangles that share every edge
    for (uint i = 0; i < paiMesh->mNumFaces; i++) 
    {
        const aiFace& face = paiMesh->mFaces[i];

        Face Unique;

        // If a position vector is duplicated in the VB we fetch the 
        // index of the first occurrence.
        for (uint j = 0; j < 3; j++)
        {
            uint Index = face.mIndices[j];
            aiVector3D& v = paiMesh->mVertices[Index];

            if (m_posMap.find(v) == m_posMap.end()) 
            {
                m_posMap[v] = Index;
            }
            else 
            {
                Index = m_posMap[v];
            }

            Unique.Indices[j] = Index;
        }

        m_uniqueFaces.push_back(Unique);

        Edge e1(Unique.Indices[0], Unique.Indices[1]);
        Edge e2(Unique.Indices[1], Unique.Indices[2]);
        Edge e3(Unique.Indices[2], Unique.Indices[0]);

        m_indexMap[e1].AddNeigbor(i);
        m_indexMap[e2].AddNeigbor(i);
        m_indexMap[e3].AddNeigbor(i);

    }

    // Step 2 - build the index buffer with the adjacency info
    for (uint i = 0; i < paiMesh->mNumFaces; i++) 
    {
        const Face& face = m_uniqueFaces[i];

        for (uint j = 0; j < 3; j++) 
        {
            Edge e(face.Indices[j], face.Indices[(j + 1) % 3]);
            assert(m_indexMap.find(e) != m_indexMap.end());
            Neighbors n = m_indexMap[e];
            uint OtherTri = n.GetOther(i);
            uint minus1 = (uint)-1;
            bool comp = (OtherTri != minus1);
            assert(comp);

            const Face& OtherFace = m_uniqueFaces[OtherTri];
            uint OppositeIndex = OtherFace.GetOppositeIndex(e);

            indices.push_back(face.Indices[j]);
            indices.push_back(OppositeIndex);
        }
    }

}

不幸的是,仅适用于接近的几何形状。这就是我用立方体测试它的原因。我尝试使用 bunny.ply,但模型的一部分有孔,我必须在搅拌机中对其进行编辑。

这是 obj 文件:

# Blender v2.76 (sub 0) OBJ File: ''
# www.blender.org
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.333333 0.666667
vt 0.333333 1.000000
vt 0.000000 1.000000
vt 0.000000 0.666667
vt 0.000000 0.333333
vt 0.333333 0.333333
vt 0.333333 0.000000
vt 0.666667 0.000000
vt 0.000000 0.000000
vt 1.000000 0.333333
vt 0.666667 0.333333
vt 0.666667 0.666667
vt 1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
f 2/1/1 3/2/1 4/3/1
f 8/1/2 7/4/2 6/5/2
f 5/6/3 6/7/3 2/8/3
f 6/9/4 7/7/4 3/6/4
f 3/10/5 7/11/5 8/8/5
f 1/11/6 4/12/6 8/1/6
f 1/4/1 2/1/1 4/3/1
f 5/6/2 8/1/2 6/5/2
f 1/11/3 5/6/3 2/8/3
f 2/5/4 6/9/4 3/6/4
f 4/13/5 3/10/5 8/8/5
f 5/6/6 1/11/6 8/1/6

非常感谢!

这是我的顶点着色器:

#version 430 core
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in vec3 normal;

out VertexData
{
    vec3 normal;
    vec2 textCoord;
} vertex;

// Values that stay constant for the whole mesh.

void main(){
  gl_Position =  vec4(vertexPosition,1.0f);
  vertex.textCoord = texCoord;
  vertex.normal = normal;
}

还有我的片段着色器:

#version 430 core

struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
}; 

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Material material;
uniform Light light;

out vec4 color;

uniform float LightIntensity;
uniform vec3 LightPos;
uniform vec3 ViewPos;

in FragmentVertexData
{
    vec3 normal;
    vec3 fragpos;
    vec2 texCoord;
} VertexOut;


void main(){


  // color of the object
  vec3 objectColor = vec3(1.0f, 0.5f, 0.31f);


  // Ambient

  vec3 ambient = light.ambient * material.ambient ;

  vec3 normal = normalize(VertexOut.normal);
  vec3 lightDir = normalize(light.position - VertexOut.fragpos);  

  float diff = max(dot(lightDir,normal), 0.0);
  vec3 diffuse = light.diffuse * diff * material.diffuse ;

  vec3 viewDir = normalize(ViewPos - VertexOut.fragpos);
  vec3 reflectDir = reflect(-lightDir, normal);  

  vec3 halfwayDir = normalize(lightDir + viewDir );

  float spec = pow(max(dot(normal, halfwayDir), 0.0), material.shininess);


  vec3 specular = light.specular * spec * material.specular ; 

  color = vec4((ambient + diffuse + specular) * objectColor, 1);

}

【问题讨论】:

    标签: c++ opengl glsl shader


    【解决方案1】:

    三角形邻接,包含三角形的邻接数据,以便可以访问相邻的三角形。 Geometry Shader 阶段可以访问 6 个顶点和属性,形成 4 个三角形。 3 个顶点形成当前渲染的三角形。其他 3 个顶点与当前渲染的三角形的 3 个边一起形成相邻(相邻)三角形。 (见GL_ARB_geometry_shader4Primitive)。

    如果Geometry Shader 应该将渲染的三角形传递到下一个着色器阶段,那么它必须只处理形成三角形的三个点,而不是处理它的邻接。

    其他问题:

    • 模型的世界空间位置被VertexOut.fragpos = gl_Position;覆盖
    • 法线向量必须转换到世界空间:
      VertexOut.normal = mat3(ModelMatrix) * vertex[i].normal;

    几何着色器应该看起来像这样:

    layout(triangles_adjacency) in;
    layout(triangle_strip, max_vertices = 3) out;
    
    in Vertex
    {
        vec3 normal;
    } vertex[];
    
    out FragmentVertexData
    {
        vec3 normal;
        vec3 fragpos;
    } VertexOut;
    
    uniform mat4 ModelMatrix;
    uniform mat4 ViewMatrix;
    uniform mat4 ProjectionMatrix;
    
    void main()
    {
        for (int i = 0; i < 6; i += 2)
        {
            vec4 fragPos      = ModelMatrix * gl_in[i].gl_Position;
            VertexOut.normal  = mat3(ModelMatrix) * vertex[i].normal;
            VertexOut.fragpos = fragPos.xyz;
            gl_Position       = ProjectionMatrix * ViewMatrix * fragPos;
            EmitVertex();
        } 
        EndPrimitive();
    }
    


    如果法向量是每个人脸,你的邻接算法将会失败:

    生成邻接索引的算法不考虑,人脸的每个点都由一对顶点位置和法向量定义。不同的面可能具有相同的角位置,但它们总是具有不同的法向量。由于您将所有顶点位置放在地图m_pos Map 中,其中位置是关键,因此失去了法线向量的区别。当你有一个立方体时,每个面都有法向量,每个顶点的位置必须是顶点缓冲区中的 3 倍,因为它由立方体的 3 个边共享并且有 3 个不同的法向量。
    如果您有一个网格,其中法线向量是每个顶点(例如球体),那么您的算法将正常工作。但是如果法线向量是每个面,你的算法就会失败,就像立方体一样。


    保留面孔并仅将邻接添加到面孔的算法如下所示:

    #include <array>
    #include <vector>
    #include <map>
    
    using TIndices  = std::vector<int>;
    using TFace     = std::array<int, 3>;
    using TFaces    = std::vector<TFace>;
    using TVertex   = std::array<float, 3>;
    using TVertices = std::vector<TVertex>;
    
    void GenerateAdjacencies( const TVertices &vertices, const TFaces &faces, TIndices &adj )
    {
        // associate each geometric vertex position with an unique ID
        std::vector<int>      uniqueMap;
        std::map<TVertex,int> tempUniqueVertices;
        int uniqueIndex = 0;
        for ( size_t vI = 0; vI < vertices.size(); ++ vI )
        {
            auto vIt = tempUniqueVertices.find( vertices[vI] );
            if ( vIt == tempUniqueVertices.end() )
            {
                tempUniqueVertices[ vertices[vI] ] = uniqueIndex;
                uniqueMap.push_back( uniqueIndex );
                uniqueIndex ++;
            }
            else
                uniqueMap.push_back( vIt->second );
        }
        tempUniqueVertices.clear();
    
        // find all edges and associate the edge with all the points, which form a triangle with it. 
        std::map< std::tuple<int, int>, std::vector<int> > edges;
        for ( auto & f : faces )
        {
          for ( int pI = 0; pI < 3; ++ pI )
          {
            int edgeU[2]{ uniqueMap[f[pI]], uniqueMap[f[(pI+1) % 3]] };
            int i0 = edgeU[0] < edgeU[1] ? 0 : 1;
            edges[{ edgeU[i0], edgeU[1-i0] }].push_back( f[(pI+2) % 3] );
          }
        }
    
        // create the adjacencies
        for ( auto & f : faces )
        {
            for ( int pI = 0; pI < 3; ++ pI )
            {
                int edgeU[2]{ uniqueMap[f[pI]], uniqueMap[f[(pI+1) % 3]] };
                int   i0   = edgeU[0] < edgeU[1] ? 0 : 1;
                auto &adjs = edges[{ edgeU[i0], edgeU[1 - i0] }];
                int   adjI = adjs.size() > 1 && adjs[0] == f[(pI+2) % 3] ? 1 : 0;
                adj.push_back( f[pI] );
                adj.push_back( adjs[adjI] );
            }
        }
    }
    

    example

    【讨论】:

    • 嗨,是的,这就是我在循环中所做的 for(int i = 0 ; i
    • 你是说光的位置?世界空间。在将顶点法线从 GL_TRIANGLE_ADJACENCY 转换为三角形条带后,我附上了一张顶点法线的图像(现在它只是一个常规立方体)。在该图像中,光线位于立方体上方,但它的某些侧面看起来像是光线在它们前面。这就是为什么我认为也必须在法线上做一些事情。
    • 这是我在片段着色器中计算法线方向和光线方向的方法。 vec3 normal = normalize(VertexOut.normal); vec3 lightDir = normalize(light.position - VertexOut.fragpos);我认为搅拌机导出每个顶点的法线。立方体面的法线是使用另一个几何着色器绘制的
    • 我做了您建议的更改,但没有得到正确的结果。此时,我认为索引邻接三角形的算法一定有问题。
    • 甜!!有用 !!。它从 +45 分钟(在我蹩脚的笔记本电脑上)下降到或多或少 1.5 分钟。非常感谢。我会推荐和提示你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-11
    • 2020-12-08
    • 2021-04-08
    • 2015-05-26
    相关资源
    最近更新 更多