RayMarching 不同SDF的混合

Number of views 294

本篇我们以下面两个SDF模型为例,分别为Sphere与Cube:

image1740559514883.png

不同SDF混合大体可以分为5种方式:

1.交集。字面上理解就是在渲染不同SDF模型时只留下相交部分,如让Sphere与Cube重合,重合后的模型状态如下:

image1740559709927.png通过 交集处理后,变成:

image1740559752935.png

通过 max(d1, d2)来实现交集函数:

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

这其实挺好理解,假设SDF在RayMarching下的判断条件为 <=0.01才能显示其SDF模型的表面,那么模型内部的SDF必然小于0.01。所以:

  1. Cube(=0.01)Sphere(<0.01)内部时,显示的是Cube的表面,因为 max(Cube(=0.01), Sphere(<0.01))=Cube(=0.01)
  2. Cube(=0.01)有部分在 Sphere(>0.01)外部时,把Cube露出的部分剔除了,因为 max(Cube(=0.01), Sphere(>0.01)外部)=Sphere(>0.01)外部。因为显示模型的表面需要满足 <=0.01,所以Cube露出的部分就都剔除了

2.并集。简单理解就是把不同的SDF合并为同一个SDF。

image1740561495671.png合并SDF的方式通过 min(d1, d2)实现。

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

3.差集。在集合论中,差集指的是从一个集合中去掉另一个集合的所有元素后剩下的部分。当Cube与Sphere以如下方式组合,想去掉Cube,只留下Sphere该如何做?

image1740562008640.png

image1740562238322.png根据上图可知,我们把Cube的部分都去除了,只留下了Sphere,所以可以看到一个镂空的Sphere。这种方式的实现通过如下函数定义:

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

如果我们要去除B就在distB前加上 -负号,如果要去除A就在distA前加上 -负号即可。

image1740562759487.png

4.混合。混合就是通过一种方法把不同的SDF进行平滑的变换。比如把Sphere变为Cube,或把Cube变为Sphere,这中间通过mix函数实现平滑变换。

image1740649861114.png

mix(cubeSdf,sphereSdf, sin(iTime)*0.5+0.5)

5.重复。重复的过程就是把一个模型在x轴与z轴或y轴上重复绘制的过程。如下图:

image1741916867021.png

实现方式通过类似下面的代码:

float fScene(vec3 pt) {
     vec3 pos;
     pos = vec3(mod(pt.x + 2, 4) - 2, pt.y, mod(pt.z + 2, 4) - 2);
     return sdScene(pos, vec3(1));
}

我们通过mod函数让原点附近的sdf沿着对应轴重复绘制。以 mod(pt.x + 2, 4) - 2做说明:

image1741917531793.png可以看到它返回的值在 -2~2之间。我们也可以扩大在原点附近可重复sdf模型的范围,比如x轴的范围在-5~5之间。z轴范围在 -10 ~ 10之间。

p = vec3(mod(p.x+5., 10.)-5.,p.y, mod(p.z+10.,20.)-10.);

image1741917984439.png

0 Answers