Skip to content

Commit

Permalink
Code cleanup, add eikonal pass, update Unity.
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelbigos committed Apr 6, 2022
1 parent c2d64fc commit 1c11960
Show file tree
Hide file tree
Showing 45 changed files with 1,247 additions and 1,484 deletions.
13 changes: 13 additions & 0 deletions .idea/.idea.unity_sdf_demo/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/.idea.unity_sdf_demo/.idea/indexLayout.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/.idea.unity_sdf_demo/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 9 additions & 39 deletions Assets/Compute/BoidPhysics.compute
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma kernel Step

#include "../Includes/SDF.cginc"

struct Boid
{
float3 position;
Expand All @@ -11,49 +13,23 @@ float3 _planetCentre;
float _timeStep;
float _gravity;

Texture3D<float> _sdfTex;
SamplerState sampler_sdfTex;
float _sdfRadius;
float _sdfDistMod;

int _numBoids;
RWStructuredBuffer<Boid> _boidBufferIn;
RWStructuredBuffer<Boid> _boidBufferOut;

float sdf(float3 uv)
{
uv /= (_sdfRadius * 2.0);
uv += float3(0.5, 0.5, 0.5);
float sdf = _sdfTex.SampleLevel(sampler_sdfTex, uv, 0);
sdf = (sdf * 2.0) - 1.0;
sdf *= (_sdfRadius * 2.0);
sdf *= _sdfDistMod;
return sdf;
}

float3 projectUonV(float3 u, float3 v)
{
float3 r;
r = v * (dot(u, v) / dot(v, v));
return r;
}

float3 calcNormal(float3 p)
{
float h = 0.001;
float2 k = float2(1, -1);
return normalize(k.xyy * sdf(p + k.xyy * h) +
k.yyx * sdf(p + k.yyx * h) +
k.yxy * sdf(p + k.yxy * h) +
k.xxx * sdf(p + k.xxx * h));
}

[numthreads(1,1,1)]
void Step (uint3 id : SV_DispatchThreadID)
void Step(uint3 id : SV_DispatchThreadID)
{
Boid boid = _boidBufferIn[id.x];

// collide with other boids
// Collide with other boids
for (uint i = 0; i < (uint)_numBoids; i++)
{
if (i == id.x)
Expand All @@ -69,7 +45,7 @@ void Step (uint3 id : SV_DispatchThreadID)
float dist = distance(p0, p1);
float r = r0 + r1;
float diff = dist - r;
if (diff <= 0.0) // hit
if (diff <= 0.0)
{
float3 mov = diff * 0.5 * normalize(p1 - p0);
boid.position += mov;
Expand All @@ -82,11 +58,12 @@ void Step (uint3 id : SV_DispatchThreadID)
}
}

float dist = sdf(boid.position.xyz) - boid.radius;
float dist = sdfWorld(boid.position.xyz) - boid.radius;

// collide with planet
// Collide with planet
{
float3 toSurface = -calcNormal(boid.position);
dist *= calcEikonalCorrection(toSurface);

float3 p0 = boid.position;
float3 p1 = boid.position + toSurface * (dist + boid.radius);
Expand All @@ -109,16 +86,9 @@ void Step (uint3 id : SV_DispatchThreadID)
nv0 -= projectUonV(v0, p0 - p1);
boid.velocity = nv0 * 1.0;
}

/*float3 toSurface = -calcNormal(boid.position);
float onPlanet = 1.0 - step(0.0, dist + 0.0001);
float speed = length(boid.velocity) * 0.4;
float normComponent = dot(boid.velocity, toSurface.xyz);
boid.velocity += (normComponent * -toSurface) * onPlanet;
boid.velocity += -toSurface * speed * onPlanet;*/
}

// gravity
// Gravity
float3 toPlanet = normalize(_planetCentre - boid.position);
float3 gravity = toPlanet * _gravity;
boid.velocity += gravity * _timeStep;
Expand Down
32 changes: 8 additions & 24 deletions Assets/Compute/SDFGen.compute
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
#pragma kernel SDFGen

RWTexture3D<float> _sdfTex;
uint _sdfTexSizeX;
uint _sdfTexSizeY;
uint _sdfTexSizeZ;
float _sdfRadius;
float _sdfDistMod;
float _sphereRadius;
#include "../Includes/SDF.cginc"

float sdSphere(float3 pos, float radius)
{
return length(pos) - radius;
}
RWTexture3D<float> _sdfTexOut;
float _sphereRadius;

[numthreads(8,8,8)]
void SDFGen(uint3 id : SV_DispatchThreadID)
{
float3 uv = float3(float(id.x), float(id.y), float(id.z)) + float3(0.5f, 0.5f, 0.5f);
uv /= float3(float(_sdfTexSizeX), float(_sdfTexSizeY), float(_sdfTexSizeZ));

float3 centre;
centre.x = 0.5f;
centre.y = 0.5f;
centre.z = 0.5f;
float sphereRadius = _sphereRadius / (_sdfRadius * 2.0f);
float dist = sdSphere(uv - centre, sphereRadius);

dist = clamp(dist / _sdfDistMod, -1.0f, 1.0f);
dist = dist * 0.5f + 0.5f;
_sdfTex[id.xyz] = dist;
float3 uv = kernelToUV(id);
float3 pos = uvToWorld(uv);
float current = sdSphere(pos, float3(0.0f, 0.0f, 0.0f), _sphereRadius);

_sdfTexOut[id.xyz] = pack(current);
}
149 changes: 55 additions & 94 deletions Assets/Compute/SDFGenMutate.compute
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
#pragma kernel SDFMutate

Texture3D<float> _sdfTexIn;
SamplerState sampler_sdfTexIn;
#include "../Includes/SDF.cginc"

RWTexture3D<float> _sdfTexOut;
uint _sdfTexSizeX;
uint _sdfTexSizeY;
uint _sdfTexSizeZ;
float _sdfRadius;
float _sdfDistMod;

bool _mouseSubtract;
bool _mouseAdd;
Expand All @@ -16,12 +11,6 @@ float4 _mouseDir;

float raySphereIntersect(float3 r0, float3 rd, float3 s0, float sr)
{
// - r0: ray origin
// - rd: normalized ray direction
// - s0: sphere center
// - sr: sphere radius
// - Returns distance from r0 to first intersecion with sphere,
// or -1.0 if no intersection.
float a = dot(rd, rd);
float3 s0_r0 = r0 - s0;
float b = 2.0 * dot(rd, s0_r0);
Expand All @@ -30,101 +19,75 @@ float raySphereIntersect(float3 r0, float3 rd, float3 s0, float sr)
{
return -1.0;
}
return (-b - sqrt((b * b) - 4.0 * a * c)) / (2.0 * a);
return (-b - sqrt(b * b - 4.0 * a * c)) / (2.0 * a);
}

float sdf(float3 uv)
float neighborMin(uint3 kernel, uint3 delta)
{
uv /= (_sdfRadius * 2.0);
uv += float3(0.5, 0.5, 0.5);
float sdf = _sdfTexIn.SampleLevel(sampler_sdfTexIn, uv, 0);
sdf = (sdf * 2.0) - 1.0;
sdf *= (_sdfRadius * 2.0);
sdf *= _sdfDistMod;
return sdf;
float a = sdfUV(kernelToUV(kernel + delta));
float b = sdfUV(kernelToUV(kernel - delta));
return min(abs(a), abs(b));
}

bool outOfBounds(float3 pos)
float eikonal1d(float h, float v, float g)
{
if (length(pos) < _sdfRadius)
{
return false;
}
return true;
return min(h, v) + g;
}

float rayMarch(float3 origin, float3 dir, float k, out float res, out float3 hitPos)
float eikonal2d(float h, float v, float g)
{
res = 1.0;
float t = 0.0001;
[loop]
for (int i = 0; i < 256; i++)
if (abs(h - v) >= g)
{
float3 current = origin + dir * t;
if (outOfBounds(current))
{
return 0.0;
}
float dist = sdf(current);
if (dist <= 0.0)
{
hitPos = current;
res = 0.0;
return 1.0;
}
dist = max(dist, 0.0001);
res = min(res, k * dist / t);
t += dist;
return eikonal1d(h, v, g);
}
return 0.0;
float hv = h + v;
float d = hv * hv - 2.0 * (h * h + v * v - g * g);
return 0.5 * (hv + sqrt(d));
}

float sdSphere(float3 pos, float radius)
{
return length(pos) - radius;
}

float opSubtraction(float d1, float d2)
{
return max(d1, -d2);
}
float opSmoothSubtraction(float d1, float d2, float k)
bool eikonal3d(float3 u, out float e, float g)
{
float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0);
return lerp(d2, -d1, h) + k * h * (1.0 - h);
float xyz = u.x + u.y + u.z;
float n = 3.0;
float d = (xyz * xyz) - n * ((u.x * u.x + u.y * u.y + u.z * u.z) - (g * g));
if (d < 0.0)
{
return false;
}
e = (1.0 / n) * (xyz + sqrt(d));
return true;
}

float opUnion(float d1, float d2)
float eikonal(float3 u, float g)
{
return min(d1, d2);
}
float opSmoothUnion(float d1, float d2, float k)
{
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
return lerp(d2, d1, h) - k * h * (1.0 - h);
float e = 0.0;
if (eikonal3d(u, e, g))
{
return e;
}
float e1 = eikonal2d(u.x, u.y, g);
float e2 = eikonal2d(u.x, u.z, g);
float e3 = eikonal2d(u.y, u.z, g);
return min(min(e1, e2), e3);
}

[numthreads(8,8,8)]
void SDFMutate(uint3 id : SV_DispatchThreadID)
{
float3 uv = float3(float(id.x), float(id.y), float(id.z)) + float3(0.5f, 0.5f, 0.5f);
uv /= float3(float(_sdfTexSizeX), float(_sdfTexSizeY), float(_sdfTexSizeZ));

float3 centre;
centre.x = 0.5f;
centre.y = 0.5f;
centre.z = 0.5f;
float3 worldUV = (uv - centre) * (_sdfRadius * 2.0);
float dist = sdf(worldUV);

//sdf = opSmoothSubtraction(sdSphere(worldUV - float3(0.0, 1.0, 0.0), 0.3), sdf, 0.15);
//sdf = opSmoothUnion(sdSphere(worldUV - float3(0.0, 0.75, 0.0), 0.5), sdf, 0.05);
//sdf = opSmoothUnion(sdSphere(worldUV - float3(0.9, 0.0, 0.0), 0.3), sdf, 0.1);
//sdf = opSmoothUnion(sdSphere(worldUV - float3(-0.9, 0.0, 0.0), 0.3), sdf, 0.1);
//sdf = opSmoothUnion(sdSphere(worldUV - float3(0.0, 0.0, 0.9), 0.3), sdf, 0.1);
//sdf = opSmoothUnion(sdSphere(worldUV - float3(0.0, 0.0, -0.9), 0.3), sdf, 0.1);
//sdf = opSmoothSubtraction(sdSphere(worldUV - float3(0.0, -1.0, 0.0), 0.5), sdf, 0.15);
float3 uv = kernelToUV(id);
float current = sdfUV(uv);
float3 world = uvToWorld(uv);

// Eikonal
float3 u;
u.x = neighborMin(id, uint3(1, 0, 0));
u.y = neighborMin(id, uint3(0, 1, 0));
u.z = neighborMin(id, uint3(0, 0, 1));

float g = _sdfRadius * 2.0 / _sdfTexSizeX;
float e = eikonal(u, g);
if (current > g) current = e;

if (_mouseAdd)
{
float toSdf = raySphereIntersect(_mouseOrigin.xyz, _mouseDir.xyz, float3(0.0, 0.0, 0.0), 1.0);
Expand All @@ -137,10 +100,10 @@ void SDFMutate(uint3 id : SV_DispatchThreadID)
{
float addRadius = 0.05;
float3 pos = ro;
dist = opSmoothUnion(sdSphere(worldUV - pos, addRadius), dist, 0.05);
current = opSmoothUnion(sdSphere(world, pos, addRadius), current, 0.05);
}
}

if (_mouseSubtract)
{
float toSdf = raySphereIntersect(_mouseOrigin.xyz, _mouseDir.xyz, float3(0.0, 0.0, 0.0), 1.0);
Expand All @@ -151,17 +114,15 @@ void SDFMutate(uint3 id : SV_DispatchThreadID)
float hit = rayMarch(ro, _mouseDir.xyz, 1.0, res, hitPos);
if (hit > 0.0)
{
float subtractRadius = 0.2;
float subtractRadius = 0.06;
for (int i = 0; i < 5; i++)
{
float3 pos = ro - rd * subtractRadius * 0.1 * float(i);
dist = opSmoothSubtraction(sdSphere(worldUV - pos, subtractRadius), dist, 0.05);
current = opSmoothSubtraction(sdSphere(world, pos, subtractRadius), current, 0.1);
}

}
}

dist /= (_sdfRadius * 2.0f);
dist /= _sdfDistMod;
_sdfTexOut[id.xyz] = dist * 0.5 + 0.5;
}

_sdfTexOut[id.xyz] = pack(current);
}
Loading

0 comments on commit 1c11960

Please sign in to comment.