Skip to content

Instantly share code, notes, and snippets.

@Vavassor
Last active October 6, 2025 03:54
Show Gist options
  • Select an option

  • Save Vavassor/a46b8e3e3ed1599b47a78a6ab4a1dfe4 to your computer and use it in GitHub Desktop.

Select an option

Save Vavassor/a46b8e3e3ed1599b47a78a6ab4a1dfe4 to your computer and use it in GitHub Desktop.
Lit shader template for Unity game engine's built-in render pipeline
// This is a lit shader example that doesn't use surface shaders.
// It supports forward rendering in the Built-in render pipeline. (BiRP)
//
// Annoyingly, it's not possible to support baked emission without a custom inspector,
// because there's no other way to set globalIlluminationFlags. So if baked emissions are required,
// switch the inspector to debug mode and change the flags manually.
Shader "Orchid Seal/Lit Shader Template"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex("Texture", 2D) = "white" {}
_Roughness("Roughness", Range(0.0, 1.0)) = 0.5
[Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
[Toggle(ALPHA_TEST_ON)] _AlphaTestOn("Alpha Test", Integer) = 0
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
[Header(Rendering)]
[Enum(UnityEngine.Rendering.BlendMode)] _BlendSrc("Source Blend", Float) = 1 // "One"
[Enum(UnityEngine.Rendering.BlendMode)] _BlendDst("Destination Blend", Float) = 10 // "OneMinusSrcAlpha"
[Enum(Add,0,Sub,1,RevSub,2,Min,3,Max,4)] _BlendOp("Blend Operation", Float) = 0 // "Add"
[Toggle(FADE_TRANSPARENCY_ON)] _FadeTransparencyOn("Fade Transparency", Integer) = 0
[Toggle(PREMULTIPLY_ALPHA_ON)] _PremultiplyAlphaOn("Premultiply Alpha", Integer) = 1
[Header(Lighting)]
[KeywordEnum(None, Probes)] Reflection_Mode("Mode", Integer) = 1
[ToggleOff] _SpecularHighlights("Specular Highlights", Integer) = 1
[Header(Culling and Depth Test)]
[Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Int) = 2 // "Back"
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4 // "LessEqual"
[Enum(Off,0,On,1)] _ZWrite("ZWrite", Float) = 1.0 // "On"
[Header(Mask Map)]
[Toggle(MASK_MAP_ON)] _MaskMapOn("Enabled", Integer) = 0
[NoScaleOffset] _MaskMap("Mask Map (ARM)", 2D) = "white" {}
_OcclusionScale("Ambient Occlusion Scale", Range(0.0, 1.0)) = 1.0
_RoughnessScale("Roughness Scale", Range(0.0, 1.0)) = 1.0
_MetallicScale("Metallic Scale", Range(0.0, 1.0)) = 1.0
[Header(Normal)]
[Toggle(NORMAL_MAP_ON)] _NormalMapOn("Enabled", Integer) = 0
_BumpScale("Normal Scale", Float) = 1.0
[Normal] [NoScaleOffset] _BumpMap("Normal Map", 2D) = "bump" {}
[Header(Parallax)]
[Toggle(PARALLAX_MAP_ON)] _ParallaxMapOn("Enabled", Integer) = 0
_Parallax("Height Scale", Range(0.005, 0.08)) = 0.02
[NoScaleOffset] _ParallaxMap("Parallax Map", 2D) = "black" {}
[Header(Emission)]
[Toggle(EMISSION_MAP_ON)] _EmissionMapOn("Enabled", Integer) = 0
_EmissionColor("Color", Color) = (0,0,0)
[NoScaleOffset] _EmissionMap("Emission", 2D) = "white" {}
[Header(Detail)]
[Toggle(DETAIL_MAP_ON)] _DetailMapOn("Enabled", Integer) = 0
[Enum(Multiply X2, 0, Multiply, 1, Add, 2, Lerp, 3)] _DetailBlendMode("Blend Mode", Integer) = 0
_DetailAlbedoMap("Detail Color", 2D) = "grey" {}
_DetailNormalScale("Normal Scale", Float) = 1.0
[Normal] [NoScaleOffset] _DetailNormalMap("Normal Map", 2D) = "bump" {}
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _DetailUvSet("UV Set", Integer) = 0
}
HLSLINCLUDE
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "UnityPBSLighting.cginc"
#if UNITY_PASS_META
#include "UnityMetaPass.cginc"
#endif
// Shadow Receiving................................................................................
// Macros from AutoLight.cginc assume variables have specific names which differ from ours.
// So redefine our own here.
#if defined(SHADOWS_SCREEN)
#if defined(UNITY_NO_SCREENSPACE_SHADOWS)
#define OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1) a._ShadowCoord = mul(unity_WorldToShadow[0], positionWs);
#else // UNITY_NO_SCREENSPACE_SHADOWS
#define OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1) a._ShadowCoord = ComputeScreenPos(positionCs);
#endif
#define OSP_SHADOW_COORDS_INTERNAL(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
#define OSP_SHADOW_ATTENUATION_INTERNAL(a) unitySampleShadow(a._ShadowCoord)
#define OSP_OFF_SURFACE_SHADOW_ATTENUATION(a, positionWs, positionSs) UnityComputeForwardShadows(a._ShadowCoord.xy, positionWs, positionSs)
#endif // SHADOWS_SCREEN
#if defined(HANDLE_SHADOWS_BLENDING_IN_GI) // handles shadows in the depths of the GI function for performance reasons
#define OSP_SHADOW_COORDS(idx1) OSP_SHADOW_COORDS_INTERNAL(idx1)
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1) OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1)
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) OSP_SHADOW_ATTENUATION_INTERNAL(a)
#elif defined(SHADOWS_SCREEN) && !defined(LIGHTMAP_ON) && !defined(UNITY_NO_SCREENSPACE_SHADOWS) // no lightmap uv thus store screenPos instead
// can happen if we have two directional lights. main light gets handled in GI code, but 2nd dir light can have shadow screen and mask.
// - Disabled on ES2 because WebGL 1.0 seems to have junk in .w (even though it shouldn't)
#if defined(SHADOWS_SHADOWMASK) && !defined(SHADER_API_GLES)
#define OSP_SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1) {a._ShadowCoord.xy = uv1 * unity_LightmapST.xy + unity_LightmapST.zw; a._ShadowCoord.zw = ComputeScreenPos(positionCs).xy;}
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(a._ShadowCoord.xy, positionWs, float4(a._ShadowCoord.zw, 0.0, UNITY_SHADOW_W(positionCs.w)));
#else
#define OSP_SHADOW_COORDS(idx1) OSP_SHADOW_COORDS_INTERNAL(idx1)
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1) OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1)
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(0, positionWs, a._ShadowCoord)
#endif
#else
#define OSP_SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
#if defined(SHADOWS_SHADOWMASK)
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1) a._ShadowCoord.xy = uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE) || UNITY_LIGHT_PROBE_PROXY_VOLUME)
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(a._ShadowCoord.xy, positionWs, UNITY_READ_SHADOW_COORDS(a))
#else
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(a._ShadowCoord.xy, 0, 0)
#endif
#else
#if !defined(UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS)
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1)
#else
#define OSP_TRANSFER_SHADOW(a, positionCs, positionWs, uv1) OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1)
#endif
#if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE))
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(0, positionWs, UNITY_READ_SHADOW_COORDS(a))
#else
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(0, positionWs, UNITY_READ_SHADOW_COORDS(a))
#else
#define OSP_SHADOW_ATTENUATION(a, positionCs, positionWs) UnityComputeForwardShadows(0, 0, 0)
#endif
#endif
#endif
#endif
#if defined(SHADOWS_DEPTH) && defined(SPOT)
#define OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1) a._ShadowCoord = mul(unity_WorldToShadow[0], positionWs)
#define OSP_OFF_SURFACE_SHADOW_ATTENUATION(a, positionWs, positionSs) UnityComputeForwardShadows(a._ShadowCoord.xy, positionWs, positionSs)
#endif
#if defined(SHADOWS_CUBE)
#define OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1) a._ShadowCoord.xyz = positionWs.xyz - _LightPositionRange.xyz
#define OSP_OFF_SURFACE_SHADOW_ATTENUATION(a, positionWs, positionSs) UnityComputeForwardShadows(a._ShadowCoord.xy, positionWs, positionSs)
#endif
#if !defined(SHADOWS_SCREEN) && !(defined(SHADOWS_DEPTH) && defined(SPOT)) && !defined(SHADOWS_CUBE)
#define OSP_TRANSFER_SHADOW_INTERNAL(a, positionCs, positionWs, uv1)
#define OSP_OFF_SURFACE_SHADOW_ATTENUATION(a, positionWs, positionSs) 1.0
#endif
// Light coordinates...............................................................................
#ifdef POINT
#define OSP_DECLARE_LIGHT_COORDS(idx) unityShadowCoord3 _LightCoord : TEXCOORD##idx;
#define OSP_COMPUTE_LIGHT_COORDS(a, positionWs) a._LightCoord = mul(unity_WorldToLight, positionWs).xyz;
#define OSP_LIGHT_ATTENUATION(destName, input, positionCs, positionWs) \
unityShadowCoord3 lightCoord = mul(unity_WorldToLight, unityShadowCoord4(positionWs, 1)).xyz; \
fixed shadow = OSP_SHADOW_ATTENUATION(input, positionCs, positionWs); \
fixed destName = tex2D(_LightTexture0, dot(lightCoord, lightCoord).rr).r * shadow;
#endif
#ifdef SPOT
#define OSP_DECLARE_LIGHT_COORDS(idx) unityShadowCoord4 _LightCoord : TEXCOORD##idx;
#define OSP_COMPUTE_LIGHT_COORDS(a, positionWs) a._LightCoord = mul(unity_WorldToLight, positionWs);
#define OSP_LIGHT_ATTENUATION(destName, input, positionCs, positionWs) \
DECLARE_LIGHT_COORD(input, positionWs); \
fixed shadow = OSP_SHADOW_ATTENUATION(input, positionCs, positionWs); \
fixed destName = (lightCoord.z > 0) * UnitySpotCookie(lightCoord) * UnitySpotAttenuate(lightCoord.xyz) * shadow;
#endif
#ifdef DIRECTIONAL
#define OSP_DECLARE_LIGHT_COORDS(idx)
#define OSP_COMPUTE_LIGHT_COORDS(a, positionWs)
#define OSP_LIGHT_ATTENUATION(destName, input, positionCs, positionWs) fixed destName = OSP_SHADOW_ATTENUATION(input, positionCs, positionWs);
#endif
#ifdef POINT_COOKIE
#define OSP_DECLARE_LIGHT_COORDS(idx) unityShadowCoord3 _LightCoord : TEXCOORD##idx;
#define OSP_COMPUTE_LIGHT_COORDS(a, positionWs) a._LightCoord = mul(unity_WorldToLight, positionWs).xyz;
#define OSP_LIGHT_ATTENUATION(destName, input, positionCs, positionWs) \
DECLARE_LIGHT_COORD(input, positionWs); \
fixed shadow = OSP_SHADOW_ATTENUATION(input, positionCs, positionWs); \
fixed destName = tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).r * texCUBE(_LightTexture0, lightCoord).w * shadow;
#endif
#ifdef DIRECTIONAL_COOKIE
#define OSP_DECLARE_LIGHT_COORDS(idx) unityShadowCoord2 _LightCoord : TEXCOORD##idx;
#define OSP_COMPUTE_LIGHT_COORDS(a, positionWs) a._LightCoord = mul(unity_WorldToLight, positionWs).xy;
#define OSP_LIGHT_ATTENUATION(destName, input, positionCs, positionWs) \
DECLARE_LIGHT_COORD(input, positionWs); \
fixed shadow = OSP_SHADOW_ATTENUATION(input, positionCs, positionWs); \
fixed destName = tex2D(_LightTexture0, lightCoord).w * shadow;
#endif
// Shadow Casting..............................................................................
#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
#define OSP_SHADOW_CASTER_NOPOS(idx1) float3 vec : TEXCOORD##idx1;
#define OSP_TRANSFER_SHADOW_CASTER_NOPOS(o, positionCs, positionWs, positionOs, normalOs) o.vec = positionWs - _LightPositionRange.xyz; (positionCs) = UnityObjectToClipPos(positionOs);
#define OSP_SHADOW_CASTER_FRAGMENT(i) UnityEncodeCubeShadowDepth((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w)
#else
#define OSP_SHADOW_CASTER_NOPOS(idx1)
#define OSP_TRANSFER_SHADOW_CASTER_NOPOS(o, positionCs, positionWs, positionOs, normalWs) (positionCs) = UnityApplyLinearShadowBias(OspClipSpaceShadowCasterPos(positionWs, normalWs));
#define OSP_SHADOW_CASTER_FRAGMENT(i) 0.0
#endif
float4 OspClipSpaceShadowCasterPos(float4 positionWs, float3 normalWs)
{
if (unity_LightShadowBias.z != 0.0)
{
float3 wLight = normalize(UnityWorldSpaceLightDir(positionWs.xyz));
// apply normal offset bias (inset position along the normal)
// bias needs to be scaled by sine between normal and light direction
// (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/)
//
// unity_LightShadowBias.z contains user-specified normal offset amount
// scaled by world space texel size.
float shadowCos = dot(normalWs, wLight);
float shadowSine = sqrt(1-shadowCos*shadowCos);
float normalBias = unity_LightShadowBias.z * shadowSine;
positionWs.xyz -= normalWs * normalBias;
}
return mul(UNITY_MATRIX_VP, positionWs);
}
// Fog.........................................................................................
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
#if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE)
// mobile or SM2.0: calculate fog factor per-vertex
#define OSP_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(positionWs, outpos) UNITY_CALC_FOG_FACTOR((outpos).z); (positionWs).w = unityFogFactor
#else
// SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel
#define OSP_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(positionWs, outpos) (positionWs).w = (outpos).z
#endif
#define OSP_EXTRACT_FOG_FROM_WORLD_POS(positionWs) float _unity_fogCoord = (positionWs).w
#else
#define OSP_EXTRACT_FOG_FROM_WORLD_POS(positionWs)
#define OSP_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(positionWs, outpos)
#endif
// Indirect Specular...........................................................................
half3 GlossyEnvironment(UNITY_ARGS_TEXCUBE(tex), half4 hdr, half perceptualRoughness, half3 reflUvw)
{
perceptualRoughness = perceptualRoughness * (1.7 - 0.7 * perceptualRoughness);
half mip = perceptualRoughnessToMipmapLevel(perceptualRoughness);
half4 rgbm = UNITY_SAMPLE_TEXCUBE_LOD(tex, reflUvw, mip);
return DecodeHDR(rgbm, hdr);
}
half3 GetProbeIndirectSpecular(half3 reflUvw, float3 positionWs, half perceptualRoughness)
{
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
// we will tweak reflUVW in glossIn directly (as we pass it to GlossyEnvironment twice for probe0 and probe1), so keep original to pass into BoxProjectedCubemapDirection
half3 originalReflUvw = reflUvw;
reflUvw = BoxProjectedCubemapDirection(originalReflUvw, positionWs, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax);
#endif
half3 env0 = GlossyEnvironment(UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, perceptualRoughness, reflUvw);
#ifdef UNITY_SPECCUBE_BLENDING
const float kBlendFactor = 0.99999;
float blendLerp = unity_SpecCube0_BoxMin.w;
UNITY_BRANCH
if (blendLerp < kBlendFactor)
{
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
reflUvw = BoxProjectedCubemapDirection(originalReflUvw, positionWs, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax);
#endif
half3 env1 = GlossyEnvironment(UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), unity_SpecCube1_HDR, perceptualRoughness, reflUvw);
return lerp(env1, env0, blendLerp);
}
else
{
return env0;
}
#else
return env0;
#endif
}
// Inputs......................................................................................
struct VertexInput
{
float4 positionOs : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float2 uv2 : TEXCOORD2;
float2 uv3 : TEXCOORD3;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct FragmentInput
{
float4 positionCs : SV_POSITION;
float4 uv0 : TEXCOORD0;
float4 positionWs : TEXCOORD1; // [xyz : positionWs | w : fogCoord]
float4 tangentToWorldAndPackedData[3] : TEXCOORD2; // [3x3 : tangentToWorld | 1x3:viewDirForParallax]
half4 ambientOrLightmapUv : TEXCOORD5;
OSP_DECLARE_LIGHT_COORDS(6)
OSP_SHADOW_COORDS(7)
float3 lightDirectionWs : TEXCOORD8;
OSP_SHADOW_CASTER_NOPOS(9)
#ifdef EDITOR_VISUALIZATION
float2 vizUV : TEXCOORD10;
float4 lightCoord : TEXCOORD11;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// UV Sets.....................................................................................
float2 SelectUvSet(VertexInput v, half set)
{
switch (set)
{
default:
case 0: return v.uv0;
case 1: return v.uv1;
case 2: return v.uv2;
case 3: return v.uv3;
}
}
// Properties..................................................................................
UNITY_DECLARE_TEX2D(_MainTex);
UNITY_DECLARE_TEX2D(_MaskMap);
UNITY_DECLARE_TEX2D(_BumpMap);
UNITY_DECLARE_TEX2D(_EmissionMap);
UNITY_DECLARE_TEX2D(_ParallaxMap);
UNITY_DECLARE_TEX2D(_DetailAlbedoMap);
UNITY_DECLARE_TEX2D(_DetailNormalMap);
CBUFFER_START(UnityPerMaterial)
half4 _Color;
float4 _MainTex_ST;
half _Cutoff;
half _Metallic;
half _MetallicScale;
float _Roughness;
float _RoughnessScale;
half _OcclusionScale;
half _BumpScale;
half4 _EmissionColor;
half _Parallax;
float4 _DetailAlbedoMap_ST;
half _DetailUvSet;
half _DetailNormalScale;
half _DetailBlendMode;
CBUFFER_END
FragmentInput VertexProgram(VertexInput v)
{
FragmentInput o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_OUTPUT(FragmentInput, o);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#if UNITY_PASS_META
o.positionCs = UnityMetaVertexPosition(v.positionOs, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST);
#elif UNITY_PASS_SHADOWCASTER
OSP_TRANSFER_SHADOW_CASTER_NOPOS(o, o.positionCs, mul(unity_ObjectToWorld, v.positionOs), v.positionOs, UnityObjectToWorldNormal(v.normal))
#else
o.positionCs = UnityObjectToClipPos(v.positionOs);
#endif
o.uv0.xy = TRANSFORM_TEX(v.uv0, _MainTex);
#if UNITY_PASS_FORWARDBASE || UNITY_PASS_FORWARDADD
float4 positionWs = mul(unity_ObjectToWorld, v.positionOs);
o.positionWs.xyz = positionWs.xyz;
o.uv0.zw = TRANSFORM_TEX(SelectUvSet(v, _DetailUvSet), _DetailAlbedoMap);
float3 normalWs = UnityObjectToWorldNormal(v.normal);
#ifdef NORMAL_MAP_ON
float4 tangentWs = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWs, tangentWs.xyz, tangentWs.w);
o.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0];
o.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1];
o.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2];
#else
o.tangentToWorldAndPackedData[0].xyz = 0;
o.tangentToWorldAndPackedData[1].xyz = 0;
o.tangentToWorldAndPackedData[2].xyz = normalWs;
#endif
OSP_COMPUTE_LIGHT_COORDS(o, positionWs);
OSP_TRANSFER_SHADOW(o, o.positionCs, positionWs, v.uv1);
#endif
#if UNITY_PASS_FORWARDBASE
half4 ambientOrLightmapUV = 0;
// Static lightmaps
#ifdef LIGHTMAP_ON
ambientOrLightmapUV.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
ambientOrLightmapUV.zw = 0;
// Sample light probe for Dynamic objects only (no static or dynamic lightmaps)
#elif UNITY_SHOULD_SAMPLE_SH
#ifdef VERTEXLIGHT_ON
// Approximated illumination from non-important point lights
ambientOrLightmapUV.rgb = Shade4PointLights(
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, positionWs.xyz, normalWs);
#endif
ambientOrLightmapUV.rgb = ShadeSHPerVertex(normalWs, ambientOrLightmapUV.rgb);
#endif
#ifdef DYNAMICLIGHTMAP_ON
ambientOrLightmapUV.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
o.ambientOrLightmapUv = ambientOrLightmapUV;
#endif
#ifdef UNITY_PASS_FORWARDADD
o.lightDirectionWs = _WorldSpaceLightPos0.xyz - positionWs.xyz * _WorldSpaceLightPos0.w;
#endif
#if PARALLAX_MAP_ON
float3 bitangent = cross(normalize(v.normal), normalize(v.tangent.xyz)) * v.tangent.w;
float3x3 rotation = float3x3(v.tangent.xyz, bitangent, v.normal);
half3 viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.positionOs));
o.tangentToWorldAndPackedData[0].w = viewDirForParallax.x;
o.tangentToWorldAndPackedData[1].w = viewDirForParallax.y;
o.tangentToWorldAndPackedData[2].w = viewDirForParallax.z;
#endif
#ifdef EDITOR_VISUALIZATION
o.vizUV = 0;
o.lightCoord = 0;
if (unity_VisualizationMode == EDITORVIZ_TEXTURE)
{
o.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST);
}
else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK)
{
o.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
o.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.positionOs.xyz, 1)));
}
#endif
OSP_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o.positionWs, o.positionCs);
return o;
}
half4 FragmentProgram(FragmentInput i) : SV_Target
{
UNITY_APPLY_DITHER_CROSSFADE(i.positionCs.xy);
// Transparent cutout
float4 uv0 = i.uv0;
#if PARALLAX_MAP_ON
half3 parallaxViewDirection = normalize(half3(
i.tangentToWorldAndPackedData[0].w,
i.tangentToWorldAndPackedData[1].w,
i.tangentToWorldAndPackedData[2].w));
half h = UNITY_SAMPLE_TEX2D(_ParallaxMap, uv0.xy).g;
float2 offset = ParallaxOffset1Step(h, _Parallax, parallaxViewDirection);
uv0 = float4(uv0.xy + offset, uv0.zw + offset);
#endif
fixed4 baseColor = _Color * UNITY_SAMPLE_TEX2D(_MainTex, uv0.xy);
#if ALPHA_TEST_ON
clip(baseColor.a - _Cutoff);
#endif
UNITY_SETUP_INSTANCE_ID(i);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
#if UNITY_PASS_FORWARDBASE || UNITY_PASS_FORWARDADD || UNITY_PASS_META
// Get material properties
#if MASK_MAP_ON
fixed4 masks = UNITY_SAMPLE_TEX2D(_MaskMap, uv0.xy);
half occlusion = _OcclusionScale * masks.r;
half perceptualRoughness = _RoughnessScale * masks.g;
half metallic = _MetallicScale * masks.b;
half detailMask = masks.a;
#else
half occlusion = 1.0;
half perceptualRoughness = _Roughness;
half metallic = _Metallic;
half detailMask = 1.0;
#endif
half3 albedo = baseColor.rgb;
#if DETAIL_MAP_ON
fixed4 detailBaseColor = UNITY_SAMPLE_TEX2D(_DetailAlbedoMap, uv0.zw);
switch (_DetailBlendMode)
{
default:
case 0:
albedo.rgb *= LerpWhiteTo(unity_ColorSpaceDouble.rgb * detailBaseColor.rgb, detailMask);
break;
case 1:
albedo.rgb *= LerpWhiteTo(detailBaseColor.rgb, detailMask);
break;
case 2:
albedo.rgb += detailMask * detailBaseColor.rgb;
break;
case 3:
albedo.rgb = lerp(albedo.rgb, detailBaseColor.rgb, detailMask);
break;
}
#endif
half oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
half3 diffuseColor = albedo * oneMinusReflectivity;
half3 specularColor = lerp(unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
#if PREMULTIPLY_ALPHA_ON
diffuseColor *= baseColor.a;
#endif
#endif
#if EMISSION_MAP_ON
half4 emissionSample = UNITY_SAMPLE_TEX2D(_EmissionMap, i.uv0.xy);
half3 emission = _EmissionColor.rgb * emissionSample.rgb;
#endif
#if UNITY_PASS_FORWARDBASE || UNITY_PASS_FORWARDADD
// Get geometric properties
float3 positionWs = i.positionWs.xyz;
float3 viewDirectionWs = positionWs.xyz - _WorldSpaceCameraPos;
float3 unitViewDirectionWs = normalize(viewDirectionWs);
#if NORMAL_MAP_ON
half3 tangent = i.tangentToWorldAndPackedData[0].xyz;
half3 bitangent = i.tangentToWorldAndPackedData[1].xyz;
half3 normal = i.tangentToWorldAndPackedData[2].xyz;
half3 normalTs = UnpackScaleNormal(UNITY_SAMPLE_TEX2D(_BumpMap, uv0.xy), _BumpScale);
#if DETAIL_MAP_ON
half3 detailNormalTs = UnpackScaleNormal(UNITY_SAMPLE_TEX2D(_DetailNormalMap, uv0.xy), _DetailNormalScale);
switch (_DetailBlendMode)
{
default:
normalTs = lerp(normalTs, BlendNormals(normalTs, detailNormalTs), detailMask);
break;
case 3:
normalTs = lerp(normalTs, detailNormalTs, detailMask);
break;
}
#endif
float3 normalWs = normalize(tangent * normalTs.x + bitangent * normalTs.y + normal * normalTs.z);
#else
float3 normalWs = normalize(i.tangentToWorldAndPackedData[2].xyz);
#endif
// Get direct lighting
UnityLight directLight;
directLight.ndotl = 0;
directLight.color = _LightColor0.rgb;
#if UNITY_PASS_FORWARDBASE
directLight.dir = _WorldSpaceLightPos0.xyz;
#else
directLight.dir = i.lightDirectionWs;
#endif
#ifndef USING_DIRECTIONAL_LIGHT
directLight.dir = normalize(directLight.dir);
#endif
OSP_LIGHT_ATTENUATION(attenuation, i, i.positionCs, positionWs);
// Get indirect lighting (Global Illumination)
UnityIndirect indirectLight;
indirectLight.diffuse = 0;
indirectLight.specular = 0;
#ifdef UNITY_PASS_FORWARDBASE
// Indirect diffuse
#if UNITY_SHOULD_SAMPLE_SH
// Light Probes
indirectLight.diffuse = ShadeSHPerPixel(normalWs, i.ambientOrLightmapUv, positionWs);
#endif
#if defined(HANDLE_SHADOWS_BLENDING_IN_GI)
half bakedAtten = UnitySampleBakedOcclusion(i.ambientOrLightmapUv.xy, positionWs);
float zDist = dot(_WorldSpaceCameraPos - positionWs, UNITY_MATRIX_V[2].xyz);
float fadeDist = UnityComputeShadowFadeDistance(positionWs, zDist);
attenuation = UnityMixRealtimeAndBakedShadows(attenuation, bakedAtten, UnityComputeShadowFade(fadeDist));
#endif
#if defined(LIGHTMAP_ON)
// Baked lightmaps
half4 bakedColorTex = UNITY_SAMPLE_TEX2D(unity_Lightmap, i.ambientOrLightmapUv.xy);
half3 bakedColor = DecodeLightmap(bakedColorTex);
#ifdef DIRLIGHTMAP_COMBINED
fixed4 bakedDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, i.ambientOrLightmapUv.xy);
indirectLight.diffuse += DecodeDirectionalLightmap(bakedColor, bakedDirTex, normalWs);
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(directLight);
indirectLight.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap(indirectLight.diffuse, attenuation, bakedColorTex, normalWs);
#endif
#else
indirectLight.diffuse += bakedColor;
#if defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
ResetUnityLight(directLight);
indirectLight.diffuse = SubtractMainLightWithRealtimeAttenuationFromLightmap(indirectLight.diffuse, attenuation, bakedColorTex, normalWs);
#endif
#endif
#endif
#ifdef DYNAMICLIGHTMAP_ON
// Dynamic lightmaps
fixed4 realtimeColorTex = UNITY_SAMPLE_TEX2D(unity_DynamicLightmap, i.ambientOrLightmapUv.zw);
half3 realtimeColor = DecodeRealtimeLightmap(realtimeColorTex);
#ifdef DIRLIGHTMAP_COMBINED
half4 realtimeDirTex = UNITY_SAMPLE_TEX2D_SAMPLER(unity_DynamicDirectionality, unity_DynamicLightmap, i.ambientOrLightmapUv.zw);
indirectLight.diffuse += DecodeDirectionalLightmap(realtimeColor, realtimeDirTex, normalWs);
#else
indirectLight.diffuse += realtimeColor;
#endif
#endif
indirectLight.diffuse *= occlusion;
// Indirect specular
#if REFLECTION_MODE_NONE
indirectLight.specular = unity_IndirectSpecColor.rgb;
#elif REFLECTION_MODE_PROBES
// Reflection Probes
indirectLight.specular = GetProbeIndirectSpecular(reflect(unitViewDirectionWs, normalWs), positionWs, perceptualRoughness);
#endif
indirectLight.specular *= occlusion;
#endif
directLight.color *= attenuation;
// Lighting
half4 color = UNITY_BRDF_PBS(diffuseColor, specularColor, oneMinusReflectivity, 1.0 - perceptualRoughness, normalWs, -unitViewDirectionWs, directLight, indirectLight);
#if EMISSION_MAP_ON
color.rgb += emission.rgb;
#endif
// Effects
OSP_EXTRACT_FOG_FROM_WORLD_POS(i.positionWs);
UNITY_APPLY_FOG(_unity_fogCoord, color.rgb);
// Final transparency
#if FADE_TRANSPARENCY_ON
color.a = baseColor.a;
#else
color.a = 1.0 - oneMinusReflectivity + baseColor.a * oneMinusReflectivity;
#endif
return color;
#endif
// Cast shadows. Also, how the object appears in the camera depth texture.
#if UNITY_PASS_SHADOWCASTER
return OSP_SHADOW_CASTER_FRAGMENT(i);
#endif
// Lightmapping
#if UNITY_PASS_META
UnityMetaInput o;
UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o);
#ifdef EDITOR_VISUALIZATION
o.Albedo = diffuseColor;
o.VizUV = i.vizUV;
o.LightCoord = i.lightCoord;
#else
o.Albedo = diffuseColor + 0.5 * perceptualRoughness * specularColor;
#endif
o.SpecularColor = specularColor;
#if EMISSION_MAP_ON
o.Emission = emission;
#endif
return UnityMetaFragment(o);
#endif
return 0;
}
ENDHLSL
SubShader
{
Tags
{
"PerformanceChecks" = "False"
"Queue" = "Geometry"
"RenderType" = "Opaque"
}
Cull [_CullMode]
ZTest [_ZTest]
ZWrite [_ZWrite]
Pass
{
Tags
{
"LightMode" = "ForwardBase"
}
Blend [_BlendSrc] [_BlendDst]
BlendOp [_BlendOp]
HLSLPROGRAM
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma target 3.0
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#pragma multi_compile_instancing
#pragma shader_feature_local ALPHA_TEST_ON
#pragma shader_feature_local DETAIL_MAP_ON
#pragma shader_feature_local EMISSION_MAP_ON
#pragma shader_feature_local FADE_TRANSPARENCY_ON
#pragma shader_feature_local MASK_MAP_ON
#pragma shader_feature_local NORMAL_MAP_ON
#pragma shader_feature_local PARALLAX_MAP_ON
#pragma shader_feature_local PREMULTIPLY_ALPHA_ON
#pragma shader_feature_local REFLECTION_MODE_NONE REFLECTION_MODE_PROBES
#pragma shader_feature_local _SPECULARHIGHLIGHTS_OFF
ENDHLSL
}
Pass
{
Tags
{
"LightMode" = "ForwardAdd"
}
Blend [_BlendSrc] One
Fog { Color (0,0,0,0) }
ZTest LEqual
ZWrite Off
HLSLPROGRAM
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma target 3.0
#pragma multi_compile_fog
#pragma multi_compile_fwdadd_fullshadows
#pragma shader_feature_local ALPHA_TEST_ON
#pragma shader_feature_local DETAIL_MAP_ON
#pragma shader_feature_local EMISSION_MAP_ON
#pragma shader_feature_local FADE_TRANSPARENCY_ON
#pragma shader_feature_local MASK_MAP_ON
#pragma shader_feature_local NORMAL_MAP_ON
#pragma shader_feature_local PARALLAX_MAP_ON
#pragma shader_feature_local PREMULTIPLY_ALPHA_ON
#pragma shader_feature_local _SPECULARHIGHLIGHTS_OFF
ENDHLSL
}
Pass
{
Tags
{
"LightMode" = "ShadowCaster"
}
ZTest LEqual
ZWrite On
HLSLPROGRAM
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma target 3.0
#pragma multi_compile_instancing
#pragma multi_compile_shadowcaster
#pragma shader_feature_local ALPHA_TEST_ON
#pragma shader_feature_local PARALLAX_MAP_ON
ENDHLSL
}
Pass
{
Tags
{
"LightMode" = "Meta"
}
Cull Off
HLSLPROGRAM
#pragma vertex VertexProgram
#pragma fragment FragmentProgram
#pragma target 3.0
#pragma shader_feature_local ALPHA_TEST_ON
#pragma shader_feature_local DETAIL_MAP_ON
#pragma shader_feature EDITOR_VISUALIZATION
#pragma shader_feature_local EMISSION_MAP_ON
#pragma shader_feature_local MASK_MAP_ON
#pragma shader_feature_local PARALLAX_MAP_ON
#pragma shader_feature_local PREMULTIPLY_ALPHA_ON
ENDHLSL
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment