Hi,
I am working on a simple raymarching shader the goal of which is to blend both colors and geometry of up to 64 spheres both by smooth union and subtraction operations.
My approach is basic:
- Whenever the scene is changed I check bounds intersection for each unique sphere and find the list of all others spheres that might have a blending impact on it
- I then create new MaterialPropertyBlock and pass to the raymarching shader all positions and colors of these spheres
- In the shader itself I loop trough these values and find the final sdf result
inline float sminExp(float a, float b, float k)
{
float res = exp2(-k * a) + exp2(-k * b);
return -log2(res) / k;
}
inline float DistanceFunction(float3 wpos)
{
float m = 0;
float r = _Rs[0];
float4 localPos = float4(wpos, 0.0) - _WorldPoses[0];
float d = Sphere(localPos, r);
m = d;
for (int i = 1; i < _Objects_N; i++)
{
r = _Rs[i];
localPos = float4(wpos, 0.0) - _WorldPoses[i];
d = Sphere(localPos, r);
m = sminExp(d, m, _Smooth).x;
}
r = _NegRs[0];
localPos = float4(wpos, 0.0) - _NegWorldPoses[0];
float negm = Sphere(localPos, r);
for (int i = 1; i < _NegObjects_N; i++)
{
r = _NegRs[i];
localPos = float4(wpos, 0.0) - _NegWorldPoses[i];
d = Sphere(localPos, r);
negm = sminExp(d, negm, _Smooth);
}
m = SmoothSub(negm, m, _Smooth * .5);
return m;
}
inline float2 smin2(float a, float b, float k)
{
float h = max(k - abs(a - b), 0.0) / k;
float m = h * h * 0.5;
float s = m * k * (1.0 / 2.0);
return (a < b) ? float2(a - s, m) : float2(b - s, m - 1.0);
}
inline void PostEffect(float3 rmpos, inout SurfaceData o)
{
float L = 0;
float dNorms[32];
float4 finalColor = _Colors[0];
float m = 0;
float r = _Rs[0];
float4 localPos = float4(rmpos, 0.0) - _WorldPoses[0];
float d = Sphere(localPos, r);
m = d;
for (int i = 1; i < _Objects_N; i++)
{
r = _Rs[i];
localPos = float4(rmpos, 0.0) - _WorldPoses[i];
d = Sphere(localPos, r);
float2 sm = smin2(m, d, _Smooth);
m = sm.x;
finalColor = lerp(finalColor, _Colors[i], abs(sm.y));
}
o.albedo = finalColor;
}
But I have 2 major problems with it:
-
To make such approach work the smooth min function has to be order independent and I was successfully able to find one in this smooth min article written by talented Inigo Quilez. But unfortunately I couldn’t find the float2 match to calculate the order independent color factor as well (not polynomial, but exp based one). All examples I find in Shadertoy, even the ones that utilize exp smooth min, do not have order independent color blending. So where can I find a proper order independent smooth min blending factor function to properly mix the colors in my clustered approach?
-
For 10+ spheres per material the performance gets very poor, perhaps it is because of the loops? I feel like there are practically no other way except to pass each of up to 64 spheres (10-20 normal scenario) and carefully calculate sdf value for them all in one place. I tried dynamic camera resolution feature, but it alters the overlay UI, so I couldn’t stick with it. Perhaps there are others ways to handle the multiple spheres sdfs calculations in a more efficient manner? The biggest bottleneck in my approach is these 2 loops I have.
Look forward for any suggestions or external links, thanks!