Sunday, May 20, 2018

opengl - How would you implement chromatic aberration?


How would you implement the effect of chromatic aberration with shaders?


Would rendering of the world with different focus distances for each color solve the problem (maybe with the usage of only one depth rendering pass)?



Answer



Chromatic aberration is caused when a lens can't focus every color to the same focal point. A simple way to fake this effect, and render it as a quick full-screen post-process, is to apply an offset to each color channel in a fragment shader.


By using a different offset for each channel, you can achieve a reasonable facsimile of the desired effect. An example of this technique can be found here; the fragment shader would look something like this:


void main () {
// Previously, you'd have rendered your complete scene into a texture
// bound to "fullScreenTexture."
vec4 rValue = texture2D(fullscreenTexture, gl_TexCoords[0] - rOffset);

vec4 gValue = texture2D(fullscreenTexture, gl_TexCoords[0] - gOffset);
vec4 bValue = texture2D(fullscreenTexture, gl_TexCoords[0] - bOffset);

// Combine the offset colors.
gl_FragColor = vec4(rValue.r, gValue.g, bValue.b, 1.0);
}

This simple hack doesn't really take into account the fact that chromatic aberration is a lens effect, though: to get a better simulation, you'd actually want to render something to act as the lens. This is similar to how you render objects that are reflective or refractive. Consequently, a typical reflection/refraction shader can be the basis for implementing chromatic aberration.


Normally, you'd compute a single refraction vector based on a view vector and some defined index of refraction, using GLSL's refract function in a vertex shader:


void main () {

// ...

// RefractionVector is a varying vec3.
// 'ratio' is the ratio of the two indices of refraction.
RefractionVector = refract(incidentVector, normalVector, ratio);

// ...
}

Then you'd use that vector in a fragment shader to perform an cube texture lookup (into an environment map). Typically this is done alongside a reflection effect as well, and combined used a computed Fresnel term.



To simulate chromatic aberration, then, you can perform three different refraction vector computations, each one slightly offset via differing indices of refraction, in the vertex shader:


void main () {
// ...

// RefractionVector is a varying vec3, as above.
// 'ratioR,' et cetera, is the ratio of indices of refraction for
// the red, green and blue components respectively.
RedRefractionVector = refract(incidentVector, normalVector, ratioR);
GreenRefractionVector = refract(incidentVector, normalVector, ratioG);
BlueRefractionVector = refract(incidentVector, normalVector, ratioB);


// ...
}

Those three different vectors can be used to perform three different cube map lookups, which can be mixed together similar to how the colors were mixed in the simple example:


void main () {
vec3 color;
color.r = vec3(textureCube(EnvironmentMap, RedRefractionVector)).r;
color.g = vec3(textureCube(EnvironmentMap, GreenRefractionVector)).g;
color.b = vec3(textureCube(EnvironmentMap, BlueRefractionVector)).b;


gl_FragColor = vec4(color, 1.0);
}

For more details, the OpenGL Orange Book is available and contains an example of the basic reflection and refraction effects, as well as an example of the chromatic aberration effect.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...