2012-03-25 2 views
4

Как часть создания простого небоскреба, я создал skybox (в основном куб, идущий от (-1, -1, -1) до (1, 1, 1), которая рисуется в конце концов моей геометрии и заставила спину через следующий простой вершинный шейдер:простой процедурный skybox

#version 330 
layout(location = 0) in vec4 position; 
layout(location = 1) in vec4 normal; 

out Data 
{ 
    vec4 eyespace_position; 
    vec4 eyespace_normal; 
    vec4 worldspace_position; 
    vec4 raw_position; 
} vtx_data; 

uniform mat4 model; 
uniform mat4 view; 
uniform mat4 projection; 

void main() 
{ 
    mat4 view_without_translation = view; 
    view_without_translation[3][0] = 0.0f; 
    view_without_translation[3][1] = 0.0f; 
    view_without_translation[3][2] = 0.0f; 

    vtx_data.raw_position = position; 
    vtx_data.worldspace_position = model * position; 
    vtx_data.eyespace_position = view_without_translation * vtx_data.worldspace_position; 

    gl_Position = (projection * vtx_data.eyespace_position).xyww; 
} 

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

Очевидно, что простое смешивание двух цветов на основе координаты Y каждого фрагмента будет выглядеть очень плохо: факт, что вы смотрите на коробку, а не на купол, немедленно clea г, как показано здесь:

wrong skybox

Обратите внимание на довольно заметны «углы» в верхнем левом и правом верхнем углу окна.

Инстинктивно я думал, что очевидным решением будет нормализация положения каждого фрагмента, чтобы получить положение на единичной сфере, а затем взять координату Y из этого. Я думал, что это приведет к значению, которое будет постоянным для данной «высоты», если это имеет смысл. Как это:

#version 330 
in Data 
{ 
    vec4 eyespace_position; 
    vec4 eyespace_normal; 
    vec4 worldspace_position; 
    vec4 raw_position; 
} vtx_data; 

out vec4 outputColor; 

const vec4 skytop = vec4(0.0f, 0.0f, 1.0f, 1.0f); 
const vec4 skyhorizon = vec4(0.3294f, 0.92157f, 1.0f, 1.0f); 

void main() 
{ 
    vec4 pointOnSphere = normalize(vtx_data.worldspace_position); 
    float a = pointOnSphere.y; 
    outputColor = mix(skyhorizon, skytop, a); 
} 

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

После некоторого случайного пустячный (культ карго программирования, я знаю: /), я понял, что это работает:

void main() 
{ 
    vec3 pointOnSphere = normalize(vtx_data.worldspace_position.xyz); 
    float a = pointOnSphere.y; 
    outputColor = mix(skyhorizon, skytop, a); 
} 

Единственное отличие состоит в том, что я нормализовать положение без его W компонент.

И вот рабочий результат: (разница является тонким в скриншотах, но довольно заметно в движении) correct skybox

Итак, наконец-то, на мой вопрос: почему эту работу, когда предыдущая версия не может? Должно быть, я неправильно понимаю что-то чрезвычайно важное о гомогенных координатах, но мой мозг просто не щелкает прямо сейчас!

ответ

3

GLSL normalize не обрабатывает однородные координаты как таковые. Он интерпретирует координату как принадлежащую R^4. Это вообще не то, что вы хотите. Однако, если vtx_data.worldspace_position.w == 0, то нормализация должна давать тот же результат.

Не знаю, что такое vec3 pointOnSphere = normalize(vtx_data.worldspace_position); означает, что левая сторона должна иметь тип vec4.

+0

vec3 pointOnSphere = normalize (vtx_data.worldspace_position) - это опечатка с моей стороны, в то время как помогаю с кодом генерировать скриншоты для этого вопроса: o Извините! И спасибо за ответ! –