Parallax occlusion

Finally got around to making it work
right side view

Had to finagle TBN matrix to obtain a proper parallax occlusion.

Lighting normal correction


Repo published -

Let me know if there’s some files missing.


Updated the repo with lighting normal correction.

1 Like

If there would be a “Hall of fame” section in the forums, your name would be at the top of it! Nice work! It’s always awesome to see what you have prepared. :+1:


Very cool demo .
I made a small modification to pass GLSL compilation on Android

1 Like

This is fantastic. Thanks a lot for the awesome work, @Lumak! :heart_eyes:

Glad ppl like this repo, I think this was something that’s been over due by several years.

@elix22 Let me know what the change is or I can’t take look at your changes in your fork.

It applies both for iOS and Android .
The change is in Parallax.glsl

Add at the top:

    precision mediump float;
    precision highp float;

change from :

const float minLayers = 8;
const float maxLayers = 36;

change to :

float minLayers = 8.0;
float maxLayers = 36.0;

change from :

    if ( fDenominator == 0.0f )
       fParallaxAmount = 0.0f;

change to :

    if ( fDenominator == 0.0 )
       fParallaxAmount = 0.0;
1 Like

can it work with terrains?

I couldn’t just answered the question but had to try it. And the answer is, you can do parallax mapping on terrain with limitations. This is because detail textures requires displacement and normal map. If you were to do that with 1-weight map and 3-detail textures, that would mean you’ll need total of 10 textures. That’ll be problematic, however, you can do it with 2 detail textures. Texture detail list:
1-weight map
2-detailmap1 with displacement(heightmap) embedded in alpha channel
3-detailmap2 with displacement(heightmap) embedded in alpha channel
4-normalmap1 for detailmap1
5-normalmap2 for detailmap2

Very restrictive but do-able. Here’s a test that I did. Nope. this is not right.
conclusion: the very first image, which is edited out, has only normal map applied and no matter what I tried, parallax mapping fails due to varying normals, even if you fix the tangents and bitangents some parts of the terrain becomes distorted. So, parallax mapping will not work, but normal map will.

@elix22 thank you for that. I’ll update the repo with your changes.

Updated the repo: bug fix for parallaxLength computation, added elix22’s android changes, added saint images.
and another pic

Is this just an adaption of the shader on Learn OpenGL or totally rewritten yourself? I mean, seeing as this is an established technique there’s going to be a lot of similarities lol.

I also wrote an Urho3D version of that shader from Learn OpenGL awhile ago. Don’t think I ever made a Github repo for it though. Anyway, it’s nice seeing someone else trying this effect.

I had no idea about your work. I wish I had known about it; that would’ve save me the trouble writing one. The shader code in my work is from DirectX SDK, along with the textures.

1 Like

@Lumak you missed a small change.
const int assignment into float will fail on some android devices

float minLayers = 8;
float maxLayers = 36;

change to :

float minLayers = 8.0;
float maxLayers = 36.0;

For those that would like to try it on an Android device,
I generated an Android apk with all the samples , this one included.


@elix22 Alright, I’ll make another update with those changes.

Ever since I’ve started on this project, I wondered about two things:
1 - I was puzzled by why the tangent and bitangent vectors needed to be swapped and negated to construct the TBN matrix, i.e.

mat3 tbn = mat3(-vec3(, vTangent.w),, vNormal);

to make this work.

2 - why when the orientation of the face changed, the parallax offset got skewed.

I finally figured it out. Of all the primitive models that we have in Data/Models folder, the Plane.mdl is the only model with the incorrect tangents. I pre-dumped every model’s tangent vectors and post-dumped them again after calling GenerateTangents() fn Plane.mdl currently stores bitangent vectors in tangent vector data.

The second problem – I’ve looked over the DirectX sample over and over again and didn’t see where I made a bad copy or translated HLSL incorrectly. Just another puzzle I couldn’t figure out. Then after looking at the Learn OpenGL version of the shader that @GoldenThumbs pointed out, I realize the transpose() could be inherent in the HLSL but needed to explicitly applied in GLSL. And sure enough, that solved the problem.

These two problems fixes the following problems:
1-- cube parallax occlusion

2-- terrain parallax occlusion

I have these test codes in several folders. I’ll collect them and add them to the repo in a day or two.


Glad I could help! Also, ay I ask where you got that terrain shader? Is this the @JTippetts terrain shader (with some modifications made by you for the POM)?

Repo updated, as I don’t think I’ll have the time to update it after today.

@GoldenThumbs It’s a modified version of the default TerrainBlend shader that comes with Urho3D.

1 Like

By the way I found that issue with the plane model a while ago. Should have been fixed by now given how there’s no benefit to having a default model with faulty tangents and the fix is very easy.

Edit: could one do a PR for art assets? I might just do it myself.

@Lumak thanks for the demo.

Small note, transpose is not supported on mobile devices
I added local transpose(in mat3 inMatrix) implementation on my side

Also updated the Android APK

1 Like

@elix22 Thanks, again. Added that function to repo.

@GoldenThumbs Typical procedure is to make the changes to SourceAssets/ *.blend files and that’ll generate the *.mdl files. Maybe @1vanK can investigate what’s wrong with the Plane.blend file to see why it’s generating erroneous tangents.