2014-10-02 2 views
5

Я пытался внедрить окклюзию окружающего пространства экрана, как описано в уроке this. Я решал проблемы с моей реализацией, поскольку я сталкивался с ними, но на этот раз я был в тупике.OpenGL: Проецирование координаты пространства обзора в НДЦ, результаты, казалось бы, вне диапазона [-1,1]

Мое понимание метода заключается в следующем. Фактор внешней окклюзии определяется образцами, взятыми изнутри полушария, выровненными с нормалью данного фрагмента. Чтобы определить, способствует ли образец влиянию на коэффициент внешней окклюзии, я должен проверить глубину изображения в пространстве просмотра относительно текстуры глубины пространства обзора (включенной в нижний левый угол изображения этого сообщения). Поэтому я знаю, какие координаты для извлечения из текстуры глубины, я должен преобразовать координаты образца из пространства вида в нормализованные координаты устройства (в диапазоне [-1,1]), а затем в диапазон [0 , 1], поэтому текстура глубины эффективно «отображает» в окне просмотра.

Следующий образ моей окклюзии окружающего мира, лежащей над моей сценой. Я знаю, что у меня есть довольно очевидная проблема с окружающей окклюзией (я полагаю, что полушария ориентированы неправильно), с которыми я буду иметь дело вовремя, но то, что раздражает мое любопытство, в настоящее время - это появление окклюзии, которая «уменьшилась» ', предполагая, что моя операция по перемещению из координат образца пространства зрения в координаты текстуры неверна.

enter image description here

Как я не хватаю стабильные шейдеров отладчика, отладка я могу сделать, это ограничивается тем, что я могу вынести на экран. Следующее изображение создаются с помощью следующего кода, с НСДОМ быть нормированным-устройство координаты для данного образца .:

if (ndcs.x > 1.0f || ndcs.y > 1.0f || ndcs.x < -1.0f || ndcs.y < -1.0f) 
{ 
    gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f); 
} 
else 
{ 
    gl_FragColor = vec4(vec3(1.0f), 1.0f); 
} 

enter image description here

Я бы ожидать изображение, чтобы быть полностью белым (или, скорее, биты, которые я использую для этого шейдера), однако, похоже, что NDC, которые я создаю, находятся за пределами диапазона [-1,1], который, я считаю, должен быть неправильным. Это не соответствует области экрана или, как вы можете видеть на следующем рисунке, где камера находится очень близко к поверхности: не

enter image description here

Я не использовал эту процедуру, прежде чем получить НЦД, так что я Я уверен, что моя логика должна быть где-то неправильной. Я загрузил демо-код, поставляемый с учебником, и я не вижу, где мой код отличается. Я также искал онлайн (в том числе и на этом сайте), и я, похоже, не могу найти никого с такими же симптомами, как я.

Вот соответствующий код из моих шейдеров:

Vert Shader:

v_eye_space_position = u_mvpMatrix * a_position; 
v_world_space_normal = normalize(u_rotationMatrix * a_normal); 
v_eye_space_normal = normalize(u_mvpMatrix * a_normal); 
gl_Position = v_eye_space_position; 

Frag Shader:

// --- SSAO Testing --- 
// Convert from the noise texture back to [-1,1] range 
// We want the noise texture to tile across the screen. 
vec3 kernel_rotation = (texture2D(s_noise, gl_FragCoord.xy * u_noise_scale) * 2.0f - 1.0f).xyz; 
vec3 eye_space_tangent = normalize(kernel_rotation - v_eye_space_normal.xyz * dot(kernel_rotation, v_eye_space_normal.xyz)); 
vec3 eye_space_bitangent = cross(v_eye_space_normal.xyz, eye_space_tangent); 
mat3 tbn = mat3(eye_space_tangent, eye_space_bitangent, v_eye_space_normal); 

float ambient_occlusion = 0.0f; 
const float hemisphere_radius = 0.05f; 

for (int i=0; i<16; i++) 
{ 
    vec3 kernel_sample = tbn * u_ssao_kernel[i]; 
    kernel_sample = kernel_sample * hemisphere_radius + v_eye_space_position.xyz; 

    // Project the sample position into screen space. 
    vec4 offset = vec4(kernel_sample, 1.0f); 
    offset = u_projection_matrix * offset; 
    offset.xy /= offset.w; 
    vec4 ndcs = offset; 
    offset.xy = 1.0f - (offset.xy * 0.5f + 0.5f); 

    // Find the depth at this sample point. 
    float sample_depth = texture2D(s_camera_depth, offset.xy).z; 

    // Check if the sample point is occluded. 
    float range_check = 0.0f; 

    float linear_eye_space_position = (v_eye_space_position.z - u_near_plane)/(u_far_plane - u_near_plane); 

    // Range check. 
    if (abs(linear_eye_space_position - sample_depth) < hemisphere_radius) 
    { 
    range_check = 1.0f; 
    } 

    float linear_kernel_sample_depth = (kernel_sample.z - u_near_plane)/(u_far_plane - u_near_plane); 
    if (sample_depth <= linear_kernel_sample_depth) 
    { 
    ambient_occlusion += 1.0f * range_check; 
    } 
} 

// Average and invert the ambient occlusion. 
ambient_occlusion = 1.0f - (ambient_occlusion/16.0f); 

Я посмотрел на каждый элемент в отдельности, и я не могу см. проблему с ними.

  • Я susbstituted собственной позиции вида пространственно-фрагмента в проекции (вместо показов пространственного положения образца), и я получаю одни и те же результатов.
  • Матрица проекции является перспективной матрицей I использовать для преобразования вершин в модели (я построил матрицу MVP в моих вершинных шейдерах, чтобы обеспечить матрицу проекции достигает шейдерную программу в такте и это).
  • Операция проектирования сама по себе - это не то, что я делал раньше, но я читал статьи и вопросы от людей с проекционными проблемами , и я не вижу, что я делаю неправильно.

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

ответ

2

С вашей вершинного шейдера:

v_eye_space_position = u_mvpMatrix * a_position; 
[...] 

pMatrix * a_normal); gl_Position = v_eye_space_position;

Из этого мы можем видеть, что v_eye_space_position является не пространства положения глаз вершины, но клипа пространства позиция, которая также должна быть назначена gl_Position. Нейме вашей равномерной матрицы также предполагает, что это ModelView Проекция -Матрица.

В вашем шейдере фрагмента вы в основном затмеваете этот результат с помощью матрицы проекции (так как вы, кажется, предполагаете, что это в пространстве глаз).

Так правильный код будет:

v_eye_space_position = u_mvMatrix * a_position; 
[...] 
gl_Position = u_projection_matrix * v_eye_space_position; 

Теперь вы можете применить проекцию v_eye_space_position снова в пиксельный шейдер. Но мой вопрос: зачем делать это снова? Если вы хотите работать на экране, gl_FragCoord уже находится в пространстве окна. Вам нужно только multpliy-add, чтобы получить из оконного пространства в NDC, просто инвертируя преобразование видового экрана (и диапазона глубины).

+0

Благодарим вас за помощь в этом. После реализации ваших предложений результаты я ожидал. Забавно, как я ослепил себя такой простой ошибкой. Извлеченный урок: всегда проверяйте «простые» вещи (в частности, координатные пространства). Большое спасибо еще раз - вы избавили меня от огромного стресса. Хорошего дня! :) –