Eugene
> Стандартные лайтпробы Юнити, не?
Они не подходят, так как я Юнити не использую, а пишу свой
движок на С++ и OpenGL (это интереснее и веселее :) ).
Mikle
Я правильно понял, что освещение в 3д лайтмапе надо просчитывать через N-ое расстояние.
Например, смещаться по x, y, z на N и в той точке считать свет. Поправьте, если не так, а
то в интернете статейки по такому подходу что-то не нашел.
Вот псевдо код:
int N = 30; // через каждые 30 пикселей считать свет. for ( float x = 0; x < SizeX; x+=N ) for ( float y = 0; y < SizeY; y+=N ) for ( float z = 0; z < SizeZ; z+=N ) { vec3 Position = vec3( x, y, z ); // здесь вычисление света и теней. }
А вот на картинке как я себе это представляю.
zombihello
Я не говорил их использовать. Я предлагаю посмотреть на то, как они работают.
zombihello
> Я правильно понял, что освещение в 3д лайтмапе надо просчитывать через N-ое расстояние.
Да, точки - это центры пикселей 3D текстуры. Методик для такого расчёта можно представить много, например:
1. С позиций всех источников света делается рендер в текстуру так, как это делается для Shadow Map.
2. Делаем две R8G8B8 Volume текстуры, проходим их попиксельно, для каждого пикселя делаем шесть рендеров в текстуру в шести направлениях (вдоль каждой оси в обоих направлениях). Задаём fovX и fovY 90 градусов, размер Render Target текстуры достаточно даже 256*256.
После рендера усредняем полученную картинку до 1 пикселя, его яркость записываем в:
R первой 3D текстуры для направления X
G первой 3D текстуры для направления Y
B первой 3D текстуры для направления Z
R второй 3D текстуры для направления -X
G второй 3D текстуры для направления -Y
B второй 3D текстуры для направления -Z
Итого, примерно подсчитаем на примере карты с размером, как в моей демке, размер 3D текстуры там 256*128*256:
Первоначальный рендер в текстуру теней для пары десятков источника света можно считать почти мгновенным.
Далее делается 256*128*256*6 = 50331648 рендеров сцены в текстуру 256*256 с использованием пары десятков Shadow Map, рендер простейшим шейдером, белым материалом без текстур и эффектов, на приличной видеокарте такая сцена рендерится с частотой порядка нескольких тысяч fps. При пяти тысячах получаем, что на расчёт всей карты понадобится порядка 10000 секунд, то есть 2.5 часа. Многовато, но вполне приемлемо, и качество будет значительно выше, чем в моей демке.
Как эту текстуру правильно накладывать на полигоны уровня? Если повертексно, то слишком низкое качество, а если проекцию, то я себе смутно представляю что в итоге получится.
g-cont
> Как эту текстуру правильно накладывать на полигоны уровня?
Попиксельно, используя мировые координаты в качестве текстурных.
g-cont
> смутно представляю что в итоге получится
Демку посмотри, там наложение уже готово, вот предварительный расчёт объёма фейковый.
Демку-то я посмотрел, но 3-д лайтмапы там не обнаружил. Выходит она считается заново каждый раз при запуске? Там достаточно низкочастотное освещение и нельзя отключить диффузки, чтобы заценить именно лайтмапу. А шейдеры бинарные или зашифрованные, я уж не знаю.
g-cont
> Там достаточно низкочастотное освещение и нельзя отключить диффузки, чтобы
> заценить именно лайтмапу
Там только лайтмапа, она с шестью направлениями, поэтому выглядит, как диффуз, а на оружии, что в руках, ещё и спек.
g-cont
> Выходит она считается заново каждый раз при запуске?
Да, там фейковый ускоренный вариант, делал когда-то для демосцены, всё никак не сделаю нормально.
g-cont
> А шейдеры бинарные или зашифрованные
Бинарные, версии 2_0.
Mikle
> 1. С позиций всех источников света делается рендер в текстуру так, как это
> делается для Shadow Map.
Это и есть Shadow Map? Если нет, то что в нее нужно записывать.
Mikle
> Делаем две R8G8B8 Volume текстуры, проходим их попиксельно, для каждого
> пикселя делаем шесть рендеров в текстуру в шести направлениях
А как быть с источниками света и текстурами лампочек которые получили в пункте 1,
как их использовать? Я так понимаю, что на этом этапе идет просчет освещения каждого пикселя с использованием
Shadow Maps, верно? Только если это так, то как учитывать свет от каждой лампочки, рендерить переключая источники света?
(в шейдер массив лампочек я не хочу передавать из-за ограничений). Но если так, то это долго будет, как мне кажется.
На этом подробнее пожалуйста, ибо смутно представляю.
Mikle
> Делаем две R8G8B8 Volume текстуры
А как использовать потом эти две Volume текстуры.
С одной как взять освещеность ясно, а с двумя?
Mikle
> проходим их попиксельно
Это имеется ввиду x+N (где N - смещение), да?
zombihello
> Это и есть Shadow Map?
Да.
zombihello
> Я так понимаю, что на этом этапе идет просчет освещения каждого пикселя с
> использованием
> Shadow Maps, верно? Только если это так, то как учитывать свет от каждой
> лампочки, рендерить переключая источники света?
> (в шейдер массив лампочек я не хочу передавать из-за ограничений). Но если так,
> то это долго будет, как мне кажется.
Верно. Даже если не использовать массив, а рендерить в несколько проходов, сильно долго не должно быть, ведь размер Render Target очень небольшой.
zombihello
> А как использовать потом эти две Volume текстуры.
> С одной как взять освещеность ясно, а с двумя?
Скалярно умножаешь нормаль на RGB первой 3D текстуры, если результат меньше нуля - приравниваешь к нулю.
То же самое для второй 3D текстуры, только со знаком минус.
Полученные величины суммируешь, получаешь освещенность с учётом нормали.
zombihello
> Это имеется ввиду x+N (где N - смещение), да?
Это почти как ты выше писал:
for ( float x = 0; x < SizeX; x++ ) for ( float y = 0; y < SizeY; y++ ) for ( float z = 0; z < SizeZ; z++ )
Спасибо, буду пытаться это реализовать. Сейчас сижу над инициализацией OpenGL'а в своем компиляторе лайтов.
Mikle
Сделал первый пункт (создание Shadow Maps) и приступил к самой генерации этой 3D лайтмапы,
но на практике столкнулся с еще несколькими вопросами:
1.
> Делаем две R8G8B8 Volume текстуры
Создать две такие текстуры на CPU будет нормально?
Вот примерно так:
vector<uint8_t> VolumeTexture(Size.x * Size.y * Size.z * 3 ); // где Size - размер уровня, например, 208x176x208
2.
> проходим их попиксельно, для каждого
> пикселя делаем шесть рендеров в текстуру в шести направлениях
Как узнать позицию в глобальных координатах с которой нужно рендерить сцену?
3.
> Да, точки - это центры пикселей 3D текстуры.
В каком месте это нужно учитывать, если во втором пункте проходимся по пикселям без этого смещения.
Нужно делать что-то такого: PositonFragment + N? (PositonFragment - позиция точки в глобальных координатах уровня)
> После рендера усредняем полученную картинку до 1 пикселя , его яркость
> записываем в..
4.1 Получается Render Target у меня будет лежать в GPU и чтобы записать ее (усредненную)
в 3д текстуру на CPU мне нужно ее от туда получить с помощью glGetTexImage(), а
не медленный такой вариант будет?
4.2 Чтобы усреднить картинку до 1ого пикселя нужно просуммировать цвета всех пикселей и поделить на их кол-во.
Примерно так, верно я думаю?
vec4 Color = SumPixels / CountPixels; // CountPixels = SizeTexture.x * SizeTexture.y
5. Как быть с Shadow Maps от направленного света, чтобы эта карта теней охватила весь уровень.
Или для каждого пикселя 3д текстуры нужно заново считать? (так как-то затратно выходит).
Mikle
Ты случайно не знаешь, как готовить сферические гармоники?
Я хочу их создавать из источников света, и я хочу освещать с их помощью объекты.
То, что гуглится, довольно трудноперевариваемое.
zombihello
> Создать две такие текстуры на CPU будет нормально?
Да. На этапе создания им нечего делать на GPU. Просто обычные массивы в памяти.
zombihello
> Как узнать позицию в глобальных координатах с которой нужно рендерить сцену?
Если у тебя 3D текстура по X шириной SizeX (индексы от 0 до SizeX-1), а карта по X от MinX до MaxX, то центр пикселя с индексом N будет:
(N+0.5)/SizeX*(MaxX-MinX)+MinX
zombihello
> В каком месте это нужно учитывать, если во втором пункте проходимся по пикселям
> без этого смещения.
Я учёл в п.2, сразу.
zombihello
> Чтобы усреднить картинку до 1ого пикселя нужно просуммировать цвета всех
> пикселей и поделить на их кол-во.
Да. Не знаю, как в OpenGL, а в D3D можно создавать RenderTarget Surface с флагом AutogenMipMap, тогда сразу на GPU будут генерироваться мипуровни, можно сразу брать последний, с размером 1*1, уже усреднённый
zombihello
> Получается Render Target у меня будет лежать в GPU и чтобы записать ее
> (усредненную)
> в 3д текстуру на CPU мне нужно ее от туда получить с помощью glGetTexImage(), а
> не медленный такой вариант будет?
Для 1*1 не должно быть сильно медленно.
zombihello
> Как быть с Shadow Maps от направленного света, чтобы эта карта теней охватила
> весь уровень.
> Или для каждого пикселя 3д текстуры нужно заново считать? (так как-то затратно
> выходит).
Не понял в чём проблема, Shadow Maps рендерится однократно в начале для каждого источника света.
Eugene
> Ты случайно не знаешь, как готовить сферические гармоники?
"сферические гармоники" чего? Речь о какой технологии?
Mikle
> "сферические гармоники" чего? Речь о какой технологии?
Unity использует сферические гармоники низших порядков для освещения динамических объектов запеченным светом. Эта тема мне довольно интересна, ибо я щас пытаюсь написать лайтмаппер для Урхи.
Eugene
> как готовить сферические гармоники?
> что гуглится, довольно трудноперевариваемое
а вот может Ambient Cube:
https://www.yumpu.com/en/document/view/31351157/present-valve/29
Тема в архиве.