Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflection/refraction with chromatic aberration - eye correction

I am writing a GLSL shader that simulates chromatic aberration for simple objects. I am staying OpenGL 2.0 compatible, so I use the built-in OpenGL matrix stack. This is the simple vertex shader:

uniform vec3 cameraPos;

varying vec3 incident;
varying vec3 normal;

void main(void) {
    vec4 position = gl_ModelViewMatrix * gl_Vertex;
    incident = position.xyz / position.w - cameraPos;
    normal   = gl_NormalMatrix * gl_Normal;

    gl_Position = ftransform();
}

The cameraPos uniform is the position of the camera in model space, as one might imagine. Here is the fragment shader:

const float etaR = 1.14;
const float etaG = 1.12;
const float etaB = 1.10;
const float fresnelPower = 2.0;
const float F = ((1.0 - etaG) * (1.0 - etaG)) / ((1.0 + etaG) * (1.0 + etaG));

uniform samplerCube environment;

varying vec3 incident;
varying vec3 normal;

void main(void) {
    vec3 i = normalize(incident);
    vec3 n = normalize(normal);

    float ratio = F + (1.0 - F) * pow(1.0 - dot(-i, n), fresnelPower);

    vec3 refractR = vec3(gl_TextureMatrix[0] * vec4(refract(i, n, etaR), 1.0));
    vec3 refractG = vec3(gl_TextureMatrix[0] * vec4(refract(i, n, etaG), 1.0));
    vec3 refractB = vec3(gl_TextureMatrix[0] * vec4(refract(i, n, etaB), 1.0));

    vec3 reflectDir = vec3(gl_TextureMatrix[0] * vec4(reflect(i, n), 1.0));

    vec4 refractColor;
    refractColor.ra = textureCube(environment, refractR).ra;
    refractColor.g  = textureCube(environment, refractG).g;
    refractColor.b  = textureCube(environment, refractB).b;

    vec4 reflectColor;
    reflectColor    = textureCube(environment, reflectDir);

    vec3 combinedColor = mix(refractColor, reflectColor, ratio);

    gl_FragColor = vec4(combinedColor, 1.0);
}

The environment is a cube map that is rendered live from the drawn object's environment.

Under normal circumstances, the shader behaves (I think) like expected, yielding this result:

correct shader behavior

However, when the camera is rotated 180 degrees around its target, so that it now points at the object from the other side, the refracted/reflected image gets warped like so (This happens gradually for angles between 0 and 180 degrees, of course):

incorrect shader behavior

Similar artifacts appear when the camera is lowered/raised; it only seems to behave 100% correctly when the camera is directly over the target object (pointing towards negative Z, in this case).

I am having trouble figuring out which transformation in the shader that is responsible for this warped image, but it should be something obvious related to how cameraPos is handled. What is causing the image to warp itself in this way?

like image 975
dflemstr Avatar asked Mar 23 '12 15:03

dflemstr


1 Answers

This looks suspect to me:

vec4 position = gl_ModelViewMatrix * gl_Vertex;
incident = position.xyz / position.w - cameraPos;

Is your cameraPos defined in world space? You're subtracting a view space vector (position), from a supposedly world space cameraPos vector. You either need to do the calculation in world space or view space, but you can't mix them.

To do this correctly in world space you'll have to upload the model matrix separately to get the world space incident vector.

like image 185
Tim Avatar answered Sep 21 '22 21:09

Tim