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

22

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

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

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


источник
Есть ли подход, который использует только один образец текстуры и просто окрашивает его? Это было бы очень полезно для таких приложений, как трассировка лучей, где трассировка трех лучей против одного очень дорога.
Тара