2010-05-21 12 views
7

Je rends isosurfaces avec des cubes marching, (ou peut-être des carrés de défilement comme ceci est 2D) et je veux faire des opérations comme set set difference, intersection et union. Je pensais que c'était facile à implémenter, en choisissant simplement entre deux scalaires de sommet provenant de deux surfaces implicites différentes, mais ce n'est pas le cas.Opérations CSG sur des surfaces implicites avec des cubes en marche

Pour mes tests initiaux, j'ai essayé avec deux sphères et l'opération différence. i.e A - B. Un cercle se déplace et l'autre est stationnaire. Voici l'approche que j'ai essayée en choisissant des scalaires de sommet et en classant des sommets de coin comme dedans ou dehors. Le code est écrit en C++. OpenGL est utilisé pour le rendu, mais ce n'est pas important. Le rendu normal sans aucune opération CSG donne le résultat attendu.



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

Cela me donne crénelage étranges: here http://www.mechcore.net/images/gfx/csgbug2.png
Il ressemble à l'opération de CSG se fait sans interpolation. Il "rejette" tout le triangle. Ai-je besoin d'interpoler d'une autre manière ou de combiner les valeurs scalaires de vertex? J'aimerais de l'aide avec ça. Un testcase complet peut être téléchargé HERE

EDIT: Fondamentalement, ma mise en œuvre de places de marche fonctionne très bien. C'est mon champ scalaire qui est cassé, et je me demande à quoi ressemblerait le bon chemin. De préférence, je suis à la recherche d'une approche générale pour mettre en œuvre les trois opérations ensemble je mentionné ci-dessus, pour les primitives habituelles (cercle, rectangle/carré, avion) ​​

EDIT 2: Voici quelques nouvelles images après la mise en œuvre de la answerer Livre blanc:

1.Difference
2.Intersection
3.Union

EDIT 3: Je mis en œuvre ce en 3D aussi, avec ombrage/éclairage approprié:

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.

Répondre

3

Ce n'est pas comment vous mélangez les champs scalaires. Vos scalaires disent une chose, mais vos drapeaux, que vous soyez à l'intérieur ou non, en disent un autre. Tout d'abord fusionner les champs, puis rendre comme si vous faisiez un seul objet composé:

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

Cet article pourrait être utile: Combining CSG modeling with soft blending using Lipschitz-based implicit surfaces.

+0

Hm, bizarre. Cela fonctionne réellement, mais le bord devient un peu bizarre. Je vais examiner si c'est un problème de précision. Il n'apparaît pas pour les cercles normaux cependant. Voici une capture d'écran d'une grille 100x100: http://www.mechcore.net/images/gfx/csgbug3.png –

+0

A droite, c'est un problème de précision. Les grands cercles fonctionnent très bien, mais l'augmentation de la tesselation de la grille ne fonctionne pas (j'utilise des flotteurs). Bonne réponse et bon papier. Mes plus sincères remerciements à vous monsieur. –

+0

De rien! Bonne chance avec votre projet, les surfaces implicites sont amusantes! –