Geometry GLSL多维数据集有符号距离字段实现说明?
我一直在研究并试图理解以下代码Geometry GLSL多维数据集有符号距离字段实现说明?,geometry,glsl,shader,raytracing,raymarching,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组件的符号,
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
的组件有混合符号的那些
我一直试图把它画出来,但没有用。如果有人能用几何/数学术语向我解释这一点,我将不胜感激。谢谢。我不久前就发现了这一点,并在这里的一篇博文中对此进行了广泛的讨论: 这里有一段摘录(完整的解释见全文): 考虑四个点,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)所做的;一种基于组件的max操作。只要向量至少有一个正分量,min(max(d.x,d.y),0.0)将解析为0,只剩下方程的第二部分。如果点在正方形内,我们希望返回方程的第一部分(因为它代表我们的第一个距离函数)。如果向量的所有分量都是负的,很容易看出我们的条件会得到满足
一旦你把头绕在3D上,这种理解就会无缝地转换回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));
}
这就是你想要的。如果你想知道它是如何工作的,最好执行以下步骤: 1.首先你应该知道形状的定义 P>2。考虑2D形状总是更好的,因为三个维度对你来说可能很复杂。 让我来解释一些形状: 圆圈 圆是一种简单的闭合形状。它是一个平面上所有点的集合,这些点与一个给定点(即中心)之间的距离是给定的 您可以使用
distance()
、length()
或sqrt()
计算到广告牌中心的距离
广场
在几何学中,正方形是规则四边形,这意味着它有四条等边和四个等角(90度角)
我在前一节中描述了2D形状,现在让我来描述3D定义 球体 球体是三维空间中的一个完美的圆形几何体,它是一个完全圆形球体的表面 与圆形一样,圆形在几何上是二维空间中的对象,球体在数学上被定义为与给定点的距离r相同但在三维空间中的一组点。 立方体 在几何学中,立方体是一个三维实体对象,由六个正方形面、面或边包围,每个顶点有三个相交。
距离函数建模 现在是理解的时候了 球体 如前几节所述。在下面的代码中,用于计算到广告牌中心的距离的
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;
}
第一步
解释得很透彻。前两张截图中的是什么软件?@DanielA.Thompson是unity的可视化脚本着色器工具,虽然我很感激你花了这么多时间来写这个答案,但我的问题是关于有符号距离字段的,你的解释针对的是无符号变量,这避免了解释负距离是如何计算的。@FabCastel我会更新我的答案,我也问了同样的问题,希望对你们有用。
// 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));
}
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.;
}
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);
}