Steel monkeys: Unity3D глазами программиста графики
-
Upload
flash-gamm -
Category
Presentations & Public Speaking
-
view
311 -
download
4
description
Transcript of Steel monkeys: Unity3D глазами программиста графики
• Рассмотрим graphics pipeline в Unity3D .• Коснемся работы с шейдерами в Unity3D .• Поговорим об оптимизации графики.• Поговорим о image post processing.
Words to say
WhoAmI()
• Программист графики.•В разное время работал с Adobe flash -> DirectX -> OpenGL -> Unity.• Работал с open-source движками: Ogre3D, Irrlicht3D, Horde3D, HGE. Контрибьютил в Irrlicht3D, Horde3D.• На данный момент работаю на мобильной разработке в Steel Monkeys (Unity 3D).
• Vertex lit (hardware transform & lighting)• Forward (multi-pass forward rendering)• Deferred (light footprint deferred shading)
Graphics pipelines
• Аппаратная трансформация, отсечение и освещение.
• Texture blending тоже аппаратный.
• Очень быстрый расчет освещения, буквально несколько тактов GPU.
• Реализуется через программный API.
• В Unity реализована в виде fixed-function шейдеров.
Hardware Transform & Lighting
// DirectX9 codeD3DLIGHT9 light;D3DMATERIAL9 material;
ZeroMemory(&light, sizeof(light));light.Type = D3DLIGHT_POINT;light.Diffuse = D3DXCOLOR(0.5, 0.5, 0.5,
0.5);light.Position = D3DXVECTOR3(0.0f, 5.0f, 0.0
f);light.Range = 100.0f;light.Attenuation0 = 0.0f;light.Attenuation1 = 0.125f;light.Attenuation2 = 0.0f;
d3ddev->SetLight(0, &light);d3ddev->LightEnable(0, TRUE);
ZeroMemory(&material, sizeof(D3DMATERIAL9));material.Diffuse = D3DXCOLOR(1, 1, 1, 1);material.Ambient = D3DXCOLOR(1, 1, 1, 1);
d3ddev->SetMaterial(&material);
Fixed function shader
Да, если Нет, если• Не требуется
попиксельного освещения.
• Вообще не требуется динамического освещения, и/или взаимодействия с лайтмапами.
• Вы работаете с очень старым железом (iphone 4, ipad 1).
• Требуется попиксельное освещение, лайтмапы, realtime-тени, любые шейдерные эффекты.
• Ваша платформа позволяет использовать что угодно другое.
Conclusion: Fixed function rendering
• Per-pixel освещение накладывается во фрагментном шейдере.
• Один Forward Base проход для самого яркого Directional источника на сцене.
• N дополнительных Forward Add проходов в аддитивном блендинге для N избранных источников света.
• До четырех per-vertex источников света в вершинном шейдере.
• Легко взаимодействовать с помощью surface-шейдеров.
Per-pixel forward rendering oveview
• 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
Surface shader
Forward Base (brightest directional light)
Stats:• 2K triangles• 4K vertices
Forward Add (x1)
Stats:• 4K triangles• 8K vertices• 1X Blend “One One”
Forward Add (x2)
Stats:• 6K triangles• 12K vertices• 2X Blend “One One”
Forward Add (x3)
Stats:• 8K triangles• 16K vertices• 3X Blend “One One”
Forward Add (x4)
Stats:• 10K triangles• 20K vertices• 4X Blend “One One”
Forward Add (x5)
Stats:• 12K triangles• 24K vertices• 5X Blend “One One”
Итого имеем:• 5X дополнительных циклов вершинной
трансформации, • 5X операций аддитивного блендинга.• 5X дополнительных текстурных операций.• 5X дополнительных итераций всего шейдерного
кода.• 5X overdraw по tris’ам.
Forward rendering overhead
Какой бы то ни было оптимизации в Light-manager’e Unity не предусмотрено.
Давайте ему поможем!
1. _WorldSpaceLightPos0 – позиция первогонаправленного источника.
2. _LightColor0 – цвет этого источника
3. unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0 – позиции четырехисточников света, которые считались бы per-vertex.
4. unity_4LightAtten0 – аттенюация этих источников света
5. unity_LightColor – цвет этих источников
Accessing built-in shader constants
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++;}
• 1X per-pixel directional light.
• 4X per-pixel point light.• All in one pass!
Result
Да, если Нет, если• Количество
динамических источников света и освещенных объектов мало.
• Требуется поддержка динамических теней от directional лайтов.
• Требуется поддержка лайтмапов из коробки.
• Количество динамических источников велико.
• Есть возможность обойтись Hardware Transform & Lighting.
• Требуется доступ к буферу глубины или view-нормалей.
Conclusion: Forward rendering
Deferred rendering overview
• Освещение рассчитывается как пост-процессинг, только для видимых фрагментов.
• Все освещение на сцене рендерится попиксельно.
• Легко получить depth и view normals для собственных манипуляций при пост-процессинге.
• Производительность сильно зависит от пропускной способности памяти видеокарты и способа реализации.
Forward approach
Deferred approach
Thousands of dynamic per-pixel lights
FORWARD• 20 objects * 50
lights = 1000 DIP
Deferred• 20 objects + 50
lights + 3 post pass = 73 DIP
Feel the difference!
Prepass: View normals & depth
Renders the scene into the RenderTexture
Lighting calculation: Rendering light footprints
Uses the RT from the previous pass
Final pass
Unfortunately, renders the scene one more time :(
Да, если Нет, если• Количество
динамических источников очень велико.
• Используется хотя бы один пост-эффект, работающих с глубиной сцены (SSAO, DOF, soft particles, point light shafts)
• Количество динамических источников невелико.
• Слабое железо или железо без поддержки рендеринга в текстуру.
• Много transparent объектов (alpha-test не считается).
Conclusion: Deferred rendering
Post processing
Попиксельная обработка отрендеренного изображения для получения необходимого эффекта:
• SSAO• Bloom• FXAA• Gamma correction• DOF• Outlines• … and many, many more!
Post processingСообщения:
• OnRenderImage() – вызывается после того, как все объекты на сцене были отрисованы в рендертекстуру.
• OnPreRender() – вызывается перед тем, как начнется рендеринг.
• OnPostRender() – вызывается после того как отрендерятся все объекты в текущем кадре.
• OnWillRenderObject() – вызывается перед рендерингом каждого видимого объекта.
Методы:• Graphics.DrawMesh() – сабмитит mesh на отрисовку.• Graphics.DrawMeshNow() – рисует mesh в текущем кадре.• Graphics.Blit() – копирует данные из рендертекстуры в
рендертекстуру
Post process example
High price of the Depth
• Camera.depthTextureMode = DepthTextureMode.Depth;
• UNITY_TRANSFER_DEPTH(), • UNITY_OUTPUT_DEPTH()
• В forward-пайплайне стоит одного дополнительного прохода рендера
• В deferred-пайплайне просто берется из G-буфера.
• К сожалению, формат данной презентации не позволяет уделить каждой реализации конвейера достаточного количество внимания.
• В погоне за универсальностью, рендер Unity нередко жертвует производительностью.
• Использование каждого из пайплайнов создает свои проблемы, но их можно устранить в рамках каждой конкретной задачи.
Conclusion
Спасибо за внимание!
inangwish
Special thanks to: <Dmitry Minsky> http://halfbus.co/