Как бы вы реализовали эффект хроматической аберрации с помощью шейдеров?
Решит ли проблему рендеринг мира с различными расстояниями фокусировки для каждого цвета (возможно, с использованием только одного прохода глубины)?
Как бы вы реализовали эффект хроматической аберрации с помощью шейдеров?
Решит ли проблему рендеринг мира с различными расстояниями фокусировки для каждого цвета (возможно, с использованием только одного прохода глубины)?
Ответы:
Хроматическая аберрация возникает, когда объектив не может сфокусировать каждый цвет на одну и ту же точку фокусировки. Простой способ подделать этот эффект и отобразить его как быструю полноэкранную постобработку - применить смещение к каждому цветовому каналу в фрагментном шейдере.
Используя различное смещение для каждого канала, вы можете получить разумную факсимильную связь с желаемым эффектом. Пример этой техники можно найти здесь ; фрагментный шейдер будет выглядеть примерно так:
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);
}
Этот простой хак на самом деле не учитывает тот факт, что хроматическая аберрация является эффектом линзы, однако: чтобы получить лучшую симуляцию, вы на самом деле захотите сделать что-то, чтобы действовать как линза. Это похоже на то, как вы визуализируете объекты, которые являются отражающими или преломляющими. Следовательно, типичный шейдер отражения / преломления может быть основой для реализации хроматической аберрации.
Обычно вы вычисляете один вектор преломления на основе вектора представления и некоторого определенного показателя преломления , используя функцию преломления GLSL в вершинном шейдере:
void main () {
// ...
// RefractionVector is a varying vec3.
// 'ratio' is the ratio of the two indices of refraction.
RefractionVector = refract(incidentVector, normalVector, ratio);
// ...
}
Затем вы использовали бы этот вектор в фрагментном шейдере, чтобы выполнить поиск текстуры куба (в карту окружения). Обычно это делается вместе с эффектом отражения, и в сочетании используется вычисленный термин Френеля .
Для имитации хроматической аберрации в вершинном шейдере вы можете выполнить три разных вычисления вектора преломления, каждое из которых будет слегка смещено с помощью разных показателей преломления:
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);
// ...
}
Эти три разных вектора могут быть использованы для выполнения трех разных поисков кубической карты, которые могут быть смешаны вместе, как цвета были смешаны в простом примере:
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);
}
Для получения более подробной информации доступна книга OpenGL Orange Book, которая содержит пример основных эффектов отражения и преломления, а также пример эффекта хроматической аберрации.