SDF Line相关公式推导

SDF Line相关公式推导

线段是SDF形状的基元之一,可以被用来建模一些形状,比如昆虫的腿,植物的根茎等。

image-20240712114012533 image-20240712114050014

下面这篇文章介绍一下Line公式的推导,首先记住我们要求的变量,点到形状最近的距离

那么对于空间中的点\(P_1, P_2, P_3\),他们的分布有如下三种

image-20240715102521984

其中\(P_1\)到线段的距离是\(|\vec{P_1Q}|\)\(P_2\)到线段的距离是\(|\vec{P_2A|}\)\(P_3\)到线段的距离是\(|\vec{P_3B}|。我们先看\) \(|\vec{P_1Q}|\)的求法,

其实本质是一个向量在另一个向量上的投影长度,此处借用云飞Ran的推导过程:

在这里插入图片描述

这里我们采用第二种方法,因此定义向量,\(\vec{BA},\vec{ BP_1}\),然后使用如下公式便可以求出\(\vec{BQ}\)的长度。

\[|\vec{BQ}| = {\vec{BP_1} \cdot \vec{BA}\over |\vec{BA}| } \]

此时投影长度的比例可以定义为:

\[|\vec{BQ}| = {\vec{BP_1} \cdot \vec{BA}\over |\vec{BA}|^2 } \]

熟悉这个求解投影长度的代码之后,在看一下另外两个点\(P_2, P_3\)我们会发现一个投影长度占BA的比例小于0,另一个大于1。

熟悉完上面的内容之后,我们就可以看一下SDF Line的实现了:

// Original SDF line segment function
float sdSegmentRegular( in vec2 p, in vec2 a, in vec2 b)
{
  vec2 bp = b-p, ba = b-a; //求解向量
  float h = clamp( dot(bp,ba)/dot(ba,ba), 0.0, 1.0 );
  return length(bp - ba*h );
}                            


void SDFLine(in vec2 p, in vec2 a, in vec2 b,  in float r, out float sdf) {
  sdf = sdSegmentRegular(p, a, b, r);
}
float h = clamp( dot(bp,ba)/dot(ba,ba), 0.0, 1.0 );

这段代码巧妙的地方在于通过这行代码统一了三种分布的点,当p在a,b点的左侧时,h = 1,此时求得是向量\(\vec{bp}-\vec{ba}\)也就是\(\vec{ap}\)的长度,这里大致如图:

image-20240715104318978

但是这段代码运行起来是看不到任何东西的,我们还需要减去一个 width,才能得到LineSegment;

// Original SDF line segment function
float sdSegmentRegular( in vec2 p, in vec2 a, in vec2 b, in float r )
{
  vec2 bp = b-p, ba = b-a;
  float h = clamp( dot(bp,ba)/dot(ba,ba), 0.0, 1.0 );
  return length( bp - ba*h ) - r;
}                            


void SDFLine(in vec2 p, in vec2 a, in vec2 b,  in float r, out float sdf) {
  sdf = sdSegmentRegular(p, a, b, r);
}

具体的原理我们可以看一下这篇博客圆角矩形小节。此处就不再赘述啦。

refer

posted @ 2024-07-15 10:51  CuriosityWang  阅读(18)  评论(0编辑  收藏  举报