Greetings from the Shader team!
We heard your feedback regarding the need for SRP compatible surface shaders, as well as a better way to integrate with Unity’s Shader system, and have been hard at work to provide a meaningful solution which we are now happy to announce in the form of Block Shaders.
Block Shaders introduce a streamlined and modular text-based shader authoring workflow, and allow to override and extend the functionality of existing shaders, without the complexity of modifying the original shader source - in a similar fashion to BiRP Surface Shaders. In addition, Block Shaders also aim to help unify shader authoring across the render pipeline.
We are at an alpha stage of development and need to hear from you! To that end, we prepared a public prototype for you to experiment with and provide your valuable input as early as possible. In order to access the demo please refer to the demo’s Quickstart Guide.
Manifesting as a new shader asset type and syntax, Block Shaders can override and extend the functionality of shader “templates”, which will be provided by the Render Pipeline’s or created freely by users. For example, a Block Shader can override and extend a lit template’s vertex or surface descriptions:
BlockShader “MyShader” implements “LitTemplate” {
Blocks {
Block VertexBlock
{
Interface
{
inout float3 PositionOS;
inout float3 NormalOS;
[Property] in float _Deformation;
}
void apply(inout Interface self)
{
// HLSL goes here...
self.PositionOS += self.NormalOS * _Deformation;
}
}
Block SurfaceBlock
{
Interface
{
in float4 UV;
out float3 Albedo;
out float Metalness;
out float Roughness;
out float Alpha;
}
void apply(inout Interface self)
{
self.Albedo = float(1.0, 0.0, 0.0); // set albedo to red
self.Metalness = 0.0; // set metalness to non-metallic
self.Roughness = 0.5; // set roughness to semi-rough
self.Alpha = 1;
}
}
}
Implementation Vertex
{
VertexBlock;
}
Implementation Surface
{
SurfaceBlock;
}
}
Users are free to declare their own custom Blocks, and define their Block’s interfaces in order to freely pass data between Blocks. In the following example, an interpolator is passed between a Vertex and Surface Block in order to implement custom fog:
Block VertexBlock
{
Interface
{
inout float3 PositionOS;
out float FogIntensity;
}
void apply(inout Interface self)
{
float3 positionWS = TransformObjectToWorld(self.PositionOS);
float4 positionCS = TransformWorldToHClip(positionWS);
float2 pos = positionCS.xy / positionCS.w;
self.FogIntensity = min(1, dot(pos, pos) * 0.5);
}
}
Block SurfaceBlock
{
Interface
{
in float FogIntensity;
out float3 Color;
}
void apply(inout Interface self)
{
self.Color = lerp(self.Color, float3(1.0,1.0,1.0), self.FogIntensity);
}
}
Block Shaders can be created from available Block Templates which define the shader’s passes and stages. Templates are constructed using a collection of linked Blocks - shader functions with a set interface (akin to shader graph nodes) to be reused and shared as assets and libraries across shaders, projects and teams.
Templates also expose public Blocks called “Customization Points” along the shader’s flow of execution, which define the template’s public interface to be implemented and extended by Block Shaders, using any number of user defined Blocks.
By authoring Blocks, as well as utilizing existing Block libraries, users can override and extend shaders in a reusable and modular fashion:
For illustration purposes only
The Universal and High Definition Render Pipelines will both provide a library of Block Templates, corresponding to their existing shader libraries, to be overridden and extended by user authored Block Shaders. In addition to the familiar vertex or surface descriptions, templates could provide any number of customizations points, for use cases such as custom lighting functions or image-based lighting override:
Block DirectionalLightingBlock
{
Interface
{
in float3 Normal;
inout float3 Color;
}
void apply(inout Interface self)
{
self.Color *= saturate(dot(self.Normal, _MainLightPosition.xyz)) * _MainLightColor.rgb;
}
}
Block ImageBasedLightingBlock
{
Interface
{
inout float3 ReflectionWS;
[Property] UnityTextureCube _CubeMap;
out float3 IBL;
}
void apply(inout Interface self)
{
self.IBL = texCUBE(self._CubeMap, self.ReflectionWS).rgb;
}
}
In order to unify the shader authoring across pipelines, we are evaluating if URP and HDRP will provide templates under cross-pipeline Template Groups, which define a shared minimal interface. Users could then author Block Shaders that target a specific template group, in order to maintain compatibility with both pipelines, with HDRP potentially implementing more complex shading and utilizing more optional customization points compared to the URP equivalent.
Due to the generic nature of Block Shaders, they also allow streamlining the creation of any type of shader, depending on the templates created by both Unity and the community. For example, a developer or asset store creator could choose to create a volumetric ray marching template - and allow technical artists to customize their own cloud or smoke shaders in a simplified manner.
This new workflow is made possible by Shader Foundry API, a new intermediate layer and API which provides a C# representation of Block Shaders and Templates, and allows for better integration with Unity’s shader system. The Shader Foundry API will allow developers to programmatically create and configure Block Shader Templates, in order to integrate and maintain shaders and tools across pipelines and engine versions.
We hope to land Shader Foundry and Block Shaders as early as possible, including official URP and HDRP template support. We will continue to improve and extend Block Shaders, and provide support for additional features such as compute or raytracing shaders, so please share your feedback and any feature or functionality you would like to see - either directly in this thread or via the Block Shaders Survey.
You can follow our progress in the Shaders forum as well as in our public roadmap, and look forward to an announcement of when the Foundry is available in the public betas. We can’t wait to see what amazing shaders and block libraries you create using Block Shaders!