WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
Customizing a production pipeline
1. GenerativeArt–MadewithUnity
Customizing a Production Pipeline
(Lightweight Render Pipeline)
Felipe Lira
Graphics Programmer
Unity Technologies
1
Note: If you are using a laptop download Unity 2018.2
and the following project: bit.ly/siggraph18
2. 2
Workshop Pre-requisites
●If you are on a SIGGRAPH computer
○ Start Unity and open SIGGRAPH2018-WORKSHOP
project in your Desktop
●If you are on your own computer
○ Download Unity 2018.2
○ Download the following project bit.ly/siggraph18
○ Start Unity and open the project you downloaded
●Slides: bit.ly/siggraph18_slides
3. 3
Workshop Agenda
●What is the Lightweight Render Pipeline (LWRP)
●Add LWRP to your project
●Convert a project to use LWRP
●Overview of LWRP rendering
●Customize LWRP renderer by adding custom passes
●Override LWRP renderer to implement a deferred renderer
4. 4
What is Lightweight Render Pipeline (LWRP)
●It’s a Scriptable Render Pipeline (SRP)
○ Rendering API exposed in C#
○ Open Source: https://github.com/Unity-Technologies/ScriptableRenderPipeline
●LWRP
○ Currently 1 of 2 of our inhouse Render Pipelines we are developing
○ Designed from the ground up to perform at best on mobile hardware
○ Modern APIs in mind, as well as Legacy APIs, eg GLES 2.0
5. 5
Why should you care about SRP and LWRP
●If you are
○ Student:
■ Learn Graphics Programming with a robust API
○ Game Developer:
■ Performance out of the box, explicit, lean and extensible
○ Researchers:
■ Implement, deploy and profile your research many platforms
23. 23
public void Setup(ScriptableRenderer renderer, … , RenderingData renderingData)
{
if (renderingData.shadowData.renderShadows)
renderer.Enqueue(m_ShadowPass);
bool requiresDepthPrepass = RequireDepthPrepass(renderingData.cameraData.requiresDepthTexture);
if (requiresDepthPrepass)
renderer.Enqueue(m_DepthPrepass);
renderer.Enqueue(m_SetupLightConstants);
renderer.Enqueue(m_RenderOpaquesForwardPass);
foreach (var pass in camera.GetComponents<IAfterOpaquePass>())
renderer.EnqueuePass(pass.GetPassToEnqueue(baseDescriptor, colorHandle, depthHandle));
if (camera.clearFlags == CameraClearFlags.Skybox)
renderer.Enqueue(m_RenderSkyboxPass);
renderer.Enqueue(m_RenderTransparentsPass);
if (renderingData.cameraData.postProcessEnabled)
renderer.Enqueue(m_PostProcessPass);
}
24. 24
public void Setup(ScriptableRenderer renderer, … , RenderingData renderingData)
{
if (renderingData.shadowData.renderShadows)
renderer.Enqueue(m_ShadowPass);
bool requiresDepthPrepass = RequireDepthPrepass(renderingData.cameraData.requiresDepthTexture);
if (requiresDepthPrepass)
renderer.Enqueue(m_DepthPrepass);
renderer.Enqueue(m_SetupLightConstants);
renderer.Enqueue(m_RenderOpaquesForwardPass);
foreach (var pass in camera.GetComponents<IAfterOpaquePass>())
renderer.EnqueuePass(pass.GetPassToEnqueue(baseDescriptor, colorHandle, depthHandle));
if (camera.clearFlags == CameraClearFlags.Skybox)
renderer.Enqueue(m_RenderSkyboxPass);
renderer.Enqueue(m_RenderTransparentsPass);
if (renderingData.cameraData.postProcessEnabled)
renderer.Enqueue(m_PostProcessPass);
}
● Enqueue render passes
based on received data
● ScriptableRenderPass is a
building block to a render
pipeline
25. 25
public void Setup(ScriptableRenderer renderer, … , RenderingData renderingData)
{
if (renderingData.shadowData.renderShadows)
renderer.Enqueue(m_ShadowPass);
bool requiresDepthPrepass = RequireDepthPrepass(renderingData.cameraData.requiresDepthTexture);
if (requiresDepthPrepass)
renderer.Enqueue(m_DepthPrepass);
renderer.Enqueue(m_SetupLightConstants);
renderer.Enqueue(m_RenderOpaquesForwardPass);
foreach (var pass in camera.GetComponents<IAfterOpaquePass>())
renderer.EnqueuePass(pass.GetPassToEnqueue(baseDescriptor, colorHandle, depthHandle));
if (camera.clearFlags == CameraClearFlags.Skybox)
renderer.Enqueue(m_RenderSkyboxPass);
renderer.Enqueue(m_RenderTransparentsPass);
if (renderingData.cameraData.postProcessEnabled)
renderer.Enqueue(m_PostProcessPass);
}
● Camera can contain scripts
that inject passes at specific
points in the pipeline
● IAfterOpaque is just one of
the many injecting points
26. 26
Quick Recap
●LWRP do every frame
1.Culling
2.Setup per frame and per camera data
3.IRendererSetup enqueue multiple ScriptableRenderPass
a.A custom ScriptableRenderPass can be added at many
hook points
b.The default renderer can be even completely overridden
4.Renderer execute all enqueued passes
27. 27
Adding a custom pass in LWRP
● Let’s switch to coding!
● We will:
○ Create a custom ScriptableRenderPass (MyNyanCatPass)
○ Inject the MyNyanCatPass after rendering opaques
(IAfterOpaque)
28. 28
Now it’s your time to code!
● What if I get lost?
○ Call for help!
○ Use AddPassAfterOpaqueCompleted.cs in your project as
reference
30. 30
Customizing the render pipeline
● How about we complete override the renderer now?!
● But first let’s review how to do a mobile deferred renderer
31. Tiled GPU rendering review
●Splits rendering into tiles
31
Textures Framebuffer
Main Memory
Fragment Shader Tile Memory
Geometry
Data
GPU
32. Tiled GPU rendering review
●Splits rendering into tiles
●For each tile
○ Tile LOAD Action
32
Textures
Main Memory
Geometry
Data
GPU
Fragment Shader Tile Memory
Framebuffer
33. Tiled GPU rendering review
●Splits rendering into tiles
●For each tile
○ Tile LOAD Action
○ Rendering
33
Textures
Main Memory
Geometry
Data
GPU
Fragment Shader Tile Memory
Framebuffer
34. Tiled GPU rendering review
●Splits rendering into tiles
●For each tile
○ Tile LOAD Action
○ Rendering
○ Tile STORE Action
34
Textures
Main Memory
Geometry
Data
GPU
Fragment Shader Tile Memory
Framebuffer
35. Tiled GPU rendering review
●Splits rendering into tiles
●For each tile
○ Tile LOAD Action
○ Rendering
○ Tile STORE Action
35
Textures
Main Memory
Geometry
Data
GPU
Fragment Shader Tile Memory
Framebuffer
36. Tiled GPU rendering review
●Splits rendering into tiles
●For each tile
○ Tile LOAD Action
○ Rendering
○ Tile STORE Action
36
Textures
Main Memory
Geometry
Data
GPU
Fragment Shader Tile Memory
Framebuffer
37. Traditional Deferred Rendering
●GBuffer pass
○ Allocate Images
○ Setup Framebuffer (MRT)
○ Render to MRT
○ Write tiles to main memory
Textures Framebuffer
Main Memory
GPU
Fragment Shader Tile Memory
Geometry
Data
Diffuse Specular +
Rougness
Normals LightAccum
(GI + Emissive)
Depth
38. Traditional Deferred Rendering
●Lighting pass
○ SetFramebuffer (LightAccum)
○ Load tiles from main memory
○ Read Input Textures from main memory
○ Render to LightAccumulation
○ Write tiles to main memory
Textures Framebuffer
Main Memory
GPU
Fragment Shader Tile Memory
Geometry
Data
Diffuse Specular Normals Light
Accumulation
Depth
39. 39
Rendering Efficiently on Mobile
●Minimize external memory read and writes
●Render Pass allows Tiled GPU interleaved rendering
○ Vulkan Multipass Mobile Deferred Done Right (Arntzen, GDC 2017)
Tile #0
Render GBuffer
Tile #0
Render Lighting
Tile #1
Render GBuffer
Tile #1
Render Lighting
Interleaved Rendering
40. 40
Rendering Efficiently on Mobile
●RenderPass API
○ Vulkan: Transient Buffers
○ Metal: Framebuffer Fetch
○ Emulated on all other rendering backends
41. 41
Mobile Deferred Renderer
● We will create a combined GBufferAndLighting renderpass
● For simplicity we will only support directional lights now
● It can easily be extended to support puntual lights
● Create an IRendererSetup
● Enqueue our render pass
● Add IRendererSetup to our camera
42. 42
Now it’s your time to code!
● What if I get lost?
○ Call for help!
○ Use MyDeferredRendererCompleted.cs in your project as
reference
43. 43
Before you leave!
1.Please rate this session in your SIGGRAPH app!
2.Save this link: bit.ly/siggraph18
3.We will have another awesome workshop on ShaderGraph!
a.Creating a Custom Production Ready Pipeline.
b.Same place, same hour!
4.We need to clear the booth for the next workshop.
5.Meet me outside for questions