Роман расскажет о разных тонкостях работы с трехмерной графикой в Unity, о работе графического конвеера, о реализации отложенного освещения в Unity3D, его преимуществах и недостатках. А также разберет все возможности работы с шейдерами и пост-эффектами в Unity.
2. Words to say
• Рассмотрим graphics pipeline в Unity3D .
• Коснемся работы с шейдерами в Unity3D .
• Поговорим об оптимизации графики.
• Поговорим о image post processing.
3. WhoAmI()
• Программист графики.
•В разное время работал с Adobe flash ->
DirectX -> OpenGL -> Unity.
• Работал с open-source движками:
Ogre3D, Irrlicht3D, Horde3D, HGE.
Контрибьютил в Irrlicht3D, Horde3D.
• На данный момент работаю на
мобильной разработке в Steel Monkeys
(Unity 3D).
5. Hardware Transform & Lighting
• Аппаратная трансформация,
отсечение и освещение.
• Texture blending тоже аппаратный.
• Очень быстрый расчет освещения,
буквально несколько тактов GPU.
• Реализуется через программный API.
• В Unity реализована в виде fixed-function
шейдеров.
7. Conclusion: Fixed function rendering
Да, если Нет, если
• Не требуется попиксельного
освещения.
• Вообще не требуется
динамического освещения,
и/или взаимодействия с
лайтмапами.
• Вы работаете с очень
старым железом (iphone 4,
ipad 1).
• Требуется попиксельное
освещение, лайтмапы,
realtime-тени, любые
шейдерные эффекты.
• Ваша платформа позволяет
использовать что угодно
другое.
8. Per-pixel forward rendering oveview
• Per-pixel освещение накладывается во
фрагментном шейдере.
• Один Forward Base проход для самого
яркого Directional источника на сцене.
• N дополнительных Forward Add
проходов в аддитивном блендинге
для N избранных источников света.
• До четырех per-vertex источников
света в вершинном шейдере.
• Легко взаимодействовать с помощью
surface-шейдеров.
9. Surface shader
• SubShader:
• Forward base
• OpenGL
• Base
• KEYWORD_A
• KEYWORD_B
• Vertex program
• Fragment program
• Shadow caster
• Shadow collector
• DX9
• WP8
…
• Forward add
• Prepass base
• Prepass final
e.g. over 100 vertex/fragment programs
16. Forward rendering overhead
Итого имеем:
• 5X дополнительных циклов вершинной трансформации,
• 5X операций аддитивного блендинга.
• 5X дополнительных текстурных операций.
• 5X дополнительных итераций всего шейдерного кода.
• 5X overdraw по tris’ам.
Какой бы то ни было оптимизации в Light-manager’e Unity не
предусмотрено.
Давайте ему поможем!
17. Accessing built-in shader constants
1. _WorldSpaceLightPos0 – позиция
первого
направленного источника.
2. _LightColor0 – цвет этого источника
3. unity_4LightPosX0, unity_4LightPosY0,
unity_4LightPosZ0 – позиции четырех
источников света, которые считались
бы per-vertex.
4. unity_4LightAtten0 – аттенюация этих
источников света
5. unity_LightColor – цвет этих источников
18. Implementing an algorithm
Get on github: https://github.com/RChehowski/devgamm_expo
int index = 0;
while (index < 4)
{
float4 lightPosition = float4( unity_4LightPosX0[index],
unity_4LightPosY0[index],
unity_4LightPosZ0[index], 1.0);
// calculate direction
float3 vertexToLightSource = lightPosition.xyz - input.posWorld.xyz;
float3 lightDirection = normalize(vertexToLightSource);
// find distance and calculate attenuation
float squaredDistance = dot(vertexToLightSource, vertexToLightSource);
float attenuation = 1.0 / (1.0 + unity_4LightAtten0[index] * squaredDistance);
// calculate diffuse intensity
float3 diffuseReflection = attenuation * unity_LightColor[index].rgb *
_Color.rgb * max(0.0, dot(input.normalDir, lightDirection));
output += diffuseReflection;
index++;
}
19. • 1X per-pixel directional light.
• 4X per-pixel point light.
• All in one pass!
Result
20. Conclusion: Forward rendering
Да, если Нет, если
• Количество динамических
источников света и
освещенных объектов мало.
• Требуется поддержка
динамических теней от
directional лайтов.
• Требуется поддержка
лайтмапов из коробки.
• Количество динамических
источников велико.
• Есть возможность обойтись
Hardware Transform &
Lighting.
• Требуется доступ к буферу
глубины или view-нормалей.
21. Deferred rendering overview
• Освещение рассчитывается как пост-
процессинг, только для видимых
фрагментов.
• Все освещение на сцене рендерится
попиксельно.
• Легко получить depth и view normals
для собственных манипуляций при
пост-процессинге.
• Производительность сильно зависит
от пропускной способности памяти
видеокарты и способа реализации.
28. Conclusion: Deferred rendering
Да, если Нет, если
• Количество динамических
источников очень велико.
• Используется хотя бы
один пост-эффект,
работающих с глубиной
сцены (SSAO, DOF, soft
particles, point light shafts)
• Количество динамических
источников невелико.
• Слабое железо или железо
без поддержки рендеринга в
текстуру.
• Много transparent объектов
(alpha-test не считается).
29. Post processing
Попиксельная обработка
отрендеренного изображения для
получения необходимого эффекта:
• SSAO
• Bloom
• FXAA
• Gamma correction
• DOF
• Outlines
• … and many, many more!
30. Post processing
Сообщения:
• OnRenderImage() – вызывается после того, как все объекты на сцене
были отрисованы в рендертекстуру.
• OnPreRender() – вызывается перед тем, как начнется рендеринг.
• OnPostRender() – вызывается после того как отрендерятся все объекты в
текущем кадре.
• OnWillRenderObject() – вызывается перед рендерингом каждого
видимого объекта.
Методы:
• Graphics.DrawMesh() – сабмитит mesh на отрисовку.
• Graphics.DrawMeshNow() – рисует mesh в текущем кадре.
• Graphics.Blit() – копирует данные из рендертекстуры в рендертекстуру
32. High price of the Depth
• Camera.depthTextureMode =
DepthTextureMode.Depth;
• UNITY_TRANSFER_DEPTH(),
• UNITY_OUTPUT_DEPTH()
• В forward-пайплайне стоит одного
дополнительного прохода рендера
• В deferred-пайплайне просто
берется из G-буфера.
33. Conclusion
• К сожалению, формат данной презентации не
позволяет уделить каждой реализации конвейера
достаточного количество внимания.
• В погоне за универсальностью, рендер Unity
нередко жертвует производительностью.
• Использование каждого из пайплайнов создает
свои проблемы, но их можно устранить в рамках
каждой конкретной задачи.
34. Спасибо за внимание!
Special thanks to: <Dmitry Minsky> http://halfbus.co/
r.chehowsky@gmail.com
inangwish
Notes de l'éditeur
В Unity реализована в форме fixed-function шейдеров. – что отчасти удобно, так как позволяет не лезть в код и иметь метаданные прямо в шейдере. Помните technique в dx11? Это оно.
В Unity реализована в форме fixed-function шейдеров. – что отчасти удобно, так как позволяет не лезть в код и иметь метаданные прямо в шейдере. Помните technique в dx11? Это оно.
Использование пост-процессинга (RToText) не является причиной, потому что его все равно можно прикрутить. Вопрос целесообразно ли это?
Методом сферических гармоник рендерятся также лайтпробыN дополнительных Forward Add проходов в аддитивном блендинге для N избранных источников света COMMENT (per-pixel) где N – «Pixel Light Count» в Quality settings.
До четырех per-vertex источников света COMMENT (рендерятся в первом проходе).
Все остальные источники света рендерятся методом сферических гармоник COMMENT (также в первом проходе).
Эти слайды проматываются за 5-10 секунд
Эти слайды проматываются за 5-10 секунд
Эти слайды проматываются за 5-10 секунд
Эти слайды проматываются за 5-10 секунд
Эти слайды проматываются за 5-10 секунд
Эти слайды проматываются за 5-10 секунд
Плюс такого подхода – остается много операций АЛУ для пользовательского кода.
Отделить геометрическую сложность сцены от процесса расчета освещения. Получить возможность использовать сколько угодно динамических попиксельных источников освещения.
Можно осуществлять разными способами – с футпринтами или без. Для каждого источника света рендерится футпринт (сфера, гекс или фрустум)
Отделить геометрическую сложность сцены от процесса расчета освещения. Получить возможность использовать сколько угодно динамических попиксельных источников освещения.
Можно осуществлять разными способами – с футпринтами или без. Для каждого источника света рендерится футпринт (сфера, гекс или фрустум)
Отделить геометрическую сложность сцены от процесса расчета освещения. Получить возможность использовать сколько угодно динамических попиксельных источников освещения.
Можно осуществлять разными способами – с футпринтами или без. Для каждого источника света рендерится футпринт (сфера, гекс или фрустум)
Отделить геометрическую сложность сцены от процесса расчета освещения. Получить возможность использовать сколько угодно динамических попиксельных источников освещения.
Можно осуществлять разными способами – с футпринтами или без. Для каждого источника света рендерится футпринт (сфера, гекс или фрустум)
Перефигачить картинку более явно указать лайты
Вызывается каждый кадр, олицетворяет перенос изображения из рендертекстуры во фреймбуффер. Нужна для image processing’a. В реальности – рисует full-screen quad. Заглушка Blit(source, dest) не помогает, нужно отключать скрипт.
Представляет из себя per-pixel обработку картинки, которая записывалась в рендертекстуру, в итоге то что получилось по-любому должно сблититься на экран, поэтому если вы используете онРендерИмэдж, вы должны сделать блитдроМешНау() для рисования аутлайнов
Graphics.DrawMesh() – сабмитит меш на отрисовку. В Update()
Graphics.DrawMeshNow() – рисует меш в текущем кадре, в OnPostRender()
Вызывается каждый кадр, олицетворяет перенос изображения из рендертекстуры во фреймбуффер. Нужна для image processing’a. В реальности – рисует full-screen quad. Заглушка Blit(source, dest) не помогает, нужно отключать скрипт.
Представляет из себя per-pixel обработку картинки, которая записывалась в рендертекстуру, в итоге то что получилось по-любому должно сблититься на экран, поэтому если вы используете онРендерИмэдж, вы должны сделать блитдроМешНау() для рисования аутлайнов
Graphics.DrawMesh() – сабмитит меш на отрисовку. В Update()
Graphics.DrawMeshNow() – рисует меш в текущем кадре, в OnPostRender()
Вызывается каждый кадр, олицетворяет перенос изображения из рендертекстуры во фреймбуффер. Нужна для image processing’a. В реальности – рисует full-screen quad. Заглушка Blit(source, dest) не помогает, нужно отключать скрипт.
Представляет из себя per-pixel обработку картинки, которая записывалась в рендертекстуру, в итоге то что получилось по-любому должно сблититься на экран, поэтому если вы используете онРендерИмэдж, вы должны сделать блитдроМешНау() для рисования аутлайнов
Graphics.DrawMesh() – сабмитит меш на отрисовку. В Update()
Graphics.DrawMeshNow() – рисует меш в текущем кадре, в OnPostRender()
В Unity реализована в форме fixed-function шейдеров. – что отчасти удобно, так как позволяет не лезть в код и иметь метаданные прямо в шейдере. Помните technique в dx11? Это оно.