2010-05-21 11 views
7

Represento isosuperficies con cubos de marcha (o tal vez marque los cuadrados ya que esto es 2D) y deseo hacer operaciones de conjunto como establecer diferencia, intersección y unión. Pensé que esto era fácil de implementar, simplemente eligiendo entre dos escalas de vértice de dos superficies implícitas diferentes, pero no es así.Operaciones de CSG en superficies implícitas con cubos de marcha

Para mis pruebas iniciales, he intentado con dos esferas círculos, y la operación de conjunto diferencia . es decir, A - B. Un círculo se está moviendo y el otro está estacionario. Este es el enfoque que probé al elegir los escalares de los vértices y al clasificar los vértices de las esquinas como interiores o exteriores. El código está escrito en C++. OpenGL se usa para renderizar, pero eso no es importante. La representación normal sin operaciones CSG da el resultado esperado.



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

Esto me da el efecto de escalón extraños: here http://www.mechcore.net/images/gfx/csgbug2.png
Parece que la operación se hace CSG sin interpolación. Simplemente "descarta" todo el triángulo. ¿Debo interpolar de alguna otra forma o combinar los valores escalares de los vértices? Me gustaría algo de ayuda con esto. Un caso de prueba completo puede descargarse HERE

EDIT: Básicamente, mi implementación de plazas de marcha funciona bien. Es mi campo escalar que está roto, y me pregunto cómo sería la forma correcta. Preferiblemente Busco un enfoque general para poner en práctica las tres operaciones de conjunto que ha comentado anteriormente, para las primitivas habituales (círculo, rectángulo/cuadrado, plano)

EDIT 2: Estas son algunas imágenes nuevas después de la implementación de la contestadora libro blanco:

1.Difference
2.Intersection
3.Union

EDITAR 3: He implementado esto en 3D también, con el sombreado adecuado/iluminación:

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.

Respuesta

3

Esto no es cómo se mezclan los campos escalares. Sus escalares dicen una cosa, pero sus banderas ya sea que esté dentro o no dicen otra. En primer lugar fusionar los campos, a continuación, hacer como si estuviera haciendo un único objeto compuesto:

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

Este artículo podría ser útil: Combining CSG modeling with soft blending using Lipschitz-based implicit surfaces.

+0

Hm, raro. Esto realmente funciona, pero el borde se vuelve un poco raro. Voy a investigar si este es un problema de precisión. Sin embargo, no aparece para círculos normales. Aquí hay una captura de pantalla de una grilla de 100x100: http://www.mechcore.net/images/gfx/csgbug3.png –

+0

Correcto, es un problema de precisión. Los círculos más grandes funcionan bien, pero aumentar la teselación de la cuadrícula no (estoy usando flotadores). Gran respuesta y gran papel. Mi más profundo agradecimiento a usted, señor. –

+0

¡De nada! ¡Buena suerte con su proyecto, las superficies implícitas son divertidas! –