<p>The normal of a given point on the height map is perpendicular to the 2 vectors defined by <code>gx</code> and <code>gy</code>. The original surface normal is not relevant to this. So in tangent space, the normal is:</p>

<pre><code>Vector tangent = Vector(1, 0, gx);
Vector bitangent = Vector(0, 1, gy);
Vector normal = normalize(cross(tangent, bitangent));
</code></pre>

<p>You then need to convert the normal from tangent space to world space. For this you need the so-called "TBN matrix" (tangent, bitangent, normal matrix). There are plenty of <a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping" rel="nofollow noreferrer">articles</a> <a href="https://www.gamasutra.com/blogs/RobertBasler/20131122/205462/Three_Normal_Mapping_Techniques_Explained_For_the_Mathematically_Uninclined.php" rel="nofollow noreferrer">around</a> explaining this. But the gist is:</p>

<pre><code>Vector T = normalize(To_World_Matrix * intersection.tangent());
Vector B = normalize(To_World_Matrix * cross(intersection.tangent(), intersection.normal()));
Vector N = normalize(To_World_Matrix * intersection.normal());
mat3 TBN = mat3(T, B, N); // GLSL syntax
</code></pre>

<p>The last thing is to do a change of basis to move the normal from tangent space to world space:</p>

<pre><code>Vector normal_world_space = normalize(TBN * normal);
</code></pre>

<p>Keep in mind that the order of some cross-products might be inverted in what I wrote if you get normals pointing inside the surface.</p>

CC BY-SA 4.0
2019-01-20T08:02:13.293Z
2019-01-20T08:02:13.293Z
bernie
<p>I'm trying to add bump mapping to my ray tracer, and I'm currently struggling to add bump mapping to it, as I don't seem to get the transformations from texture space to world space correctly.</p>

<p>I have an arbitary Triangle in world-Space defined by it's vertices.
Each of the vertices store a normalized UV-Coordinate to interpolate the position on the height map for an Intersection Point.
The height map is a gray-Scale Image
So when I intersect with the Triangle, I calculate the x and y derivatives of the height map at the corresponding uv-coordinate, transform the x and y unit Vectors (of the Texture) to world-Space, and calculate the changed normal. This currently looks like this:</p>

<pre><code>        Point p = lerpbar(uv_vert1, uv_vert2, uv_vert3, 
               intersection.barycentric.u, intersection.barycentric.v);
        float gx = this-&gt;_bmap-&gt;getColorDX(p);
        float gy = this-&gt;_bmap-&gt;getColorDY(p);
        Vector wx = (To_World_Matrix * Vector(1, 0, 0))).normalize();
        Vector wy = (To_World_Matrix * Vector(0, 1, 0))).normalize();
        Vector n = intersection.normal();
        return n + (gx * cross(n, wy) - gy * cross(n, wx));
</code></pre>

<p>However, I just can't figure out what Matrix I'd need to use so this produces correct results, as I just don't really understand how to map from unit Vectors to World-Space Vectors when I only know how arbitay Triangle Edges relate to arbitay Vectors in Texture Space.</p>

<raytracing><transformations>
Bump mapping with triangles and height maps
Fallere
# Bump mapping with triangles and height maps

(Asked by: username_0 on 2019-01-18)

I'm trying to add bump mapping to my ray tracer, and I'm currently struggling to add bump mapping to it, as I don't seem to get the transformations from texture space to world space correctly.

I have an arbitary Triangle in world-Space defined by it's vertices.
Each of the vertices store a normalized UV-Coordinate to interpolate the position on the height map for an Intersection Point.
The height map is a gray-Scale Image
So when I intersect with the Triangle, I calculate the x and y derivatives of the height map at the corresponding uv-coordinate, transform the x and y unit Vectors (of the Texture) to world-Space, and calculate the changed normal. This currently looks like this:

```
        Point p = lerpbar(uv_vert1, uv_vert2, uv_vert3, 
               intersection.barycentric.u, intersection.barycentric.v);
        float gx = this->_bmap->getColorDX(p);
        float gy = this->_bmap->getColorDY(p);
        Vector wx = (To_World_Matrix * Vector(1, 0, 0))).normalize();
        Vector wy = (To_World_Matrix * Vector(0, 1, 0))).normalize();
        Vector n = intersection.normal();
        return n + (gx * cross(n, wy) - gy * cross(n, wx));

```

However, I just can't figure out what Matrix I'd need to use so this produces correct results, as I just don't really understand how to map from unit Vectors to World-Space Vectors when I only know how arbitay Triangle Edges relate to arbitay Vectors in Texture Space.

**Tags:** raytracing, transformations


---

## 1 answers

### Answer by username_1 on 2019-01-20. Score: 2 | Accepted answer

The normal of a given point on the height map is perpendicular to the 2 vectors defined by `gx` and `gy`. The original surface normal is not relevant to this. So in tangent space, the normal is:

```
Vector tangent = Vector(1, 0, gx);
Vector bitangent = Vector(0, 1, gy);
Vector normal = normalize(cross(tangent, bitangent));

```

You then need to convert the normal from tangent space to world space. For this you need the so-called "TBN matrix" (tangent, bitangent, normal matrix). There are plenty of [articles](https://learnopengl.com/Advanced-Lighting/Normal-Mapping) [around](https://www.gamasutra.com/blogs/RobertBasler/20131122/205462/Three_Normal_Mapping_Techniques_Explained_For_the_Mathematically_Uninclined.php) explaining this. But the gist is:

```
Vector T = normalize(To_World_Matrix * intersection.tangent());
Vector B = normalize(To_World_Matrix * cross(intersection.tangent(), intersection.normal()));
Vector N = normalize(To_World_Matrix * intersection.normal());
mat3 TBN = mat3(T, B, N); // GLSL syntax

```

The last thing is to do a change of basis to move the normal from tangent space to world space:

```
Vector normal_world_space = normalize(TBN * normal);

```

Keep in mind that the order of some cross-products might be inverted in what I wrote if you get normals pointing inside the surface.


---

