Как работает алгоритм отображения теней куба? - PullRequest
2 голосов
/ 15 октября 2011

Я искал в Интернете, но не смог найти подходящего описания.Я хотел бы сделать следующее в OpenGL ES 2.0 :

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

Я понимаю базовый алгоритм, а именно:

1.) Рендеринг из POV light в 6 раз больше сцены.Сохраните значения глубины в соответствующей грани кубической карты.(если свет смотрит на + X, то грань куба + X, если смотрит на -X, то грань куба -X и т. д.)

2.) Выполните рендеринг сцены из POV камеры и используйте значения глубины, хранящиеся в кубической картедля сравнения:

если глубина <<em> расстояние от света , то фрагмент находится в тени ...

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

Мои проблемы:

Как мне получить карту куба?Я знаю, что для этого нужно использовать vec3, но как рассчитать этот вектор сборщика?У меня есть только одна идея: использовать вектор vertexPosition - lightPosition , но я не совсем уверен, хорошо ли это.: (

Другая проблема заключается в следующем: расстояние от света: оно находится в мировой координате, поэтому это просто значение с плавающей запятой ... значения глубины находятся в диапазоне [0.0, 1.0] ...

Как создать расстояние в диапазоне [0.0, 1.0]? Моя идея состоит в том, что я передаю все 6 матриц вида освещения и матрицу проекции источника света и вершинному шейдеру. Я вычисляю положение вершины 2 раза: один для камеры.MVP (как обычно) и один для MVP света (для вычисления тени, используя правильную матрицу вида). Таким образом, я снова получу положение фрагмента в POV света, и из-за деления w это значение z может быть использовано как расстояниеот света в [0.0, 1.0] после смещения, чтобы я мог сравнить его со значением глубины, полученным из моей карты теней куба ... Я прав?

Пожалуйста, помогите мне. Заранее спасибо.

Редактировать:

Хорошо, теневое кубическое отображение начинает работать. Однако есть некоторая ошибка, которую я сейчас пытаюсь исправить.

Сначалатени были "глупыми".эй, должно быть, были или полностью "тупые" тени были отрисованы ...

Настройки были: камера в (0, 4,9, 0), глядя на (0,0,0), вверх (0, 1,0).Виды для света:

+ X: LookAt (eyeX, eyeY, eyeZ, eyeX +1, eyeY, eyeZ, 0,1,0, матрица);// собственная реализация, которая работает так же, как gluLookAt

-X: LookAt (eyeX, eyeY, eyeZ, eyeX -1, eyeY, eyeZ, 0,1,0, матрица);

+ Y: LookAt (eyeX, eyeY, eyeZ, eyeX, eyeY +1, eyeZ, -1,0,0, матрица);

и т. Д. *

Это неРабота.Хорошо, но я оживил его и увидел, что ложная тень двигалась вместе с источником света: источник света двигался вверх, так же как и тень, ls перемещалась вниз, тень тоже ...

(Источник света был в (0,0,0) и переместился по оси Y, поле осталось от источника света.)

Итак, для тестирования я сделал следующее в фрагментном шейдере:

vec3 fetcher = v_posWorld.xyz - u_light_pos;

fetcher.y * = -1.0;

Эта идея возникла потому, что я подумал, что, возможно, проблема в том, что при рендеринге на текстуре визуализированное изображение будет отображаться вверх ногами,Этот тест сработал, но, конечно, только для лиц -X и + X ...

Поэтому я закомментировал "fetcher.y * = -1.0;"линии и изменил вид освещения:

+ X: LookAt (eyeX, eyeY, eyeZ, eyeX +1, eyeY, eyeZ, 0, -1,0, матрица);

-X: LookAt (eyeX, eyeY, eyeZ, eyeX -1, eyeY, eyeZ, 0, -1,0, матрица);

+ Y: LookAt (eyeX, eyeY, eyeZ, eyeX, eyeY+1, eyeZ, 0,0, -1, матрица);

-Y: LookAt (eyeX, eyeY, eyeZ, eyeX, eyeY-1, eyeZ, 0,0,1, матрица);

+ Z: LookAt (eyeX, eyeY, eyeZ, eyeX, eyeY, eyeZ +1, 0, -1,0, матрица);

-Z: LookAt (eyeX, eyeY, eyeZ, eyeX, eyeY, eyeZ -1, 0, -1,0, матрица);

Это работает! Почти, потому что настройки просмотра для + Y и -Y не работают, как я ожидал :( Немного поиграв с ним, я изменил положение камеры на (0, -4.9, 0), и все, что работало, стало чем-то плохим : тени снова стали «глупыми».

Я полностью потерян здесь. Я не знаю, где мой алгоритм не работает. Может ли быть так, что для рендеринга на текстуре я должен использовать левое правило (я имею в виду при создании матриц вида для света) ...?

В любом случае, я продолжаю работать, но, может быть, я не очень хорошо понимаю кубические карты. (

(и простите за долгое редактирование)

1 Ответ

1 голос
/ 15 октября 2011
  1. Использование вектора от света к вершине, как вы и предполагали, действительно должен быть правильным вектором для координат текстуры.

  2. Вы также можете просто сохранитьлинейная глубина в текстуру глубины, просто записывая расстояние вершины до источника света (деленное на некоторое известное максимальное расстояние влияния света, чтобы преобразовать его в [0,1]) в gl_FragDepth в первые 6 проходов, вместоспроецированная глубина вершины.Таким образом, вы можете просто использовать расстояние вершины до источника света при сравнении глубины без необходимости что-либо проецировать в пространство света.Таким образом, вам не нужно отслеживать 6 разных матриц и выбирать правильную для каждой вершины или фрагмента.

РЕДАКТИРОВАТЬ: Кажется, выне может писать в gl_FragDepth в ES, что делает рендеринг вашей собственной глубины немного более сложным.Простой рендеринг в обычную текстуру не подходит, поскольку 8-битная точность на канал слишком мала на практике.

Но вы должны иметь возможность линеаризовать глубину в вершинном шейдере, просто сохраняярасстояние от вершины до света в z-компоненте вершины (преобразованной в [-1,1]), умноженной на ее w-компонент, который затем делится на w и преобразуется в [0,1] растеризатором для получения фрагментаглубина:

uniform mat4 lightModelView;
uniform mat4 lightProjection;
unfiorm float maxLightDistance;

attribute vec4 vertex;

void main()
{
    vec4 lightSpaceVertex = lightModelView * vertex;
    float lightDistance = length(lightSpaceVertex.xyz) / maxLightDistance;

    gl_Position = lightProjection * lightSpaceVertex;
    gl_Position.z = (2.0*lightDistance-1.0) * gl_Position.w;
}

Это может быть оптимизировано простым изменением матрицы проекции света соответственно, но этот код (в сочетании с простым сквозным фрагментным шейдером) должен хранить линейное расстояние света до вершины вбуфер глубины, если я не на совершенно неверном пути.Он просто умножает вершину z на ее w и поэтому должен противодействовать шагу деления перспективы, что приведет к нелинейному значению глубины (и, конечно же, также учитывает преобразование из [-1,1] в [0,1]).

РЕДАКТИРОВАТЬ: В соответствии с вашими новыми проблемами: во-первых, я надеюсь, что ваш свет расположен в (eyeX, eyeY, eyeZ), так как камера для генерации карты теней должнаконечно, находиться в положении света.Если (eyeX, eyeY, eyeZ) на самом деле является положением вашей (нормальной) камеры сцены, то это, конечно, неправильно, и вместо этого вам следует использовать (lightX, lightY, lightZ).

Далее вам следуетКонечно, используйте поле зрения (поле зрения) точно под углом 90 градусов для источников света, поэтому матрица проекции должна быть сгенерирована следующим образом:

glFrustum(-near, near, -near, near, near, far);

или это:

gluPerspective(90, 1, near, far);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...