HLSLPROGRAM
Content | Built-in | URP |
---|---|---|
Core | Unity.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl |
Light | AutoLight.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl |
Shadows | AutoLight.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl |
Surface shaders | Lighting.cginc | None, but you can find a side project for this here |
Other useful includes:
Built-in | URP |
---|---|
ForwardBase | UniversalForward |
ForwardAdd | Gone |
Deferred and related | UniversalGBuffer seems to have just been added to URP |
Vertex and related | Gone |
ShadowCaster | ShadowCaster |
MotionVectors | Not suppoted yet |
The other light modes supported are:
URP support some variants, so depending on the things you are using, you might need to add some #pragma multi_compile
for some of the following keywords:
_MAIN_LIGHT_SHADOWS
_MAIN_LIGHT_SHADOWS_CASCADE
_ADDITIONAL_LIGHTS_VERTEX
_ADDITIONAL_LIGHTS
_ADDITIONAL_LIGHT_SHADOWS
_SHADOWS_SOFT
_MIXED_LIGHTING_SUBTRACTIVE
Built-in | URP |
---|---|
UNITY_PROJ_COORD(a) | Gone. Do a.xy/a.w instead |
UNITY_INITIALIZE_OUTPUT(type, name) | ZERO_INITIALIZE(type, name) |
You must include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”.
Built-in | URP |
---|---|
UNITY_DECLARE_SHADOWMAP(tex) | TEXTURE2D_SHADOW_PARAM(textureName, samplerName) |
UNITY_SAMPLE_SHADOW(tex, uv) | SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord3) |
UNITY_SAMPLE_SHADOW_PROJ(tex, uv) | SAMPLE_TEXTURE2D_SHADOW(textureName, samplerName, coord4.xyz/coord4.w) |
Unity has a bunch of texture/sampler macros to improve cross compatibility between APIs, but people are not used to use them. Those still exist in URP, but now with different names and new additions. I will not put all of them here because it’s a lot, but you can check their definitions per platform in the API includes.
Built-in | URP |
---|---|
UNITY_DECLARE_TEX2D(name) | TEXTURE2D(textureName); SAMPLER(samplerName); |
UNITY_DECLARE_TEX2D_NOSAMPLER(name) | TEXTURE2D(textureName); |
UNITY_DECLARE_TEX2DARRAY(name) | TEXTURE2D_ARRAY(textureName); SAMPLER(samplerName); |
UNITY_SAMPLE_TEX2D(name, uv) | SAMPLE_TEXTURE2D(textureName, samplerName, coord2) |
UNITY_SAMPLE_TEX2D_SAMPLER(name, samplername, uv) | SAMPLE_TEXTURE2D(textureName, samplerName, coord2) |
UNITY_SAMPLE_TEX2DARRAY(name, uv) | SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index) |
UNITY_SAMPLE_TEX2DARRAY_LOD(name, uv, lod) | SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) |
Important to note that SCREENSPACE_TEXTURE
has become TEXTURE2D_X
. If you are working on some screen space effect for VR in Single Pass Instanced or Multi-view modes, you must declare the textures used with TEXTURE2D_X
. This macro will handle for you the correct texture (array or not) declaration. You also have to sample the textures using SAMPLE_TEXTURE2D_X
and use UnityStereoTransformScreenSpaceTex
for the uv.
You can find them all in “Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl”.
Built-in | URP |
---|---|
float4 UnityObjectToClipPos(float3 pos) | float4 TransformObjectToHClip(float3 positionOS) |
float3 UnityObjectToViewPos(float3 pos) | TransformWorldToView(TransformObjectToWorld(positionOS)) |
Built-in | URP | |
---|---|---|
float3 WorldSpaceViewDir (float4 v) | float3 GetWorldSpaceViewDir(float3 positionWS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl” |
float3 ObjSpaceViewDir (float4 v) | Gone. Do TransformWorldToObject(GetCameraPositionWS()) - objectSpacePosition; | |
float2 ParallaxOffset (half h, half height, half3 viewDir) | Gone? Copy from UnityCG.cginc | |
fixed Luminance (fixed3 c) | real Luminance(real3 linearRgb) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl” |
fixed3 DecodeLightmap (fixed4 color) | real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl” decodeInstructions is used as half4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h) by URP |
float4 EncodeFloatRGBA (float v) | Gone? Copy from UnityCG.cginc | |
float DecodeFloatRGBA (float4 enc) | Gone? Copy from UnityCG.cginc | |
float2 EncodeFloatRG (float v) | Gone? Copy from UnityCG.cginc | |
float DecodeFloatRG (float2 enc) | Gone? Copy from UnityCG.cginc | |
float2 EncodeViewNormalStereo (float3 n) | Gone? Copy from UnityCG.cginc | |
float3 DecodeViewNormalStereo (float4 enc4) | Gone? Copy from UnityCG.cginc |
Built-in | URP | |
---|---|---|
float3 WorldSpaceLightDir (float4 v) | _MainLightPosition.xyz - TransformObjectToWorld(objectSpacePosition) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
float3 ObjSpaceLightDir (float4 v) | TransformWorldToObject(_MainLightPosition.xyz) - objectSpacePosition | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
float3 Shade4PointLights (…) | Gone. You can try to use half3 VertexLighting(float3 positionWS, half3 normalWS) | For VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
Built-in | URP | |
---|---|---|
float4 ComputeScreenPos (float4 clipPos) | float4 ComputeScreenPos(float4 positionCS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl” |
float4 ComputeGrabScreenPos (float4 clipPos) | Gone. |
Built-in | URP | |
---|---|---|
float3 ShadeVertexLights (float4 vertex, float3 normal) | Gone. You can try to use UNITY_LIGHTMODEL_AMBIENT.xyz + VertexLighting(...) | For VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
A bunch of utilities can be found in “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl”.
Most of the shader variables remains the same, except by lighting.
Built-in | URP | |
---|---|---|
_LightColor0 | _MainLightColor | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
_WorldSpaceLightPos0 | _MainLightPosition | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
_LightMatrix0 | Gone ? Cookies are not supported yet | |
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0 | In URP, additional lights are stored in an array/buffer (depending on platform). Retrieve light information using Light GetAdditionalLight(uint i, float3 positionWS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
unity_4LightAtten0 | In URP, additional lights are stored in an array/buffer (depending on platform). Retrieve light information using Light GetAdditionalLight(uint i, float3 positionWS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
unity_LightColor | In URP, additional lights are stored in an array/buffer (depending on platform). Retrieve light information using Light GetAdditionalLight(uint i, float3 positionWS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
unity_WorldToShadow | float4x4 _MainLightWorldToShadow[MAX_SHADOW_CASCADES + 1] or _AdditionalLightsWorldToShadow[MAX_VISIBLE_LIGHTS] | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl” |
If you want to loop over all additional lights using GetAdditionalLight(...)
, you can query the additional lights count by using GetAdditionalLightsCount()
.
For more info about shadows, check “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”.
Built-in | URP | |
---|---|---|
UNITY_SHADOW_COORDS(x) | Gone? DIY, e.g. float4 shadowCoord : TEXCOORD0; | |
TRANSFER_SHADOW(a) | a.shadowCoord = TransformWorldToShadowCoord(worldSpacePosition) | With cascades on, do this on fragment to avoid visual artifacts |
SHADOWS_SCREEN | Gone. Not supported. |
For more info about fog, check “Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl”.
Built-in | URP |
---|---|
UNITY_FOG_COORDS(x) | Gone? DIY, e.g. float fogCoord : TEXCOORD0; |
UNITY_TRANSFER_FOG(o, outpos) | o.fogCoord = ComputeFogFactor(clipSpacePosition.z); |
UNITY_APPLY_FOG(coord, col) | color = MixFog(color, i.fogCoord); |
To use the camera depth texture, include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl” and the _CameraDepthTexture
will be declared for you as well as helper the functions SampleSceneDepth(...)
and LoadSceneDepth(...)
.
Built-in | URP | |
---|---|---|
LinearEyeDepth(sceneZ) | LinearEyeDepth(sceneZ, _ZBufferParams) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl” |
Linear01Depth(sceneZ) | Linear01Depth(sceneZ, _ZBufferParams) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl” |
Built-in | URP | |
---|---|---|
ShadeSH9(normal) | SampleSH(normal) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
unity_ColorSpaceLuminance | Gone. Use Luminance() | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl” |
URP does not support OnPreCull
, OnPreRender
, OnPostRender
and OnRenderImage
. It does support OnRenderObject
and OnWillRenderObject
, but you might find issues depending on what you want to do. So, If you used to use those when creating your visual effects, I recommend learning how to use the new approaches available. The RenderPipelineManager
provides the following injection points in the pipeline:
beginCameraRendering(ScriptableRenderContext context, Camera camera)
endCameraRendering(ScriptableRenderContext context, Camera camera)
beginFrameRendering(ScriptableRenderContext context,Camera[] cameras)
endFrameRendering(ScriptableRenderContext context,Camera[] cameras)
Example of usage:
void OnEnable()
{
RenderPipelineManager.beginCameraRendering += MyCameraRendering;
}
void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= MyCameraRendering;
}
void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
...
if(camera == myEffectCamera)
{
...
}
...
}
Like I said, OnWillRenderObject
is supported, however if you need to perform a render call inside of it (e.g. water reflection/refraction), it will not work. As soon as you call Camera.Render()
, you will see the following message:
Recursive rendering is not supported in SRP (are you calling Camera.Render from within a render pipeline?)
In this case, replace the OnWillRenderObject
by begin/endCameraRendering
(like the example above) and call RenderSingleCamera()
from URP instead of Camera.Render()
. Changing the example above, you would have something like
void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
...
if(camera == myEffectCamera)
{
...
UniversalRenderPipeline.RenderSingleCamera(context, camera);
}
...
}
The other approach to work with Post-processing is to use a ScriptableRendererFeature
. This post has a great explanation of an outline effect using this feature. A ScriptableRendererFeature
allows you to inject ScriptableRenderPass(es)
at different stages of the pipeline, thus being a powerful tool for creating post-processing effects. The injection places are the following:
BeforeRendering
BeforeRenderingShadows
AfterRenderingShadows
BeforeRenderingPrepasses
AfterRenderingPrePasses
BeforeRenderingOpaques
AfterRenderingOpaques
BeforeRenderingSkybox
AfterRenderingSkybox
BeforeRenderingTransparents
AfterRenderingTransparents
BeforeRenderingPostProcessing
AfterRenderingPostProcessing
AfterRendering
This is a simple example of a ScriptableRendererFeature
performing a blit with a custom material:
public class CustomRenderPassFeature : ScriptableRendererFeature
{
class CustomRenderPass : ScriptableRenderPass
{
CustomRPSettings _CustomRPSettings;
RenderTargetHandle _TemporaryColorTexture;
private RenderTargetIdentifier _Source;
private RenderTargetHandle _Destination;
public CustomRenderPass(CustomRPSettings settings)
{
_CustomRPSettings = settings;
}
public void Setup(RenderTargetIdentifier source, RenderTargetHandle destination)
{
_Source = source;
_Destination = destination;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
_TemporaryColorTexture.Init("_TemporaryColorTexture");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get("My Pass");
if (_Destination == RenderTargetHandle.CameraTarget)
{
cmd.GetTemporaryRT(_TemporaryColorTexture.id, renderingData.cameraData.cameraTargetDescriptor, FilterMode.Point);
cmd.Blit(_Source, _TemporaryColorTexture.Identifier());
cmd.Blit(_TemporaryColorTexture.Identifier(), _Source, _CustomRPSettings.m_Material);
}
else
{
cmd.Blit(_Source, _Destination.Identifier(), _CustomRPSettings.m_Material, 0);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void FrameCleanup(CommandBuffer cmd)
{
if (_Destination == RenderTargetHandle.CameraTarget)
{
cmd.ReleaseTemporaryRT(_TemporaryColorTexture.id);
}
}
}
[System.Serializable]
public class CustomRPSettings
{
public Material m_Material;
}
public CustomRPSettings m_CustomRPSettings = new CustomRPSettings();
CustomRenderPass _ScriptablePass;
public override void Create()
{
_ScriptablePass = new CustomRenderPass(m_CustomRPSettings);
_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
_ScriptablePass.Setup(renderer.cameraColorTarget, RenderTargetHandle.CameraTarget);
renderer.EnqueuePass(_ScriptablePass);
}
}
You can create a ScriptableRendererFeature
by clicking on “Create > Rendering > Universal Render Pipeline > Renderer Feature”. The feature that you have created has to be added to your ForwardRenderer
. To do so, select the ForwardRenderer
, click on “Add Renderer Feature” and select the feature to be added. You can expose properties in the feature inspector, for example, if you add the example above, you will see a material slot available.
That’s it for now. I will try to keep this updated (narrator: he won’t) according to the new things I’m learning or new features that I see added. If you have comments or suggestions, you can find me on twitter.
Unity’s Scriptable Render Pipeline represents a great advance on the way that unity deals with graphics, giving more power to the users to customize the pipeline the way they want....
Read MoreContinuing the posts of stuff that I should have posted last year but for some reason didn’t. Here, some (not deep) thoughts on Cook-Torrance and lookup textures.
Read More