[Math] Surface normal to point on displaced sphere

differential-geometrygeometrylinear algebra

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$.

Picture of the deformed sphere
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$,

  1. Let $\vec{g}(\vec{x}) = \nabla f(\vec{x})$. Here, $\vec{g}$ is the true gradient of $f$ in 3-space, and you can calculate that in cartesian coordinates, so you get $\vec{g} = (g_x,g_y,g_z)$.
  2. Project out the radial component of $\vec{g}$ to get $\vec{h}(\vec{x})$. To do this, $\vec{h} = \vec{g} - \frac{\vec{g}\cdot\vec{x}}{\vec{x}\cdot\vec{x}}\vec{x}$. Note that the denominator should be 1. Here, $\vec{h}$ represents the component of $\vec{g}$ that should be tangential to a sphere centered at the origin and passing through $\vec{P}$.
  3. An outward normal vector to the surface is $\vec{n} = \vec{x} - s\cdot \vec{h}$. Normalize it to get a unit normal vector.

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.