CSG在带有行军立方体的隐式曲面上的操作 [英] CSG operations on implicit surfaces with marching cubes

查看:184
本文介绍了CSG在带有行军立方体的隐式曲面上的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用行军立方体渲染等值面(或者行军正方形,因为这是2D),我想做set操作,如集合差异,交集和联合。我认为这很容易实现,只需从两个不同的隐式曲面中选择两个顶点标量,但它不是。



对于我的初始测试,我尝试了两个球体圆圈和设置的操作差异。即A - B。一个圆圈正在移动,另一个是静止的。以下是我在挑选顶点标量和将角点顶点分类为内部或外部时尝试的方法。代码是用C ++编写的。 OpenGL用于渲染,但这并不重要。没有任何CSG操作的正常渲染确实会给出预期的结果。



  void march (const vec2& cmin,//网格单元的最小x和y 
const vec2& cmax,//网格单元的最大x和y
std :: vector< vec2>& tri,
float iso,
float(* cmp1)(const vec2& amp;),//距静止圆的距离
float(* cmp2)(const vec2& amp;)//距离移动圆的距离

{
unsigned int squareindex = 0;
浮点标量[4];
vec2 verts [8];
/ *网格单元的初始设置* /
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;
/ **********************************
******* *感兴趣的循环******
*******设置****
*******之间的差异两个隐式表面******
********************************** /
(int i = 0, j = 0; i <4; ++ i,j + = 2){
s1 = cmp1(verts [j]);
s2 = cmp2(verts [j]); ((s1 if((s2 中标量[i] = s2; //然后将标量设置为动圈
} else {
scalar [i] = s1; //只在circle1
squareindex | =(1 << i); //标记为
}
}
else {
标量[i] = s1; //不在任何圆圈内
}
}

if(squareindex == 0)
return;
/ *边缘点之间的通常插值计算
新交点* /
verts [1] = mix(iso,verts [0],verts [2],scalar [0] ,标量[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个三角形,+一个结束符
int index = triTable [squareindex] [i] ; //查看我们的三角化指数
if(index == -1)
break;
tri.push_back(verts [index]);






$ p这给了我很奇怪的锯齿:这里http://www.mechcore.net/images/gfx/csgbug2.png

看起来CSG操作是在没有内插的情况下完成的。它只是丢弃整个三角形。我是否需要以其他方式进行插值,还是结合顶点标量值?我很乐意为此提供一些帮助。
可以下载完整的测试用例 HERE



编辑:基本上,我的 marching squares 的执行效果很好。它是我的标量字段被破坏了,我不知道正确的方式是什么样子。最好我正在寻找一种通用的方法来实现我上面讨论过的三组操作,例如通常的基本操作(圆形,矩形/方形,平面)。

编辑2:下面是实施回答者的白皮书后的一些新图片:



1.差异

2.交叉点

3.Union



编辑3:我也在3D中实现了这一点,照明:



1.大球与小球之间的区别

2.在中心的一个更大的球体和一个更小的球体之间的差别,两边的两个平面夹住,然后与中心的球体结合

3.两个圆柱体之间的联合。

解决方案

这不是你如何混合标量字段。你的标量说了一件事,但是你的旗子是否在内部或者不在说另一个。首先合并字段,然后渲染,就好像你在做单个复合对象一样:

  for(int i = 0,j = 0; i <4; ++ i,j + = 2){
s1 = cmp1(verts [j]);
s2 = cmp2(verts [j]);
s = max(s1,iso-s2); //如果(s squareindex | =(1 << i); //这是秘密酱

}
标量[i] = s;
}

这篇文章可能会有帮助:结合CSG建模和软混合基于Lipschitz的隐式曲面

I render isosurfaces with marching cubes, (or perhaps marching squares as this is 2D) and I want to do set operations like set difference, intersection and union. I thought this was easy to implement, by simply choosing between two vertex scalars from two different implicit surfaces, but it is not.

For my initial testing, I tried with two spheres circles, and the set operation difference. i.e A - B. One circle is moving and the other one is stationary. Here's the approach I tried when picking vertex scalars and when classifying corner vertices as inside or outside. The code is written in C++. OpenGL is used for rendering, but that's not important. Normal rendering without any CSG operations does give the expected result.



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

This gives me weird jaggies: here http://www.mechcore.net/images/gfx/csgbug2.png
It looks like the CSG operation is done without interpolation. It just "discards" the whole triangle. Do I need to interpolate in some other way, or combine the vertex scalar values? I'd love some help with this. A full testcase can be downloaded HERE

EDIT: Basically, my implementation of marching squares works fine. It is my scalar field which is broken, and I wonder what the correct way would look like. Preferably I'm looking for a general approach to implement the three set operations I discussed above, for the usual primitives (circle, rectangle/square, plane)

EDIT 2: Here are some new images after implementing the answerer's whitepaper:

1.Difference
2.Intersection
3.Union

EDIT 3: I implemented this in 3D too, with proper shading/lighting:

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.

解决方案

This is not how you mix the scalar fields. Your scalars say one thing, but your flags whether you are inside or not say another. First merge the fields, then render as if you were doing a single compound object:

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

This article might be helpful: Combining CSG modeling with soft blending using Lipschitz-based implicit surfaces.

这篇关于CSG在带有行军立方体的隐式曲面上的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆