GLSL立方体签名距离字段实现说明?

时间:2016-02-10 21:32:27

标签: geometry glsl shader raytracing raymarching

我一直在寻找并尝试理解以下代码

float sdBox( vec3 p, vec3 b )
{
  vec3 d = abs(p) - b;
  return min(max(d.x,max(d.y,d.z)),0.0) +
         length(max(d,0.0));
}

我理解length(d)处理SDF情况,其中该点离开'角落'(即d的所有成分都是正数)并且max(d.x, d.y, d.z)给了我们正确的在所有其他情况下的距离。我不明白的是,如果不使用if语句检查d组件的符号,这两者是如何组合在一起的。

如果所有d成分都是正数,则返回表达式可以缩减为length(d),因为min/max将评估的方式 - 以及所有d组件是否定的,我们得到max(d.x, d.y, d.z)。但我怎么理解中间案件呢?那些d的成分有混合符号的那些?

我一直试图把它绘制成无济于事。如果有人能用几何/数学术语向我解释,我真的很感激。感谢。

2 个答案:

答案 0 :(得分:5)

如果您想知道它是如何工作的,请执行以下步骤:

1.首先,你应该知道形状的定义

2.考虑它们的二维形状总是更好,因为三个维度对你来说可能很复杂。

让我来解释一些形状:

Circle

圆圈是一种简单的封闭形状。它是一个平面中距离给定点(中心)给定距离的所有点的集合。

  

您可以使用distance()length()sqrt()来计算到广告牌中心的距离。

     

The book of shaders - Chapter 7

Square

在几何中,正方形是规则的四边形,这意味着它有四个相等的边和四个相等的角(90度角)。

我描述2D形状现在让我来描述3D定义。

Sphere

  

球体是三维空间中完美圆形的几何物体,是完全圆球的表面。

     

就像一个几何上是二维空间中的物体的圆,球体在数学上被定义为与给定点在相同距离r但在三维空间中的点集。   Refrence - Wikipedia

立方

Cube

  

在几何体中,立方体是由六个正方形面,面或边界限定的三维立体对象,在每个顶点处有三个会合。   Refrence : Wikipedia

使用距离函数建模

现在是理解modeling with distance functions

的时候了

如上所述。在下面的代码length()中,用于计算到广告牌中心的距离,您可以通过 s 参数来缩放此形状。

//Sphere - signed - exact
/// <param name="p">Position.</param>
/// <param name="s">Scale.</param>
float sdSphere( vec3 p, float s )
{
  return length(p)-s;
}

// Box - unsigned - exact
/// <param name="p">Position.</param>
/// <param name="b">Bound(Scale).</param> 
float udBox( vec3 p, vec3 b )
{
  return length(max(abs(p)-b,0.0));
}

length()像之前的例子一样使用。 接下来我们有max(x,0)它叫Positive and negative parts Positive_and_negative_parts

这意味着下面的代码是等价的:

float udBox( vec3 p, vec3 b )
{

   vec3 value = abs(p)-b;


   if(value.x<0.){
   value.x = 0.;  
   }

  if(value.y<0.){
  value.y = 0.;  
  }

  if(value.z<0.){
  value.z = 0.;  
  }  

  return length(value);
}

第1步

   if(value.x<0.){
   value.x = 0.;  
   }

step1

第2步

  if(value.y<0.){
  value.y = 0.;  
  }

step2

第3步

  if(value.z<0.){
  value.z = 0.;  
  }  

step3

第4步

接下来我们有绝对功能。它曾用于删除其他部分。

absolution

step4

赦免步骤

step3

赦免步骤1

if(value.x < -1.){
   value.x = 1.; 
}

abs1

赦免步骤2

if(value.y < -1.){
value.y = 1.; 
}

abs2

赦免步骤3

if(value.z < -1.){
value.z = 1.; 
}

step4

您还可以使用构造实体几何体来制作任何形状。

Constructive solid geometry

CSG建立在3个基本操作之上:交集(),联合()和差异(-)。

事实证明,当组合表示为SDF的两个表面时,这些操作都可以简洁地表达。

intersectSDF

float intersectSDF(float distA, float distB) {
    return max(distA, distB);
}

unionSDF

float unionSDF(float distA, float distB) {
    return min(distA, distB);
}

differenceSDF

float differenceSDF(float distA, float distB) {
    return max(distA, -distB);
}

答案 1 :(得分:2)

我刚才想出来,并在博文中广泛写了这篇文章:http://fabricecastel.github.io/blog/2016-02-11/main.html

这是一段摘录(详见完整帖子):

考虑四个点,A,B,C和D.让我们粗略地减少距离函数,试图摆脱最小/最大函数,以便了解它们的效果(因为这是令人费解的这个函数)。下面的符号有点草率,我使用方括号来表示2D向量。

// 2D version of the function
d(p) = min(max(p.x, p.y), 0)
       + length(max(p, 0))

---

d(A) = min(max(-1, -1), 0)
       + length(max([-1, -1], 0))

d(A) = -1 + length[0, 0]

---

d(B) = min(max(1, 1), 0)
       + length(max([1, 1], 0))

d(B) = 0 + length[1, 1]

好的,到目前为止没什么特别的。当A在正方形内部时,我们基本上得到基于平面/线的第一个距离函数,当B处于我们的第一个距离函数不准确的区域时,它被归零,我们得到第二个距离函数(长度)。诀窍在于另外两种情况C和D.让我们解决它们。

d(C) = min(max(-1, 1), 0)
      + length(max([-1, 1], 0))

d(C) = 0 + length[0, 1]

---

d(D) = min(max(1, -1), 0)
       + length(max([-1, 1], 0))

d(D) = 0 + length[1, 0]

如果你回头看上面的图表,你会注意到C'和D'。这些点分别具有坐标[0,1]和[1,0]。这种方法使用两个距离场在轴上相交的事实 - D和D'与正方形的距离相同。

如果我们将矢量的所有负分量归零并取其长度,我们将得到点与正方形之间的适当距离(仅适用于正方形之外的点)。这是max(d,0.0)的作用;分量最大化操作。只要向量具有至少一个正分量,min(max(d.x,d.y),0.0)将解析为0,只留下方程的第二部分。如果点在方形内,我们想要返回方程的第一部分(因为它代表我们的第一个距离函数)。如果向量的所有组成部分都是负数,则很容易看出我们的条件将得到满足。

一旦你将头部包裹起来,这种理解应该无缝地转变为3D。您可能需要或不必手动绘制一些图表以“真正”获取它 - 我知道我做过并且如果您对我的解释不满意,我会鼓励您这样做。

将此实现应用到我们自己的代码中,我们得到了这个:

float distanceToNearestSurface(vec3 p){
  float s = 1.0;
  vec3 d = abs(p) - vec3(s);
  return min(max(d.x, max(d.y,d.z)), 0.0)
      + length(max(d,0.0));
}

你有它。