Feedback Wanted: Lightweight Render Pipeline

LWRP 4.0.0-preview is out

Upgrading to this version requires Unity 2018.3.0b3.

This version changes the light attenuation computation to be physically based. This change means that you don’t have to increase the range of your light to control the attenuation. Instead, you should control the attenuation with the light intensity. Baked GI has changed to match the realtime attenuation. When you upgrade to LWRP 4.0.0-preview, it is likely that you have to upgrade your light settings as well.

We are pushing work to have LWRP out of preview as soon as possible. Therefore for this version, we focused most of our time in API design to implement much feedback we received over the past months and evolve both our C# and shader API to be more easy to use, extensible and flexible.

This version introduces API breaking changes. Breaking changes are the reason we bumped the major version number. If you didn’t fork LWRP or authored custom shaders without using ShaderGraph, upgrading your shaders to this version requires some work. We apologize for the nuisance, but this is required so we can evolve. Once out of preview, there won’t be any more breaking changes.

Please check the changelog to help you upgrade shaders to version 4.0.0-preview and reach out in this thread with upgrading issues so we can help you.

If you authored custom shaders, please make sure you update the shader variants in your shader to match the new ones.

// -------------------------------------
// Lightweight Render Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE

These multi_compile keywords are stripped from the build depending on:

  • Settings in the LWRP asset that is assigned when you build your project, f.ex, if you disable Additional Lights in the asset, LWRP strips all related variants from the build.

  • LWRP strips invalid variant combinations. f.ex _MAIN_LIGHT_SHADOWS_CASCADE defined but not _MAIN_LIGHT_SHADOWS are invalid and therefore stripped

  • Unused passes. If you select in the asset you don’t support shadows then all shadow caster passes are stripped from the build. Same with meta pass that is only used for baking lightmaps.

I’ve updated the LWRP Physically Based shader example to 4.0.0-preview. You can use that as well to help you upgrade your shaders.

State of the Docs

Lack of documentation was one of the significant feedbacks we received, and we are putting much effort into writing them. We will layout them in phases soon. Meanwhile, use this post as a reference.

The LWRP Forward Renderer
LWRP cull lights per-object, and they are all shaded in a single pass. Compared to Built-in forward renderer, LWRP shades multiple lights with less overdraw and less draw calls.

LWRP (on the left) renders GI and all realtime lights in the same pass. Light attenuation is physically based. Built-in render pipeline (on the right) renders GI and a directional light in a base pass. Each additional light is rendered with an additional pass additively. Attenuation is not physically based and is affected by both light intensity and range. The image difference is purely because of the light attenuation difference.

Below are a couple of shots from Angry Bots 2 comparing Built-in render pipeline and LWRP. This shot was taken in package 3.3.0-preview when light attenuation was the same so they are pretty close to each other. This scene has a shadow-casting directional light + 2 point light and 2 shadow-casting spot lights.

Compared to Built-in, LWRP renders that specific frame with about half as many draw calls.
If you are unsure of what Batches and SetPass calls mean in that image, check this guide.

This is how LWRP shades a scene. It chooses the brightest directional light as the Main Light. This light is shaded outside the light loop in the shader and it has a dedicated set of shader variables/shading path in order to shade it as fast as possible. This makes possible to scale rendering up for multiple lights without adding shading overhead to games supporting a single directional light.

Shading of additional lights happens in a loop. We want to avoid branching on light-type, and we cannot classify them in a forward renderer. We perform a generic shading function that works for directional, point and spot light types.

There’s a current issue with Graphics Emulation that prevents LWRP to store a large amount of lighting data efficiently. This issue limits the number of lights LWRP can shade. There is currently a limit of 1 main light + 4 additional lights per-object. Also, if you have more than 16 lights visible by the camera, LWRP omits some of them. Once we fix the Graphics Emulation issue, these limits will only impact GLES2.0 and GLES3.0

We have also updated the LWRP asset to make it more clear and easily configurable. It’s very important to check the settings in the LWRP asset because it controls quality and passes in your rendering. Configure the asset to support only the least features your game requires for better performance.

What about other rendering approaches?

It’s on our roadmap to support a mobile-friendly deferred renderer based on this approach. Currently, if you want to use a different shading strategy than standard forward rendering you can override the LWRP render pipeline to do so.

We provide ScriptableRenderPass class that you can use to create custom-render passes and inject that in LWRP. There are two ways of injecting custom render passes in LWRP. You can inject them at specific points in the default renderer. Take a look at the LWRP default renderer to see some injection points. Boat Attack uses that to render special water effects. Alternatively, you can completely override the LWRP renderer by implementing your own IRendererSetup. A renderer setup is a script that can be attached to a camera and it executes all ScriptableRenderPasses registered in it. You can use this to implement a Forward+ renderer with compute in LWRP for instance.

VR and Lightweight Render Pipeline

There are currently some issues with MSAA and PostProcessing in VR. There’s also a current issue with Daydream devices. Although they support multi-view, Google blacklisted multi-view on these devices due to driver issues. There was no other strategy to fall back in SRP because Multi View is deprecated. The effect is that they render black.

We added single pass double wide as the fallback to SRP in 2019.1, and we might backport it to 2018.3.

Built-in Shaders
All unlit shaders from built-in render pipeline work with LWRP. Because the lighting strategy is different, the built-in lit shaders don’t work with LWRP. We provide a new set of lit shader with LWRP. These shaders are distributed along with the LWRP package. When LWRP package is installed you can see them by going in Unity to your project window under the folder Packages/Lightweight RP/Shaders or you can check them in Github. LWRP provides Lit, SimpleLit, and Unlit shaders that cover most of the Unity built-in render pipeline shaders.

We provide a Material Upgrader utility that upgrades Built-in shader to LWRP. It’s in the Unity toolbar at Edit → Render Pipeline → Upgrade project materials to Lightweight RP materials.

Custom Shaders

If you are writing custom shaders we recommend using our new Core RP shader library. This is a modern library written in hlsl. LWRP further extends the Core SRP shader library with additional functions specific for it. You get the Core RP and LWRP shader libraries installed on your computer when you install these packages. They can be located in Packages/Core RP Library/ShaderLibrary and Packages/Lightweight RP/ShaderLibrary. Alternatively you can also check their source in Github: CoreRP, LWRP

The most important things when writing custom shaders are:

  • Make sure you add the multi_compile pragmas as in this shader example. If you want to remove some of them because of shader compiler variants you can disable settings in the pipeline asset instead and the keywords will be stripped.

  • Include “Packages/com.unity.render-pipelines.lightweight/Core.hlsl” in all your shaders. This will include shader variables and most utility functions you need. Think of it as legacy UnityCG.cginc.

  • If you are doing lit shaders include “Packages.com.unity.render-pipelines.lightweight/Lighting.hlsl”. This will include, GI, Lighting, IBL and shadow functions.

  • Material shader properties are not defined in Core shader library or LWRP shader library. This means _Color, _MainTex, _MainTex_ST, and all variables in the Properties section of a shader must be defined by the shader itself. If you define all those properties in a CBUFFER names UnityPerMaterial, SRP can cache the material properties between frames and reduce significantly the cost of each draw call. Each of LWRP shaders define theirs constants in a *Input.hlsl. You can check LitInput.hlsl for an example.

  • Invest some time learning the new shader library. Docs are not done yet but all the source code is there. You can check LWRP shaders for reference.

All built-in shader variables described in this page except Lighting variables work with LWRP.

Don’t reference LWRP lighting shader variables in your shader. Instead we provide two functions to initialize a Light struct that has all lighting information you need for shading a light. These are GetMainLight, and GetAdditionalLight and they are defined in Lighting.hlsl

Light struct is defined as follow:

struct Light
{
half3 direction;
half3 color;
half distanceAttenuation;
half shadowAttenuation;
};

If you have any feedback on the shader API we would be glad to know. This is the chance to help shape the API to better suit your usage. We want to provide an easy to use and flexible API.

Performance
We are benchmarking LWRP and Built-in on several mobile devices and a few test projects. The process very slow given the amount of architecture fragmentation for platforms we support. Optimizing for a GLES2 capable device is completely different work than doing for a Vulkan one, and yet more different than PC and consoles.

We just found out that there was a performance regression on some android devices between 2.X and 3.X. We are yet about to re-run our tests in 4.X version.

We want to make sure to fix this performance regression before sharing a detailed data with benchmarking. Overall, compared to built-in you should expect at this point:

  • PC, Consoles, Mobile (Vulkan and Metal), and VR

  • Slightly better performance with a single directional light.

  • Considerable better performance with multiple lights. We are investigating some issues with performance on some devices next week.

  • Mobile (GLES3+)

  • About same performance with a single directional light.

  • Some devices have better and some worse performance. We are investigating this issue as well and figuring out perf regressions.

  • Mobile (GLES2)

  • About same performance with a single directional light

  • Worse performance issues depending on the scene with multiple lights. GLES2 enforce support in their specs for dynamic indexing in pixel shaders. Most mobile GPU manufacturers support it though. We are working with them to figure out which GPUs we can patch our shaders to support dynamic indexing. This is more likely to only land in 19.1. So, if you are in GLES2 and LWRP it’s ideal to fallback to either single directional light or shading additional lights per-vertex.

The matrix of different architectures and different games rendering styles makes it really hard to cover all performance cases. It’s extremely important to have your help in this. If you are using LWRP and have worse performance compared to built-in render pipeline, please open a bug report with your test scene, LWRP version and the device you tested. We will figure out what is happening and improve it.

When comparing performance between LWRP and Built-in renderer please make sure:

  • Built-in is set to forward renderer as it is the only renderer we support for now

  • Make sure the Quality Settings in Built-in match LWRP. Quality Settings in LWRP are configured in the LWRP asset.

  • If you using a Android 7.0 or above capable device make sure to check Sustained Performance mode in Player Settings.

  • If you are on a mobile device that does not support Sustained Performance mode make sure you give some minutes for the device to cool down between profiling sessions. This happens because mobile GPUs have passive cooling system. When they overheat the CPU and GPU clocks down to cool down and this impacts severely performance.

Current Limitations

  • Currently only one directional light is supported. We’ll add support to shade additional directional lights in the light loop. This is coming soon.

  • Light culling layer for the main directional light is not yet implemented. Main light is not culled per-object and there’s currently no efficient way to implement this in a single pass renderer for all platforms. We are working on changes to engine to allow support for efficiently doing this. This is most likely coming only in 19.1.

  • Due to issues with Graphics Emulation we are limiting shading to 1 main light + 4 additional lights per-object. Also, there’s a limit to at most 16 visible lights globally. This limit will be removed once we fix the Graphics Emulation issue. This way we can store light data in StructuredBuffers for platforms that support it. We are investigating a workaround for the issue for 18.3. Otherwise it will only be fixed in 19.1

  • There’s currently no built-in support for postfx AO. A user has added support to MSVO in LWRP

  • Motion Vectors and Camera Normals are not supported yet. This makes some post effects not supported in LWRP.

  • Speed Tree shaders are not yet ported to LWRP.

  • Particles shaders are not yet fully ported to LWRP.

  • LPPV, Mixed Lighting Mode, Occlusion Probes are not supported. This is most likely only coming in 19.2

  • Point light shadows are not supported. This is most likely only coming in 19.2

  • Camera Relative rendering is not supported. This is most likely only coming in 19.3

  • Box Projection and Reflection Probe blending is not supported. This is most likely coming in 19.3.

  • Detail maps and parallax is not supported in the built-in LWRP shaders yet.

  • Realtime GI is not supported.

That’s it. Please let us know of any issues you have.

15 Likes

Thanks for explanation, it is very useful. The same post for the state of hdrp 4.0.0 will be great.

Release notes are here:
https://docs.unity3d.com/Packages/com.unity.render-pipelines.lightweight@4.0/changelog/CHANGELOG.html

2 Likes

Hi, thanks for the hard work on this- really exciting update. Currently lack of motion blur support is the only factor limiting me from moving to the LWRP, does the ‘yet’ imply the feature is on the roadmap?

2 Likes

I’m so excited about this update. My current VR game under development is making use of the LWRP. I’m really loving the quality and high performance with the LWRP. I’m hitting 90 FPS with 73+% headroom on the Rift and the Go compile is getting a solid 60 FPS. I just wished Oculus would jump on board and update their Avatars to be compatible with the LWRP. I’ve had to use Shader Graph to make new shaders for the avatar. For now I’m ok with it and not letting this hold me up. I really enjoyed the talk by Tony Parisi and Brad Weiers at Oculus Connect 5! So glad I made it to their talk.

1 Like

Please write some sort of reference or tutorial on how to modify/customize the LWRP. I did some tests in really early LWRP releases and I was able to figure stuff out, more or less. But in more recent versions I am more or less lost, since it seems the complexity of the set-up has gone up quite a bit (or I’m simply missing some piece of understanding that will make everything click).

My intent is to take the final LWRP and make my custom one, removing all features we don’t use (which is most of them :stuck_out_tongue: ). But at this point, it seems so complicated, I might be better off writing one from scratch.

2 Likes

Can you fix this unlit example too?

2 Likes

-When will it be available via the package manager?

-Once camera relative rendering works in the LW SRP, do I need to change my unlit shader code?

-Also, can you make a MixFog() version which supports half4 colors, so I don’t have to do a conversion?

Currently:

half4 col = //compute the color using a texture with alpha channel (unlit transparent object).

//Conversion
half3 color = col.xyz

MixFog(color, fogFactor);

return half4(color, col.w);
1 Like

So MSAA is still a no-go for VR in LWRP?

It’s on our roadmap but we don’t have an idea yet when it’s coming.

1 Like

I have one that’s for an older version. I’ll polish it up and update for 4.0.0-preview.

What features you want to removed? You can disable a lot of features in the LWRP asset and the pipeline will be smart enough to strip down the cost of them. Let me know if there’s something you want to strip that’s not covered there.

2 Likes

It’s updated now.

It’s already available. Are you having issues seeing it?

It will be transparent as long as you don’t reference matrix variables directly. Instead these functions and MACROS for matrices and space transforms. https://github.com/Unity-Technologies/ScriptableRenderPipeline/blob/master/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl

There was an issue fixed related to MSAA in 4.0.0-preview. I’m not sure if all issues were related to this. I’ll check. Meanwhile I encourage to try and let me know if you have issues with it.

Any ETA for the PostProccessing + VR?

1 Like

Thanks for the response @phil_lira - does the mixed lighting mode that might make it in 19.2 include distance shadowmasks?

We use all custom CG vert/frag shaders, baked lightmaps, light probes and our own post processing. No actual realtime lighting at all, no reflection probes (we do our own cubemaps). Performance is actually okay with our setup, but I can’t help feeling like the CPU side could be much cleaner, which is why I have an interest in using SRP.

But I kinda feel like what I’m trying to do is so removed from LWRP, I might as well write my own. But I currently lack the know-how to do one from scratch.

With all that said, I haven’t had too much time spent with new SRP stuff, so I’ll probably have more specific questions/suggestions when I find the time to play with them more.

I see it tonight (Saturday Sept 29th at 7:09 PM Eastern). It was not up on Friday at 11 pm Eastern. I kept trying. Interestingly I observed the top most LWRP version go from 3.3.0 to 3.0.0 So maybe some changes were still taking place in the background. But I got 4.0.0 tonight. I’m off to go work with it and Unity 2018.3.0b3.

Still cant see it in Package Manager, it only lists 3.0.0 as latest. Im using 2018.2.10f1

LWRP 4.0.0 requires Unity 2018.3.0b3. Make a backup of your project. Download and update it to 2018.3.0b3. Or just create a new project in 2018.3.0b3 and try it out.

Package Manager looks a bit different now in 2018.3.0b3. It used to have two tabs: In Project, and All.
Now its one tab, Packages with some drop down options. So make sure you select “All packages” (default)
in the drop down.

Edit 10/3/18: Well it looks like my work around broke with Oculus Integration 1.29. The only Shader Graph shader that is getting displayed is the base. The hands, body and head are back to being pink. At this point I’m just going to wait till Oculus comes out with a LWRP compatible local and remote avatars.

Thanks!