I am trying to implement the Parallax Refraction effect explained by Jorge Jimenez on this presentation: http://www.iryoku.com/downloads/Next-Generation-Character-Rendering-v6.pptx and I am facing some difficulties. Here is a screenshot of the interesting part.


But this document lacks a bit of explanations especially the second part with the Physically based Refraction.

Here is what I've achieved for the moment.
This is the simple Parallax Refraction effect and, as you might notice in the screenshot, there is small glitch at grazing angles in the iris when the Parallax Scale value is too high.

This seems to be caused by the parallax calculation but are there some tricks to avoid or minimize such issue ?

I don't want to go deeper with parallax mapping for the moment, so I don't want to use Steep Parallax Mapping or Parallax Occlusion Mapping.


This is the simple Parallax Refraction part.

// height value comes from a texture
float2 offset = height * viewDir;
offset.y = -offset.y;
texcoord -= ParallaxScale * offset;
// Next there is the texture sampling with the texcoord value

Here is the way I calculate the refraction vector according to Snell's law.

float cosine = dot(viewDir, worldNormal);
float sine = sqrt(1 - cosine * cosine);

float sine2 = (_IOR * sine);
float cosine2 = sqrt(1 - sine2 * sine2);

float3 x = -worldNormal;
float3 y = normalize(cross(cross(viewDir, worldNormal), worldNormal));
float3 refractedW = x * cosine2 + y * sine2;

This is integrated with the Physically based Refraction and it gives interesting results but I still don't know how to get rid of the high parallax scale issue which appear at grazing angles...

Any idea how to get rig of that ?
Thanks a lot.


1 Answer 1


As I am working with Unity, I found an interesting way of calculating the parallax offset inside the engine. It's not physically based but it gives better results than the classic parallax refraction.

float2 ParallaxOffset(half h, half height, half3 viewDir)
    h = h * height - height / 2.0;
    float3 v = normalize(viewDir);
    v.z += 0.42;
    return h * (v.xy / v.z);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .