Компьютерная графика

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Компьютерная графика » Программирование графики и GPU » Некоторые комментарии к некоторым статьям :)


Некоторые комментарии к некоторым статьям :)

Сообщений 1 страница 27 из 27

1

Статья: Получение исходных 3D-координат по значениям из z-буфера.
Приведены подробные вычисления в соответствии с матрицей проекции. В конце выведена формула для частного случая:
Самым простым способом достижения этого является вывод прямоугольника с zeye=1 границы которого соответствуют пересечению данной плоскости и (неусеченной) пирамиды видимости.
в которой мы находим положение камеры
    float zEye     = zFar * zNear / ( d * (zFar - zNear) - zFar );
vec3  eyeCoord = pos * zEye;
И самое неприятное - для другой матрицы проекции нам снова надо пройти все эти вычисления

Как то все сложно. Гораздо проще на мой взгляд привести позицию позицию фрагмента к кубу [-1; 1] и умножить на обратную матрицу проекции gl_ProjectionMatrixInverse
И таким образом код фрагментного шейдера выглядит так:

uniform sampler2D depthMap;
uniform vec2 uWindowSize; //ширина и высота вьюпорта (с рассчетом на то что вьюпорт у нас начинается в точке 0,0)
uniform vec2 uTexSize; //ширина и высота заполненой части текстуры для NPOT текстуры
void main()
{
    vec2 texCoord = gl_FragCoord.xy / uTexSize; //я тут не использую NPOT текстуры, поэтому перевожу координаты фрагмента в координаты текстуры
    float Depth = texture2D(depthMap, texCoord).r; //читам глубину
    vec4  PixelPos = gl_ProjectionMatrixInverse * vec4((gl_FragCoord.xy/uWindowSize * 2.0 - 1.0), Depth * 2.0 - 1.0, 1.0); //переводим XY Depth в куб [-1; 1] и умножаем на обратную матрицу
    PixelPos /= PixelPos.w; //восстанавливаем W в 1
}
Все, в PixelPos имеем координаты пикселя, Eye координаты у нас находятся в точке 0,0,0
Приимущества очевидны - не зависим от матрицы проекции. Главное только чтобы на обоих проходах была одна и та же матрица проекции.
Может стоит добавить этот способ в эту статью, а тот рассматривать как альтернативный вариант?

Статья: Deferred Shading.

Цитирую:
Как видно из данного рисунка необходимо вычислять освещенность только для тех фрагментов нелицевой части границы области влияния источника (сферы), для которых не пройден тест глубины.
Это позволяет использовать буфер трафарета (отключив при этом запись во все остальные буфера) для выделения фрагментов, действительно требующих освещения.
При этом каждый источник требует двух проходов - на первом (очень быстром, так как идет запись только в буфер трафарета) помечаются те фрагменты, которые нужно освещать (т.е. для которых тест глубины не пройден), а на втором - осуществляется вычисление освещенности тех фрагментов, которые проходят тест трафарет.
Таким образом, первый проход запрещает запись во все буфера, кроме буфера трафарета, устанавливает отсечение лицевых граней, в качестве теста глубины задает режим GL_LESS, в качестве теста трафарета задает режим GL_ALWAYS и задает операцию GL_REPLACE для тех фрагментов, для которых не пройден тест глубины.
В результате этого прохода у нас в буфере трафарета будут помечены заданным значением только те пикселы, которые требуют освещения.
Второй проход опять выводит только нелицевые грани области влияния источника света, выключив запись в буфер глубины и буфер трафарета, однако задав отбрасывание при помощи теста трафарета ненужных фрагментов.

Вопрос: Зачем?
Зачем делать 2 прохода? Зачем писать в стенсил? Зачем, если во время первого прохода, если имеем Depth test fail - то попадаем во фрагментный, в котором можем как надо все осветить сразу?
Более того, ни слова не сказано, что при подобном способе рискуем на zNear и zFar клапминг для треугольников. А ведь для "мощных" источников света с большим Range сфера запросто может пересечь zFar. Вывод: надо следить за этим либо отключать клампинг глубины используя например NV_DEPTH_CLAMP расширение.

Статья: Screen-Space Ambient Occlusion.
Я сначала скачал демки и посмотрел. Удивился высокой фрагментированности теней. На всех демках явно виден тайлинг тени. Стал читать. Сначала разумно все объясняется про случайные вектора, все как надо, но потом смотрю в шейдер и вижу:
vec4 rndTable [8] = vec4 [8]
(
    vec4 ( -0.5, -0.5, -0.5, 0.0 ),
    vec4 (  0.5, -0.5, -0.5, 0.0 ),
    vec4 ( -0.5,  0.5, -0.5, 0.0 ),
    vec4 (  0.5,  0.5, -0.5, 0.0 ),
    vec4 ( -0.5, -0.5,  0.5, 0.0 ),
    vec4 (  0.5, -0.5,  0.5, 0.0 ),
    vec4 ( -0.5,  0.5,  0.5, 0.0 ),
    vec4 (  0.5,  0.5,  0.5, 0.0 )
);
Просто в шейдере (даже не в юниформе) заполняем КОНСТАНТАМИ :'(
Не удивительно что тень фрагментирована. Смысл то reflect тогда? Дополнительное вычисление не приводящее посути ни к какому визуальному изменению?
Решение: rndTable нужно сделать зависмой от gl_FragCoord.

Пока все, вот как то так...

0

2

Статья: High Dynamic Range Rendering в OpenGL
Касательно bloom эффекта сказано:
ДЛя этого данное размытое изображение прибавляется к исходному (возможно с некоторым весом). Для избегания появления клеточной структуры следует для размытой текстуры использовать билинейную фильтрацию.
На практике же - имеем очень сильный засвет, который как минимум выше в 2 раза в ярких областях. Более логично смешивать 2 текстуры выбирая max в шейдере:
http://donrenessans2000.com/othimages/sample1.png
Никаких чрезмерных засветов.

p.s. Хотелось бы услышать комментарии автора статей. Интересно согласен он со мной или нет.

0

3

1. Согласен, Ваш способ более общий и я добавлю его в статью
Просто у используемого способа не совсем частный случай матрицы проектирования - это матрица, даваемая gluPerspective и именно этот вариант очень часто встречается.
И для него предложенный код быстрее, чем в общем случае с умножением на обратную матрицу

2. Если я не ошибаюсь идея двух прохоходов (взятая из главы в GPU Gems II про deferred shading в STALKER) в том, что перый проход получается очень быстрым и второй тоже оказывается более дешевым за счет использования стенсила. Т.е. именно для оптимизации, возможно на современном железе выйгрышь от этого минимален, если вообще есть.
Насчет клампинга - полностью согласен, добавлю в статью

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

4. По классике нужно именно сложение - в сетчатке галаза яркий свет попадающий на фоторецепторы вызывает возбуждение у соседний клеток, т.е. добавляет им сигнал
А для борьбы с засветкой служит tone mapping, именно он переводит HDR в обычнй диапазон

0

4

2. Если я не ошибаюсь идея двух прохоходов (взятая из главы в GPU Gems II про deferred shading в STALKER) в том, что перый проход получается очень быстрым и второй тоже оказывается более дешевым за счет использования стенсила. Т.е. именно для оптимизации, возможно на современном железе выйгрышь от этого минимален, если вообще есть.
Насчет клампинга - полностью согласен, добавлю в статью

При первом проходе у нас все пиксели, для которых тест глубины не прошел пишутся в стенсил буфер. Какой смысл сначала писать в стенсил, а потом еще раз отрисовывать пиксели по стенсилу? Ведь мы можем изменить тест глубины на glDepthFunc(GL_GEQUAL); и тогда во фрагментный попадут только те пиксели, для которых прошел этот тест глубины. Мы просто экономим на записи в стенсил буфер, и суммарно по филлрейту даже экономнее получается. Имхо лишняя отрисовка в стенсил.

4. По классике нужно именно сложение - в сетчатке галаза яркий свет попадающий на фоторецепторы вызывает возбуждение у соседний клеток, т.е. добавляет им сигнал
А для борьбы с засветкой служит tone mapping, именно он переводит HDR в обычнй диапазон

Ну не знаю не знаю... я например не уверен, то что именно добавляет им сигнал. Мне кажется там все гораздо сложнее. Но для меня логичнее, если при построении bloom еффекта у нас есть пиксель, который не прошел это условие:   

Код:
if ( length ( base.rgb ) < 0.8 ) base.rgb = vec3 ( 0.0 );

То он останется таким же каким и был до эффекта, а у нас получается что он запросто умножается в 2 раза при аддитивном блендинге. Конечно это можно отчасти победить tone mapping-ом, но если брать чисто bloom эффект, то лучше помоему выборку делать через max. имхо.

0

5

2. Это только мерять быстродействие причем для сложной сцены - что окажется быстрее
4. а что такое чисто bloom - как ореол вокруг ярких мест, т.е. IMHO сложение. И tonemapping именно нужен в нормальном HDR

0

6

2. Это только мерять быстродействие причем для сложной сцены - что окажется быстрее

Наверное кто то кого то не понял... Я себе представляю это так:
вот это:
A=2;
B=3;
D=A*B;
выполняется всегда медленнее чем вот это:
D=2*3;
(с отлюченной оптимизацией)

Реализация в 2 прохода:
Выводим геометрию источников света.
Проходим Z тест.
Для пикселей не прошедших Z тест пишем в стенсил.
Выводим квад.
Для пикселей прошедших стенсил тест - освещаем.

Реализация в 1 проход:
Выводим геометрию источников света.
Проходим Z тест.
Для пикселей не прошедших Z тест - освещаем.

Во втором случае все эти операции есть для двух проходов. Количество пикселей для которых выполняется фраментный - одинаково.
Каким образом второй вариант может оказаться медленнее? Не понимаю.

4. а что такое чисто bloom - как ореол вокруг ярких мест, т.е. IMHO сложение. И tonemapping именно нужен в нормальном HDR

Ладно, будем считать что это дело "вкуса".

0

7

MrShoor написал(а):

источников

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

Итак, давайте проясним все моменты.
1. Буфер глубины в данном случае - буфер глубины, оставшийся с первого прохода
2. Источник i рисуется с отключенной записью в буферы глубины и цвета.
3. В стенсиле помечаются те точки, на которых тест глубины провалился (то есть какая-то геометрия будет освещенна) (остальные ставятся в 0)
3.1 Для оптимизации филлрейта (хотя он очень низкий в данном случае) можно использовать scissors test/DBT
4. При выводе квада тяжелый шейдер второго прохода выполнится только для тех точек, которые отмеченны в стенсил буффере.
4.1 Оптимизации из 3.1 по прежнему еще сильнее снижают нагрузку на шину памяти GPU
5. Повторяем с п.2 для всех источников
6. ???
7. PROFIT!

По пунктам очевидные минусы вашего варианта:
1. на модельном примере 100 маленьких, одинаковых, не пересекающихся источников филлрейт будет выше в 99*100 = 9900 раз.
2. фрагментый шейдер должен будет учитывать не всегда тривиальную топологию источника света (даже если для пойнтов рисовать кубики), проводить коррекцию координат с учетом этой топологии. Это приводит к увеличению вычислительной сложности шейдера и накапливанию ошибок выбора. Второй вариант, задавать отображения "источника" на "g-buffer" текстурными координатами, но это приводит к CPU intensive задаче, а вторую проблему это не решает.
3. Переключения функции теста глубины, хотя этого недостатка не лишен и первый метод (правда для функции стенсил теста)
4. Он не способен корректно обрабатывать пересекающиеся источники

0

8

1. Буфер глубины в данном случае - буфер глубины, оставшийся с первого прохода
2. Источник i рисуется с отключенной записью в буферы глубины и цвета. НО тест глубины для него делаем glDepthFunc(GL_GEQUAL);
3. В результате в фрагментный шейдер вызовется только для тех точек, для который тест глубины не прошел. (что аналогично пункту 3 и 4 в Вашем описании).
3.1 Точно так же при желании используем сциссор тест :) Хотя что отсекать непонятно, мы же не фуллскрин квад выводим.
4. Повторяем с п.2 для всех источников.
5. ???
6. PROFIT!

В результате профита достигаем раньше, без "дерганья" стенсил буфера.

Я кажется начинаю догадываться почему не понимают моей реализации. Так вот, касательно пункта 2:
2. Источник i рисуется с отключенной записью в буферы глубины и цвета. НО тест глубины для него делаем glDepthFunc(GL_GEQUAL);
При прорисовке источника можно использовать сильно лоуполи модель. Я думал что при отрисовке в стенсил используется именно такой подход (судя по рисуночкам к статье), но в силу написанного:

2. фрагментый шейдер должен будет учитывать не всегда тривиальную топологию источника света (даже если для пойнтов рисовать кубики), проводить коррекцию координат с учетом этой топологии. Это приводит к увеличению вычислительной сложности шейдера и накапливанию ошибок выбора. Второй вариант, задавать отображения "источника" на "g-buffer" текстурными координатами, но это приводит к CPU intensive задаче, а вторую проблему это не решает.

Я так понял что в стенсил мы рисуем фуллскрин квад, в фрагментном считаем расстояние и сохраняем глубину: gl_FragDepth = чтото В результате если тест глубины у нас фейлится после фрагментного - то сохраняем в стенсиле точку.
Я в коде использую немного другой подход. Я генерю себе лоуполи модельку сферы с единичным радиусом (для спотлайтов - конусы с радиусом основания 1 и высотой 1). Моделька достаточно лоуполи, чтобы не нагружать вершинный. Далее вычисляю матрицу трансформации, чтобы эта моделька полностью описывала источник света и рисую ее с glDepthFunc(GL_GEQUAL).

Опять же в силу написанного:

2. фрагментый шейдер должен будет учитывать не всегда тривиальную топологию источника света (даже если для пойнтов рисовать кубики), проводить коррекцию координат с учетом этой топологии. Это приводит к увеличению вычислительной сложности шейдера и накапливанию ошибок выбора. Второй вариант, задавать отображения "источника" на "g-buffer" текстурными координатами, но это приводит к CPU intensive задаче, а вторую проблему это не решает.

Не должен ничего фагментный шейдер этого учитывать. У нас есть gl_FragCoord и карта глубины. Этого достаточно чтобы определить координаты пиксея в eyespace.

4. Он не способен корректно обрабатывать пересекающиеся источники

У меня прекрасно обрабатывает :)

+1

9

Гм, да, после ваших уточнений - да, все должно работать. Но, во-первых, далеко не факт что быстрее, т.к. выборки из g-buffer становятся dependent (хотя выборки и остаются, по идее, cache friendly), во-вторых, color write отключать нельзя по понятным причинам, в третьих на железе без/с плохой поддержкой rect текстур появятся операции приведения координат в texture space.
"Проход", описанный у меня в п. 3 фактически бесплатен, т.к. вершинный и фрагментый шейдеры тривиальны, не требуют сетапа константных буфеоров, а непосредственно дорогой draw call (самая дорогая операция, в данном случае) присутствует в обоих способах.

MrShoor написал(а):

Я кажется начинаю догадываться почему не понимают моей реализации

Непонятным было употребление слова источник во множественном числе, что я и выделил в начале своего предыдущего поста.

MrShoor написал(а):

Я думал что при отрисовке в стенсил используется именно такой подход

Да, именно такой подход. Я просто не учел, что есть возможность dependent выборок из буфера с использование gl_FragCoord.

MrShoor написал(а):

Этого достаточно чтобы определить координаты пиксея в eyespace.

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

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

0

10

В первую очередь, скорее, интересует производительность выборок из минимум трех текстур.

Так ведь в Вашем подходе те же самые 3 выборки. Из глубины, дифузной, карты нормалей.

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

Вот код шейдера. Делает выборки из (в моем случае 4-х, добавлена спекуляр текстура) текстур:

Код:
uniform vec2 uTexSize;
uniform vec2 uClipSize;

uniform sampler2D uTex1; //FtexNormal
uniform sampler2D uTex2; //FtexDiffuse
uniform sampler2D uTex3; //FtexSpecular
uniform sampler2D uTex4; //FtexDepth

uniform vec3 uLPos;
uniform vec4 uLColor;
uniform vec3 uLDir;
uniform vec2 uLAngle;
uniform float uLRange;

void main()
{
	vec2 texCoord = gl_FragCoord.xy / uTexSize;

    float Depth    = texture2D(uTex4, texCoord).r;
	vec4  PixelPos = gl_ProjectionMatrixInverse * vec4((gl_FragCoord.xy/uClipSize * 2.0 - 1.0), Depth * 2.0 - 1.0, 1.0);
	PixelPos /= PixelPos.w;
	vec4  sMapColor = texture2D(uTex1, texCoord);
    vec3  Normal   = 2.0*(sMapColor.rgb - vec3(0.5));	
    vec4  Diffuse  = texture2D(uTex2, texCoord);
	vec4  Specular = texture2D(uTex3, texCoord);

	vec3 lDir = uLPos - PixelPos.xyz;
	float lightK = 1.0 - clamp(dot(lDir, lDir)/uLRange, 0.0, 1.0);	
	lDir = normalize(lDir);
	float spotK = smoothstep(uLAngle.y, uLAngle.x, dot(-lDir, uLDir));
	
	float DiffK = max(0.0, dot(Normal, lDir));
	float SpecK = pow(clamp(dot(normalize(PixelPos.xyz), normalize(reflect(lDir, Normal))), 0.0, 1.0), sMapColor.a * 255.0) * Specular.a;

	gl_FragColor = vec4((Diffuse.rgb * DiffK + Specular.rgb * SpecK) * lightK * spotK * uLColor.rgb, Diffuse.a);
}

Математику я не оптимизирвал еще, но уже видно что выборки независимые. Или я что то не понимаю?

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

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

И опять же не понял, почему выборки будут зависимыми?

p.s. Подход со стенсилом конечно может и выйграть, но только если в моем способе использовать ну очень сильно лоуполи модельки, тогда лишних фрагментов для освещения будет чуть больше. Но как правило сферы в 150 поликов (при этом кулфейсом срежется пол сферы) хватает с головой, а для вершинного 75 поликов - это семечки.

0

11

MrShoor написал(а):

но уже видно что выборки независимые. Или я что то не понимаю?

Non dependent texture fetch происходит в том случае, если источником текстурных координат является интерполятор (varying в терминах GLSL). В этом случае GPU очень легко предсказывать к каким текселям произойдет обращение при выполнении фрагментного шейдера. В Вашем случае вычисление текстурных координат происходит непосредственно в шейдере, что не дает GPU возможности правильно предсказывать, какие тексели понадобятся следующими. Хотя, по идее, особых проблем на современных PC железках это и не принесет. Но, во первых, сталкер писался давно, а во вторых PC - не единственная платформа для применения deferred техник освещения.

MrShoor написал(а):

тогда лишних фрагментов для освещения будет чуть больше.

Видимо столько же. Фрагменты, пролезший на lighting pass, но не влезающие в источник должны бодро лечиться ранним discard'ом. Причем это достаточно редкий случай, когда discard реально даст буст к производительности.

0

12

Non dependent texture fetch происходит в том случае, если источником текстурных координат является интерполятор (varying в терминах GLSL). В этом случае GPU очень легко предсказывать к каким текселям произойдет обращение при выполнении фрагментного шейдера. В Вашем случае вычисление текстурных координат происходит непосредственно в шейдере, что не дает GPU возможности правильно предсказывать, какие тексели понадобятся следующими. Хотя, по идее, особых проблем на современных PC железках это и не принесет. Но, во первых, сталкер писался давно, а во вторых PC - не единственная платформа для применения deferred техник освещения.

Ну впринципе я так и предполагал. В таком случае использование npot текстур поидее должно дать гарантированно независимую выборку при использовании только gl_FragCoord.

Видимо столько же. Фрагменты, пролезший на lighting pass, но не влезающие в источник должны бодро лечиться ранним discard'ом. Причем это достаточно редкий случай, когда discard реально даст буст к производительности.

Проверить надо.. лишний if в шейдере это отнюдь нехороший вариант, и если число не освещаемых пикселей достаточно мало, то discard (за счет if-а) может только подкинуть тормозов. Это можно установить только тестами.

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

p.s.s. Мы теперь друг друга правильно поняли?

0

13

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

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

Итак, в моей сцене было довольно много спотлайтов (конусных источников света) установленных на уровне пола и освещающих сцену снизу. Все спотлайты были с довольно узким углом освещения, но с большой дистанцией. Довольно часто спотлайт мог освещать только кусочек стены:
http://donrenessans2000.com/othimages/sample2.jpg
На картинке приведен пример, когда спотлайт освещает только часть грани коробочки.

Я подготовил более схематичное изображение:
http://donrenessans2000.com/othimages/sample3.png
Здесь спотлайт освещает кусок бруска. Розовым обозначена зона, где конус входит в брусок, зеленым - зона где конус находится внутри бруска, голубым - зона выхода конуса из бруска. Если отбросить лицевые грани, и выбрать все пиксели для которых ztest fail, то мы аккурат получим розовую + зеленую + голубую зону. По рисунку видно какой бешеный overdraw выходит у нас, когда нам нужно только розовую зону осветить.

Используя стенсил буфер (но не так как написано в статье, а по другому) можно исключить зеленую зону, оставив только пиксели, которые лежат внутри конуса.
Для этого надо немного изменить алгоритм работы со стенсилом.
1. Очищаем стенсил буфер в ноль
2. Включаем стенсил тест и ставим ему GL_ALWAYS, чтобы стенсил тест всегда проходил
3. Выставляем glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
4. Отключаем отсечение каких либо граней, glCullMode(GL_FRONT_AND_BACK);
5. Рисуем собственно наш конус/сферу.
6. В результате все пиксели пиксели лежащие внутри конуса/сферы у нас будут отмечены в стенсиле единичкой.

После таких манипуляций осталась только розовая + голубая зона.

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

Если после прочтения сего опуса - сложилось впечатление что такая проблема справедлива только для спотлайтов - это не так. Для поинтлайтов тоже самое. Просто на спотлайтах это более выраженно, и легче изобразить схематично. Для поинтлайтов я немного изменил рисунок который прилагался к статье:
http://donrenessans2000.com/othimages/sample4.png
Красная зона и есть тот самый overdraw. Т.е. во всех случаях, когда точечный источник перекрыт каким либо объектом - по алгоритму предложенному в статье получаем овердрав на всю эту зону.

Отредактировано MrShoor (2011-04-20 15:07:03)

0

14

Если у кого-либо есть менение/соображения по поводу производительности второго метода, с выборкой depth+normal буду рад услышать.

0

15

Ну, традиционно рендерятся только не лицевые грани "источников". Есть еще возможные улучшения, но они требуют либо еще одного стенсил прохода, либо two sided stencil (он, правда, есть на всем железе, на котором осмысленно использовать деферед). И да, смысл дефереда скорее в очень большем количестве очень маленких поинт-дайтов, а не в куче "длинных" спотов. Потому что от мелких поинтов тени делать не то, что не нужно, а даже скорее нельзя. А спот без тени, смотрится, мягко говоря, awkward. Особенно, если он длинный...

0

16

Особенно, если он длинный...

Ну у меня то он длинный, но маленький по углу, и освещает маленькую площадь, и тень там абсолютно не нужна. А смысл дефферед скорее не в куче маленьких поинт источников, а чтобы отделить сложную геометрию от освещения.

Сейчас пытаюсь оптимизировать вывод источников (хоть точечных, хоть спотлайтов), и пришел к забавному результату.
Использование сциссор отсечения сильно спасает, посему сциссор must have. Но в моем конкретном случае, когда у меня узкие спотлайты, которые могут быть наклонены под углом сциссоры часто выходят громадные. Для спотлайтов оптимальнее оказалось "покласть" на сциссор, и выводить 3 раза модельку конуса :D
Сначала рендерю конус чтобы почистить стенсилбуфер. Включаю отсечение видимых граней, ставлю стенсил:
glStencilFunc(GL_NEVER, 0, $FF);
glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
ну и далее рисую модельку конуса. (да да, по тестам чистка через glClear выходит медленнее без сциссора)

Далее отключаю отсечение граней, и вывожу все грани с таким стенсилом и включенным Z тестом:
glStencilFunc(GL_ALWAYS, 0, $FF);
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);

На предыдущих двух этапах отрисовка только в стенсил.
Ну и последний раз включаю отсечение лицевой геометрии, включаю отрисовку в колорбуфер, и опять рендерю конус, тут уже освещаю пиксели как надо. Стенсил тест на третьем проходе:
glStencilFunc(GL_EQUAL, 1, $FF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

Ну для поинтлайтов сциссор обязательно.

Кроме того наблюдаю забавную картину. Непонятно с чем связано, но если рендерить фуллскринквад без сциссор теста, при правильно заполненном стенсилбуфере - то непонятно куда сливается львиная доля профита... Неужели стенсилтест такой долгий? Включаю сциссор - как рукой снимает, хотя сциссор только локализует зону заполненную стенсилом... Мб у меня какая то дикая реализация от вендора... а может я чего то недогоняю?

p.s. Вообще тема переросла уже от комментариев к статьям - в какой то "мой блог" :D надо закруглятся с этим...  ну или хотябы отделить "блог" в другую ветку ^_^

0

17

MrShoor написал(а):

Ну у меня то он длинный

Ну вот в том то и проблема. Самый треш будет, когда он "проткнет" один обект на сцене и осветит объект за ним.

MrShoor написал(а):

А смысл дефферед скорее не в куче маленьких поинт источников

Неа. Именно в маленьких, не бросающих тень поинтах. Они почти бесплатны, а дают много профита на частицах и прочей лаве. Плюс чуть менее псевдо индерект освещение, чем SSAO. Правда для приличного качества нужно столько источников, что видяшка все равно умирает. Все остальное - "маркетинг", который либо ломается об shadow cast источники, либо решается early-z проходом.

MrShoor написал(а):

да да, по тестам чистка через glClear выходит медленнее без сциссора

glClear в принципе очень дорогой.

MrShoor написал(а):

Включаю сциссор - как рукой снимает

Сциссор отбрасывает фрагменты без обращений к памяти. А деферед - очень сильно memory bandwidth bound.

MrShoor написал(а):

Далее отключаю отсечение граней, и вывожу все грани с таким стенсилом и включенным Z тестом:

Обычно INCR для задних и DECR для передних. Либо только INCR для задних.

Вообще говоря, если ваши скрины отражают реальное разрешение и реальную сложность сцены и у вас тормоза - то тут проблема где-то в другом месте. Например, в лейауте g-буфера. Или в видеокарте нижнего уровня с 32/64(/128) битной шиной памяти...

0

18

Сциссор отбрасывает фрагменты без обращений к памяти. А деферед - очень сильно memory bandwidth bound.

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

Вообще говоря, если ваши скрины отражают реальное разрешение и реальную сложность сцены и у вас тормоза - то тут проблема где-то в другом месте. Например, в лейауте g-буфера. Или в видеокарте нижнего уровня с 32/64(/128) битной шиной памяти...

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

Обычно INCR для задних и DECR для передних. Либо только INCR для задних.

У меня стенсил 8 бит. Выходит два инкримента. Это для однобитного стенсила в 2 прохода, а тут я решил сэкономить на батче. Не знаю... может стоит подумать над однобитным стенсилом, может и будет чуть профита, не знаю только какой фреймбуфер для этого надо собрать.

0

19

MrShoor написал(а):

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

Не хочу казаться КО, но стенсил лежит в видеопамяти.

MrShoor написал(а):

Не знаю... может стоит подумать над однобитным стенсилом, может и будет чуть профита, не знаю только какой фреймбуфер для этого надо собрать.

Посмотрите на тот, как делаются стенсил тени. Здесь ровна та же идея и с 1-битным стенсилом она не взлетит

0

20

Не хочу казаться КО, но стенсил лежит в видеопамяти.

Просто все равно на мой взгляд выходило слиишком долго, даже с учетом выборки из стенсила. Хотя мб оно так и должно быть.

Посмотрите на тот, как делаются стенсил тени. Здесь ровна та же идея и с 1-битным стенсилом она не взлетит

Я знаю как делаются стенсильные тени, и прекрасно понимаю про INC DEC проходы. Просто у меня на один проход меньше за счет того что я сразу вывожу и лицевые и нелицевые, ну и в результате в стенсиле у меня будут лежать нули, единички и двоечки. С INC DEC будут только нули и единички, и INC DEC проходы подходят даже под однобитный стенсил. Так что разницы посути нет.

Сейчас вот возникла идея как выводить множество источников без чистки стенсила, и тут как раз INC DEC проходы и помогут.
Идея такова. В самом начале перед входом в цикл рисования источников света чистим один раз стенсил в 0. Далее INC DEC проходы. В результате то что надо осветить у нас в стенсиле помечено как единичка. Рисуем то что надо осветить и одновременно затираем эти единички в 0. Красота :) Щас попробую покрутить в общем.

0

21

Красота, от 5% до 10% фпс в плюс без чистки стенсила для каждого источника. Выпилил сциссор тест нафиг ^_^, даже для поинтлайтов. Вместо квадов рисую сферки, ну и выборка depended в фрагментном. Осталось прогнать всю систему на разных карточках чтобы убедится что depended выборка не сильно убивает древнее железо.

0

22

У меня есть один вопрос. Почему в статье про скелетную анимацию кости передаются через атрибуты вершин? Разве нельзя использовать uniform массив костей, а в вершинах хранить их индексы? В статье про рендеринг в вершинный буфер, где описывается как при помощи этого сделать скелетную анимацию тоже написано:

Хотя в простейших случаях скелетную анимацию можно реализовать и при помощи вершинных программ, подобная реализация оказывается эффективной только при очень небольшом числе костей (joints) на вершину (1-2). Это связано с тем, что для каждой кости необходимо передать довольно большое количество данных. Пока все эти данные помещаются в стандартные вершинные атрибуты OpenGL все хорошо. Однако при количестве костей на вершину 5 и больше (а в моделях из DooM III используется до 10 костей на вершину) передаваемые для каждой вершины данные уже не помещаются в стандартные атрибуты OpenGL и приходится использовать вершинные атрибуты общего вида (glVertexAttrib*).

P. S.: Вы мне так и не ответили на вопрос в теме про separate shader objects.

0

23

gammaker написал(а):

Разве нельзя использовать uniform массив костей

В атрибуте хранятся индекс и вес. Вес - 1 float.

Таким образом мы имеем по два флоата (а реально - можно в один уложить без проблем, frac в помощь, если мощности хватает) у вершины на каждую кость, которая на нее влияет. Количества атрибутов достаточно на очень большее количество влияющих костей даже на PowerVR SGX 530. Упремся все равно в количество юниформов (на iOS, например, приходится "резать" модели на батчи, потому, что есть ограничение на 512 юниформ float'ов, при этом при попытке апдейта всех 512 телефон выстрелит вам в ногу от счастья)

У Кармака, в прочем, несколько странная трактовка понятия "вес". Нигде, кроме id Tech 4 я такого не встречал. Всегда вес - один float, а у Кармака, по какой-то странной причине - это float и позиция. Это возможно и удобно, если меш описывать ручками (хотя, текстовый формат файла модели как бы намекает, что что-то у них пошло не так), но абсолютно бессмысленно в реальном мире, и даже в транспортных форматах никто так отскиненные модели не хранит. Хотя бы по той причине, что сначала моделится и текстурируется сам меш, а потом уже к нему привязывается скелет и его "расслабленное" положение соответствует исходному мешу. Таким образом, мы получаем, что на вершину достаточно хранить ровно одну позицию, а не внезапно по количеству костей, влияющих на эту вершину. И количества атрибутов становится внезапно достаточно. Впрочем, как ни странно, такой странный подход может следовать из неумной любви Кармака к стенсильним теням, которые автоматически на не DX10 железе блокируют возможность расчета меша на GPU, причем как с трансформ фидбеком (та еще радость до DX10, ага), так и без. А на CPU можно не заботиться о количестве атрибутов, там других проблем хватает.

Касательно separate shader object - я почти уверен, что до HD2xxx у ATI/AMD вы их не найдете. Они то может и давно в D3D, но AMD не любитель поддержки даже ARB расширений. В прочем, утверждать я этого не буду, потому что у OpenGL Extension Viewer очень не полная база по ARB(EXT)_separate_shader_objects.

0

24

А, я не правильно понял, о чём там говорилось. Я думал, что там все кости передаются через вершинные атрибуты. Только я не понял, зачем нужно несколько костей на 1 вершину?

Касательно separate shader object - я почти уверен, что до HD2xxx у ATI/AMD вы их не найдете. Они то может и давно в D3D, но AMD не любитель поддержки даже ARB расширений. В прочем, утверждать я этого не буду, потому что у OpenGL Extension Viewer очень не полная база по ARB(EXT)_separate_shader_objects.

Вообще-то, у меня был вопрос к steps3d, когда он напишет об этом расширении статью. Он писал, что постарается поскорее, но уже месяц прошёл, а новостей нет.
К тому времени, когда я напишу что-нибудь толковое, уже наверное у всех будет видеокарта с поддержкой этого расширения.

0

25

gammaker написал(а):

А, я не правильно понял, о чём там говорилось.

Нет, Алексей имел ввиду именно то, что вы поняли. Просто он по какой-то причине решил анимировать на GPU формат, не предназначенный для анимации на GPU. Почему Кармак выбрал именно такой подход к организации скининга мне не ясно. Традиционный подход будет даже на несколько, скорее все, тысячных процента быстрее из-за того, что будет ниже нагрузка на кеш ввтду отсутствия выборок лишних позиций. Сакральный смысл передавать индекс родительской кости в позиции тоже не ясен, в шейдере этот вопрос тоже не раскрыт. А матрица констант на гпу не резиновая и апдейт очень не бесплатный. Так же есть ряд моментов, справедливых только для GL2.1 (например - про атрибуты общего назначения). Но на момент написания статьи такая оптимизация действительно была актуальной.

0

26

gammaker написал(а):

Вообще-то, у меня был вопрос к steps3d, когда он напишет об этом расширении статью. Он писал, что постарается поскорее, но уже месяц прошёл, а новостей нет.

Мне Алексей полтора месяца назад (в самом верху его пост) сказал что внесет дополнения в свои статьи (а это далеко не статью написать). До сих пор правок нет ;)

Остается только надеятся что Алексей соберется с духом, убьет на раздел со статьями время, и внесет правки, а может и напишет/разместит новые статьи. А то уже который месяц висит:
>>> В ближайшее следующая статья статья про CoreAnimation
на шапке страницы.

В любом случае труд Алексея бесценен. Поэтому огромное ОГРОМНОЕ спасибо за тот материал который уже есть ;)

+1

27

В любом случае труд Алексея бесценен. Поэтому ОГРОМНОЕ спасибо за тот материал который уже есть

Только ошибок и опечаток там много. Не знаю, как для остальных, но меня они отвлекают (особенно слово "выйгрышь").

В ближайшее следующая статья статья про CoreAnimation

Даже тут ошибки!

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

Вот только я на лето уезжаю и вряд ли у меня там будет интернет, чтобы прочитать статью. Придётся разбираться самому.

0


Вы здесь » Компьютерная графика » Программирование графики и GPU » Некоторые комментарии к некоторым статьям :)


создать форум