I'm working on implementing Parallax Occlusion mapping.

So far I've gotten some pretty nice results (as long as the height scale is low), but I'm not entire sure if my results are completely correct.

I know that at grazing angles the naive parallax mapping effect breaks, but other tweaks exist to minimize those errors.

My question is this: is it normal for the perceived depth into a parallax mapped surface to stretch and scale depending on the viewing angle? Like, the effect works pretty good, but when I start looking at it at a shallow angle the depth into the map seems to drop:

I'm doing this effect during my gbuffer filling pass, and modify the incoming texture coordinates as so:

Code:

const vec3 ViewTangentEyePos = mat3(InvVMatrix) * ViewTBN * EyePosition.xyz; // ViewTBN is the viewspace Tangent,Bitangent,Normal (TBN) matrix
const vec3 ViewTangentFragPos = mat3(InvVMatrix) * ViewTBN * m_vertex.xyz;
const vec3 View_Dir = normalize(ViewTangentEyePos - (mMatrix * vec4(vertex,1.0)));
const float View_Angle = abs(dot(vec3(0.0, 0.0, 1.0), View_Dir));
const float minLayers = 8.0;
const float maxLayers = 32.0;
const float numLayers = mix(maxLayers, minLayers, View_Angle);
const float layerDepth = 1.0f / numLayers;
const vec2 P = View_Dir.xy * height_scale;
const vec2 deltaTexCoords = P / numLayers;
vec2 currentTexCoords = TexCoord0;
float currentDepthMapValue = 1.0f - texture(MaterialMap, vec3(currentTexCoords, 1)).a; // Height stored in alpha channel
float currentLayerDepth = 0.0;
while(currentLayerDepth < currentDepthMapValue)
{
currentTexCoords -= deltaTexCoords;
currentDepthMapValue = 1.0f - texture(MaterialMap, vec3(currentTexCoords, 1)).a;
currentLayerDepth += layerDepth;
}
const vec2 prevTexCoords = currentTexCoords + deltaTexCoords;
const float afterDepth = currentDepthMapValue - currentLayerDepth;
const float beforeDepth = 1.0f - texture(MaterialMap, vec3(prevTexCoords, 1)).a - currentLayerDepth + layerDepth;
const float weight = afterDepth / (afterDepth - beforeDepth);
const vec2 Parallax_TexCoord = prevTexCoords * weight + currentTexCoords * (1.0 - weight);

Edited:

Fixed, I needed to divide View_Dir.xy by its Z component in vec2 P, so it now reads:

Code:

const vec2 P = View_Dir.xy / View_Dir.z * height_scale;