2010-05-21 13 views
7

Ich render Isoflächen mit marschierenden Cubes, (oder vielleicht marschierende Quadrate, da dies 2D ist) und ich möchte Set-Operationen wie Set-Differenz, Schnittpunkt und Union. Ich dachte, das wäre einfach zu implementieren, indem man einfach zwischen zwei Vertex-Skalaren von zwei verschiedenen impliziten Oberflächen wählt, aber das ist es nicht.CSG-Operationen auf impliziten Oberflächen mit Marching-Cubes

Für meine ersten Tests habe ich mit zwei Kugeln Kreise versucht, und die eingestellte Operation Unterschied. a. B. Ein Kreis bewegt sich und der andere ist stationär. Hier ist der Ansatz, den ich bei der Auswahl von Eckpunktskalaren und bei der Klassifizierung von Eckpunkten wie innen oder außen ausprobiert habe. Der Code ist in C++ geschrieben. OpenGL wird für das Rendern verwendet, aber das ist nicht wichtig. Normales Rendern ohne CSG-Operationen liefert das erwartete Ergebnis.



 void march(const vec2& cmin, //min x and y for the grid cell 
        const vec2& cmax, //max x and y for the grid cell 
        std::vector<vec2>& tri, 
        float iso, 
        float (*cmp1)(const vec2&), //distance from stationary circle 
        float (*cmp2)(const vec2&) //distance from moving circle 
) 
{ 
    unsigned int squareindex = 0; 
    float scalar[4]; 
    vec2 verts[8]; 
    /* initial setup of the grid cell */ 
    verts[0] = vec2(cmax.x, cmax.y); 
    verts[2] = vec2(cmin.x, cmax.y); 
    verts[4] = vec2(cmin.x, cmin.y); 
    verts[6] = vec2(cmax.x, cmin.y); 

    float s1,s2; 
    /********************************** 
    ********For-loop of interest****** 
    *******Set difference between **** 
    *******two implicit surfaces****** 
    **********************************/ 
    for(int i=0,j=0; i<4; ++i, j+=2){ 
    s1 = cmp1(verts[j]); 
    s2 = cmp2(verts[j]); 
    if((s1 < iso)){ //if inside circle1 
     if((s2 < iso)){ //if inside circle2 
     scalar[i] = s2; //then set the scalar to the moving circle 
     } else { 
     scalar[i] = s1; //only inside circle1 
     squareindex |= (1<<i); //mark as inside 
     } 
    } 
    else { 
     scalar[i] = s1; //inside neither circle 
    } 
    } 

    if(squareindex == 0) 
    return; 
    /* Usual interpolation between edge points to compute 
    the new intersection points */ 
    verts[1] = mix(iso, verts[0], verts[2], scalar[0], scalar[1]); 
    verts[3] = mix(iso, verts[2], verts[4], scalar[1], scalar[2]); 
    verts[5] = mix(iso, verts[4], verts[6], scalar[2], scalar[3]); 
    verts[7] = mix(iso, verts[6], verts[0], scalar[3], scalar[0]); 

    for(int i=0; i<10; ++i){ //10 = maxmimum 3 triangles, + one end token 
    int index = triTable[squareindex][i]; //look up our indices for triangulation 
    if(index == -1) 
     break; 
    tri.push_back(verts[index]); 
    } 
} 

Das gibt mir seltsam jaggies: here http://www.mechcore.net/images/gfx/csgbug2.png
Es sieht aus wie die CSG Operation wird ohne Interpolation. Es "verwirft" einfach das ganze Dreieck. Muss ich auf andere Weise interpolieren oder die Vertex-Skalarwerte kombinieren? Ich würde gerne etwas Hilfe dabei haben. Grundsätzlich meine Implementierung von Marsch Quadraten gut funktioniert: Ein vollständiger Testfall kann HERE

EDIT heruntergeladen werden. Es ist mein skalares Feld welches gebrochen ist, und ich frage mich, wie der richtige Weg aussehen würde. Ich suche vorzugsweise für eine allgemeine Ausrichtung der drei Set-Operationen I oben,

EDIT 2 für die üblichen Primitiven (Kreis, Rechteck/Quadrat, Flugzeug) diskutiert umzusetzen: Hier sind die einige neue Bilder nach der Umsetzung der Antworter White Paper:

1.Difference
2.Intersection
3.Union

EDIT 3: Ich implementiert diese in 3D auch mit der richtigen Beschattung/Beleuchtung:

1.Difference between a greater sphere and a smaller sphere
2.Difference between a greater sphere and a smaller sphere in the center, clipped by two planes on both sides, and then union with a sphere in the center.
3.Union between two cylinders.

Antwort

3

Dies ist nicht, wie Sie die Skalarfelder mischen. Deine Skalare sagen eine Sache, aber deine Flags, ob du drinnen bist oder nicht, sagen ein anderes. Zunächst verschmelzen die Felder, dann machen, als ob Sie eine einzelne Verbindung Objekt tun wurden:

for(int i=0,j=0; i<4; ++i, j+=2){ 
    s1 = cmp1(verts[j]); 
    s2 = cmp2(verts[j]); 
    s = max(s1, iso-s2); // This is the secret sauce 
    if(s < iso) { // inside circle1, but not inside circle2 
    squareindex |= (1<<i); 
    } 
    scalar[i] = s; 
} 

Dieser Artikel könnte hilfreich sein: Combining CSG modeling with soft blending using Lipschitz-based implicit surfaces.

+0

Hm, komisch. Das funktioniert tatsächlich, aber die Kante wird irgendwie komisch. Ich werde untersuchen, ob das ein Präzisionsproblem ist. Es erscheint jedoch nicht für normale Kreise. Hier ist ein Screenshot eines 100x100 Grids: http://www.mechcore.net/images/gfx/csgbug3.png –

+0

Richtig, es ist ein Genauigkeitsproblem. Größere Kreise funktionieren gut, aber die Gitter-Tesselation erhöht nicht (ich verwende Floats). Große Antwort und tolles Papier. Mein tiefster Dank an Sie, mein Herr. –

+0

Gern geschehen! Viel Glück mit Ihrem Projekt, implizite Oberflächen machen Spaß! –

Verwandte Themen