<p>You can do this a little bit more efficiently and accurately by calculating derivatives of $P$ with respect to $u, v$—or the derivatives with respect to $\phi, \theta$, equivalently (up to a scalar multiple).</p>

<p>Start by expressing $P$ in terms of the spherical coordinates:
$$\begin{aligned}
P_x &amp;= r \cos \theta \cos \phi \\
P_y &amp;= r \sin \theta \\
P_z &amp;= r \cos \theta \sin \phi
\end{aligned}$$</p>

<p>Now you can get the tangent as $T = \partial P / \partial \phi$, which works out as:
$$\begin{aligned}
T_x &amp;= -r \cos \theta \sin \phi \\
T_y &amp;= 0 \\
T_z &amp;= r \cos \theta \cos \phi
\end{aligned}$$</p>

<p>Once you normalize it, the $r \cos \theta$ factors drop out and you're left with just $T = (-\sin \phi, 0, \cos \phi)$. Pretty simple!</p>

<p>You can similarly get the bitangent as $B = \partial P / \partial \theta$, or you can just calculate it as the cross product $N \times T$, which is probably faster. (Note it should be $N \times T$, not $T \times N$, assuming you want $T, B, N$ to form a right-handed basis in that order.)</p>

<hr>

<p>The above approach will work for pretty much any kind of surface that can be parameterized, not just spheres. However, in the case of spheres with the usual $\phi, \theta$ coordinates, there's an even quicker shortcut that you can do with just vector math, no trig at all. Let $C$ be the center of the sphere, and $A$ be a vector representing the axis of the spherical coordinates—i.e. pointing from the center toward the north pole. Then you can just calculate $T = \text{normalize}\bigl(A \times (P - C) \bigr)$, then $B = N \times T$ as before.</p>

CC BY-SA 3.0
2017-08-15T14:26:26.903Z
Thank you! I knew derivatives were the answer, just couldn't figure it out by myself. The vector way is really elegant and clever.
MadEqua
CC BY-SA 3.0
2017-08-14T22:22:22.820Z
2017-08-14T22:22:22.820Z
Nathan Reed
<p>I'm implementing normal mapping on my toy pathtracer. I need to compute the tangent (and bitangent) of any sphere point in order to create the matrix that will transform tangent space to world space.</p>

<p>More specifically, I want the tangent that runs along the u texture coordinate, and the bitangent that runs along the v coordinate.</p>

<p>Here's how I implemented it:</p>

<ul>
<li>At the intersection point P, compute the spherical coordinates
(theta, phi) of P.</li>
<li>Add a tiny delta to the angle that relates to the u texture
coordinate (phi), finding another point Q on the sphere.</li>
<li>Compute Q - P and normalize it to have the tangent.</li>
<li>The bitangent is then computed by doing the cross product of the
tangent and the normal at the point P.</li>
</ul>

<p>Relevant code on the sphere collision function:</p>

<pre><code>    hitRecord.point = ray.pointAtParameter(t);

    Vec3 localCoord = hitRecord.point - center;
    float theta = asin(localCoord.y / radius); //[-pi/2,pi/2]
    float phi = atan2(localCoord.z, localCoord.x); //[-pi,+pi]

    float deltaPhi = phi + FLOAT_BIAS;
    Vec3 deltaPoint(radius * cos(theta) * cos(deltaPhi),
        radius * sin(theta),
        radius * cos(theta) * sin(deltaPhi));

    //Assume local space to be aligned with world space
    //So this is also the tangent in world space
    hitRecord.tangent = deltaPoint - localCoord;
    hitRecord.tangent.normalize();

    hitRecord.normal = localCoord / radius;
    hitRecord.bitangent = hitRecord.tangent.cross(hitRecord.normal);
    hitRecord.bitangent.normalize();
</code></pre>

<p>This seems to work, but all this trigonometry is not light and makes me wonder if there is a better way of doing it. Does anyone has any ideias/pointers?</p>

CC BY-SA 3.0
2017-08-15T06:29:18.053Z
Would like to add that normal map is about bump mapping, it wouldn't be "lighting" the surface. Lighting equation does that and so check that if you aren't getting them lit.
ChaoSXDemon
CC BY-SA 3.0
2017-08-18T08:57:32.860Z
Couldn't you get the tangent by just doing a cross product between the normal and the main axis of your spherical coordinate system?
russ
CC BY-SA 3.0
2017-08-23T05:13:09.937Z
whoops so he did, i didn't read that far down ;)
russ
<raytracing><pathtracing><normal-mapping>
Compute sphere tangent for normal mapping
MadEqua
# Compute sphere tangent for normal mapping

(Asked by: username_0 on 2017-08-14)

I'm implementing normal mapping on my toy pathtracer. I need to compute the tangent (and bitangent) of any sphere point in order to create the matrix that will transform tangent space to world space.

More specifically, I want the tangent that runs along the u texture coordinate, and the bitangent that runs along the v coordinate.

Here's how I implemented it:

* At the intersection point P, compute the spherical coordinates
  (theta, phi) of P.
* Add a tiny delta to the angle that relates to the u texture
  coordinate (phi), finding another point Q on the sphere.
* Compute Q - P and normalize it to have the tangent.
* The bitangent is then computed by doing the cross product of the
  tangent and the normal at the point P.

Relevant code on the sphere collision function:

```
    hitRecord.point = ray.pointAtParameter(t);

    Vec3 localCoord = hitRecord.point - center;
    float theta = asin(localCoord.y / radius); //[-pi/2,pi/2]
    float phi = atan2(localCoord.z, localCoord.x); //[-pi,+pi]

    float deltaPhi = phi + FLOAT_BIAS;
    Vec3 deltaPoint(radius * cos(theta) * cos(deltaPhi),
        radius * sin(theta),
        radius * cos(theta) * sin(deltaPhi));

    //Assume local space to be aligned with world space
    //So this is also the tangent in world space
    hitRecord.tangent = deltaPoint - localCoord;
    hitRecord.tangent.normalize();

    hitRecord.normal = localCoord / radius;
    hitRecord.bitangent = hitRecord.tangent.cross(hitRecord.normal);
    hitRecord.bitangent.normalize();

```

This seems to work, but all this trigonometry is not light and makes me wonder if there is a better way of doing it. Does anyone has any ideias/pointers?

**Tags:** raytracing, pathtracing, normal-mapping

> **Comments:**
> **username_1**: Would like to add that normal map is about bump mapping, it wouldn't be "lighting" the surface. Lighting equation does that and so check that if you aren't getting them lit.  
> **username_2**: Couldn't you get the tangent by just doing a cross product between the normal and the main axis of your spherical coordinate system?  
> **username_2**: whoops so he did, i didn't read that far down ;)  

---

## 1 answers

### Answer by username_3 on 2017-08-14. Score: 6 | Accepted answer

You can do this a little bit more efficiently and accurately by calculating derivatives of $P$ with respect to $u, v$—or the derivatives with respect to $\phi, \theta$, equivalently (up to a scalar multiple).

Start by expressing $P$ in terms of the spherical coordinates:
$$\begin{aligned}
P\_x &= r \cos \theta \cos \phi \\
P\_y &= r \sin \theta \\
P\_z &= r \cos \theta \sin \phi
\end{aligned}$$

Now you can get the tangent as $T = \partial P / \partial \phi$, which works out as:
$$\begin{aligned}
T\_x &= -r \cos \theta \sin \phi \\
T\_y &= 0 \\
T\_z &= r \cos \theta \cos \phi
\end{aligned}$$

Once you normalize it, the $r \cos \theta$ factors drop out and you're left with just $T = (-\sin \phi, 0, \cos \phi)$. Pretty simple!

You can similarly get the bitangent as $B = \partial P / \partial \theta$, or you can just calculate it as the cross product $N \times T$, which is probably faster. (Note it should be $N \times T$, not $T \times N$, assuming you want $T, B, N$ to form a right-handed basis in that order.)

---

The above approach will work for pretty much any kind of surface that can be parameterized, not just spheres. However, in the case of spheres with the usual $\phi, \theta$ coordinates, there's an even quicker shortcut that you can do with just vector math, no trig at all. Let $C$ be the center of the sphere, and $A$ be a vector representing the axis of the spherical coordinates—i.e. pointing from the center toward the north pole. Then you can just calculate $T = \text{normalize}\bigl(A \times (P - C) \bigr)$, then $B = N \times T$ as before.

> **Comments:**
> **username_0**: Thank you! I knew derivatives were the answer, just couldn't figure it out by myself. The vector way is really elegant and clever.  

---

