2017-09-02 2 views
2

Nehmen wir an, ich habe meine Geometrie und erstellt einen Index-Puffer, der die Dreieck-Adjazenz-Informationen enthält. Dann wurde der Zeichenmodus von GL_TRIANGLES in GL_TRIANGLE_ADJACENCY geändert. Die Frage ist, kann ich die Geometrie von Dreieck Nachbarschaft zu Dreiecke Streifen mit dem Geometrie-Shader konvertieren?opengl - Dreieck Nachbarschaft zum Dreieck Streifen

etwas wie folgt aus:

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(); 
} 

ich schon versucht, und in der Tat zieht es auf die Geometrie, sondern etwas ist mit den Normalen falsch. Muss ich sie auch indexieren? Vermisse ich einen Schritt?

enter image description here

und das ist, wie ich die fragpos und normal in dem Fragment-Shader bin mit

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

Das ist mein Algorithmus ist das Dreieck adjacency Indexpuffer zu schreiben:

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); 
     } 
    } 

} 

Funktioniert leider nur für enge Geometrien. Deshalb teste ich es mit einem Würfel. Ich habe es mit bunny.ply versucht, aber ein Teil des Modells hat Löcher und ich muss es im Mixer bearbeiten.

und dies ist die OBJ-Datei:

# 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 

Thank you very much!

Dies ist mein Vertexshader:

#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; 
} 

und meine Fragment-Shader:

#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); 

} 

Antwort

4

Ein Dreieck adjacency, adjacency Daten für Dreiecke enthält, so dass benachbarte Dreiecke zugegriffen werden kann. Die Stufe Geometry Shader hat Zugriff auf 6 Scheitelpunkte und Attribute, die 4 Dreiecke bilden. 3 Eckpunkte bilden das Dreieck, das gerade gerendert wird. Die anderen 3 Eckpunkte bilden die benachbarten (benachbarten) Dreiecke in Kombination mit den 3 Seitenkanten des aktuell dargestellten Dreiecks. (siehe GL_ARB_geometry_shader4 und Primitive).

trianglesa djacency

Wenn ein Geometry Shader das gerenderte Dreieck auf die nächste Stufe Shader passieren soll, dann hat es nur die drei Punkte zu verarbeiten, die das Dreieck bilden, und nicht deren Umgebung.

Weitere Ausgaben:

  • Die Weltraumposition des Modells durch VertexOut.fragpos = gl_Position;
  • der Normalvektor überschrieben wird, muss Welt Raum transformiert werden:
    VertexOut.normal = mat3(ModelMatrix) * vertex[i].normal;

Die Geometrie-Shader sollte sehe irgendwie so aus:

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(); 
} 


Wenn die Normalvektoren pro Fläche sind, wird Ihr adjacency Algorithmus versagen:

Der Algorithmus, der das adjacency Indizes erzeugt nicht berücksichtigen, dass jeder Punkt eines Gesichts durch ein Paar von Scheitelpunkt-Position definiert ist, und normaler Vektor Verschiedene Gesichter haben möglicherweise identische Eckpositionen, aber sie haben immer unterschiedliche Normalenvektoren. Da Sie alle Eckpunktpositionen in einer Karte m_pos Map platzieren, wo die Position der Schlüssel ist, ist die Unterscheidung des normalen Vektors verloren. Wenn Sie einen Würfel mit Normalenvektoren pro Fläche haben, muss jede Eckpunktposition im Vertexpuffer drei Mal sein, da sie von drei Seiten des Würfels geteilt wird und drei verschiedene Normalenvektoren hat.
Wenn Sie ein Netz haben, wo die normalen Vektoren pro Vertex sind (z. B. eine Kugel), wird Ihr Algorithmus richtig funktionieren. Aber Ihr Algorithmus schlägt fehl, wenn die normalen Vektoren pro Fläche sind, wie es bei einem Würfel der Fall ist.


Ein Algorithmus, hält fügt die Gesichter und nur die Umgegend auf die Gesichter würde wie folgt aussehen:

#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]); 
     } 
    } 
} 

die example

+1

Hallo Siehe, ja das ist, was ich in meiner Schleife tun für (int i = 0; i Camilo

+0

meinst du die Position des Lichts? Weltraum. Ich habe ein Bild der Vertex-Normalen angehängt, nachdem ich sie von GL_TRIANGLE_ADJACENCY in einen Dreiecks-Streifen umgewandelt habe (jetzt ist es nur ein normaler Würfel). In diesem Bild ist das Licht über dem Würfel, aber einige Seiten davon sehen aus wie das Licht vor ihnen. Deshalb denke ich, dass auch bei den Normalen etwas getan werden muss. – Camilo

+0

So berechne ich die Normal- und Lichtrichtung im Fragment-Shader. vec3 normal = normalisieren (VertexOut.normal); vec3 lightDir = normalisieren (light.position - VertexOut.fragpos); Ich denke, Blender exportiert die Normalen pro Vertex. Die Normalen in den Flächen des Würfels werden mit einem anderen Geometrieshader gezeichnet. – Camilo