我一直在寻找并尝试理解以下代码
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
的成分有混合符号的那些?
我一直试图把它绘制成无济于事。如果有人能用几何/数学术语向我解释,我真的很感激。感谢。
答案 0 :(得分:5)
如果您想知道它是如何工作的,请执行以下步骤:
1.首先,你应该知道形状的定义
2.考虑它们的二维形状总是更好,因为三个维度对你来说可能很复杂。
让我来解释一些形状:
圆圈是一种简单的封闭形状。它是一个平面中距离给定点(中心)给定距离的所有点的集合。
您可以使用
distance()
,length()
或sqrt()
来计算到广告牌中心的距离。
在几何中,正方形是规则的四边形,这意味着它有四个相等的边和四个相等的角(90度角)。
我描述2D形状现在让我来描述3D定义。
球体是三维空间中完美圆形的几何物体,是完全圆球的表面。
就像一个几何上是二维空间中的物体的圆,球体在数学上被定义为与给定点在相同距离r但在三维空间中的点集。 Refrence - Wikipedia
在几何体中,立方体是由六个正方形面,面或边界限定的三维立体对象,在每个顶点处有三个会合。 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
这意味着下面的代码是等价的:
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);
}
if(value.x<0.){
value.x = 0.;
}
if(value.y<0.){
value.y = 0.;
}
if(value.z<0.){
value.z = 0.;
}
接下来我们有绝对功能。它曾用于删除其他部分。
if(value.x < -1.){
value.x = 1.;
}
if(value.y < -1.){
value.y = 1.;
}
if(value.z < -1.){
value.z = 1.;
}
您还可以使用构造实体几何体来制作任何形状。
CSG建立在3个基本操作之上:交集(∩
),联合(∪
)和差异(-
)。
事实证明,当组合表示为SDF的两个表面时,这些操作都可以简洁地表达。
float intersectSDF(float distA, float distB) {
return max(distA, distB);
}
float unionSDF(float distA, float distB) {
return min(distA, distB);
}
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));
}
你有它。