I want to calculate the surface normal to a point on a deformed sphere. The surface of the sphere is displaced along its (original) normals by a function $f(\vec x)$.
In mathematical terms:
Let $\vec x$ be a unit length vector in 3D, i.e. any point on the unit sphere centered on the origin. And let $f:\vec x \to \mathbb{R}$ be a function with a well-defined and continuous gradient $\nabla f(\vec x)$ for every $\vec x$.
Now a point on the surface of the resulting sphere is defined as:
$\vec P(\vec x) = (R + s \cdot f(\vec x)) \cdot \vec x$
where $R$ and $s$ are constants for the radius and the modulation depth, respectively.
The question now: Is this information sufficient to calculate the surface normal to the point $\vec P$? I feel like this should be possible, but it is entirely possible that it is not.
More information:
The function in my case is 3D Simplex Noise which gives values on the range $(-1,1)$ for any $\vec x$. The values for $R$ are about 10 times larger than those of $s$, probably more. Maybe this helps if only an approximation is possible.
UPDATE:
Yes, it is possible, though there is still some error in here:
- Calculate the gradient: $\vec g = \nabla f(\vec x)$
- Then project it into the tangent plane to the sphere passing through the point:
$\vec h = \vec g – (\vec g \cdot \vec x)\vec x$ - The normal can then be calculated as
$\vec n = \vec x – s \cdot \vec h$
This works as long as the radius is $R=1$ and something like $s \ll R$.
I think for $R \ne 1$ the gradient has to be rescaled: $\vec g = \dfrac{1}{R} \nabla f(\vec x)$
But I have no idea why the error gets larger with increasing $s$.
UPDATE 2:
Alright, the rescaling factor was only half complete $\vec g = \dfrac{\nabla f(\vec x)}{R + s \cdot f(\vec x)}$
Now it works for all $R$ and $s$.
Here is an image to give some intuition what this thing looks like (with approximated normals).
Best Answer
Let's say that your surface is defined by $\vec{r}(\Theta) = [r_0 + s f(\Theta) ] \hat{r}$, where $\Theta$ represents the spherical angles. I'm going to conjecture that the normal vector in radial coordinates is proportional to $\vec{n} = (-s\nabla f,1)$, where the gradient is a 2-vector in the angle space, and the last component is the radial direction.
We can verify this by making sure the normal vector is orthogonal to the surface. Note that a tangent vector to the surface is $(1,s\nabla f)$. This tangent points along the gradient direction. A normal vector orthogonal to this one points along an isocontour, which by construction is $(\hat{\Theta}^\perp,0)$, where $\hat{\Theta}^\perp$ is 90 degree rotation of the unit angular vectors in the tangent plane to the sphere passing through the point. The dot product with both of these is zero; the first is obvious, while for the second, $\nabla f \cdot \hat{\Theta}^\perp = 0$.
TL;DR: In radial coordinates: $(-s\nabla f,1)$, then just normalize and convert to cartesian if needed.
Elaboration: Based on your comment, it seems that your $f(\vec{x})$ is a scalar function of a 3-vector. Then $\nabla f$ is a 3-vector. The notation I use lumps the spherical coordinates $(\phi,\theta)$ into a single abstract 2-vector-like quantity $\Theta$, so that when you say $f(\Theta)$, that means $f$ is a function of only the spherical coordinate angles (and not a function of radius). Then $\nabla f(\Theta)=\nabla_\Theta f(\Theta)$ is a gradient in this 2-dimensional angle space. Your $\nabla f$ needs to be projected onto the surface of a sphere first, since you only ever sample $f(\vec{x})$ for $\lVert \vec{x} \rVert = 1$.
So, to calculate your normals, given a point $\vec{P}(\vec{x}) = [R + s f(\vec{x})]\vec{x}$ with $\vec{x}$ such that $\lVert \vec{x} \rVert = 1$,
All these computations can be done in Cartesian coordinates, but notice that I never had to resort to referring to the Cartesian components of any vector; the basic operations are vector arithmetic and dot products.