Website icon.

georgeom | posts

Parallax Mapping

Introduction

Like normal mapping, Parallax Mapping is a technique used in 3D real time software that aims to provide more fidelity to surfaces without having to use an absurd amount of triangles. With normal mapping, each texel of the normal map that’s used provides a surface normal which can be used in per-fragment lighting calculations. This allows us to calculate the lighting for every single fragment of a single triangle, meaning we can have a low-polygon surface with fairly convincing light interactions.

Per-Vertex Normals Per-Fragment Normals Using Normal Mapping

With parallax mapping, we again use a texture to encode per-fragment data, but instead of each texel representing a fragment’s surface normal, each texel represents a fragments height relative to the surface. This of course means we only need to use a single colour channel, instead of three.

Normal Map Height Map

Really, though, the techniques cannot be compared. Normal mapping conveys depth to the viewer by increasing the fidelity of the light interactions of a surface, whereas parallax mapping actually attempts to simulate the varying depths of the irregularities upon a surface. For the best results, we will combine both normal mapping and parallax mapping.

Theory

The theory behind simple parallax mapping is actully quite straight forward. Here is a step-by-step run down of how we produce the desired texture coordinates for each fragment using parallax mapping:

In Practice

vec2 parallax_mapping(vec2 p_tex_coords, vec3 p_view_dir)
{
    // Sample the height map using our original texture coordinates
    // We take this value away from 1, so we have a depth instead of a height
    float depth = 1.0 - texture(u_height_map, p_tex_coords).r;

    // ...
    vec2 parallax_displacement = p_view_dir.xy / p_view_dir.z * (depth * u_height_scale);

    // Return the parallaxed texture coordinates
    return p_tex_coords - parallax_displacement;
}

Steep Parallax Mapping