You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
5.6 KiB
HLSL
219 lines
5.6 KiB
HLSL
/******************************************************************************/
|
|
/*
|
|
Project - MudBun
|
|
Publisher - Long Bunny Labs
|
|
http://LongBunnyLabs.com
|
|
Author - Ming-Lun "Allen" Chou
|
|
http://AllenChou.net
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
#ifndef MUDBUN_SDF_PRIMITIVES
|
|
#define MUDBUN_SDF_PRIMITIVES
|
|
|
|
#include "../Math/Vector.cginc"
|
|
#include "../Noise/CachedNoise3D.cginc"
|
|
#include "../Noise/ClassicNoise3D.cginc"
|
|
#include "../Noise/TriangleNoise3D.cginc"
|
|
|
|
// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
|
|
|
|
// r: radius
|
|
float sdf_sphere(float3 p, float r)
|
|
{
|
|
return length(p) - r;
|
|
}
|
|
|
|
// h: extent
|
|
float sdf_ellipsoid(float3 p, float3 h)
|
|
{
|
|
float k0 = max(kEpsilon, length(p / h));
|
|
float k1 = max(kEpsilon, length(p / (h * h)));
|
|
return 0.6f * (k0 * (k0 - 1.0f) / k1);
|
|
}
|
|
|
|
// c: center
|
|
// h: extent
|
|
// r: round
|
|
float sdf_box(float3 p, float3 h, float r = 0.0f)
|
|
{
|
|
h = abs(h);
|
|
float3 d = abs(p) - h;
|
|
return length(max(d, 0.0f)) + min(max_comp(d), 0.0f) - r;
|
|
}
|
|
|
|
// a: point A
|
|
// b: point B
|
|
// r: radius
|
|
float sdf_capsule(float3 p, float3 a, float3 b, float r)
|
|
{
|
|
float3 ab = b - a;
|
|
float3 ap = p - a;
|
|
p -= a + saturate(dot(ap, ab) / dot(ab, ab)) * ab;
|
|
return length(p) - r;
|
|
}
|
|
|
|
// h: height
|
|
// r1: radius 1
|
|
// r2: radius 2
|
|
// r: round
|
|
float sdf_capped_cone(float3 p, float h, float r1, float r2, float r = 0.0f)
|
|
{
|
|
float2 q = float2(length(p.xz), p.y);
|
|
float2 k1 = float2(r2, h);
|
|
float2 k2 = float2(r2 - r1, 2.0f * h);
|
|
float2 ca = float2(q.x - min(q.x, (q.y < 0.0f) ? r1 : r2), abs(q.y) - h);
|
|
float2 cb = q - k1 + k2 * clamp(dot(k1 - q, k2) / dot(k2, k2), 0.0f, 1.0f);
|
|
float s = (cb.x < 0.0f && ca.y < 0.0f) ? -1.0f : 1.0f;
|
|
return s * sqrt(min(dot(ca, ca), dot(cb, cb))) - r;
|
|
}
|
|
|
|
// h: height
|
|
// r: radius
|
|
// rr: extra radius
|
|
float sdf_cylinder(float3 p, float h, float r, float rr = 0.0f)
|
|
{
|
|
float2 d = abs(float2(length(p.xz), p.y)) - float2(r, h);
|
|
return min(max(d.x, d.y), 0.0f) + length(max(d, 0.0f)) - rr;
|
|
}
|
|
|
|
float sdf_torus(float3 p, float h, float r1, float r2)
|
|
{
|
|
float3 q = float3(max(abs(p.x) - h, 0.0f), p.y, p.z);
|
|
return length(float2(length(q.xz) - r1, q.y)) - r2;
|
|
}
|
|
|
|
float sdf_solid_angle(float3 p, float2 c, float r, float rr = 0.0f)
|
|
{
|
|
// c is the sin/cos of the angle
|
|
float2 q = float2(length(p.xz), p.y);
|
|
float l = length(q) - r;
|
|
float m = length(q - c * clamp(dot(q, c), 0.0f, r));
|
|
return max(l, m*sign(c.y * q.x - c.x * q.y)) - rr;
|
|
}
|
|
|
|
float sdf_noise(int type, float3 p, float3 boundsMin, float3 boundsMax, float3 offset, float3 size, float threshold, int numOctaves, float octaveOffsetFactor, float3 period = 100.0f)
|
|
{
|
|
float n = 0.0f;
|
|
float f = 1.0f;
|
|
switch (type)
|
|
{
|
|
case kSdfNoiseTypePerlin:
|
|
n = 0.8f * (saturate(mbn_pnoise(p / size, offset, numOctaves, octaveOffsetFactor, period)) - 0.5f) + 0.5f;
|
|
f = 0.9f;
|
|
break;
|
|
|
|
case kSdfNoiseTypeCachedPerlin:
|
|
n = 0.9f * mbn_cached_noise(p / size, offset, numOctaves, octaveOffsetFactor);
|
|
f = 0.8f;
|
|
break;
|
|
|
|
case kSdfNoiseTypeTriangle:
|
|
n = mbn_triangle_noise(p / size, offset, numOctaves, octaveOffsetFactor);
|
|
f = 0.4f;
|
|
break;
|
|
}
|
|
|
|
float d = threshold - n;
|
|
|
|
// noise is not an actual SDF
|
|
// we need to scale the result to make it behave like one
|
|
// making the result slightly smaller than it should be would prevent false positive voxel node culling
|
|
d *= f * min(min(size.x, size.y), size.z);
|
|
|
|
return d;
|
|
}
|
|
|
|
float sdf_round_cone(float3 p, float3 a, float3 b, float r1, float r2)
|
|
{
|
|
// sampling independent computations (only depend on shape)
|
|
float3 ba = b - a;
|
|
float l2 = dot(ba, ba);
|
|
float rr = r1 - r2;
|
|
float a2 = l2 - rr * rr;
|
|
float il2 = 1.0f / l2;
|
|
|
|
// sampling dependent computations
|
|
float3 pa = p - a;
|
|
float y = dot(pa, ba);
|
|
float z = y - l2;
|
|
float3 g = pa * l2 - ba * y;
|
|
float x2 = dot(g, g);
|
|
float y2 = y * y * l2;
|
|
float z2 = z * z * l2;
|
|
|
|
// single square root!
|
|
float k = sign(rr) * rr * rr * x2;
|
|
if (sign(z) * a2 * z2 > k)
|
|
return sqrt(x2 + z2) * il2 - r2;
|
|
|
|
if (sign(y) * a2 * y2 < k)
|
|
return sqrt(x2 + y2) * il2 - r1;
|
|
|
|
return (sqrt(x2*a2*il2) + y * rr)*il2 - r1;
|
|
}
|
|
|
|
// https://www.shadertoy.com/view/MsXGWr
|
|
float2 sdf_segment(float3 p, float3 a, float3 b)
|
|
{
|
|
float3 pa = p - a, ba = b - a;
|
|
float h = saturate(dot(pa, ba) / dot(ba, ba));
|
|
return float2(length(pa - ba * h), h);
|
|
}
|
|
|
|
// https://www.shadertoy.com/view/ldj3Wh
|
|
float2 sdf_bezier(float3 pos, float3 A, float3 B, float3 C)
|
|
{
|
|
float3 a = B - A;
|
|
float3 b = A - 2.0f * B + C;
|
|
float3 c = a * 2.0f;
|
|
float3 d = A - pos;
|
|
|
|
float kk = 1.0f / dot(b, b);
|
|
float kx = kk * dot(a, b);
|
|
float ky = kk * (2.0f * dot(a, a) + dot(d, b)) / 3.0f;
|
|
float kz = kk * dot(d,a);
|
|
|
|
float2 res;
|
|
|
|
float p = ky - kx * kx;
|
|
float p3 = p * p * p;
|
|
float q = kx * (2.0f * kx * kx - 3.0f * ky) + kz;
|
|
float h = q * q + 4.0f * p3;
|
|
|
|
if(h >= 0.0f)
|
|
{
|
|
h = sqrt(h);
|
|
float2 x = (float2(h, -h) - q) / 2.0f;
|
|
float2 uv = sign(x) * pow(abs(x), 0.33333333f);
|
|
float t = clamp(uv.x + uv.y - kx, 0.0f, 1.0f);
|
|
|
|
// 1 root
|
|
float3 g = d + (c + b * t) * t;
|
|
res = float2(dot(g, g), t);
|
|
}
|
|
else
|
|
{
|
|
float z = sqrt(-p);
|
|
float v = acos(q / (p * z * 2.0f)) / 3.0f;
|
|
float m = cos(v);
|
|
float n = sin(v) * 1.732050808f;
|
|
float3 t = clamp(float3(m + m,-n - m, n - m) * z - kx, 0.0f, 1.0f);
|
|
|
|
// 3 roots, but only need two
|
|
float3 g = d + (c + b * t.x) * t.x;
|
|
float dis = dot(g, g);
|
|
res = float2(dis, t.x);
|
|
|
|
g = d + (c + b * t.y) * t.y;
|
|
dis = dot(g, g);
|
|
if(dis < res.x)
|
|
res = float2(dis, t.y);
|
|
}
|
|
|
|
res.x = sqrt(res.x);
|
|
return res;
|
|
}
|
|
|
|
#endif
|