Отложенное затенение в OpenGL?

У меня странная проблема с реализацией отложенного затенения. Я визуализирую необходимую информацию через MRT в FBO, в настоящее время диффузное, положение и нормали в мировом пространстве, которое выглядит так:

введите здесь описание изображения

Это делается с помощью следующей настройки для всех текстур дерева:

diffuse = std::shared_ptr<bb::Texture>(new bb::Texture(GL_TEXTURE_2D)); // generates texture ID
diffuse->bind();
diffuse->texture2D(0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, 0); // glTexture2D
diffuse->parameterf(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
diffuse->parameterf(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
diffuse->parameterf(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
diffuse->parameterf(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
diffuse->unbind();
texture2D(GL_COLOR_ATTACHMENT0+1, diffuse->getID(), 0);

Затем они используются на моем этапе рисования:

dsShader->bind();
dsShader->enableVertexAttribArrays();

ds->diffuse->bind(GL_TEXTURE0); // "ds" is an FBO containing the textures
ds->position->bind(GL_TEXTURE0+1);
ds->normal->bind(GL_TEXTURE0+2);

dsShader->sendUniform("diffuse", 0);
dsShader->sendUniform("position", 1);
dsShader->sendUniform("normal", 2);

dsShader->sendUniform("camera", camera3D->position.x, camera3D->position.y, camera3D->position.z);

dsOut->indexBuffer->bind();
dsOut->vertex2Buffer->bind();
dsOut->vertex2Buffer->vertexAttribPointer(dsShader->getAttribLocation("vertex0"), 2, GL_FLOAT, false, 0, 0);

glDrawElements(GL_TRIANGLES, dsOut->indexBuffer->size(), GL_UNSIGNED_INT, 0);

ds->diffuse->unbind();
ds->position->unbind();
ds->normal->unbind();

dsShader->disableVertexAttribArrays();
dsShader->unbind();

Со следующим шейдером (только необходимая часть, источник света жестко запрограммирован):

struct DirLight{
    vec3 direction;
    vec4 diffuse, specular;
};

uniform sampler2D diffuse;
uniform sampler2D position;
uniform sampler2D normal;

uniform vec3 camera;

DirLight light0 = DirLight(vec3(1, 1, 0), vec4(0.3), vec4(0.1));

in vec2 vertex;

void main(){
    vec4 color = texture(diffuse, vertex)*0.5;
    vec3 p = vec3(texture(position, vertex));
    vec3 n = normalize(vec3(texture(normal, vertex)));

    float ndotl = max(dot(n, normalize(light0.direction)), 0.0); // simple phong

    if(ndotl > 0.0){
        color += ndotl*light0.diffuse;
    }

    gl_FragColor = color;
}

Странная часть заключается в том, что если я установлю направление источника света на отрицательные значения, скажем:

DirLight light0 = DirLight(vec3(-1, 0, 0), vec4(0.3), vec4(0.1));

Окончательный результат не затенен. Это выглядит правильно для положительных значений (более или менее). Вот изображение вывода:

введите здесь описание изображения

Также может быть проблема с нормалями, отмеченными в красной области.


person Kugel    schedule 06.04.2014    source источник
comment
Это похоже на проблему с вашими нормами. Пробовали ли вы визуализировать сцену без отложенного затенения?   -  person Gurgadurgen    schedule 06.04.2014
comment
Да пробовал, без проблем. Вы можете увидеть вывод всех текстур дерева на первом изображении. Что-то, что я забыл упомянуть, это то, что моя ось Z является верхней осью.   -  person Kugel    schedule 06.04.2014
comment
Похоже, ваши нормали поменялись местами, в первом. Я бы посоветовал сначала попытаться исправить это, а затем вернуться и снова протестировать отрицательные значения.   -  person Gurgadurgen    schedule 06.04.2014
comment
Нет, я так не думаю. Если я их инвертирую, большая часть карты нормалей будет черной. И я протестировал геометрию в блендере, нормали обращены наружу. Но может быть проблема с моим расчетом? В настоящее время я умножаю каждую нормаль на инвертированную транспонированную матрицу модели.   -  person Kugel    schedule 06.04.2014
comment
Вот увеличенное изображение карты нормалей: нажмите   -  person Kugel    schedule 06.04.2014
comment
Каков формат вашего обычного G-буфера? На приложенном снимке экрана вы пренебрегли масштабированием и смещением нормалей в видимый цветовой диапазон... то есть любая нормаль с отрицательным значением обрезается GL при отображении в буфере кадра по умолчанию просто до черного. Если вы пытаетесь сохранить нормали в формате, подобном GL_RGB, то сам G-буфер также имеет такое поведение. Вы можете либо использовать что-то вроде GL_RGB8_SNORM, либо сделать старый * 0.5 + 0.5 для ручного масштабирования до [0,1] и трюк * 2.0 - 1.0 для уменьшения до [-1,1].   -  person Andon M. Coleman    schedule 07.04.2014
comment
Убедитесь, что вы сделали это, по крайней мере, когда придет время визуализировать нормали. Они будут ложно окрашены, так как отрицательные цвета бессмысленны, но наметанный глаз знает, что значения от 0,0 до 0,5 в обычном G-буфере являются отрицательными, а > 0,5 — положительными.   -  person Andon M. Coleman    schedule 07.04.2014
comment
Спасибо, я попробую это и дам вам знать :)   -  person Kugel    schedule 08.04.2014
comment
@ AndonM.Coleman Ваше решение, похоже, сработало для ОП. Вы должны рассмотреть возможность публикации его в качестве ответа.   -  person Jason C    schedule 09.04.2014


Ответы (1)


Хорошо, решение Andon M. Coleman работает, я переключил внутренний формат на GL_RGB8_SNORM. Спасибо за вашу помощь :)

person Kugel    schedule 09.04.2014
comment
Поскольку это появилось в очереди на проверку с отметкой, вот примечание для рецензентов: на самом деле это является ответом, а не благодарностью. В настоящее время нет других ответов на этот вопрос. Ответ был предложен в комментариях к вопросу, и ОП услужливо обобщил его здесь. @ user3476897: Предложите принять ответ Андона, если он решит опубликовать ответ. - person Jason C; 09.04.2014