使用unity版本为2022.2.21f1
shader文件
Shader "Unlit/SRUniversal"
{
Properties
{
[KeywordEnum(None,Face,Hair,UpperBody,LowerBody)] _Area("Material area", Float) = 0
[HideInInspector] _HeadForward("", Vector) = (0,0,1)
[HideInInspector] _HeadRight("", Vector) = (1,0,0)
[Header(Base Color)]
[HideInInspector] _BaseMap("", 2D) = "white"{}
[NoScaleOffset] _FaceColorMap("Face color map (Default white)", 2D) = "white"{}
[NoScaleOffset] _HairColorMap("Hair color map (Default white)", 2D) = "white"{}
[NoScaleOffset] _UpperBodyColorMap("Upper body color map (Default white)", 2D) = "white"{}
[NoScaleOffset] _LowerBodyColorMap("Lower body color map (Default white)", 2D) = "white"{}
_FrontFaceTintColor("Front face tint color (Default white)", Color) = (1,1,1)
_BackFaceTintColor("Back face tint color (Default white)", Color) = (1,1,1)
_Alpha("Alpha (Default 1)", Range(0, 1)) = 1
_AlphaClip("Alpha clip (Default 0.333)", Range(0, 1)) = 0.333
[Header(Light Map)]
[NoScaleOffset] _HairLightMap("Hair light map (Default black)", 2D) = "black"{}
[NoScaleOffset] _UpperBodyLightMap("Upper body light map (Default black)", 2D) = "black"{}
[NoScaleOffset] _LowerBodyLightMap("Lower body light map (Default black)", 2D) = "black"{}
[Header(Ramp Map)]
[NoScaleOffset] _HairCoolRamp("Hair cool ramp (Default white)", 2D) = "white"{}
[NoScaleOffset] _HairWarmRamp("Hair warm ramp (Default white)", 2D) = "white"{}
[NoScaleOffset] _BodyCoolRamp("Body cool ramp (Default white)", 2D) = "white"{}
[NoScaleOffset] _BodyWarmRamp("Body warm ramp (Default white)", 2D) = "white"{}
[Header(Indirect Lighting)]
_IndirectLightFlattenNormal("Indirect light flatten normal (Default 0)", Range(0, 1)) = 0
_IndirectLightUsage("Indirect light usage (Default 0.5)", Range(0, 1)) = 0.5
_IndirectLightOcclusionUsage("Indirect light occlusion usage (Default 0.5)", Range(0, 1)) = 0.5
_IndirectLightMixBaseColor("Indirect light base color (Default 1)", Range(0, 1)) = 1
[Header(Main Lighting)]
_MainLightColorUsage("Main light color usage (Default 1)", Range(0, 1)) = 1
_ShadowThresholdCenter("Shadow threshold center (Default 0)", Range(-1, 1)) = 0
_ShadowThresholdSoftness("Shadow threshold softness (Default 0.1)", Range(0, 1)) = 0.1
_ShadowRampOffset("Shadow ramp offset (Default 0.75)", Range(0, 1)) = 0.75
[Header(Face)]
[NoScaleOffset] _FaceMap("Face map (Default black)", 2D) = "black"{}
_FaceShadowOffset("Face shadow offset (Default -0.01)", Range(-1, 1)) = -0.01
_FaceShadowTransitionSoftness("Face shadow transition softness (Default 0.05)", Range(0, 1)) = 0.05
[Header(Specular)]
_SpecularExpon("Specular exponent (Default 50)", Range(1, 128)) = 50
_SpecularKsNonMetal("Specular Ks non-metal (Default 0.04)", Range(0, 1)) = 0.04
_SpecularKsMetal("Specular Ks metal (Default 1)", Range(0, 1)) = 1
_SpecularBrightness("Specular brightness (Default 1)", Range(0, 10)) = 1
[Header(Sockings)]
[NoScaleOffset] _UpperBodyStockings("Upper body stockings (Default black)", 2D) = "black"{}
[NoScaleOffset] _LowerBodyStockings("Lower body stockings (Default black)", 2D) = "black"{}
_StockingsDarkColor("Stocking dark color (Default black)", Color) = (0,0,0)
[HDR] _StockingsLightColor("Stocking light color (Default 1.8 1.48299 0.856821)", Color) = (1.8, 1.48299, 0.856821)
[HDR] _StockingsTransitionColor("Stocking Transition color (Default 0.360381 0.242986 0.358131)", Color) = (0.360381, 0.242986, 0.358131)
_StockingsTransitionThreshold("Stocking transition threshold (Default 0.58)", Range(0, 1)) = 0.58
_StockingsTransitionPower("Stocking transition Power (Default 1)", Range(0.1, 50)) = 1
_StockingsTransitionHardness("Stocking transition hardness (Default 0.4)", Range(0, 1)) = 0.4
_StockingsTextureUsage("Stocking texture usage (Default 0.1)", Range(0, 1)) = 0.1
[Header(Rim Lighting)]
_RimLightWidth("Rim light width (Default 1)", Range(0, 10)) = 1
_RimLightThreshold("Rim light threshold (Default 0.05)", Range(-1, 1)) = 0.05
_RimLightFadeout("Rim light fadeout (Default 1)", Range(0.01, 1)) = 1
[HDR] _RimLightTintColor("Rim light tint color (Default white)", Color) = (1,1,1)
_RimLightBrightness("Rim light brightness (Default 1)", Range(0, 10)) = 1
_RimLightMixAlbedo("Rim light mix albedo (Default 0.9)", Range(0, 1)) = 0.9
[Header(Emission)]
[Toggle(_EMISSION_ON)] _UseEmission("Use emission (Default False)", Float) = 0
_EmissionMixBaseColor("Emission mix base color (Default 1)", Range(0, 1)) = 1
_EmissionTintColor("Emission tint color (Default white)", Color) = (1,1,1)
_EmissionIntensity("Emission intensity (Default 1)", Range(0, 100)) = 1
[Header(Outline)]
[Toggle(_OUTLINE_ON)] _UseOutline("Use outline (Default True)", Float) = 1
[Toggle(_OUTLINE_VERTEX_COLOR_SMOOTH_NORMAL)] _OutlineUseVertexColorSmoothNormal("Use vertex color smooth normal (Default False)", Float) = 0
_OutlineWidth("Outline width (Default 1)", Range(0, 10)) = 1
_OutlineGamma("Outline gamma (Default 16)", Range(1, 255)) = 16
[Header(Surface Options)]
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull (Default back)", Float) = 2
[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlendMode("Src blend mode (Default One)", Float) = 1
[Enum(UnityEngine.Rendering.BlendMode)] _DstBlendMode("Dst blend mode (Default Zero)", Float) = 0
[Enum(UnityEngine.Rendering.BlendOp)] _BlendOp("Blend operation (Default Add)", Float) = 0
[Enum(Off, 0, On, 1)] _ZWrite("ZWrite (Default On)", Float) = 1
_StencilRef("Stencil reference (Default 0)", Range(0, 255)) = 0
[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil comparison (Default disabled)", Int) = 0
[Enum(UnityEngine.Rendering.StencilOp)] _StencilPassOp("Stencil pass operation (Default keep)", Int) = 0
[Enum(UnityEngine.Rendering.StencilOp)] _StencilFailOp("Stencil fail operation (Default keep)", Int) = 0
[Enum(UnityEngine.Rendering.StencilOp)] _StencilZFailOp("Stencil Z fail operation (Default keep)", Int) = 0
[Header(Draw Overlay)]
[Toggle(_DRAW_OVERLAY_ON)] _UseDrawOverlay("Use draw overlay (Default False)", Float) = 0
[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlendModeOverlay("Overlay pass src blend mode (Default One)", Float) = 1
[Enum(UnityEngine.Rendering.BlendMode)] _DstBlendModeOverlay("Overlay pass src blend mode (Default Zero)", Float) = 0
[Enum(UnityEngine.Rendering.BlendOp)] _BlendOpOverlay("Overlay pass blend operation (Default Add)", Float) = 0
_StencilRefOverlay("Overlay pass stencil reference (Default 0)", Range(0, 255)) = 0
[Enum(UnityEngine.Rendering.CompareFunction)] _StencilCompOverlay ("Overlay pass stencil comparison (Default disabled)", Int) = 0
}
SubShader
{
LOD 100
HLSLINCLUDE
HLSL code that you want to share goes here
#pragma shader_feature_local _AREA_FACE
#pragma shader_feature_local _AREA_HAIR
#pragma shader_feature_local _AREA_UPPERBODY
#pragma shader_feature_local _AREA_LOWERBODY
#pragma shader_feature_local _OUTLINE_ON
#pragma shader_feature_local _OUTLINE_VERTEX_COLOR_SMOOTH_NORMAL
#pragma shader_feature_local _DRAW_OVERLAY_ON
#pragma shader_feature_local _EMISSION_ON
ENDHLSL
Pass
{
Name "ShadowCaster"
Tags{"LightMode" = "ShadowCaster"} // 阴影贴图
ZWrite [_ZWrite]
ZTest LEqual
ColorMask RGBA
Cull [_Cull]
HLSLPROGRAM
//#pragma exclude_renders gles gles3 glcore
#pragma targe 4.5
// -------------------------------------------------------------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
// -------------------------------------------------------------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
// -------------------------------------------------------------------------------------------
// Universial Pipeline keywords
// this is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
ENDHLSL
}
Pass
{
Name "DepthOnly"
Tags{"LightMode" = "DepthOnly" "Queue" = "Transparent" } // 深度贴图
ZWrite [_ZWrite]
ColorMask RGBA
Cull [_Cull]
HLSLPROGRAM
//#pragma exclude_renders gles gles3 glcore
#pragma targe 4.5
// -------------------------------------------------------------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
// -------------------------------------------------------------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
#pragma Vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
Pass
{
Name "DepthNormals"
Tags{"LightMode" = "DepthNormals"} // 向SSAO传输值
ZWrite [_ZWrite]
Cull [_Cull]
HLSLPROGRAM
//#pragma exclude_renders gles gles3 glcore
#pragma targe 4.5
// -------------------------------------------------------------------------------------------
// Material Keywords
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _PARALLAXMAP
#pragma shader_feature_local _ _DETAIL_MULTX2 _DETAIL_SCALED
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
// -------------------------------------------------------------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl"
ENDHLSL
}
Pass
{
Name "DrawCore"
Tags{ "RenderPipeline" = "UniversalRenderPipeline" "RenderType" = "Opaque" "LightMode" = "SRPDefaultUnlit"}
Cull [_Cull]
Stencil{
Ref [_StencilRef] //这是传进去的int值(默认0【0,255】注意这是二进制11111111),如果在测试就用这个值和模板值(如果没有写入过默认0)作比较,受readMask影响、如果在写入就是写入这个值,受writeMask影响
Comp [_StencilComp] //何时通过模板测试,这个和写入没有任何关系,还有CompBack和CompFront专门针对背面和正面,如果存在Comp则会覆盖他们,值为:Never、Less、Equal、LEqual、Greater、NotEqual、GEqual、Always
Pass [_StencilPassOp] //设置对通过模板测试的像素怎么处理,还有PassBack和PassFront专门针对背面和正面,如果存在Pass则会覆盖他们,值为:Keep(保持原值)、Zero(写入模板值0)、Replace(写入Ref值)、IncrSat(加上去但不超过255)、DecrSat(相减但不小于0)、Invert(所有位取反)、IncrWrap(加上去但超过255会从0重新开始)、DecrWrap(相减但小于0会从255重新开始)
Fail [_StencilFailOp] //设置对未通过模板测试的像素怎么处理,还有FailBack和FailFront专门针对背面和正面,如果存在Fail则会覆盖他们,值和Pass的相同
ZFail [_StencilZFailOp] //当像素通过模板测试但未通过深度测试时怎么处理,还有ZFailBack和ZFailFront专门针对背面和正面,如果存在ZFail则会覆盖他们,值和Pass的相同
}
Blend [_SrcBlendMode] [_DstBlendMode]
BlendOp [_BlendOp]
ZWrite [_ZWrite]
HLSLPROGRAM
//#pragma exclude_renders gles gles3 glcore
#pragma targe 4.5
#pragma multi_compile _MAIN_LIGHT_SHADOWS
#pragma multi_compile _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _SHADOW_SOFT
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "SRUniversalInput.hlsl"
#include "SRUniversalDrawCorePass.hlsl"
ENDHLSL
}
Pass
{
Name "DrawOutline"
Tags{ "RenderPipeline" = "UniversalRenderPipeline" "RenderType" = "Opaque" "LightMode" = "UniversalForwardOnly" }
Cull Front
ZWrite[_ZWrite]
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#if _OUTLINE_ON
#include "SRUniversalInput.hlsl"
#include "SRUniversalDrawOutlinePass.hlsl"
#else
struct Attribute {};
struct Varyings
{
float4 positionCS : SV_POSITION;
};
Varyings vert(Attribute input)
{
return (Varyings)0;
}
float4 frag(Varyings input) : SV_TARGET
{
return 0;
}
#endif
ENDHLSL
}
}
Fallback Off
}
hlsl文件
SRUniversalInput
#ifndef _SR_UNIVERSAL_INPUT_INCLUDED
#define _SR_UNIVERSAL_INPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
/*
包含VertexPositionInputs、VertexNormalInputs结构以及各种基础定义 #define TEXTURE2D_X(textureName) TEXTURE2D_ARRAY(textureName)
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
约定:
unity在世界空间是左手,但是在视图空间为右手。世界到视图空间的矩阵行列式是负的
对于cubmap捕获(反射探针),视图空间仍是左手,行列式为正
//WS:世界空间
//RWS:相机相对世界空间。为了提高精度,已经减去了相机平移的空间
//VS:视图空间
//OS:对象空间
//CS:同构剪辑空间
//TS:切线空间
//TXS:纹理空间
大写字母矢量都指向像素位置且归一View vector、Light vector、Light vector、Half vector
out和inout过滤器,当声明函数的“out”参数时,它们总是最后一个
不要使用SetGlobalFloatArray或SetComputeFloatParams。//数组可以是hlsl中的别名。示例:uniform float4-packedArray[3];static float unpackedArray[12]=(float[12])packedArray;
*包含非常多的常用基本函数定义PackHeightmap、GetPositionInput、SinFromCos、Orthonormalize等等*
-----------------------------------------------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl"
Unpack888UIntToFloat2(uint3 x)、Unpack8ToFloat2(float f)、PackToR5G6B5(float3 rgb) 看起来是各种格式互转的方法
-----------------------------------------------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
UNITY_VERSION宏
-----------------------------------------------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
InputData结构体、很多常量输入(应该是unity给值,直接拿那种)比如_MainLightPosition
-----------------------------------------------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl"
各种各样的方法,GetWorldSpaceViewDir之类的获取各种输入结构、LinearDepthToEyeDepth变换方法、TransformScreenUV(inout float2 uv)甚至编码解码什么的
*/
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
/*
各种光照方法LightingLambert、LightingSpecular、LightingPhysicallyBased、VertexLighting、CalculateLightingColor、CalculateBlinnPhong、UniversalFragmentPBR、UniversalFragmentBlinnPhong、UniversalFragmentBakedLit
结构体LightingData获取各种光照信息
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl" 光反射模型
结构体BRDFData、方法:InitializeBRDFData、EnvironmentBRDFSpecular、DirectBRDFSpecular
{
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/BSDF.hlsl" 包括BRDF反射、BTDF透射、BDDF衍射
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
方法:ClampRoughnessForRaytracing、BlendNormal、ConvertRoughnessToAnisotropy材质属性(粗糙度)相关的
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
定义SurfaceData结构体,是物体表面的各种属性摩擦、金属、间接光遮....
}
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/Debugging3D.hlsl"
方法:CanDebugOverrideOutputColor、CalculateColorForDebugMaterial看起来都是debug用的方法
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GlobalIllumination.hlsl"
方法:SampleProbeVolumePixel、SampleLightmap、GlossyEnvironmentReflection、GlobalIllumination都是一些全局照明所需要的方法
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
定义Light结构、方法:灯光衰减DistanceAttenuation、GetMainLight等
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/AmbientOcclusion.hlsl"
定义AmbientOcclusionFactor结构,GetScreenSpaceAmbientOcclusion屏幕空间环境光遮挡
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl" 看起来是贴花相关的东西
*/
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
//只是声明深度图,附带采样、读取方法SampleSceneDepth、LoadSceneDepth
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
//阴影相关,定义ShadowSamplingData结构体,GetMainLightShadowSamplingData、GetMainLightShadowParams、SampleShadowmap、ApplyShadowBias
/*
像这样做就是放在常量缓冲区,下面这种做法是unity宏,确保在支持时使用它们
cbuffer UnityPerFrame {
float4x4 unity_MatrixVP;
};
*/
CBUFFER_START(UnityPerMaterial)
float3 _HeadForward;
float3 _HeadRight;
sampler2D _BaseMap;
float4 _BaseMap_ST;
#if _AREA_FACE
sampler2D _FaceColorMap;
#elif _AREA_HAIR
sampler2D _HairColorMap;
#elif _AREA_UPPERBODY
sampler2D _UpperBodyColorMap;
#elif _AREA_LOWERBODY
sampler2D _LowerBodyColorMap;
#endif
float3 _FrontFaceTintColor;
float3 _BackFaceTintColor;
float _Alpha;
float _AlphaClip;
#if _AREA_HAIR
sampler2D _HairLightMap;
#elif _AREA_UPPERBODY
sampler2D _UpperBodyLightMap;
#elif _AREA_LOWERBODY
sampler2D _LowerBodyLightMap;
#endif
#if _AREA_HAIR
sampler2D _HairCoolRamp;
sampler2D _HairWarmRamp;
#elif _AREA_FACE || _AREA_UPPERBODY || _AREA_LOWERBODY
sampler2D _BodyCoolRamp;
sampler2D _BodyWarmRamp;
#endif
float _IndirectLightFlattenNormal;
float _IndirectLightUsage;
float _IndirectLightOcclusionUsage;
float _IndirectLightMixBaseColor;
float _MainLightColorUsage;
float _ShadowThresholdCenter;
float _ShadowThresholdSoftness;
float _ShadowRampOffset;
#if _AREA_FACE
sampler2D _FaceMap;
float _FaceShadowOffset;
float _FaceShadowTransitionSoftness;
#endif
#if _AREA_HAIR || _AREA_UPPERBODY || _AREA_LOWERBODY
float _SpecularExpon;
float _SpecularKsNonMetal;
float _SpecularKsMetal;
float _SpecularBrightness;
#endif
#if _AREA_UPPERBODY || _AREA_LOWERBODY
#if _AREA_UPPERBODY
sampler2D _UpperBodyStockings;
#elif _AREA_LOWERBODY
sampler2D _LowerBodyStockings;
#endif
float3 _StockingsDarkColor;
float3 _StockingsLightColor;
float3 _StockingsTransitionColor;
float _StockingsTransitionThreshold;
float _StockingsTransitionPower;
float _StockingsTransitionHardness;
float _StockingsTextureUsage;
#endif
float _RimLightWidth;
float _RimLightThreshold;
float _RimLightFadeout;
float3 _RimLightTintColor;
float _RimLightBrightness;
float _RimLightMixAlbedo;
#if _OUTLINE_ON
float _OutlineWidth;
float _OutlineGamma;
#endif
CBUFFER_END
#endif
SRUniversalDrawOutlinePass
struct Attributes
{
float3 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float4 color : COLOR;
float4 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float fogFactor : TEXCOORD1;
float4 color : TEXCOORD2;
};
float GetCameraFOV()
{
//https://answers.unity.com/questions/770838/how-can-i-extract-the-fov-information-from-the-pro.html
float t = unity_CameraProjection._m11;
float Rad2Deg = 180 / 3.1415;
float fov = atan(1.0f / t) * 2.0 * Rad2Deg;
return fov;
}
float ApplyOutlineDistanceFadeOut(float inputMulFix)
{
//make outline "fadeout" if character is too small in camera's view
return saturate(inputMulFix);
}
float GetOutlineCameraFovAndDistanceFixMultiplier(float positionVS_Z)
{
float cameraMulFix;
if(unity_OrthoParams.w == 0)
{
// Perspective camera case
// keep outline similar width on screen accoss all camera distance
cameraMulFix = abs(positionVS_Z);
// can replace to a tonemap function if a smooth stop is needed
cameraMulFix = ApplyOutlineDistanceFadeOut(cameraMulFix);
// keep outline similar width on screen accoss all camera fov
cameraMulFix *= GetCameraFOV();
}
else
{
// Orthographic camera case
float orthoSize = abs(unity_OrthoParams.y);
orthoSize = ApplyOutlineDistanceFadeOut(orthoSize);
cameraMulFix = orthoSize * 50; // 50 is a magic number to match perspective camera's outline width
}
return cameraMulFix * 0.00005; // mul a const to make return result = default normal expand amount WS
}
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
VertexPositionInputs vertexPositionInput = GetVertexPositionInputs(input.positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
float width = _OutlineWidth;
width *= GetOutlineCameraFovAndDistanceFixMultiplier(vertexPositionInput.positionVS.z);
float3 positionWS = vertexPositionInput.positionWS;
positionWS += vertexNormalInput.normalWS * width;
output.positionCS = TransformWorldToHClip(positionWS);
output.uv = TRANSFORM_TEX(input.uv, _BaseMap); // 加偏移
output.fogFactor = ComputeFogFactor(vertexPositionInput.positionCS.z);
return output;
}
float4 frag(Varyings input) : SV_TARGET
{
//描边加颜色,用的采样出来的Ramp
float3 coolRamp = 0;
float warmRamp = 0;
#if _AREA_HAIR
float2 outlineUV = float2(0, 0.5);
coolRamp = tex2D(_HairCoolRamp, outlineUV).rgb;
warmRamp = tex2D(_HairWarmRamp, outlineUV).rgb;
#elif _AREA_UPPERBODY || _AREA_LOWERBODY
float4 lightMap = 0;
#if _AREA_UPPERBODY
lightMap = tex2D(_UpperBodyLightMap, input.uv);
#elif _AREA_LOWERBODY
lightMap = tex2D(_LowerBodyLightMap, input.uv);
#endif
float materialEnum = lightMap.a;
float materialEnumOffset = materialEnum + 0.0425;
float outlineUVy = lerp(materialEnumOffset, materialEnumOffset + 0.5 > 1 ? materialEnumOffset + 0.5 - 1 : materialEnumOffset + 0.5 , fmod((round(materialEnumOffset/0.0625) - 1)/2, 2));
float2 outlineUV = float2(0, outlineUVy);
coolRamp = tex2D(_BodyCoolRamp, outlineUV).rgb;
warmRamp = tex2D(_BodyWarmRamp, outlineUV).rgb;
#elif _AREA_FACE
float2 outlineUV = float2(0, 0.0625);
coolRamp = tex2D(_BodyCoolRamp, outlineUV).rgb;
warmRamp = tex2D(_BodyWarmRamp, outlineUV).rgb;
#endif
float3 ramp = lerp(coolRamp, warmRamp, 0.5);
float3 albedo = pow(saturate(ramp), _OutlineGamma);
float4 color = float4(albedo,1);
color.rgb = MixFog(color.rgb, input.fogFactor);
return color;
}
SRUniversalDrawCorePass
#ifndef _SR_UNIVERSAL_DRAW_CORE_PASS_INCLUDED
#define _SR_UNIVERSAL_DRAW_CORE_PASS_INCLUDED
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
float3 normalWS : TEXCOORD2;
float3 viewDirectionWS : TEXCOORD3;
float3 SH : TEXCOORD4;
float4 positionCS : SV_POSITION;
};
//去饱和方法
float3 desaturation(float3 colorIn)
{
float3 grayXfer = float3(0.3, 0.59, 0.11); // 心理学灰度因子
float grayf = dot(colorIn, grayXfer);
return float3(grayf, grayf, grayf);
}
struct Gradient
{
int colorsLength;
float4 colors[8];
};
//梯度颜色
Gradient GradientConstruct()
{
Gradient g;
g.colorsLength = 2;
g.colors[0] = float4(1,1,1,0);
g.colors[1] = float4(1,1,1,1);
g.colors[2] = float4(0,0,0,0);
g.colors[3] = float4(0,0,0,0);
g.colors[4] = float4(0,0,0,0);
g.colors[5] = float4(0,0,0,0);
g.colors[6] = float4(0,0,0,0);
g.colors[7] = float4(0,0,0,0);
return g;
}
//渐变采样方法
float3 SampleGradient(Gradient Gradient, float Time)
{
float3 tempColor = Gradient.colors[0].rgb;
for (int c = 1; c < Gradient.colorsLength; c++)
{
float colorPos = saturate((Time - Gradient.colors[c - 1].w) / (Gradient.colors[c].w - Gradient.colors[c - 1].w)) * step(c, Gradient.colorsLength - 1);
tempColor = lerp(tempColor, Gradient.colors[c].rgb, colorPos);
}
#ifdef UNITY_COLORSPACE_GAMMA
tempColor = LinearToSRGB(tempColor);
#endif
return tempColor;
}
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
//VertexPositionInputs和VertexNormalInputs两个结构体定义在Core.hlsl中,
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
/*
这两个方法在ShaderVariablesFunctions文件中,用于获取VertexPositionInputs和VertexNormalInputs,它们包括大部分需求的信息
struct VertexPositionInputs
{
float3 positionWS; // World space position
float3 positionVS; // View space position
float4 positionCS; // Homogeneous clip space position
{
input.positionCS.x:通常表示屏幕上的水平位置。其范围通常从0(屏幕的左边缘)到屏幕宽度减1(屏幕的右边缘,以像素为单位)。
input.positionCS.y:通常表示屏幕上的垂直位置。其范围通常从0(屏幕的顶部)到屏幕高度减1(屏幕的底部,以像素为单位)。
input.positionCS.z:通常表示片段在深度缓冲区中的深度值。其范围通常在0.0到1.0之间,表示从近裁剪平面到远裁剪平面的深度值。
input.positionCS.w:通常表示屏幕空间中的透视除法系数。在一般情况下,你不太会直接使用它来进行计算。
}
float4 positionNDC;// Homogeneous normalized device coordinates
{
positionNDC.x:通常表示裁剪坐标系中的X坐标,其范围从-1表示裁剪体积的左侧边界,到1表示裁剪体积的右侧边界。
positionNDC.y:通常表示裁剪坐标系中的Y坐标,其范围从-1表示裁剪体积的底部边界,到1表示裁剪体积的顶部边界。
positionNDC.z:通常表示裁剪坐标系中的Z坐标,其范围从-1表示裁剪体积的近裁剪平面,到1表示裁剪体积的远裁剪平面。
positionNDC.w:通常用于执行透视除法,将坐标从裁剪坐标系转换为标准化设备坐标系。它在顶点着色器中通常为非零值,但在片段着色器中可能会变为零,因为透视除法是在顶点着色器中执行的。
}
};
struct VertexNormalInputs
{
real3 tangentWS;
real3 bitangentWS;
float3 normalWS;
};
*/
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
/*
TRANSFORM_TEX这个宏定义在Macros.hlsl文件中,这个文件中还有还能多定义比如PI:3.1415926、LOG2_E:1.442695
#define TRANSFORM_TEX(tex, name) ((tex.xy) * name##_ST.xy + name##_ST.zw) 看起来不过是添加ST控制,不需要的话不做这个操作也可以,比如这里,_BaseMap不过是个白图
*/
output.positionWSAndFogFactor = float4(vertexInput.positionWS, ComputeFogFactor(vertexInput.positionCS.z)); // 做个组合w分量利用一下,省一点空间
output.normalWS = vertexNormalInput.normalWS;
output.viewDirectionWS = unity_OrthoParams.w == 0 ? GetCameraPositionWS() - vertexInput.positionWS : GetWorldToViewMatrix()[2].xyz;
/*
如果不是ortho,直接坐标相减计算视角向量,如果是ortho,GetWorldToViewMatrix返回的是float4x4 UNITY_MATRIX_V,
unity_OrthoParams这个量来自StdLib.hlsl文件,这里面也有关于PI的定义,看起来很多量都可以从这里拿
float4x4 unity_CameraProjection;
float4x4 unity_MatrixVP;
float4x4 unity_ObjectToWorld;
float4x4 unity_WorldToCamera;
float3 _WorldSpaceCameraPos;
float4 _ProjectionParams; // x: 1 (-1 flipped), y: near, z: far, w: 1/far
float4 unity_ColorSpaceLuminance;
float4 unity_DeltaTime; // x: dt, y: 1/dt, z: smoothDt, w: 1/smoothDt
float4 unity_OrthoParams; // x: width, y: height, z: unused, w: ortho ? 1 : 0
float4 _ZBufferParams; // x: 1-far/near, y: far/near, z: x/far, w: y/far or in case of a reversed depth buffer (UNITY_REVERSED_Z is 1) x = -1+far/near, y = 1, z = x/far, w = 1/far 这里看来是后者
float4 _ScreenParams; // x: width, y: height, z: 1+1/width, w: 1+1/height
float4 _Time; // x: t/20, y: t, z: t*2, w: t*3
float4 _SinTime; // x: sin(t/20), y: sin(t), z: sin(t*2), w: sin(t*3)
float4 _CosTime; // x: cos(t/20), y: cos(t), z: cos(t*2), w: cos(t*3)
还有一些方法GradientNoise、LinearEyeDepth。也定义了TRANSFORM_TEX,不止一个地方定义过这个呢
*/
output.SH = SampleSH(lerp(vertexNormalInput.normalWS, float3(0,0,0), _IndirectLightFlattenNormal)); // 球谐函数,就是传入法线返回unity保存好的漫反射数据中对应位置的颜色,这里加了参数控制,因为卡渲有时不需要太多细节
/*
half3 SampleSH(half3 normalWS)
{
// LPPV is not supported in Ligthweight Pipeline
real4 SHCoefficients[7];
SHCoefficients[0] = unity_SHAr;
SHCoefficients[1] = unity_SHAg;
SHCoefficients[2] = unity_SHAb;
SHCoefficients[3] = unity_SHBr;
SHCoefficients[4] = unity_SHBg;
SHCoefficients[5] = unity_SHBb;
SHCoefficients[6] = unity_SHC;
return max(half3(0, 0, 0), SampleSH9(SHCoefficients, normalWS));
}
*/
output.positionCS = vertexInput.positionCS;
return output;
}
float4 frag(Varyings input, bool isFrontFace : SV_IsFrontFace): SV_TARGET
{
float3 positionWS = input.positionWSAndFogFactor.xyz;
float4 shadowCoord = TransformWorldToShadowCoord(positionWS);
Light mainLight = GetMainLight(shadowCoord);
float3 lightDirectionWS = normalize(mainLight.direction);
float3 normalWS = normalize(input.normalWS);
float3 viewDirectionWS = normalize(input.viewDirectionWS);
float3 baseColor = tex2D(_BaseMap, input.uv); // baseColor是纯白画布
float4 areaMap = 0;
#if _AREA_FACE
areaMap = tex2D(_FaceColorMap, input.uv);
#elif _AREA_HAIR
areaMap = tex2D(_HairColorMap, input.uv);
#elif _AREA_UPPERBODY
areaMap = tex2D(_UpperBodyColorMap, input.uv);
#elif _AREA_LOWERBODY
areaMap = tex2D(_LowerBodyColorMap, input.uv);
#endif
baseColor = areaMap.rgb;
//baseColor *= lerp((1,1,1), (1,1,1), 0.5);
baseColor *= lerp(_BackFaceTintColor, _FrontFaceTintColor, isFrontFace);
float4 lightMap = 0;
#if _AREA_HAIR || _AREA_UPPERBODY || _AREA_LOWERBODY
{
#if _AREA_HAIR
lightMap = tex2D(_HairLightMap, input.uv);
#elif _AREA_UPPERBODY
lightMap = tex2D(_UpperBodyLightMap, input.uv);
#elif _AREA_LOWERBODY
lightMap = tex2D(_LowerBodyLightMap, input.uv);
#endif
}
#endif
float4 faceMap = 0;
#if _AREA_FACE
faceMap = tex2D(_FaceMap, input.uv);
#endif
//-----------------------------------------------------------------------------------------------------------------
//间接光
float3 indirectLightColor = input.SH.rgb * _IndirectLightUsage;
// 添加光照图细节
#if _AREA_HAIR || _AREA_UPPERBODY || _AREA_LOWERBODY
indirectLightColor *= lerp(1, lightMap.r, _IndirectLightOcclusionUsage);
#elif _AREA_FACE
indirectLightColor *= lerp(1, lerp(faceMap.g, 1, step(faceMap.r, 0.01)), _IndirectLightOcclusionUsage);
/*
注意,step是后面值小于前面值,返回0,反之返回1,别想反了
step(faceMap.r, 0.01)分出来是否受距离影响的区域 根据图片,不受距离影响的区域即r通道有值的部分:为嘴巴,眼睛,眉毛等。值为0,反之受影响的为1
即lerp(faceMap.g, 1, step(faceMap.r, 0.01))不受距离影响地方r通道有值的部分:用的是faceMap.g的值,受距离影响的r通道没有值的部分是1,也就是正常漫反射光
但是g通道有一部分本身即是1,那么根据rg通道的差异,得出的r通道覆盖的区域减去g通道覆盖的区域,也就是只有口部分是0其他部分全为1,这里做这么多只是为了筛选出口部分
*/
#endif
indirectLightColor *= lerp(1, baseColor, _IndirectLightMixBaseColor);
//-----------------------------------------------------------------------------------------------------------------
//主光
float mainLightShadow = 1;
float3 mainLightColor = lerp(desaturation(mainLight.color), mainLight.color, _MainLightColorUsage); // 这里做了降饱和插值提升效果,不然直接=mainLight.color;就行
#if _AREA_HAIR || _AREA_UPPERBODY || _AREA_LOWERBODY
{
float NoL = dot(normalWS, lightDirectionWS); // 计算法相和主光向量的dot [-1, 1]
float remapNoL = NoL * 0.5 + 0.5; // [0, 1]
mainLightShadow = smoothstep(1 - lightMap.g + _ShadowThresholdCenter - _ShadowThresholdSoftness, 1 - lightMap.g + _ShadowThresholdCenter + _ShadowThresholdSoftness, remapNoL); // 二值化朗伯特
// 在光照图的g通道,有很多衣服上阴影的细节,接下来添加上去
mainLightShadow *= lightMap.r;
// 光照图的r通道,用于标识一些点不亮的也就是所谓的AO区域,直接乘上去,头发上的蝴蝶结就是点不亮的标识区域
}
#elif _AREA_FACE
{
float3 headForward = normalize(_HeadForward);
float3 headRight = normalize(_HeadRight);
float3 headUp = cross(headForward, headRight);
float3 fixedLightDirectionWS = normalize(lightDirectionWS - dot(lightDirectionWS, headUp) * headUp); // 看起来是投影,把主光源的光照方向投影在垂直于headUp的平面上
/*
投影到垂直于headUp的平面上,ws-up*(|ws.y|/|up|)
因为ws为单位向量,所以|ws.y| = cosθ、|up| = 1
所以简化为ws-up*cosθ。而cosθ= dot(lightDirectionWS, headUp)
故求出投影到垂直于headUp的平面上的向量
*/
float2 sdfUV = float2(sign(dot(fixedLightDirectionWS, headRight)), 1) * float2(-1, 1) * input.uv; // 判断光照在左脸(负)还是右脸(正) float2(-1, 1)是因为sdf图应该左白右黑,所以反向
/*
float2(sign(dot(fixedLightDirectionWS, headRight)), 1)如果光照方向是右半就是float2(1,1),反之float2(-1,1)。只需要处理x是1还是-1,因为按照脸部中心对称
但是这张图是左右反过来的,所以我们再反一次* float2(-1, 1),最后* input.uv。算出脸部修正uv
但是在光和headRight夹角为90时,也就是光从正后方打来时,看cos曲线为0,由于sign的特性(-1,0,1),也就是说sdfUV的x永远为0
*/
float sdfValue = tex2D(_FaceMap, sdfUV).a; // 如果是光和headRight夹角为90时,看那张图的a通道,采样的都是最左边白色,都是1,所以即使阈值是1也没办法奈何他
// 然后用这个脸部修正uv采样sdf图获取sdf值
float sdfThreshold = 1 - (dot(fixedLightDirectionWS, headForward) * 0.5 + 0.5); //主光越接近正面,阈值越接近0,阈值越低表示越容易被点亮 [0,1]
sdfThreshold += _FaceShadowOffset; // 所以为了限制光和headRight夹角为90时sdfUV的x永远为0,采样的都是最左边白色,都是1的情况,把阈值做个小小的偏移,加上一点点0.01就好,只要超过1就行
float sdf = smoothstep(sdfThreshold - _FaceShadowTransitionSoftness, sdfThreshold + _FaceShadowTransitionSoftness, sdfValue);
mainLightShadow = lerp(faceMap.g, sdf, step(faceMap.r, 0.01)); // sdf不应该影响ao区域,
}
#endif
//-----------------------------------------------------------------------------------------------------------------
//Ramp
//计算uv
float2 rampUV;
int rampRowIndex = 0;
int rampRowNum = 1;
#if _AREA_HAIR
{
rampRowIndex = 0;
rampRowNum = 1;
}
#elif _AREA_UPPERBODY || _AREA_LOWERBODY
{
int rawIndex = (round((lightMap.a + 0.0425)/0.0625) - 1)/2;
rampRowIndex = lerp(rawIndex, rawIndex + 4 < 8 ? rawIndex + 4 : rawIndex + 4 - 8, fmod(rawIndex, 2));
rampRowNum = 8;
}
#elif _AREA_FACE
{
rampRowIndex = 0;
rampRowNum = 8;
}
#endif
// 使用预规定的方式计算行数,用于计算采样uv的y坐标,x坐标使用阴影值
float rampUVy = (2 * rampRowIndex + 1) * (1.0 / (rampRowNum * 2));
float rampUVx = mainLightShadow * (1 - _ShadowRampOffset) + _ShadowRampOffset; // 做个映射,[0.75,1]这张图在0.85左右往后就是白色,我感觉不映射直接用mainLightShadow效果差异也不大
rampUV = float2(rampUVx, rampUVy);
//采样
float3 rampColor;
float3 coolRamp = 1;
float3 warmRamp = 1;
#if _AREA_HAIR
{
coolRamp = tex2D(_HairCoolRamp, rampUV).rgb;
warmRamp = tex2D(_HairWarmRamp, rampUV).rgb;
}
#elif _AREA_FACE || _AREA_UPPERBODY || _AREA_LOWERBODY
{
coolRamp = tex2D(_BodyCoolRamp, rampUV).rgb;
warmRamp = tex2D(_BodyWarmRamp, rampUV).rgb;
}
#endif
//根据白天夜晚插值冷暖色
float isDay = lightDirectionWS.y * 0.5 + 0.5;
rampColor = lerp(coolRamp, warmRamp, 1);
//-----------------------------------------------------------------------------------------------------------------
//修补主光源
float3 fixedMainLightColor = mainLightColor * baseColor * rampColor;
//-----------------------------------------------------------------------------------------------------------------
//高光
float3 specularColor = 0;
#if _AREA_HAIR || _AREA_UPPERBODY || _AREA_LOWERBODY
{
//布林冯,但是直接这样看起来太光滑
float3 halfVectorWS = normalize(viewDirectionWS + lightDirectionWS);
float NoH = dot(normalWS, halfVectorWS);
float blinnPhong = pow(saturate(NoH), _SpecularExpon);
//用光照图的蓝色通道作为阈值,超过阈值才会产生高光 这里金属和非金属分别处理
//非金属 反射率Ks,固定0.04
float nonMetalSpecular = step(1.0 - blinnPhong, lightMap.b) * _SpecularKsNonMetal;
//金属 反射率都比较大且差异较大,蓝色通道控制各个金属部分差异
float metalSpecular = blinnPhong * lightMap.b * _SpecularKsMetal;
//得有一个lerp控制什么时候是金属什么时候是非金属,在光照图的阿尔法通道,0.52灰度值表示金属
//找出金属部分,metallic越接近于0就越靠近金属
float metallic = 0;
#if _AREA_UPPERBODY || _AREA_LOWERBODY
{
metallic = saturate( (1 - 10 * abs(lightMap.a - 0.52)) ); // 金属影响系数,暂定10
}
#endif
specularColor = lerp(nonMetalSpecular, metalSpecular * baseColor, metallic);
specularColor *= mainLight.color;
specularColor *= _SpecularBrightness;
}
#endif
//-----------------------------------------------------------------------------------------------------------------
//黑丝
float3 stockingsEffect = 1;
#if _AREA_UPPERBODY || _AREA_LOWERBODY
{
//红通道是遮罩,绿通道是丝的透光度,蓝通道是丝的细节,uv放大一定倍数采样可以提升细节量
//采样
float2 stockingsMapRG = 0;
float stockingsMapB = 0;
#if _AREA_UPPERBODY
{
stockingsMapRG = tex2D(_UpperBodyStockings, input.uv).rg;
stockingsMapB = tex2D(_UpperBodyStockings, input.uv * 20).b;
}
#elif _AREA_LOWERBODY
{
stockingsMapRG = tex2D(_LowerBodyStockings, input.uv).rg;
stockingsMapB = tex2D(_LowerBodyStockings, input.uv * 20).b;
}
#endif
//混入细节
float NoV = dot(normalWS, viewDirectionWS);
//都不过是为了加控制
float fac = pow(saturate(NoV), _StockingsTransitionPower);;
fac = saturate( (fac - _StockingsTransitionHardness/2) / (1 - _StockingsTransitionHardness) );
fac = fac * (stockingsMapB * _StockingsTextureUsage + (1 - _StockingsTextureUsage));
fac = lerp(fac, 1, stockingsMapRG.g);
//构造颜色曲线
Gradient curve = GradientConstruct();
curve.colorsLength = 3;
curve.colors[0] = float4(_StockingsDarkColor, 0);
curve.colors[1] = float4(_StockingsTransitionColor, _StockingsTransitionThreshold);
curve.colors[2] = float4(_StockingsLightColor, 1);
//采样渐变
float3 stockingsColor = SampleGradient(curve, fac);
//加遮罩
stockingsEffect = lerp(1, stockingsColor, stockingsMapRG.r);
}
#endif
//-----------------------------------------------------------------------------------------------------------------
//鼻尖的描边
float fakeOutlineEffect = 0;
float3 fakeOutlineColor = 0;
#if _AREA_FACE && _OUTLINE_ON
{
float4 faceMap = tex2D(_FaceMap, input.uv);
float fakeOutline = faceMap.b;
float3 headForward = normalize(_HeadForward);
fakeOutlineEffect = smoothstep(0.0, 0.25, pow(saturate(dot(headForward, viewDirectionWS)), 20) * fakeOutline);
float2 outlineUV = float2(0, 0.0625);
float3 coolRamp = tex2D(_BodyCoolRamp, outlineUV).rgb;
float3 warmRamp = tex2D(_BodyWarmRamp, outlineUV).rgb;
float3 ramp = lerp(coolRamp, warmRamp, 0.5);
fakeOutlineColor = pow(ramp, _OutlineGamma);
}
#endif
//-----------------------------------------------------------------------------------------------------------------
//边缘光 打开URP深度图
float linearEyeDepth = LinearEyeDepth(input.positionCS.z, _ZBufferParams) / 10; // 离相机越近就越黑 正确
float3 normalVS = mul((float3x3)UNITY_MATRIX_V, normalWS); // 正确
float2 uvOffset = float2(sign(normalVS.x), 0) * _RimLightWidth / (1 + linearEyeDepth); // 正确
int2 loadTexPos = input.positionCS.xy + uvOffset * _ScaledScreenParams.xy; // 正确
float offsetSceneDepth = LoadSceneDepth(loadTexPos) * 5;
float offsetLinearEyeDepth = LinearEyeDepth(offsetSceneDepth, _ZBufferParams);
float rimLight = saturate(offsetLinearEyeDepth - (linearEyeDepth + _RimLightThreshold)) / _RimLightFadeout;
//这里模型的深度图因材质问题搞不定,放置了,之后再说吧
//-----------------------------------------------------------------------------------------------------------------
float3 albedo = 0;
albedo += indirectLightColor;
albedo += fixedMainLightColor;
albedo += specularColor;
albedo *= stockingsEffect;
albedo = lerp(albedo, fakeOutlineColor, fakeOutlineEffect);
float alpha = _Alpha;
//albedo = viewDirectionWS.rgb;
float4 finalColor = float4(albedo, alpha);
return finalColor;
}
#endif
SendVectorToShader脚本
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Mathematics;
using Unity.VisualScripting;
using UnityEngine;
public class SendVectorToShader : MonoBehaviour
{
public Transform HeadBoneTransform;
public Transform HeadForwardTransform;
public Transform HeadRightTransform;
private Renderer[] allRenderers;
private int HeadForwardID = Shader.PropertyToID("_HeadForward");
private int HeadRightID = Shader.PropertyToID("_HeadRight");
#if UNITY_EDITOR
private void OnValidate()
{
LateUpdate();
}
#endif
private void LateUpdate()
{
if(allRenderers == null)
{
allRenderers = GetComponentsInChildren<Renderer>(true);
}
Renderer tempRenderer;
for (int i = 0; i < allRenderers.Count(); i++)
{
tempRenderer = allRenderers[i];
foreach(Material tempMaterial in tempRenderer.sharedMaterials)
{
if (tempMaterial.shader)
{
if(tempMaterial.shader.name == "Unlit/SRUniversal")
{
tempMaterial.SetVector(HeadForwardID, HeadForwardTransform.position - HeadBoneTransform.position);
tempMaterial.SetVector(HeadRightID, HeadRightTransform.position - HeadBoneTransform.position);
}
}
}
}
}
}
cg/hlsl语法链接:
Unity URP CG/HLSL精简规范总结_凯尔315的博客-CSDN博客
unitypackage资源链接:
https://download.csdn.net/download/qq_55895529/88370041?spm=1001.2014.3001.5503
原作视频链接:
【Unity/虚幻5/Blender】3种引擎 崩坏: 星穹铁道风格 卡通渲染 从球谐光照到眉毛透过刘海 完整流程_哔哩哔哩_bilibili