 # 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:

• First we start by obtaining the fragment-to-view vector, that is, a vector pointing from the current fragment and to the position of the viewer.
• We then sample the height map at the coordinates of the current fragment to obtain the height value.
• Using that height value we limit the magnitude of the FtV vector to obtain a new vector whose length is equal to the sampled value.
• The components of the new vector that align with the coordinates of the texture are used to offset our existing texture coordinates when we sample whatever textures we’re using in our fragment shader (diffuse map, normal map, specular, etc.).

# 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;
}
``````