How to Make a Parallax Occlusion Shader in Blender
Parallax occlusion mapping (POM) is a shader technique that simulates detailed 3D depth and surface relief on flat geometry without increasing polygon counts. While Blender does not feature a single native "POM" node, you can construct a high-performance parallax occlusion network inside the Shader Editor using vector math and texture coordinates. This guide provides a direct, step-by-step walkthrough to build an iterative ray-marched parallax occlusion shader suitable for both EEVEE and Cycles.
Step 1: Calculate the Tangent-Space View Vector
Parallax mapping offsets texture coordinates based on the angle between the surface and the camera. To make the effect view-dependent, you must convert the camera view direction into the surface's tangent space.
- Add a Texture Coordinate node and a Geometry node.
- Add a Vector Transform node:
- Set the type to Vector.
- Convert from World to Object.
- Connect the Incoming output from the Geometry node to the Vector input of the Vector Transform node.
- Add a Tangent node (set to UV Map).
- Combine the transformed incoming vector with the Tangent and Normal
vectors using a Vector Math (Dot Product) network to
isolate the \(X, Y,\) and \(Z\) components relative to the surface
plane:
- Calculate \(X = \text{Incoming} \cdot \text{Tangent}\)
- Calculate \(Y = \text{Incoming} \cdot \text{Bitangent}\) (Bitangent is the Cross Product of Normal and Tangent)
- Calculate \(Z = \text{Incoming} \cdot \text{Normal}\)
- Combine \(X, Y, Z\) into a single vector using a Combine XYZ node, then divide \(X\) and \(Y\) by \(Z\) using a Vector Math (Divide) node to calculate the view slope.
Step 2: Set Up Depth and Scale Controls
- Add a Value node and name it
Depth Scale. This controls the apparent depth of the effect. - Multiply the normalized tangent-space view vector \((X/Z, Y/Z)\) by the
Depth Scaleusing a Vector Math (Multiply) node. - Invert the result or multiply by \(-1\) so the parallax pushes inward into the surface rather than protruding.
Step 3: Implement Iterative Ray Marching
True parallax occlusion requires stepping through the height map in layers to find the exact intersection point where the view ray hits the virtual surface.
- Define Sample Count: Decide on the number of samples (typically between 8 and 32 steps). A higher count reduces visual slicing artifacts at steep angles.
- Step Size Calculation:
- Divide the total depth vector by the sample count (e.g., \(1 / 16\) for a 16-step setup).
- Divide the UV offset vector by the same sample count to establish the offset increment per step.
- Ray-March Node Group:
- Create a reusable Node Group that takes the Current UV, Current Depth, UV Step, and Depth Step as inputs.
- Sample your Height/Displacement Map using the Current UV.
- Compare the sampled height value against the Current Depth using a Math (Less Than) node.
- Add the UV Step to the Current UV, and add the Depth Step to the Current Depth.
- Chain the Steps:
- Chain multiple copies of this Node Group together in sequence (e.g., 8 to 16 iterations).
- Pass the output coordinates of each step into the input of the next step until the ray intersects the height map.
Step 4: Apply Linear Interpolation (Occlusion Refinement)
To achieve smooth results without stair-step artifacts, interpolate between the step right before the ray penetrated the surface and the step right after:
- Retrieve the height sample before the intersection and the height sample after the intersection.
- Calculate the difference between the ray depth and the surface depth for both steps.
- Use a Map Range or Mix (Interpolate) node to compute the precise sub-step intersection UV coordinate.
Step 5: Drive Material Textures with Parallax UVs
- Take the final interpolated UV coordinate output from your parallax calculation.
- Route this modified UV output directly into the
Vector input of all your material texture maps:
- Base Color Map
- Normal Map (Ensure the normal map uses the modified UV coordinates)
- Roughness Map
- Metallic / Ambient Occlusion Maps
- Connect the texture outputs into a Principled BSDF shader and connect the shader to the Material Output.
Best Practices and Optimization
- Clamp UV Boundaries: If tiling is not desired, place a Clamp node on the UV coordinates to prevent repeating edge artifacts.
- Node Groups: Encapsulate the entire POM network
into a custom Node Group with exposed parameters for
Depth Scale,Sample Steps, andHeight Map Inputto reuse it easily across different materials. - Performance: For flat surfaces viewed at shallow angles, keep the sample count around 12 to 16 to maintain fast real-time viewport playback in EEVEE while retaining crisp depth fidelity.