Skip to content

Instantly share code, notes, and snippets.

@NedMakesGames
Last active October 7, 2023 23:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NedMakesGames/4c9bc4ae54c8c481f299538ce420b29a to your computer and use it in GitHub Desktop.
Save NedMakesGames/4c9bc4ae54c8c481f299538ce420b29a to your computer and use it in GitHub Desktop.
NedMakesGames
// MIT License
// Copyright (c) 2023 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
Shader "NedMakesGames/MyLit" {
Properties{
[Header(Surface options)]
[MainTexture] _ColorMap("Color", 2D) = "white" {}
[MainColor] _ColorTint("Tint", Color) = (1, 1, 1, 1)
_Cutoff("Alpha cutout threshold", Range(0, 1)) = 0.5
_Smoothness("Smoothness", Float) = 0
[HideInInspector] _Cull("Cull mode", Float) = 2 // 2 is "Back"
[HideInInspector] _SourceBlend("Source blend", Float) = 0
[HideInInspector] _DestBlend("Destination blend", Float) = 0
[HideInInspector] _ZWrite("ZWrite", Float) = 0
[HideInInspector] _SurfaceType("Surface type", Float) = 0
[HideInInspector] _FaceRenderingMode("Face rendering type", Float) = 0
}
SubShader {
Tags {"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
Pass {
Name "ForwardLit"
Tags{"LightMode" = "UniversalForward"}
Blend[_SourceBlend][_DestBlend]
ZWrite[_ZWrite]
Cull[_Cull]
HLSLPROGRAM
#define _SPECULAR_COLOR
#pragma shader_feature_local _ALPHA_CUTOUT
#pragma shader_feature_local _DOUBLE_SIDED_NORMALS
#if UNITY_VERSION >= 202120
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#else
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#endif
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma vertex Vertex
#pragma fragment Fragment
#include "MyLitForwardLitPass.hlsl"
ENDHLSL
}
Pass {
Name "ShadowCaster"
Tags{"LightMode" = "ShadowCaster"}
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma shader_feature_local _ALPHA_CUTOUT
#pragma shader_feature_local _DOUBLE_SIDED_NORMALS
#pragma vertex Vertex
#pragma fragment Fragment
#include "MyLitShadowCasterPass.hlsl"
ENDHLSL
}
}
CustomEditor "MyLitCustomInspector"
}
// MIT License
// Copyright (c) 2023 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef MY_LIT_COMMON_INCLUDED
#define MY_LIT_COMMON_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_ColorMap); SAMPLER(sampler_ColorMap);
float4 _ColorMap_ST;
float4 _ColorTint;
float _Cutoff;
float _Smoothness;
void TestAlphaClip(float4 colorSample) {
#ifdef _ALPHA_CUTOUT
clip(colorSample.a * _ColorTint.a - _Cutoff);
#endif
}
#endif
// MIT License
// Copyright (c) 2023 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
public class MyLitCustomInspector : ShaderGUI {
public enum SurfaceType {
Opaque, TransparentBlend, TransparentCutout
}
public enum FaceRenderingMode {
FrontOnly, NoCulling, DoubleSided
}
public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader) {
base.AssignNewShaderToMaterial(material, oldShader, newShader);
if(newShader.name == "NedMakesGames/MyLit") {
UpdateSurfaceType(material);
}
}
#if UNITY_2022_1_OR_NEWER
public override void ValidateMaterial(Material material) {
base.ValidateMaterial(material);
UpdateSurfaceType(material);
}
#endif
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) {
Material material = materialEditor.target as Material;
var surfaceProp = BaseShaderGUI.FindProperty("_SurfaceType", properties, true);
var faceProp = BaseShaderGUI.FindProperty("_FaceRenderingMode", properties, true);
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
MaterialEditor.BeginProperty(surfaceProp);
#endif
surfaceProp.floatValue = (int)(SurfaceType)EditorGUILayout.EnumPopup("Surface type", (SurfaceType)surfaceProp.floatValue);
#if UNITY_2022_1_OR_NEWER
MaterialEditor.EndProperty();
#endif
#if UNITY_2022_1_OR_NEWER
MaterialEditor.BeginProperty(faceProp);
#endif
faceProp.floatValue = (int)(FaceRenderingMode)EditorGUILayout.EnumPopup("Face rendering mode", (FaceRenderingMode)faceProp.floatValue);
#if UNITY_2022_1_OR_NEWER
MaterialEditor.EndProperty();
#endif
if(EditorGUI.EndChangeCheck()) {
UpdateSurfaceType(material);
}
base.OnGUI(materialEditor, properties);
}
private void UpdateSurfaceType(Material material) {
SurfaceType surface = (SurfaceType)material.GetFloat("_SurfaceType");
switch(surface) {
case SurfaceType.Opaque:
material.renderQueue = (int)RenderQueue.Geometry;
material.SetOverrideTag("RenderType", "Opaque");
break;
case SurfaceType.TransparentCutout:
material.renderQueue = (int)RenderQueue.AlphaTest;
material.SetOverrideTag("RenderType", "TransparentCutout");
break;
case SurfaceType.TransparentBlend:
material.renderQueue = (int)RenderQueue.Transparent;
material.SetOverrideTag("RenderType", "Transparent");
break;
}
switch(surface) {
case SurfaceType.Opaque:
case SurfaceType.TransparentCutout:
material.SetInt("_SourceBlend", (int)BlendMode.One);
material.SetInt("_DestBlend", (int)BlendMode.Zero);
material.SetInt("_ZWrite", 1);
break;
case SurfaceType.TransparentBlend:
material.SetInt("_SourceBlend", (int)BlendMode.SrcAlpha);
material.SetInt("_DestBlend", (int)BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
break;
}
if(surface == SurfaceType.TransparentCutout) {
material.EnableKeyword("_ALPHA_CUTOUT");
} else {
material.DisableKeyword("_ALPHA_CUTOUT");
}
material.SetShaderPassEnabled("ShadowCaster", surface != SurfaceType.TransparentBlend);
FaceRenderingMode faceRenderingMode = (FaceRenderingMode)material.GetFloat("_FaceRenderingMode");
if(faceRenderingMode == FaceRenderingMode.FrontOnly) {
material.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Back);
} else {
material.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
}
if(faceRenderingMode == FaceRenderingMode.DoubleSided) {
material.EnableKeyword("_DOUBLE_SIDED_NORMALS");
} else {
material.DisableKeyword("_DOUBLE_SIDED_NORMALS");
}
}
}
// MIT License
// Copyright (c) 2023 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef MY_LIT_FORWARD_LIT_PASS_INCLUDED
#define MY_LIT_FORWARD_LIT_PASS_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "MyLitCommon.hlsl"
struct Attributes {
float3 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
};
struct Interpolators {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
float3 normalWS : TEXCOORD2;
};
Interpolators Vertex(Attributes input) {
Interpolators output;
// Found in URP/ShaderLib/ShaderVariablesFunctions.hlsl
VertexPositionInputs posnInputs = GetVertexPositionInputs(input.positionOS);
VertexNormalInputs normInputs = GetVertexNormalInputs(input.normalOS);
output.positionCS = posnInputs.positionCS;
output.uv = TRANSFORM_TEX(input.uv, _ColorMap);
output.normalWS = normInputs.normalWS;
output.positionWS = posnInputs.positionWS;
return output;
}
float4 Fragment(Interpolators input
#ifdef _DOUBLE_SIDED_NORMALS
, FRONT_FACE_TYPE frontFace : FRONT_FACE_SEMANTIC
#endif
) : SV_TARGET {
float2 uv = input.uv;
float4 colorSample = SAMPLE_TEXTURE2D(_ColorMap, sampler_ColorMap, uv) * _ColorTint;
TestAlphaClip(colorSample);
float3 normalWS = normalize(input.normalWS);
#ifdef _DOUBLE_SIDED_NORMALS
normalWS *= IS_FRONT_VFACE(frontFace, 1, -1);
#endif
InputData lightingInput = (InputData)0; // Found in URP/ShaderLib/Input.hlsl
lightingInput.positionWS = input.positionWS;
lightingInput.normalWS = normalWS;
lightingInput.viewDirectionWS = GetWorldSpaceNormalizeViewDir(input.positionWS); // In ShaderVariablesFunctions.hlsl
lightingInput.shadowCoord = TransformWorldToShadowCoord(input.positionWS); // In Shadows.hlsl
SurfaceData surfaceInput = (SurfaceData)0;
surfaceInput.albedo = colorSample.rgb;
surfaceInput.alpha = colorSample.a;
surfaceInput.specular = 1;
surfaceInput.smoothness = _Smoothness;
#if UNITY_VERSION >= 202120
return UniversalFragmentBlinnPhong(lightingInput, surfaceInput);
#else
return UniversalFragmentBlinnPhong(lightingInput, surfaceInput.albedo, float4(surfaceInput.specular, 1), surfaceInput.smoothness, surfaceInput.emission, surfaceInput.alpha);
#endif
}
#endif
// MIT License
// Copyright (c) 2023 NedMakesGames
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef MY_LIT_SHADOW_CASTER_PASS_INCLUDED
#define MY_LIT_SHADOW_CASTER_PASS_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "MyLitCommon.hlsl"
struct Attributes {
float3 positionOS : POSITION;
float3 normalOS : NORMAL;
#ifdef _ALPHA_CUTOUT
float2 uv : TEXCOORD0;
#endif
};
struct Interpolators {
float4 positionCS : SV_POSITION;
#ifdef _ALPHA_CUTOUT
float2 uv : TEXCOORD0;
#endif
};
float3 FlipNormalBasedOnViewDir(float3 normalWS, float3 positionWS) {
float3 viewDirWS = GetWorldSpaceNormalizeViewDir(positionWS);
return normalWS * (dot(normalWS, viewDirWS) < 0 ? -1 : 1);
}
float3 _LightDirection;
float4 GetShadowCasterPositionCS(float3 positionWS, float3 normalWS) {
float3 lightDirectionWS = _LightDirection;
#ifdef _DOUBLE_SIDED_NORMALS
normalWS = FlipNormalBasedOnViewDir(normalWS, positionWS);
#endif
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#endif
return positionCS;
}
Interpolators Vertex(Attributes input) {
Interpolators output;
VertexPositionInputs posnInputs = GetVertexPositionInputs(input.positionOS); // Found in URP/ShaderLib/ShaderVariablesFunctions.hlsl
VertexNormalInputs normInputs = GetVertexNormalInputs(input.normalOS); // Found in URP/ShaderLib/ShaderVariablesFunctions.hlsl
output.positionCS = GetShadowCasterPositionCS(posnInputs.positionWS, normInputs.normalWS);
#ifdef _ALPHA_CUTOUT
output.uv = TRANSFORM_TEX(input.uv, _ColorMap);
#endif
return output;
}
float4 Fragment(Interpolators input) : SV_TARGET {
#ifdef _ALPHA_CUTOUT
float2 uv = input.uv;
float4 colorSample = SAMPLE_TEXTURE2D(_ColorMap, sampler_ColorMap, uv);
TestAlphaClip(colorSample);
#endif
return 0;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment