Parallax Occlusion Mapping looks flat
ImplementsLegend opened this issue ยท 2 comments
With current lighting system, self-shadowing with voxelized LPV is pretty much impossible. I am curious about your implementation of directional lighting based on POM normals tho. How did ya do it?
I modified the POM function to detect which side was "hit", then I used that information to rotate the normal vector.
I tried using very differen algorithm for POM. The idea was, instead of having fixed number of steps, you always jump to next edge of 2 texels. When you have depth information for two points you can tell whether you hit an edge or face (if firstSampleDepth higher than testedDepth then you hit face, if secondSampleDepth higher than testedDepth then you hit edge, else no hit). Based on how the two texels are aligned, you can tell the axis of edge hit and based on view direction you can tell the direction of edge hit.
This is what my POM function looked like, although I'm sure it didn't work exactly as intended:
vec2 getParallaxCoord(vec2 texCoord, float parallaxFade, out float surfaceDepth, out int normalModifier) {
vec2 coord = vTexCoord.st;
surfaceDepth = 1.0;
normalModifier = 0;
if (viewVector != viewVector) {
return texCoord;
}
float dither = Bayer8(gl_FragCoord.xy);//unused since this algorithm should be accurate enough to not need it
#ifdef TAA
dither = fract(dither + frameTimeCounter * 16.0);
#endif
float currentStep = 1.0;
vec3 normalMap = readNormal(coord).xyz * 2.0 - 1.0;
float normalCheck = normalMap.x + normalMap.y;
if (parallaxFade >= 1.0 || normalCheck < -1.999) return texCoord;
vec2 tsize = 1/vTexCoordAM.pq;
vec2 fpixCoords = coord*tsize;
float depth = readNormal(coord).a;
vec2 sdir = -viewVector.xy/viewVector.z;
vec2 scaledDirPix = sdir.xy*tsize;
int normalModifierX = viewVector.x>0?2:1;
int normalModifierY = viewVector.y>0?3:4;
int _normalModifier = 0;
for(int smp = 0;smp<10000;smp++){/*teoretically should only need low single digits at mo*/
if(currentStep<=depth){
normalModifier=0;
float stepLength = (depth-currentStep);
fpixCoords-=scaledDirPix*stepLength;
break;
}
float newDepth = readNormal(fpixCoords/tsize).a;
if(currentStep<=newDepth){
normalModifier=_normalModifier;
break;
}
depth=newDepth;
vec2 amountBeyondEdge = fract(fpixCoords);
amountBeyondEdge.x=amountBeyondEdge.x>0.999?0.0:amountBeyondEdge.x;
amountBeyondEdge.y=amountBeyondEdge.y>0.999?0.0:amountBeyondEdge.y;
vec2 vstepLength;
vstepLength.x=(1.0-amountBeyondEdge.x)/abs(scaledDirPix.x);
vstepLength.y= (1.0-amountBeyondEdge.y)/abs(scaledDirPix.y);
bool flag = vstepLength.x<vstepLength.y;
float stepLength = flag?vstepLength.x:vstepLength.y;
_normalModifier = flag?normalModifierX:normalModifierY;
fpixCoords+=scaledDirPix.xy*stepLength;
currentStep-=stepLength/(PARALLAX_DEPTH*4);
}
coord = fract((fpixCoords/tsize).st) * vTexCoordAM.pq + vTexCoordAM.st;
surfaceDepth = depth;
return coord;
}