parallaxOcclusion

@three-blocks/coreWebGPUWebGL
parallaxOcclusion(v_uv : Node<vec2>, dispTex : Node<Texture>, parallaxScale : Node<float>, blueNoiseTex : Node<Texture>|null, minSamples : Node<int>, maxSamples : Node<int>, refineSteps : Node<int>, edgeMargin : Node<float>) : Node<vec3>

Parallax Occlusion Mapping (POM) node for high-quality surface displacement.

Algorithm

  • Ray-marches through displacement texture along view direction
  • Adaptive sampling: more samples at grazing angles
  • Binary search refinement for sub-texel precision
  • Blue noise jittering to eliminate banding artifacts
  • Edge fading prevents UV stretching at borders
  • Computes depth offset for correct depth buffer integration

Benefits

  • Creates deep surface detail without tessellation
  • Accurate self-shadowing and occlusion
  • Smooth interpolation via binary refinement
  • Perceptually uniform with blue noise sampling
  • Automatic LOD via adaptive sample count
Parameters
v_uvNode<vec2>
UV coordinates node.
dispTexNode<Texture>
Displacement/height map texture (white=raised, black=recessed).
parallaxScaleoptionalNode<float>
Scale factor controlling depth of parallax effect.
Default is 0.05.
blueNoiseTexoptionalNode<Texture> | null
Optional blue noise texture for jitter (reduces banding).
Default is null.
minSamplesoptionalNode<int>
Minimum ray-march samples (used at perpendicular view).
Default is 24.
maxSamplesoptionalNode<int>
Maximum ray-march samples (used at grazing angles).
Default is 96.
refineStepsoptionalNode<int>
Binary search refinement iterations for precision.
Default is 3.
edgeMarginoptionalNode<float>
UV margin for edge fade (prevents stretching).
Default is 0.02.
Returns
Node<vec3> — Displaced UV coordinates (xy) and depth pixel offset (z).
See also
  • {@link https://web.archive.org/web/20150419215321/http://sunandblackcat.com/tipFullView.php?l=eng&topicid=28}
  • {@link https://learnopengl.com/Advanced-Lighting/Parallax-Mapping}
Example
import { parallaxOcclusion } from '@three-blocks/core';
import { texture, uv } from 'three/tsl';

const material = new MeshStandardNodeMaterial();
const heightMap = texture(heightTexture);
const blueNoise = texture(blueNoiseTexture);

// Apply POM to displace UVs
const result = parallaxOcclusion(
  uv(),
  heightMap,
  0.08,        // parallax depth scale
  blueNoise,   // optional noise for quality
  32,          // min samples
  128,         // max samples
  4            // refinement steps
);

// Use displaced UVs for texture sampling
material.colorNode = texture(diffuseTex, result.xy);
material.normalNode = normalMap(texture(normalTex, result.xy));