Hi I was experimenting with Parallel Occlusion Mapping and stumbled upon this OpenGL tutorial.
I have my code on glitch.
https://hammerhead-mixolydian-garden.glitch.me
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);
}`
});