Skip to content

Instantly share code, notes, and snippets.

@ArieLeo
Forked from shivaduke28/URP_Normal.shader
Created April 27, 2023 08:47
Show Gist options
  • Save ArieLeo/889e306d8cc68dd33ed0e199b276abb9 to your computer and use it in GitHub Desktop.
Save ArieLeo/889e306d8cc68dd33ed0e199b276abb9 to your computer and use it in GitHub Desktop.
simple URP Lit shaders for learning
Shader "MyShader/URP_Normal"
{
Properties
{
[Header(Base Color)]
[MainTexture]_BaseMap("_BaseMap (Albedo)", 2D) = "white" {}
[HDR][MainColor]_BaseColor("_BaseColor", Color) = (1,1,1,1)
[Header(Normal)]
[MainTexture]_NormalMap("_NormalMap", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Lit"
"Queue"="Geometry"
}
Pass
{
Name "ForwardLit"
Tags
{
"LightMode"="UniversalForward"
}
HLSLPROGRAM
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float3 positionOS : POSITION;
half3 normalOS : NORMAL;
half4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 positionWSAndFogFactor : TEXCOORD1; // xyz: positionWS, w: vertex fog factor
half3 normalWS : TEXCOORD2;
float4 positionCS : SV_POSITION;
float3 lightTS : TEXCOORD3; // light Direction in tangent space
};
sampler2D _BaseMap;
sampler2D _NormalMap;
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _NormalMap_ST;
CBUFFER_END
/* MEMO
from Core.hlsl
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
from Core.hlsl
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
from Lighting.hlsl
struct Light
{
half3 direction;
half3 color;
half distanceAttenuation;
half shadowAttenuation;
};
*/
Varyings vert (Attributes input)
{
Varyings output;
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.positionCS = TransformWorldToHClip(vertexInput.positionWS);
//output.normalWS = vertexNormalInput.normalWS;
// Get Main Light
Light mainLight = GetMainLight();
// world to tangent
float3x3 tangentMat = float3x3(vertexNormalInput.tangentWS, vertexNormalInput.bitangentWS, vertexNormalInput.normalWS);
output.lightTS = mul(tangentMat, mainLight.direction);;
return output;
}
half4 frag (Varyings input) : SV_Target
{
half4 col = tex2D(_BaseMap, input.uv);
float3 normal = UnpackNormal(tex2D(_NormalMap, input.uv));
float diff = saturate(dot(input.lightTS, normal));
col *= diff;
return col;
}
ENDHLSL
}
}
}
Shader "MyShader/URP_Parallax"
{
Properties
{
[Header(Base Color)]
[MainTexture]_BaseMap("_BaseMap (Albedo)", 2D) = "white" {}
[HDR][MainColor]_BaseColor("_BaseColor", Color) = (1,1,1,1)
[Header(Bump Map)]
[MainTexture]_NormalMap("_NormalMap", 2D) = "white" {}
[MainTexture]_HeightMap("_HeightMap", 2D) = "white" {}
_Height("_Height",float) = 1
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Lit"
"Queue"="Geometry"
}
Pass
{
Name "ForwardLit"
Tags
{
"LightMode"="UniversalForward"
}
HLSLPROGRAM
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float3 positionOS : POSITION;
half3 normalOS : NORMAL;
half4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 positionWSAndFogFactor : TEXCOORD1; // xyz: positionWS, w: vertex fog factor
half3 normalWS : TEXCOORD2;
float4 positionCS : SV_POSITION;
float3 lightTS : TEXCOORD3; // light Direction in tangent space
float3 viewTS : TEXCOORD4; // camera direction in tangent space
};
sampler2D _BaseMap;
sampler2D _NormalMap;
sampler2D _HeightMap;
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _NormalMap_ST;
float4 _HeightMap_ST;
float _Height;
CBUFFER_END
/* MEMO
from Core.hlsl
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
from Core.hlsl
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
from Lighting.hlsl
struct Light
{
half3 direction;
half3 color;
half distanceAttenuation;
half shadowAttenuation;
};
*/
Varyings vert (Attributes input)
{
Varyings output;
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.positionCS = TransformWorldToHClip(vertexInput.positionWS);
//output.normalWS = vertexNormalInput.normalWS;
// Get Main Light
Light mainLight = GetMainLight();
// world to tangent
float3x3 tangentMat = float3x3(vertexNormalInput.tangentWS, vertexNormalInput.bitangentWS, vertexNormalInput.normalWS);
output.lightTS = mul(tangentMat, mainLight.direction);;
// view direction
float3 camera = _WorldSpaceCameraPos;
output.viewTS = mul(tangentMat, normalize(camera - vertexInput.positionWS));
return output;
}
half4 frag (Varyings input) : SV_Target
{
float height = tex2D(_HeightMap, input.uv) * _Height * 0.01;
// creepy animation
//height *= sin(_Time.y * 2) + 1;
float2 uvh = input.uv + input.viewTS.xy * height;
half4 col = tex2D(_BaseMap, uvh);
float3 normal = UnpackNormal(tex2D(_NormalMap, uvh));
float diff = saturate(dot(input.lightTS, normal));
col *= diff;
return col;
}
ENDHLSL
}
}
}
Shader "MyShader/URP_Tessellation"
{
Properties
{
[Header(Base Color)]
[MainTexture]_BaseMap("_BaseMap (Albedo)", 2D) = "white" {}
[HDR][MainColor]_BaseColor("_BaseColor", Color) = (1,1,1,1)
[Header(Bump Map)]
[MainTexture]_NormalMap("_NormalMap", 2D) = "white" {}
[MainTexture]_HeightMap("_HeightMap", 2D) = "white" {}
_Height("_Height",float) = 1
[Header(Tessellation)]
_TessFactor("Tessellation", Range(1, 50)) = 10
_MinEdge("Min Edge", Range(0, 0.5)) = 0.4
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Lit"
"Queue"="Geometry"
}
Pass
{
Name "ForwardLit"
Tags
{
"LightMode"="UniversalForward"
}
HLSLPROGRAM
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma vertex vert
#pragma fragment frag
#pragma hull hull
#pragma domain domain
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct VSInput
{
float3 positionOS : POSITION;
half3 normalOS : NORMAL;
half4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
struct HsInput
{
float4 positionOS : POS;
half3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
half4 tangentOS : TEXCOORD1;
};
struct HsControlPointOutput
{
float3 positionOS : POS;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD;
float4 tangentOS : TEXCOORD3;
};
struct HsConstantOutput
{
float tessFactor[3] : SV_TessFactor;
float insideTessFactor : SV_InsideTessFactor;
};
struct DsOutput
{
float4 positionCS : SV_Position;
float2 uv : TEXCOORD0;
float3 lightTS : TEXCOORD1;
};
sampler2D _BaseMap;
sampler2D _NormalMap;
sampler2D _HeightMap;
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _NormalMap_ST;
float4 _HeightMap_ST;
float _Height;
float _MinEdge;
float _TessFactor;
CBUFFER_END
/* MEMO
from Core.hlsl
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
from Core.hlsl
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
from Lighting.hlsl
struct Light
{
half3 direction;
half3 color;
half distanceAttenuation;
half shadowAttenuation;
};
*/
HsInput vert (VSInput input)
{
HsInput output;
output.positionOS = float4(input.positionOS, 1);
output.uv = input.uv;
output.tangentOS = input.tangentOS;
output.normalOS = input.normalOS;
// NOT transform from OS to WS here.
return output;
}
[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[patchconstantfunc("hullConst")]
[outputcontrolpoints(3)]
HsControlPointOutput hull(InputPatch<HsInput, 3> input, uint id : SV_OutputControlPointID)
{
HsControlPointOutput output;
output.positionOS = input[id].positionOS.xyz;
output.normalOS = input[id].normalOS;
output.uv = input[id].uv;
output.tangentOS = input[id].tangentOS;
return output;
}
HsConstantOutput hullConst(InputPatch<HsInput, 3> i)
{
HsConstantOutput o;
float4 p0 = i[0].positionOS;
float4 p1 = i[1].positionOS;
float4 p2 = i[2].positionOS;
o.tessFactor[0] = _TessFactor;
o.tessFactor[1] = _TessFactor;
o.tessFactor[2] = _TessFactor;
o.insideTessFactor = _TessFactor;
return o;
}
[domain("tri")]
DsOutput domain(
HsConstantOutput hsConst,
const OutputPatch<HsControlPointOutput, 3> input,
float3 bary : SV_DomainLocation)
{
DsOutput output;
float3 positionOS =
bary.x * input[0].positionOS +
bary.y * input[1].positionOS +
bary.z * input[2].positionOS;
float3 normalOS = normalize(
bary.x * input[0].normalOS +
bary.y * input[1].normalOS +
bary.z * input[2].normalOS);
output.uv =
bary.x * input[0].uv +
bary.y * input[1].uv +
bary.z * input[2].uv;
float4 tangentOS = normalize(
bary.x * input[0].tangentOS +
bary.y * input[1].tangentOS +
bary.z * input[2].tangentOS);
// displacement
float2 st = abs(output.uv - 0.5);
// factor to avoid "gap"
float edge = 1 - smoothstep(_MinEdge, 0.5, max(st.x, st.y));
float disp = tex2Dlod(_HeightMap, float4(output.uv, 0, 0)).r * _Height * edge;
positionOS.xyz += normalOS * disp;
// ----------------- copied from vertex shader -------------------
// get vectors in the world coordinate
VertexPositionInputs vertexInput = GetVertexPositionInputs(positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(normalOS, tangentOS);
output.positionCS = TransformWorldToHClip(vertexInput.positionWS);
// Get Main Light
Light mainLight = GetMainLight();
// world to tangent
float3x3 tangentMat = float3x3(vertexNormalInput.tangentWS, vertexNormalInput.bitangentWS, vertexNormalInput.normalWS);
output.lightTS = mul(tangentMat, mainLight.direction);;
// ----------------- copied from vertex shader END-------------------
return output;
}
half4 frag (DsOutput input) : SV_Target
{
half4 col = tex2D(_BaseMap, input.uv);
float3 normal = UnpackNormal(tex2D(_NormalMap, input.uv));
float diff = saturate(dot(input.lightTS, normal));
col *= diff;
return col;
}
ENDHLSL
}
}
}
Shader "MyShader/URP_Tessellation_Shadow"
{
Properties
{
[Header(Base Color)]
[MainTexture]_BaseMap("_BaseMap (Albedo)", 2D) = "white" {}
[HDR][MainColor]_BaseColor("_BaseColor", Color) = (1,1,1,1)
[Header(Bump Map)]
[MainTexture]_NormalMap("_NormalMap", 2D) = "white" {}
[MainTexture]_HeightMap("_HeightMap", 2D) = "white" {}
_Height("_Height",float) = 1
_HeightForNormal("_HeightForNormal",float) = 1
[Header(Tessellation)]
_TessFactor("Tessellation", Range(1, 1000)) = 10
_MinEdge("Min Edge", Range(0, 0.5)) = 0.4
[Header(Lighting)]
_ReceiveShadowMappingPosOffset("ShadowMapping Offset", Range(0, 1)) = 0
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Lit"
"Queue"="Geometry"
}
Pass
{
Name "ForwardLit"
Tags
{
"LightMode"="UniversalForward"
}
HLSLPROGRAM
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma vertex vert
#pragma hull hull
#pragma domain domain
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct VSInput
{
float3 positionOS : POSITION;
half3 normalOS : NORMAL;
half4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
struct HsInput
{
float4 positionOS : POS;
half3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
half4 tangentOS : TEXCOORD1;
};
struct HsControlPointOutput
{
float3 positionOS : POS;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD;
float4 tangentOS : TEXCOORD3;
};
struct HsConstantOutput
{
float tessFactor[3] : SV_TessFactor;
float insideTessFactor : SV_InsideTessFactor;
};
struct DsOutput
{
float4 positionCS : SV_Position;
float2 uv : TEXCOORD0;
float3 lightTS : TEXCOORD1;
float3 positionWS : TEXCOORD2;
float3 normalWS : TEXCOORD3;
real3 tangentWS : TEXCOORD4;
real3 bitangentWS : TEXCOORD5;
};
struct LightingData
{
half3 normalWS;
float3 positionWS;
half3 viewDirectionWS;
float4 shadowCoord;
};
sampler2D _BaseMap;
sampler2D _NormalMap;
sampler2D _HeightMap;
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _NormalMap_ST;
float4 _HeightMap_ST;
float _Height;
float _HeightForNormal;
float _MinEdge;
float _TessFactor;
float _ReceiveShadowMappingPosOffset;
CBUFFER_END
/* MEMO
from Core.hlsl
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
float4 positionNDC;// Homogeneous normalized device coordinates
};
from Core.hlsl
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
from Lighting.hlsl
struct Light
{
half3 direction;
half3 color;
half distanceAttenuation;
half shadowAttenuation;
};
*/
HsInput vert (VSInput input)
{
HsInput output;
output.positionOS = float4(input.positionOS, 1);
output.uv = input.uv;
output.tangentOS = input.tangentOS;
output.normalOS = input.normalOS;
// Keep OS coordinate in the vertex stage.
return output;
}
[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[patchconstantfunc("hullConst")]
[outputcontrolpoints(3)]
HsControlPointOutput hull(InputPatch<HsInput, 3> input, uint id : SV_OutputControlPointID)
{
HsControlPointOutput output;
output.positionOS = input[id].positionOS.xyz;
output.normalOS = input[id].normalOS;
output.uv = input[id].uv;
output.tangentOS = input[id].tangentOS;
return output;
}
HsConstantOutput hullConst(InputPatch<HsInput, 3> i)
{
HsConstantOutput o;
float4 p0 = i[0].positionOS;
float4 p1 = i[1].positionOS;
float4 p2 = i[2].positionOS;
// you can arrange tessellation factor here (eg. with respect to distance from camera)
o.tessFactor[0] = _TessFactor;
o.tessFactor[1] = _TessFactor;
o.tessFactor[2] = _TessFactor;
o.insideTessFactor = _TessFactor;
return o;
}
float3 normalTSfromHeight(float2 uv, float height)
{
float2 e = float2(1,0) / 256;
float L = tex2Dlod(_HeightMap, float4(uv - e, 0, 0)).r;
float R = tex2Dlod(_HeightMap, float4(uv + e, 0, 0)).r;
float D = tex2Dlod(_HeightMap, float4(uv - e.yx, 0, 0)).r;
float U = tex2Dlod(_HeightMap, float4(uv + e.yx, 0, 0)).r;
return normalize(float3(2*(L-R) * height * _HeightForNormal, 2*(U-D) * height * _HeightForNormal, 4));
}
[domain("tri")]
DsOutput domain(
HsConstantOutput hsConst,
const OutputPatch<HsControlPointOutput, 3> input,
float3 bary : SV_DomainLocation)
{
DsOutput output;
float3 positionOS =
bary.x * input[0].positionOS +
bary.y * input[1].positionOS +
bary.z * input[2].positionOS;
float3 normalOS = normalize(
bary.x * input[0].normalOS +
bary.y * input[1].normalOS +
bary.z * input[2].normalOS);
output.uv =
bary.x * input[0].uv +
bary.y * input[1].uv +
bary.z * input[2].uv;
float4 tangentOS = normalize(
bary.x * input[0].tangentOS +
bary.y * input[1].tangentOS +
bary.z * input[2].tangentOS);
// displacement
float2 st = abs(output.uv - 0.5);
// make displacement zero at edge
float edge = 1 - smoothstep(_MinEdge, 0.5, max(st.x, st.y));
float disp = tex2Dlod(_HeightMap, float4(output.uv, 0, 0)).r * _Height * edge;
positionOS.xyz += normalOS * disp;
float3 normal2TS = normalTSfromHeight(output.uv, _Height * edge);
// real sign = tangentOS.w * GetOddNegativeScale();
// float3 bitangentOS = cross(normalOS, tangentOS.xyz) * sign;
// // // OS to TS
// float3x3 objectMat = float3x3(tangentOS.xyz, bitangentOS, normalOS);
// float3 normal2OS = mul(objectMat, normalTS);
// float3 tangent2OS = normalize(tangentOS.xyz - dot(normal2OS, tangentOS) * normal2OS);
// ----------------- copied from vertex shader -------------------
// get vectors in the world coordinate
VertexPositionInputs vertexInput = GetVertexPositionInputs(positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(normalOS, tangentOS);
output.positionCS = TransformWorldToHClip(vertexInput.positionWS);
output.positionWS = vertexInput.positionWS;
// output.normalWS = vertexNormalInput.normalWS;
// Get Main Light
Light mainLight = GetMainLight();
// world to tangent
float3 tangentWS = vertexNormalInput.tangentWS;
float3x3 tangentMat = float3x3(vertexNormalInput.tangentWS, vertexNormalInput.bitangentWS, vertexNormalInput.normalWS);
float3 normal2WS = mul(transpose(tangentMat), normal2TS);
float3 tangent2WS = normalize(tangentWS - dot(tangentWS, normal2WS) * normal2WS);
float3 bitangent2WS = cross(normal2WS, tangent2WS);
float3x3 tangent2Mat = float3x3(tangent2WS, bitangent2WS, normal2WS);
output.lightTS = mul(tangent2Mat, mainLight.direction);
// ----------------- copied from vertex shader END-------------------
return output;
}
LightingData InitializeLightingData(DsOutput input)
{
LightingData lightingData;
lightingData.positionWS = input.positionWS;
lightingData.viewDirectionWS = SafeNormalize(GetCameraPositionWS() - lightingData.positionWS);
float3 normal = UnpackNormal(tex2D(_NormalMap, input.uv));
lightingData.normalWS = normalize(input.normalWS); //interpolated normal is NOT unit vector, we need to normalize it
return lightingData;
}
half3 BaseColor(DsOutput input)
{
half4 col = tex2D(_BaseMap, input.uv);
float3 normal = UnpackNormal(tex2D(_NormalMap, input.uv));
float diff = saturate(dot(input.lightTS, normal));
col *= diff;
//col.rgb = input.lightTS;
return col.xyz;
}
half3 ShadeMainLight(half3 col, LightingData lightingData)
{
Light mainLight = GetMainLight();
float3 shadowTestPosWS = lightingData.positionWS + mainLight.direction * _ReceiveShadowMappingPosOffset;
//#ifdef _MAIN_LIGHT_SHADOWS
float4 shadowCoord = TransformWorldToShadowCoord(shadowTestPosWS);
mainLight.shadowAttenuation = MainLightRealtimeShadow(shadowCoord);
//#endif
col *= (mainLight.color * mainLight.shadowAttenuation);
return col;
}
half4 frag (DsOutput input) : SV_Target
{
LightingData lightingData = InitializeLightingData(input);
half3 col = BaseColor(input);
half3 shaded = ShadeMainLight(col, lightingData);
return half4(shaded, 1);
}
ENDHLSL
}
Pass
{
Name "ShadowCaster"
Tags{"LightMode" = "ShadowCaster"}
// more explict render state to avoid confusion
ZWrite On // the only goal of this pass is to write depth!
ZTest LEqual // early exit at Early-Z stage if possible
ColorMask 0 // we don't care about color, we just want to write depth, ColorMask 0 will save some write bandwidth
Cull Back // support Cull[_Cull] requires "flip vertex normal" using VFACE in fragment shader, which is maybe beyond the scope of a simple tutorial shader
HLSLPROGRAM
// the only keywords we need in this pass = _UseAlphaClipping, which is already defined inside the HLSLINCLUDE block
// (so no need to write any multi_compile or shader_feature in this pass)
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#pragma vertex vert
#pragma hull hull
#pragma domain domain
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct VSInput
{
float3 positionOS : POSITION;
half3 normalOS : NORMAL;
half4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
struct HsInput
{
float4 positionOS : POS;
half3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
half4 tangentOS : TEXCOORD1;
};
struct HsControlPointOutput
{
float3 positionOS : POS;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD;
float4 tangentOS : TEXCOORD3;
};
struct HsConstantOutput
{
float tessFactor[3] : SV_TessFactor;
float insideTessFactor : SV_InsideTessFactor;
};
struct DsOutput
{
float4 positionCS : SV_Position;
float2 uv : TEXCOORD0;
float3 lightTS : TEXCOORD1;
};
sampler2D _BaseMap;
sampler2D _NormalMap;
sampler2D _HeightMap;
float3 _LightDirection;
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
float4 _NormalMap_ST;
float4 _HeightMap_ST;
float _Height;
float _MinEdge;
float _TessFactor;
CBUFFER_END
HsInput vert (VSInput input)
{
HsInput output;
output.positionOS = float4(input.positionOS, 1);
output.uv = input.uv;
output.tangentOS = input.tangentOS;
output.normalOS = input.normalOS;
// NOT transform from OS to WS here.
return output;
}
[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[patchconstantfunc("hullConst")]
[outputcontrolpoints(3)]
HsControlPointOutput hull(InputPatch<HsInput, 3> input, uint id : SV_OutputControlPointID)
{
HsControlPointOutput output;
output.positionOS = input[id].positionOS.xyz;
output.normalOS = input[id].normalOS;
output.uv = input[id].uv;
output.tangentOS = input[id].tangentOS;
return output;
}
HsConstantOutput hullConst(InputPatch<HsInput, 3> i)
{
HsConstantOutput o;
float4 p0 = i[0].positionOS;
float4 p1 = i[1].positionOS;
float4 p2 = i[2].positionOS;
o.tessFactor[0] = _TessFactor;
o.tessFactor[1] = _TessFactor;
o.tessFactor[2] = _TessFactor;
o.insideTessFactor = _TessFactor;
return o;
}
[domain("tri")]
DsOutput domain(
HsConstantOutput hsConst,
const OutputPatch<HsControlPointOutput, 3> input,
float3 bary : SV_DomainLocation)
{
DsOutput output;
float3 positionOS =
bary.x * input[0].positionOS +
bary.y * input[1].positionOS +
bary.z * input[2].positionOS;
float3 normalOS = normalize(
bary.x * input[0].normalOS +
bary.y * input[1].normalOS +
bary.z * input[2].normalOS);
output.uv =
bary.x * input[0].uv +
bary.y * input[1].uv +
bary.z * input[2].uv;
float4 tangentOS = normalize(
bary.x * input[0].tangentOS +
bary.y * input[1].tangentOS +
bary.z * input[2].tangentOS);
// displacement
float2 st = abs(output.uv - 0.5);
// factor to avoid "gap"
float edge = 1 - smoothstep(_MinEdge, 0.5, max(st.x, st.y));
float disp = tex2Dlod(_HeightMap, float4(output.uv, 0, 0)).r * _Height * edge;
positionOS.xyz += normalOS * disp;
// get vectors in the world coordinate
VertexPositionInputs vertexInput = GetVertexPositionInputs(positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(normalOS, tangentOS);
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(vertexInput.positionWS, vertexNormalInput.normalWS, _LightDirection));
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#endif
output.positionCS = positionCS;
return output;
}
void frag (DsOutput input)
{
}
ENDHLSL
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment