# Parallel Occlusion Mapping

**URL:** <https://discourse.threejs.org/t/parallel-occlusion-mapping/75252>\
**Category:** Questions\
**Tags:** shaders\
**Created:** [December 16, 2024, 12:58pm UTC](https://discourse.threejs.org/t/parallel-occlusion-mapping/75252 "2024-12-16T12:58:32Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![rudrakpatra](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/rudrakpatra/32/54782_2.png) [@rudrakpatra](https://discourse.threejs.org/u/rudrakpatra)\
**Post date:** [December 16, 2024, 12:58pm UTC](https://discourse.threejs.org/t/parallel-occlusion-mapping/75252/1 "2024-12-16T12:58:33Z")

</div>

Hi I was experimenting with Parallel Occlusion Mapping and stumbled upon this OpenGL tutorial.

> **[LearnOpenGL - Parallax Mapping](https://learnopengl.com/Advanced-Lighting/Parallax-Mapping)**
>
> Learn OpenGL . com provides good and clear modern 3.3+ OpenGL tutorials with clear examples. A great resource to learn modern OpenGL aimed at beginners.

I have my code on glitch.  
[https://hammerhead-mixolydian-garden.glitch.me](https://hammerhead-mixolydian-garden.glitch.me)

> **[Glitch Code Editor ･ﾟ✧](https://glitch.com/edit/#!/hammerhead-mixolydian-garden)**
>
> Simple, powerful, free tools to create and use millions of apps.

the main issue is that the parallax steps are not linearly interpolating even.  
A copy of the shader code incase I change the glitch example

const shaderMaterial = new THREE.ShaderMaterial({  
uniforms: {  
diffuseMap: { value: diffuseMap },  
depthMap: { value: depthMap },  
iCameraPos:{value: new THREE.Vector3()},  
iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },  
iTime: { value: 0 },  
heightScale: { value: 0.1 } // Adjust to control the depth effect  
},  
vertexShader: `  
varying vec2 vUv;  
varying vec3 vViewDir;  
varying vec3 vPos;

```
  void main() {
      vPos = position;
      vUv = uv; // Pass UV coordinates to the fragment shader
      vViewDir = (modelViewMatrix * vec4(position, 1.0)).xyz; // Calculate the view direction
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }

`,
fragmentShader: `

```

uniform sampler2D diffuseMap; // Diffuse texture  
uniform sampler2D depthMap; // Depth map texture  
uniform vec3 iCameraPos;  
uniform vec2 iResolution; // Screen resolution  
uniform float iTime; // Time for animation effects  
uniform float heightScale; // Scale for heightmap intensity  
varying vec2 vUv; // UV coordinates from the vertex shader  
varying vec3 vPos;  
varying vec3 vViewDir; // View direction from the vertex shader

float depth\_scale=0.5;

vec2 ParallaxMapping(vec2 texCoords, vec3 viewDir)  
{  
float depth = texture2D(depthMap, texCoords).r;  
vec2 p = viewDir.xy / viewDir.z \* (depth \* depth\_scale);  
return texCoords - p;  
}

vec2 ParallaxOcclusionMapping(vec2 texCoords, vec3 viewDir)  
{  
// number of depth layers  
float minLayers = 8.0;  
float maxLayers = 32.0;  
float numLayers = mix(maxLayers, minLayers, max(dot(vec3(0.0, 0.0, 1.0), viewDir), 0.0));  
// calculate the size of each layer  
float layerDepth = 1.0 / numLayers;  
// depth of current layer  
float currentLayerDepth = 0.0;  
// the amount to shift the texture coordinates per layer (from vector P)  
vec2 P = viewDir.xy \* depth\_scale;  
vec2 deltaTexCoords = P / numLayers;

```
// get initial values
vec2 currentTexCoords = texCoords;
float currentDepthMapValue = texture2D(depthMap, currentTexCoords).r;

while(currentLayerDepth < currentDepthMapValue)
{
    // shift texture coordinates along direction of P
    currentTexCoords -= deltaTexCoords;
    // get depthmap value at current texture coordinates
    currentDepthMapValue = texture2D(depthMap, currentTexCoords).r;  
    // get depth of next layer
    currentLayerDepth += layerDepth;  
}

// get texture coordinates before collision (reverse operations)
vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

// get depth after and before collision for linear interpolation
float afterDepth = currentDepthMapValue - currentLayerDepth;
float beforeDepth = texture2D(depthMap, prevTexCoords).r - currentLayerDepth + layerDepth;

// interpolation of texture coordinates
float weight = afterDepth / (afterDepth - beforeDepth);
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

return finalTexCoords;  

```

}

void main() {

```
// Normalize the view direction
vec3 viewDir = normalize(vPos-iCameraPos);

// Perform parallax mapping to get new texture coordinates
vec2 texCoords = ParallaxOcclusionMapping(vUv, viewDir);
if(texCoords.x > 1.0 || texCoords.y > 1.0 || texCoords.x < 0.0 || texCoords.y < 0.0)
discard;

// Sample the diffuse map with the modified UVs
vec4 color = texture2D(diffuseMap, texCoords);

// Output final color
gl_FragColor = vec4(color.xyz,1.0);

```

}`  
});
