I'm reading shadertoy tutorial here: https://inspirnathan.com/posts/52-shadertoy-tutorial-part-6
there is a normal method to calculate the normal of the sphere:
vec3 calcNormal(vec3 p) {
float e = 0.0005; // epsilon
float r = 1.; // radius of sphere
return normalize(vec3(
sdSphere(vec3(p.x + e, p.y, p.z), r) - sdSphere(vec3(p.x - e, p.y, p.z), r),
sdSphere(vec3(p.x, p.y + e, p.z), r) - sdSphere(vec3(p.x, p.y - e, p.z), r),
sdSphere(vec3(p.x, p.y, p.z + e), r) - sdSphere(vec3(p.x, p.y, p.z - e), r)
));
}
then, he got a simpler one:
vec3 calcNormal(vec3 p) {
vec2 e = vec2(1.0, -1.0) * 0.0005; // epsilon
float r = 1.; // radius of sphere
return normalize(
e.xyy * sdSphere(p + e.xyy, r) +
e.yyx * sdSphere(p + e.yyx, r) +
e.yxy * sdSphere(p + e.yxy, r) +
e.xxx * sdSphere(p + e.xxx, r)
);
}
and the sdSphere function:
// p is the point location, r is radius, sdSphere calculate the distance of the point in the world and the origin point(0,0) with the radius of r.
float sdSphere(vec3 p, float r)
{
return length(p) - r; // p is the test point and r is the radius of the sphere
}
I can understand the normal method, but the simpler one, How could he do it, and it's correct?
I search for a while, can't get the answer, need some help, thanks.
I am the author of this tutorial. Sorry for the late response to this question . The second
calcNormalfunction is an alternative approach for creating a small gradient. The normal vector can be approximated by finding the distance between two close points on a sphere.Both the first and second approaches for implementing the
calcNormalfunction are not exactly equivalent. I have updated this on my blog to prevent future confusion. However, both functions get the job done for finding a small gradient because they both find two close points on the surface of the sphere or near the surface of the sphere.I have created a small JavaScript program that emulates some behavior of GLSL code in case you wanted to compare the differences between each
calcFunctionimplementation.As we can see, the results are very close!