Отражение / преломление с хроматической аберрацией - коррекция зрения - PullRequest
6 голосов
/ 23 марта 2012

Я пишу шейдер GLSL, который имитирует хроматическую аберрацию для простых объектов. Я остаюсь OpenGL 2.0 совместимым, поэтому я использую встроенный стек OpenGL матрицы. Это простой вершинный шейдер:

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();
}

Форма cameraPos - это, как можно себе представить, положение камеры в пространстве модели. Вот фрагмент шейдера:

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);
}

environment - это карта куба, которая отображается в реальном времени из среды нарисованного объекта.

При нормальных обстоятельствах шейдер ведет себя (как мне кажется), как ожидалось, давая такой результат:

correct shader behavior

Однако, когда камера поворачивается на 180 градусов вокруг своей цели, так что теперь она указывает на объект с другой стороны, преломленное / отраженное изображение деформируется примерно так (это происходит постепенно для углов от 0 до 180 градусов, конечно):

incorrect shader behavior

Подобные артефакты появляются при опускании / поднятии камеры; Кажется, что он работает правильно на 100% только тогда, когда камера находится прямо над целевым объектом (в данном случае указывает на отрицательный Z).

У меня возникают проблемы с выяснением, какое преобразование в шейдере отвечает за это искаженное изображение, но должно быть что-то очевидное, связанное с обработкой cameraPos. Что вызывает искажение изображения таким образом?

1 Ответ

2 голосов
/ 23 марта 2012

Мне это кажется подозрительным:

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

Определен ли ваш cameraPos в мировом пространстве? Вы вычитаете вектор пространства вида (position) из предположительно мирового пространства cameraPos вектора. Вам нужно либо выполнить вычисления в мировом пространстве, либо просмотреть пространство, но вы не можете смешивать их.

Чтобы сделать это правильно в мировом пространстве, вам нужно будет загрузить матрицу модели отдельно, чтобы получить вектор инцидента в мировом пространстве.

...