Normalen berechnen mit Winkel / für Smoothing



  • Hallo

    weis von euch jemand,
    wie die Normalenberechnung mit einem angegebenen Winkel funktioniert?

    In größeren CAD Programmen heisst die Funktion
    - Recalculate Normals - Übergabeparameter: der Winkel
    - Smoothing - selber Übergabeparameter

    In OpenSG ist dies implementiert: calcVertexNormals(geo, deg2rad(30))
    OpenSceneGraph, welchen ich verwende, enthält dies leider nicht.

    wäre sehr nett wenn mir jemand helfen könnte.

    Benötige ein Smoothing, im Winkel von 30 Grad

    Dankeschön
    Gruß Matthias



  • Da werden die Normalen an Eckpunkten "gemittelt" (z.B. durch die Fläche der beteiligten Polygone gewichtet), wenn der Winkel zwischen den Normalen nicht größer als der angegebene Winkel ist. Zumindest kenne ich das noch so, aus damaligen Zeiten.



  • Wie würde das in einer Funktion aussehen?


  • Mod

    ich kenne das anders.
    jedes dreieck regestriert sich an der ecke mit seiner normalen. im zweiten pass geht man fuer jedes dreieck, fuer jede ecke die regestrierten normalen durch und bezieht nur die in seine berechnungen ein, die unter dem schwellenwert sind, bezueglich der normalen des dreiecks.



  • wo kann man solch eine funktion mal anschauen?
    kennt von euch jemand ein Beispiel?
    mir würde auch pseudocode reichen



  • Gegeben sei ein Array von Vertex-Position und eine Indexed-Triangle-List (diese beinhaltet pro Dreieck jeweils 3 Indizes in das Vertex-Array).
    Daraus kannst Du einen Datensatz erzeugen der fuer jede Vertex-Position die anliegenden Dreiecke enthaelt:

    typedef std::vector<int> TriList; // beliebiger Container
    
    TriList* buildTrianglesPerVertex(int *indices, int numTriangles, int numVertices)
    {
       TriList *facesAtVertex= new TriList[numVertices];
       for (int tri=0;tri<numTriangles;tri++)
       {
          for (int index=0;index<3;index++)
          {
             // nummer des dreiecks in die entsprechende Vertexliste einfuegen
             facesAtVertex[*indices++].push_back(tri);
          }
       }
       return faceAtVertex;
    }
    

    Anhand dessen nimmst Du Dir jetzt jeden Eckpunkt eines Dreiecks und addierst die Normalenvektoren der anliegenden Dreiecke sofern der Winkel zwischen den Dreiecken einen gegebenen Schwellwert nicht ueberschreitet:

    Vector* averageFaceNormals(int *indices, Vector *faceNormals, int numTriangles, float threshold)
    {
       // threshold ist der maximal erlaubte winkel zwischen zwei flaechen in rad
       threshold= cos(threshold); // spart acos() bei winkelvergleich
    
       // Normalen anlegen (3 pro Dreieck) und mit (0,0,0) initialisieren
       Vector *averageNormals= new Vector[numTriangles*3];
       for (int i=0;i<numTriangles*3;i++) averageNormals[i]= Vector(0,0,0);
    
       // alle dreiecke durchgehen
       for (int tri=0;tri<numTriangles;tri++) 
       {
          // an jedem eckpunkt den mittelwert aller anliegenden dreiecke bilden
          for (int index=0;index<3;index++)
          {
             // liste der anliegenden dreiecke:
             const TriList& list= faceAtVertex[*indices++];
    
             Vector average(0,0,0);
    
             // alle Flaechen-Normalen summieren
             for (TriList::const_iterator it= list.begin();it!=list.end();it++)
             {
                // winkel zwischen der beiden flaechen bestimmen (dot-product)
                float angle= faceNormals[*it] * faceNormals[tri];
                if (angle>threshold)
                   average+= faceNormals[*it];
             }
    
             average.normalize();
             mVertexNormals[tri*3+index]= average;
          }
       }
    
       return averageNormals;
    }
    

    Um die Normalenvektoren pro Vertex zu speichern wuerde ein weiterer Schritt folgen der alle Vertices dupliziert deren Referenz an unterschiedliche Dreiecken auch unterschiedliche Normalen hat und die Indizes entsprechend anpasst.


Anmelden zum Antworten