First: Why do you need the closest point? You should be able to test for collisions without knowing it (you just need to be able to evaluate the distance function at the center of the sphere). Is it because you want to evaluate the gradient there? Have you tried just using the gradient at the sphere's center?
In order to respond to the collision I need a surface normal (which, with the distance, implies a closest point). Evaluating at the center of the sphere failed in the case of compound operations (union/intersection/subtraction); since things seemed to converge on the correct normal when distance=0, I figured marching downward towards the closest point (distance=0) might be useful. But it's not
Second: When you're inside, if you have a signed distance function and you want to find the closest point on the surface, you need to go uphill, but when you're outside you need to go downhill. Consider the one-dimensional "d(x)=abs(x)-1" example.
I think I was doing this right -- I was marching against the gradient, pos -= distance*gradient (which marches downhill when distance is positive and uphill when negative).
For points outside union(S1,S2), it's correct. The definition of the distance from the point to a set, is that it's the minimum over all the distances to all the points in that set.
But for points inside union(S1, S2), it is only an upper bound on the signed distance (lower bound on the distance to complement). It does always have the correct sign and the correct zero-level set.
Yeah, this is what I was afraid of.
It's not the union so much as the subtraction/intersection operations -- with union you expect your objects to stay on the outside (of course, in practice they might not, but that can be addressed later) so things will be well-behaved. But in the case of subtraction/intersection, all of one/some of both volumes (respectively) will be empty space, which means it's likely that the query point will be inside the volume and ruin the correct result (which only happens when the query point is outside of both volumes).
In 1d, all signed distance functions take the form
d(x) = abs(x-a)+b
for some constants a and b.
Now say your sets are the intervals,
S1 = [-5, 1]
S2 = [-1, 5] .
Then you have the signed distance functions
d1(x) = abs(x+2)-3
d2(x) = abs(x-2)-3 .
Now define the function
f(x) = min(d1(x), d2(x)).
Question: Is f(x) a distance function? If you plot it, you'll see that the answer is "no." It doesn't have the shape of a shifted/translated absolute value function.
Thanks, this makes it clear to me.
I guess there's just no way to do what I want? (e.g compose simple primitive distance functions -- sphere, box, etc. -- into compound functions which represent CSG operations on sets of primitives)