Как бы вы реализовали хроматическую аберрацию?


22

Как бы вы реализовали эффект хроматической аберрации с помощью шейдеров?

Решит ли проблему рендеринг мира с различными расстояниями фокусировки для каждого цвета (возможно, с использованием только одного прохода глубины)?


Почему вы хотите реализовать хроматическую аберрацию?
— ashes999

3
Вы можете действовать так же, как достигается цветение. Вы должны объединить вашу обычную сцену с 3 размытыми версиями; каждая из этих трех текстур должна быть окрашена преимущественно в 3 основных цвета. Конечно, возможны вариации, если вы используете разные стратегии размытия для 3 текстур (например, направленное размытие с различными угловыми смещениями может помочь).
— Теодрон

3
@ ashes999 - Возможно, снайперский прицел или другой длинный объектив, чтобы добавить немного реалистичности? Хроматическая аберрация является артефактом многих сложных линз.
— KeithS

Вы также можете использовать хроматическую аберрацию, чтобы противостоять любой аберрации, вызванной линзой, через которую просматривается игра. Например, хорошей идеей будет иметь хроматическую аберрацию по краям вида в игре, в которую играют с Oculus Rift.
— Джозеф Мэнсфилд

Ответы:


22

Хроматическая аберрация возникает, когда объектив не может сфокусировать каждый цвет на одну и ту же точку фокусировки. Простой способ подделать этот эффект и отобразить его как быструю полноэкранную постобработку - применить смещение к каждому цветовому каналу в фрагментном шейдере.

Используя различное смещение для каждого канала, вы можете получить разумную факсимильную связь с желаемым эффектом. Пример этой техники можно найти здесь ; фрагментный шейдер будет выглядеть примерно так:

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, которая содержит пример основных эффектов отражения и преломления, а также пример эффекта хроматической аберрации.


Есть ли подход, который использует только один образец текстуры и просто окрашивает его? Это было бы очень полезно для таких приложений, как трассировка лучей, где трассировка трех лучей против одного очень дорога.
— Тара
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.