Files
ichni_Creator_Studio/Assets/Shaders/BlendUnlit.shader

418 lines
16 KiB
Plaintext
Raw Normal View History

2026-03-30 03:23:36 -04:00
// BlendUnlit.shader
// Soullies - Hand-written URP 17 Unlit Sprite/Mesh Shader
// Derived from TrackShader (ASE), rewritten for clarity and extensibility.
//
// Core Feature: Base Color * Texture, optionally multiplied by an HDR Emission Color,
// allowing illuminated objects to retain proper transparency.
// New Feature : Runtime-selectable Blend Mode (Alpha, Additive, Multiply, Premultiplied).
Shader "Soullies/BlendUnlit"
{
Properties
{
[Header(Texture)]
_MainTexture ("Main Texture", 2D) = "white" {}
[Space(8)]
[Header(Color)]
[MainColor] _BaseColor ("Base Color", Color) = (1, 1, 1, 1)
[Space(8)]
[Header(Emission)]
[Toggle(_EMISSION_ON)] _EnableEmission ("Enable Emission", Float) = 0
[HDR] _EmissionColor ("Emission Color (HDR)", Color) = (0, 0, 0, 1)
[Space(8)]
[Header(Alpha Source)]
// When toggled ON : uses the Red channel of the texture as Alpha (for single-channel masks).
// When toggled OFF : uses the A channel of the texture (standard RGBA sprite).
[Toggle(_USEREDASALPHA_ON)] _UseRedAsAlpha ("Use Red Channel as Alpha", Float) = 0
[Space(8)]
[Header(Blend Mode)]
// 0 = Alpha Blend (SrcAlpha, OneMinusSrcAlpha) standard transparent
// 1 = Additive (SrcAlpha, One) add light, black = invisible
// 2 = Multiply (DstColor, Zero) darken underlying pixels
// 3 = Premultiplied(One, OneMinusSrcAlpha) for pre-multiplied alpha textures
[KeywordEnum(Alpha, Additive, Multiply, Premultiplied)] _BlendMode ("Blend Mode", Float) = 0
[Space(8)]
[Header(Render State)]
[Enum(UnityEngine.Rendering.CullMode)] _CullMode ("Cull Mode", Float) = 2 // Back
[Enum(Off, 0, On, 1)] _ZWrite ("Z Write", Float) = 0
// Internal blend equation floats managed by BlendUnlitShaderGUI.
// Default values = Alpha blend: SrcAlpha(5), OneMinusSrcAlpha(10).
// MUST be declared here so Unity serialises them into the .mat asset
// and they survive domain reloads / Ctrl+S without resetting to 0(Zero,Zero=black).
[HideInInspector] _SrcBlendRGB ("Src Blend (Internal)", Float) = 5
[HideInInspector] _DstBlendRGB ("Dst Blend (Internal)", Float) = 10
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalPipeline"
"RenderType" = "Transparent"
"Queue" = "Transparent"
"UniversalMaterialType" = "Unlit"
"IgnoreProjector" = "True"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
// ---------------------------------------------------------------------------
// Blend equations for each mode (controlled by shader_feature variants):
// Alpha : SrcAlpha, OneMinusSrcAlpha (standard transparency)
// Additive : SrcAlpha, One (screen-style additive, black is invisible)
// Multiply : DstColor, Zero (multiply blend, darkens below)
// Premultiplied : One, OneMinusSrcAlpha (for pre-multiplied textures/HDR)
// ---------------------------------------------------------------------------
Cull [_CullMode]
ZWrite [_ZWrite]
ZTest LEqual
// ---------------------------------------------------------------------------
// Pass 1 Universal 2D (sprite renderer main path)
// ---------------------------------------------------------------------------
Pass
{
Name "BlendUnlit_Universal2D"
Tags { "LightMode" = "Universal2D" }
// Blend state driven by shader_feature variant
Blend [_SrcBlendRGB] [_DstBlendRGB]
HLSLPROGRAM
#pragma target 3.5
#pragma prefer_hlslcc gles
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#pragma multi_compile_vertex _ SKINNED_SPRITE
// Feature toggles local so they only generate variants for this material
#pragma shader_feature_local_fragment _EMISSION_ON
#pragma shader_feature_local_fragment _USEREDASALPHA_ON
// Blend mode variants (local_fragment: blend equation changes are per-draw, not per-pass)
#pragma shader_feature_local _BLENDMODE_ALPHA _BLENDMODE_ADDITIVE _BLENDMODE_MULTIPLY _BLENDMODE_PREMULTIPLIED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/Core2D.hlsl"
// -----------------------------------------------------------------------
// Shared CBUFFER (SRP Batcher compatible)
// -----------------------------------------------------------------------
TEXTURE2D(_MainTexture); SAMPLER(sampler_MainTexture);
CBUFFER_START(UnityPerMaterial)
float4 _MainTexture_ST;
half4 _BaseColor;
half4 _EmissionColor;
float _ZWrite;
float _SrcBlendRGB;
float _DstBlendRGB;
CBUFFER_END
// -----------------------------------------------------------------------
// Vertex / Fragment structs
// -----------------------------------------------------------------------
struct Attributes
{
float3 positionOS : POSITION;
float2 uv : TEXCOORD0;
half4 color : COLOR;
UNITY_SKINNED_VERTEX_INPUTS
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
half4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// -----------------------------------------------------------------------
// Shared pixel logic (inlined as a function to avoid copy-paste)
// -----------------------------------------------------------------------
half4 ComputeColor(float2 uv, half4 vertexColor)
{
half4 texSample = SAMPLE_TEXTURE2D(_MainTexture, sampler_MainTexture, uv);
// Alpha channel selection
#if defined(_USEREDASALPHA_ON)
half texAlpha = texSample.r;
#else
half texAlpha = texSample.a;
#endif
// Reconstruct colour from texture
half4 texColor = half4(texSample.rgb, texAlpha);
// Base colour multiply (tint)
half4 color = texColor * _BaseColor;
// Emission multiply
#if defined(_EMISSION_ON)
color *= _EmissionColor;
#endif
// (when emission is OFF we simply skip the multiply equivalent to multiplying by white)
// Vertex color (Sprite tint / SpriteRenderer.color)
color *= vertexColor;
return color;
}
// -----------------------------------------------------------------------
// Vertex Shader
// -----------------------------------------------------------------------
Varyings vert(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
UNITY_SKINNED_VERTEX_COMPUTE(IN);
// Respect SpriteRenderer Flip X/Y
IN.positionOS = UnityFlipSprite(IN.positionOS, unity_SpriteProps.xy);
VertexPositionInputs vpi = GetVertexPositionInputs(IN.positionOS);
OUT.positionCS = vpi.positionCS;
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTexture);
OUT.color = IN.color * unity_SpriteColor;
return OUT;
}
// -----------------------------------------------------------------------
// Fragment Shader
// -----------------------------------------------------------------------
half4 frag(Varyings IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
return ComputeColor(IN.uv, IN.color);
}
ENDHLSL
}
// ---------------------------------------------------------------------------
// Pass 2 Universal Forward (MeshRenderer / 3D object fallback path)
// ---------------------------------------------------------------------------
Pass
{
Name "BlendUnlit_Forward"
Tags { "LightMode" = "UniversalForwardOnly" }
Blend [_SrcBlendRGB] [_DstBlendRGB]
HLSLPROGRAM
#pragma target 3.5
#pragma prefer_hlslcc gles
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#pragma multi_compile_fog
#pragma shader_feature_local_fragment _EMISSION_ON
#pragma shader_feature_local_fragment _USEREDASALPHA_ON
#pragma shader_feature_local _BLENDMODE_ALPHA _BLENDMODE_ADDITIVE _BLENDMODE_MULTIPLY _BLENDMODE_PREMULTIPLIED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/Core2D.hlsl"
TEXTURE2D(_MainTexture); SAMPLER(sampler_MainTexture);
CBUFFER_START(UnityPerMaterial)
float4 _MainTexture_ST;
half4 _BaseColor;
half4 _EmissionColor;
float _ZWrite;
float _SrcBlendRGB;
float _DstBlendRGB;
CBUFFER_END
struct Attributes
{
float3 positionOS : POSITION;
float2 uv : TEXCOORD0;
half4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
half4 color : COLOR;
half fogFactor : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
half4 ComputeColor(float2 uv, half4 vertexColor)
{
half4 texSample = SAMPLE_TEXTURE2D(_MainTexture, sampler_MainTexture, uv);
#if defined(_USEREDASALPHA_ON)
half texAlpha = texSample.r;
#else
half texAlpha = texSample.a;
#endif
half4 texColor = half4(texSample.rgb, texAlpha);
half4 color = texColor * _BaseColor;
#if defined(_EMISSION_ON)
color *= _EmissionColor;
#endif
color *= vertexColor;
return color;
}
Varyings vert(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
VertexPositionInputs vpi = GetVertexPositionInputs(IN.positionOS);
OUT.positionCS = vpi.positionCS;
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTexture);
OUT.color = IN.color;
OUT.fogFactor = ComputeFogFactor(vpi.positionCS.z);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
half4 color = ComputeColor(IN.uv, IN.color);
color.rgb = MixFog(color.rgb, IN.fogFactor);
return color;
}
ENDHLSL
}
// ---------------------------------------------------------------------------
// Pass 3 Scene Selection (Editor picking highlight)
// ---------------------------------------------------------------------------
Pass
{
Name "SceneSelectionPass"
Tags { "LightMode" = "SceneSelectionPass" }
Cull Off
HLSLPROGRAM
#pragma target 3.5
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _MainTexture_ST;
half4 _BaseColor;
half4 _EmissionColor;
float _ZWrite;
float _SrcBlendRGB;
float _DstBlendRGB;
CBUFFER_END
int _ObjectId;
int _PassValue;
struct Attributes { float3 positionOS : POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID };
struct Varyings { float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID };
Varyings vert(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
OUT.positionCS = TransformObjectToHClip(IN.positionOS);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
return half4(_ObjectId, _PassValue, 1.0, 1.0);
}
ENDHLSL
}
// ---------------------------------------------------------------------------
// Pass 4 Scene Picking (Editor object picking)
// ---------------------------------------------------------------------------
Pass
{
Name "ScenePickingPass"
Tags { "LightMode" = "Picking" }
Cull Off
HLSLPROGRAM
#pragma target 3.5
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _MainTexture_ST;
half4 _BaseColor;
half4 _EmissionColor;
float _ZWrite;
float _SrcBlendRGB;
float _DstBlendRGB;
CBUFFER_END
float4 _SelectionID;
struct Attributes { float3 positionOS : POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID };
struct Varyings { float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID };
Varyings vert(Attributes IN)
{
Varyings OUT = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
OUT.positionCS = TransformObjectToHClip(IN.positionOS);
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
return unity_SelectionID;
}
ENDHLSL
}
}
// ---------------------------------------------------------------------------
// Custom Editor: drives the Blend Mode property → actual GPU Blend state
// ---------------------------------------------------------------------------
CustomEditor "BlendUnlitShaderGUI"
FallBack "Hidden/Universal Render Pipeline/FallbackError"
}