Heuristic42
Blog
Opengl
Meta
Rendering
1
comment
Apr 19 at 11:24
Matrices
Please have whoever is in charge of the business call me at the…
–
anonymous
comment
Apr 13 at 0:25
Matrices
Hey there! Looking to save on energy costs? Look no further! …
–
anonymous
comment
Apr 5 at 9:43
Matrices
If you look closely in the Bible, there are very specific warni…
–
anonymous
comment
Mar 27 at 17:19
Matrices
Are you still in business? heuristic42.com
–
anonymous
comment
Mar 25 at 4:59
Matrices
Hey There I tried calling your phone number but it was unsuc…
–
anonymous
comment
Mar 5 at 15:39
Matrices
Hi, I hope this message finds you well. I'm reaching out to …
–
anonymous
comment
Feb 7 at 5:45
Microsoft Natural Ergonomic 4000 Replacement
Thank you so much for sharing your thoughts here, it tells me e…
–
anonymous
comment
Jan 28 at 23:31
Microsoft Natural Ergonomic 4000 Replacement
Oh man, I feel this post. Not sure if you've seen the "new" new…
–
anonymous
comment
Jan 25 at 12:06
Matrices
Hi, Mark here. If it is ok for your business processes to be…
–
anonymous
comment
Jan 20 at 3:11
Matrices
[deleted]
–
anonymous
reverted
Dec 21 '23
Route contention when running docker and a VPN
updating to latest
–
admin
edited
Dec 21 '23
Route contention when running docker and a VPN
Things have improved since the original post. It may have been …
–
pknowles
edited
Dec 21 '23
Route contention when running docker and a VPN
Things have improved since the original post. It may have been …
–
anonymous
edited
Dec 21 '23
Route contention when running docker and a VPN
This have improved since the original post. It may have been up…
–
anonymous
comment
Nov 24 '23
Matrices
[deleted]
–
anonymous
edited
Sep 17 '23
Writing custom C++ containers, iterators and value references
Generic containers are awesome. 1. The effort required to wr…
–
pknowles
created
Sep 17 '23
Writing custom C++ containers, iterators and value references
Generic containers are awesome. 1. The effort required to wr…
–
pknowles
comment
Sep 15 '23
DerBard: Custom Split Mechanical Keyboard Prototype
Hey. Thanks for your interest! I've uploaded the files here, bu…
–
pknowles
comment
Sep 13 '23
DerBard: Custom Split Mechanical Keyboard Prototype
Hi! Is it possible to get some models so I can also make it?
–
anonymous
edited
Aug 14 '23
On docker stealing routes and breaking the internet
Boy this is frustrating. The internet just doesn't work with do…
–
pknowles
edited
Aug 14 '23
On docker stealing routes and breaking the internet
Boy this is frustrating. The internet just doesn't work with do…
–
pknowles
created
Aug 14 '23
On docker stealing routes and breaking the internet
Boy this is frustrating. The internet just doesn't work with do…
–
pknowles
comment
Jul 13 '23
Matrices
[deleted]
–
anonymous
comment
Jul 6 '23
Matrices
[deleted]
–
anonymous
…
View All
Log in
Tangent Space
leave this field blank to prove your humanity
Slug
*
A URL path component
Parent page
<root>
3D Rendering (Computer Graphics)
--- Cameras
--- Matrices
------ Projection Matrix
--- Vectors
--- 3D Geometry
------ triangle_meshes
--- Shading
------ Transparency and Alpha Blending
--- Lights
--- rasterization
------ Deep Image
--- Shadows
--- Vector Spaces
------ Tangent Space
------ Clip Space
--- rotations
--- images
------ mipmapping
--- materials
OpenGL Tutorials
--- Order Independent Transparency (OIT)
--- The Framebuffer
Pages About This Site
--- Contributing
--- Bugs
--- Why does this website exist?
The parent page this belongs to.
Article title
*
Article revisions must have a non-empty title
Article body
*
Tangent space lies on the surface of geometry, allowing operations relative to the surface. Unlike other spaces, it bends and warps relative to world space. The basis vectors are the normal and two tangents at each vertex of a mesh. Like the normals, tangent space is typically interpolated over the geometry faces. Tangent space is most popular in *normal mapping*, which perturbs the geometry normals based on a normal map texture. The texture coordinates of the normal map provide the two tangent vectors implicitly, as described below. One of them is usually precomputed before rendering for efficiency. As tangent space is based on the geometry normals, normal mapping simply uses the normals from the texture in tangent space directly. They are then an additional direction applied on top of the geometry normal. Parallax mapping also uses tangent space and in particular parallax occlusion mapping, or relief mapping, involves tracing through the texture as a heightmap within tangent space. # Transforming to tangent space It may be simpler to describe how to use a tangent space mapping before how to creating it, i.e. find the tangent vectors. In the following example, we have a normal $n$ and single precomputed tangent $t$ for each vertex in a triangle mesh. We want to find a direction vector towards a light $l_T$ for a point on a triangle in tangent space. Then for example in the case of normal mapping, the dot product between the normal in the texture and $l_T$ gives a lambert diffuse scalar. Firstly, we need all input vectors in the same space. The light vector is often in world or eye space, and it can be more convenient to transform the normal and tangent vector to the same as often this is done anyway add part of rendering, rather than convert the light to object space. However, since the transformation is not necessarily orthonormal, it may be necessary to re-normalize the normal and tangent and adjust the tangent vector so that it remains orthographic/perpendicular. Also note that the tangent is transformed with the vertices by the regular transformation matrix while the normal is transformed by the inverse of the transpose to keep it perpendicular. The second tangent vector, $b$ often called the bi-normal (sometimes bi-tangent) is implicit, being orthonormal and can be found using the cross product. This can be used to make sure the original tangent vector is orthographic if it isn't already. $$ \begin{align} b &= t \times n \\ t_\perp &= n \times b \end{align} $$ Now that we have all the basis vectors, the direction vector $l$ can be found in tangent space $l_T$ as $x, y, z$ amounts of $t$, $b$ and $n$ respectively. Note that there is a strong convention of $z$ being the direction of the normal. $$ \begin{align} l_{T_x} &= t \cdot l \\ l_{T_y} &= b \cdot l \\ l_{T_z} &= n \cdot l \\ \end{align} $$ These dot products can be rewritten in matrix form. The tangent space transformation matrix aptly named TBN is built by $t$, $b$, and $n$ forming rows. $$ l_T = \mathsf{TBN} \, l $$ With $l_T$ known for each vertex, it can be interpolated to find the value at a point on the triangle. This is equivalent to interpolating TBN, although the vectors need to be normalized after interpolation. The position in tangent space is typically the 2D interpolated texture coordinate. Tangent space is then generally used for direction only, hence the $3\times3$ $\mathsf{TBN}$ matrix. A more general tangent space transformation including position is discussed later. # Finding the tangents Tangent space lies on the surface of an object. Its up direction must point away from the surface, but there is no orientation constraint from the geometry alone. Texture coordinates can provide a constraint for a tangent space relative to a mapped texture. The constraint could be chosen arbitrarily, but this is essentially attempting automatic texture mapping, which is a very challenging problem. Texture mapping is often constructed by hand to reduce seams and provide good texel density and automatic methods often produce poor results. With that said, seams and stretching of tangent space may not be so important depending on the application. ## From texture coordinates To compute tangents for each vertex in a triangle mesh, imagine a triangle of your mesh drawn over its texture, as in the image below. We need to create a transformation between object space and texture space. This happens at each triangle and is not valid as a global transformation. Rather than map the basis vectors globally, as described in the [matrices](/9/rendering/matrices/) page, a more direct tangent space derivation maps triangle edge vectors. This is described first, but for completeness we discuss the relation to global basis vectors later. ![tangent space and texture visualization][1] Given three vertices, $A$, $B$, $C$, the vectors $u=\overrightarrow{AB}$ and $v=\overrightarrow{AC}$ in object space must match the same vectors in texture space $s=\overrightarrow{AB}_T$ and $t=\overrightarrow{AC}_T$. A third dimension is added for the normal, although the normal direction in tangent space is implicitly $(0, 0, 1)$. It can be ignored but is shown here for context. Note the construction of matrices using row and column vectors. $$ \begin{bmatrix}s & t & (0, 0, 1) \end{bmatrix} = \begin{bmatrix}t \\ b \\ n \end{bmatrix} \begin{bmatrix}u & v & n \end{bmatrix} $$ Here we have six unknowns and six equations using them. I.e. the components for $t$ and $b$ are unknown but we have equations for $s$ and $t$. This can be solved in matrix form by multiplying both sides by the inverse of $\begin{bmatrix}u & v & n \end{bmatrix}$. $$ \begin{bmatrix}t \\ b \\ n \end{bmatrix} = \begin{bmatrix}s & t & (0, 0, 1) \end{bmatrix} \begin{bmatrix}u & v & n \end{bmatrix}^{-1} $$ Alternatively, the inverse of a $2\times2$ matrix is simpler and this equation can be rearranged as follows. This is possible as we assume the $\mathsf{TBN}$ matrix is orthonormal and can be inverted by taking the transpose. $n$ is ignored as it is known and the tangents are perpendicular and linearly independent. $$ \begin{align} \begin{bmatrix}t & b \end{bmatrix} &= \begin{bmatrix}u & v \end{bmatrix} \begin{bmatrix}s & t \end{bmatrix}^{-1} \\ &= \frac{1}{s_x t_y - s_y t_x} \begin{bmatrix}u & v \end{bmatrix} \begin{bmatrix} t_y & -t_x \\ -s_y & s_x \end{bmatrix} \end{align} $$ Expanding the matrix representation to vector components gives the final answer. Remember, $(u, v)$ are the triangle edge vectors in object space and $(s, t)$ are the same edges in texture space. $$ \begin{align} d &= \frac{1}{s_x t_y - s_y t_x} \\ t_x &= d (u_x t_y - v_x s_y) \\ t_y &= d (u_y t_y - v_y s_y) \\ t_z &= d (u_z t_y - v_z s_y) \\ b_x &= d (v_x s_x - u_x t_x) \\ b_y &= d (v_y s_x - u_y t_x) \\ b_z &= d (v_z s_x - u_z t_x) \\ \end{align} $$ ## Smooth tangent vectors ## Relative to basis vectors ## Position ## Without texture coordinates # External Links - [Eric Lengyel's tangent space article](http://www.terathon.com/code/tangent.html) has excellent descriptions and source code. [1]: /u/img/ff5e4cc94010.svg
Toggle Preview
Edit message
*
A description of the changes made
Discard Draft
Save Draft
leave this field blank to prove your humanity
Flag
the thing you clicked
for moderator attention.
Reason choice:
Spam, promoting, advertising without disclosure
Rude, inappropriate, generally offensive
Too arrogant or demeaning to others
Other
Reason:
The reason for raising the flag
Error