//-------------------------------------------------------------------------------------------------------------------------------- // Cartoon FX // (c) 2012-2020 Jean Moreno //-------------------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------------------- // UBERSHADER //-------------------------------------------------------------------------------------------------------------------------------- #if defined(CFXR_UBERSHADER) #if defined(UNITY_SAMPLE_FULL_SH_PER_PIXEL) #undef UNITY_SAMPLE_FULL_SH_PER_PIXEL #endif #define UNITY_SAMPLE_FULL_SH_PER_PIXEL defined(_NORMALMAP) #include "UnityCG.cginc" #include "UnityStandardUtils.cginc" #include "AutoLight.cginc" #if defined(CFXR_URP) #include "CFXR_URP.cginc" #else #include "UnityLightingCommon.cginc" #endif #if defined(_CFXR_LIGHTING_INDIRECT) || defined(_CFXR_LIGHTING_DIRECT) || defined(_CFXR_LIGHTING_ALL) #define LIGHTING #endif #if defined(_CFXR_LIGHTING_DIRECT) || defined(_CFXR_LIGHTING_ALL) #define LIGHTING_DIRECT #endif #if defined(_CFXR_LIGHTING_INDIRECT) || defined(_CFXR_LIGHTING_ALL) #define LIGHTING_INDIRECT #endif #if (defined(_CFXR_LIGHTING_DIRECT) || defined(_CFXR_LIGHTING_ALL)) && defined(_CFXR_LIGHTING_BACK) #define LIGHTING_BACK #endif #include "CFXR_SETTINGS.cginc" // -------------------------------- CBUFFER_START(UnityPerMaterial) float4 _OverlayTex_Scroll; half _BumpScale; float4 _GameObjectWorldPosition; half _LightingWorldPosStrength; half _IndirectLightingMix; half4 _ShadowColor; half _DirectLightingRamp; half _DirLightScreenAtten; half _BacklightTransmittance; half _InvertDissolveTex; half _DoubleDissolve; half2 _DissolveScroll; half _DissolveSmooth; half4 _DistortScrolling; half _Distort; half _FadeAlongU; half _SecondColorSmooth; half _HdrMultiply; half _ReceivedShadowsStrength; half _Cutoff; half _SoftParticlesFadeDistanceNear; half _SoftParticlesFadeDistanceFar; half _EdgeFadePow; half4 _DissolveTex_ST; #if !defined(SHADER_API_GLES) float _ShadowStrength; float4 _DitherCustom_TexelSize; #endif CBUFFER_END sampler2D _MainTex; sampler2D _OverlayTex; sampler2D _BumpMap; sampler2D _DissolveTex; sampler2D _DistortTex; sampler2D _SecondColorTex; // sampler2D _GradientMap; UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); #if !defined(SHADER_API_GLES) sampler3D _DitherMaskLOD; sampler3D _DitherCustom; #endif // -------------------------------- // Input/output struct appdata { float4 vertex : POSITION; half4 color : COLOR; float4 texcoord : TEXCOORD0; //xy = uv, zw = random float4 texcoord1 : TEXCOORD1; //additional particle data: x = dissolve, y = animFrame float4 texcoord2 : TEXCOORD2; //additional particle data: second color #if defined(PASS_SHADOW_CASTER) || _CFXR_EDGE_FADING || defined(LIGHTING) float3 normal : NORMAL; #endif #if defined(LIGHTING) && _NORMALMAP float4 tangent : TANGENT; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; // vertex to fragment struct v2f { float4 pos : SV_POSITION; half4 color : COLOR; float4 uv_random : TEXCOORD0; //uv + particle data float4 custom1 : TEXCOORD1; //additional particle data #if _CFXR_SECONDCOLOR_LERP || _CFXR_FONT_COLORS || (defined(LIGHTING) && _EMISSION) float4 secondColor : TEXCOORD2; #endif #if !defined(GLOBAL_DISABLE_SOFT_PARTICLES) && ((defined(SOFTPARTICLES_ON) || defined(CFXR_URP) || defined(SOFT_PARTICLES_ORTHOGRAPHIC)) && defined(_FADING_ON)) float4 projPos : TEXCOORD3; #endif #if defined(LIGHTING_DIRECT) || (defined(LIGHTING_INDIRECT) && _NORMALMAP) float3 worldPos : TEXCOORD4; #endif #if defined(LIGHTING_INDIRECT) && !_NORMALMAP float3 shColor : TEXCOORD5; #endif #if defined(LIGHTING_DIRECT) && defined(LIGHTING_BACK) float3 viewDirWS : TEXCOORD6; #endif #if defined(_CFXR_LIGHTING_WPOS_OFFSET) && (defined(LIGHTING_DIRECT) || defined(LIGHTING_INDIRECT)) float3 worldPosDiff : TEXCOORD7; #endif #if !defined(PASS_SHADOW_CASTER) UNITY_FOG_COORDS(8) //note: does nothing if fog is not enabled // SHADOW_COORDS(8) #endif #if defined(LIGHTING) float3 normalWS : NORMAL; #if _NORMALMAP float4 tangentWS : TANGENT; #endif #endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // vertex to fragment (shadow caster) struct v2f_shadowCaster { V2F_SHADOW_CASTER_NOPOS half4 color : COLOR; float4 uv_random : TEXCOORD1; //uv + particle data float4 custom1 : TEXCOORD2; //additional particle data UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // -------------------------------- #include "CFXR.cginc" // -------------------------------- // Vertex #if defined(PASS_SHADOW_CASTER) void vertex_program (appdata v, out v2f_shadowCaster o, out float4 opos : SV_POSITION) #else v2f vertex_program (appdata v) #endif { #if !defined(PASS_SHADOW_CASTER) v2f o = (v2f)0; #if defined(CFXR_URP) o = (v2f)0; #else UNITY_INITIALIZE_OUTPUT(v2f, o); #endif #else o = (v2f_shadowCaster)0; #endif UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); #if !defined(PASS_SHADOW_CASTER) o.pos = UnityObjectToClipPos(v.vertex); #if defined(LIGHTING_DIRECT) || (defined(LIGHTING_INDIRECT) && _NORMALMAP) // Particle Systems already output their vertex position in world space o.worldPos = v.vertex.xyz; #if defined(LIGHTING_BACK) o.viewDirWS = normalize(_WorldSpaceCameraPos.xyz - o.worldPos); //o.viewDirWS = normalize(mul((float3x3)unity_ObjectToWorld, v.vertex.xyz)); #endif #endif #if defined(LIGHTING) && defined(_CFXR_LIGHTING_WPOS_OFFSET) o.worldPosDiff = _GameObjectWorldPosition.xyz - v.vertex.xyz; #endif #endif o.color = GetParticleColor(v.color); o.custom1 = v.texcoord1; GetParticleTexcoords(o.uv_random.xy, o.uv_random.zw, o.custom1.y, v.texcoord, v.texcoord1.y); //o.uv_random = v.texcoord; #if _CFXR_SECONDCOLOR_LERP || _CFXR_FONT_COLORS || (defined(LIGHTING) && _EMISSION) o.secondColor = v.texcoord2; #endif #if defined(LIGHTING) o.normalWS = v.normal.xyz; #if _NORMALMAP o.tangentWS = v.tangent; #endif #endif // Ambient Lighting / Light Probes, per-vertex if no normal map #if defined(LIGHTING_INDIRECT) && !_NORMALMAP half3 shColor = ShadeSHPerVertex(v.normal.xyz, half3(0,0,0)); o.shColor = shColor; #endif /* #if !defined(PASS_SHADOW_CASTER) // Shadows Receiving TRANSFER_SHADOW(o); #endif */ #if defined(PASS_SHADOW_CASTER) vert(v, o, opos); #else return vert(v, o); #endif } // -------------------------------- // Shade4PointLights Custom float3 CFXR_Shade4PointLights ( float4 lightPosX, float4 lightPosY, float4 lightPosZ, float3 lightColor0, float3 lightColor1, float3 lightColor2, float3 lightColor3, float4 lightAttenSq, float3 pos, float3 normal) { // to light vectors float4 toLightX = lightPosX - pos.x; float4 toLightY = lightPosY - pos.y; float4 toLightZ = lightPosZ - pos.z; // squared lengths float4 lengthSq = 0; lengthSq += toLightX * toLightX; lengthSq += toLightY * toLightY; lengthSq += toLightZ * toLightZ; // don't produce NaNs if some vertex position overlaps with the light lengthSq = max(lengthSq, 0.000001); // NdotL float4 ndotl = 0; ndotl += toLightX * normal.x; ndotl += toLightY * normal.y; ndotl += toLightZ * normal.z; ndotl = smoothstep(0.5 - _DirectLightingRamp * 0.5, 0.5 + _DirectLightingRamp * 0.5, ndotl * 0.5 + 0.5); // correct NdotL float4 corr = rsqrt(lengthSq); ndotl = max (float4(0,0,0,0), ndotl * corr); // attenuation float4 atten = 1.0 / (1.0 + lengthSq * lightAttenSq); float4 diff = ndotl * atten; // final color float3 col = 0; col += lightColor0 * diff.x; col += lightColor1 * diff.y; col += lightColor2 * diff.z; col += lightColor3 * diff.w; return col; } // -------------------------------- // Fragment #if defined(PASS_SHADOW_CASTER) float4 fragment_program (v2f_shadowCaster i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target #else half4 fragment_program (v2f i) : SV_Target #endif { UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); // ================================================================ // UV Distortion #if _CFXR_UV_DISTORTION #if _CFXR_UV2_DISTORTION float2 uvDistortion = tex2D(_DistortTex, i.custom1.xy * _DistortScrolling.zw + i.uv_random.zw + frac(_DistortScrolling.xy * _Time.yy)).rg; #else float2 uvDistortion = tex2D(_DistortTex, i.uv_random.xy * _DistortScrolling.zw + i.uv_random.zw + frac(_DistortScrolling.xy * _Time.yy)).rg; #endif #if _CFXR_UV_DISTORTION_ADD uvDistortion = i.uv_random.xy + (uvDistortion * 2.0 - 1.0) * _Distort; #else uvDistortion = lerp(i.uv_random.xy, uvDistortion, _Distort); #endif if (_FadeAlongU > 0) { uvDistortion = lerp(i.uv_random.xy, uvDistortion, i.uv_random.y * 0.5); } #define main_uv uvDistortion #else #define main_uv i.uv_random #endif // ================================================================ // Color & Alpha #if _CFXR_SINGLE_CHANNEL half4 mainTex = half4(1, 1, 1, tex2D(_MainTex, main_uv.xy).r); #else half4 mainTex = tex2D(_MainTex, main_uv.xy); #endif #ifdef _FLIPBOOK_BLENDING #if _CFXR_SINGLE_CHANNEL half4 mainTex2 = tex2D(_MainTex, i.uv_random.zw).r; #else half4 mainTex2 = tex2D(_MainTex, i.uv_random.zw); #endif mainTex = lerp(mainTex, mainTex2, i.custom1.y); #endif #if _CFXR_OVERLAYTEX_1X float2 timeOffset = frac(_Time.yy * _OverlayTex_Scroll.xy); float2 overlayUv = ((i.uv_random.xy + i.uv_random.zw) * _OverlayTex_Scroll.zz) + timeOffset; half4 overlay = tex2D(_OverlayTex, overlayUv).r; #elif _CFXR_OVERLAYTEX_2X float2 timeOffset = frac(_Time.yy * _OverlayTex_Scroll.xy); float2 overlayUv = ((i.uv_random.xy + i.uv_random.zw) * _OverlayTex_Scroll.zz) + timeOffset; half4 overlay = tex2D(_OverlayTex, overlayUv).r; overlayUv = ((i.uv_random.xy + i.uv_random.wz) * _OverlayTex_Scroll.ww) + timeOffset; half4 overlay2 = tex2D(_OverlayTex, overlayUv).r; mainTex.a *= (overlay.r + overlay2.r) / 2.0; #endif #if _CFXR_OVERLAYTEX_1X || _CFXR_OVERLAYTEX_2X #if _CFXR_OVERLAYBLEND_A mainTex.a *= overlay.r; #elif _CFXR_OVERLAYBLEND_RGB mainTex.rgb *= overlay.rgb; #else mainTex.rgba *= overlay.rgba; #endif #endif /* #if _CFXR_GRADIENTMAP mainTex.rgb = tex2D(_GradientMap, mainTex.a).rgb; #endif */ #if _CFXR_FONT_COLORS half3 particleColor = mainTex.b * i.color.rgb + mainTex.g * i.custom1.rgb + mainTex.r * i.secondColor.rgb; half particleAlpha = mainTex.a * i.color.a; #else half3 particleColor = mainTex.rgb * i.color.rgb; half particleAlpha = mainTex.a * i.color.a; #endif #if _CFXR_SECONDCOLOR_LERP half secondColorMap = tex2D(_SecondColorTex, i.uv_random.xy).r; float time = lerp(-_SecondColorSmooth, 1+_SecondColorSmooth, i.secondColor.a); secondColorMap = smoothstep(secondColorMap - _SecondColorSmooth, secondColorMap + _SecondColorSmooth, time); particleColor.rgb += i.secondColor.rgb * secondColorMap; #endif #if _CFXR_HDR_BOOST #ifdef UNITY_COLORSPACE_GAMMA _HdrMultiply = LinearToGammaSpaceApprox(_HdrMultiply); #endif particleColor.rgb *= _HdrMultiply * GLOBAL_HDR_MULTIPLIER; #endif /* #if !defined(PASS_SHADOW_CASTER) // Shadows Receiving half shadows = SHADOW_ATTENUATION(i); particleColor.rgb *= saturate(shadows + (1.0 - _ReceivedShadowsStrength)); #endif */ // ================================================================ // Lighting #if !defined(PASS_SHADOW_CASTER) #if defined(LIGHTING) half3 particleLighting = half3(0, 0, 0); #if defined(CFXR_URP) #define UNPACK_SCALE_NORMAL UnpackNormalScale float3 mainLightDir = _MainLightPosition.xyz; float3 mainLightColor = _MainLightColor.rgb; #else #define UNPACK_SCALE_NORMAL UnpackScaleNormal float3 mainLightDir = _WorldSpaceLightPos0.xyz; float3 mainLightColor = _LightColor0.rgb; #endif #if _NORMALMAP half3 normalTS = UnpackScaleNormal_CFXR(tex2D(_BumpMap, main_uv.xy), _BumpScale); // tangent space to world space: float sgn = i.tangentWS.w; // should be either +1 or -1 float3 bitangent = sgn * cross(i.normalWS.xyz, i.tangentWS.xyz); float3 normalWS = mul(normalTS, half3x3(i.tangentWS.xyz, bitangent.xyz, i.normalWS.xyz)); #else half3 normalWS = i.normalWS; #endif #if defined(_CFXR_LIGHTING_WPOS_OFFSET) normalWS = normalize(normalWS.xyz - i.worldPosDiff.xyz * _LightingWorldPosStrength); #endif #endif // - Direct #if defined(LIGHTING_DIRECT) // Main Directional half ndl = dot(normalWS, mainLightDir); ndl = smoothstep(0.5 - _DirectLightingRamp * 0.5, 0.5 + _DirectLightingRamp * 0.5, ndl * 0.5 + 0.5); half mainDirectLighting = max(0, ndl); #if defined(LIGHTING_BACK) half viewAtten = length(mainLightDir + i.viewDirWS); viewAtten = 1 - smoothstep(0, _DirLightScreenAtten, viewAtten); mainDirectLighting += (viewAtten * viewAtten) * _BacklightTransmittance; #endif // particleColor.rgb = lerp(_ShadowColor.rgb, particleColor.rgb * mainLightColor.rgb, mainDirectLighting); particleColor.rgb *= lerp(_ShadowColor.rgb, mainLightColor.rgb, mainDirectLighting); // Point Lights #if defined(ENABLE_POINT_LIGHTS) #if defined(CFXR_URP) uint additionalLightsCount = GetAdditionalLightsCount(); for (uint lightIndex = 0u; lightIndex < additionalLightsCount; ++lightIndex) { Light light = GetAdditionalLight(lightIndex, i.worldPos); half ndl = dot(normalWS, light.direction); ndl = smoothstep(0.5 - _DirectLightingRamp * 0.5, 0.5 + _DirectLightingRamp * 0.5, ndl * 0.5 + 0.5); ndl = max(0, ndl); #if defined(LIGHTING_BACK) half backNdl = dot(-normalWS, light.direction); backNdl = smoothstep(0.5 - _DirectLightingRamp * 0.5, 0.5 + _DirectLightingRamp * 0.5, backNdl * 0.5 + 0.5); ndl += max(0, backNdl) * _BacklightTransmittance; #endif particleColor.rgb += ndl * light.color.rgb * light.distanceAttenuation; } #else half3 pointLights = CFXR_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, i.worldPos, normalWS); #if defined(LIGHTING_BACK) // TODO Tweak CFXR_Shade4PointLights to handle both front & back lights more efficiently? pointLights += CFXR_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, i.worldPos, -normalWS) * _BacklightTransmittance; #endif particleColor.rgb += pointLights; #endif #endif #endif // - Indirect #if defined(LIGHTING_INDIRECT) #if _NORMALMAP half3 shColor = ShadeSHPerPixel(normalWS, half3(0,0,0), float3(0,0,0)); particleColor.rgb += shColor.rgb * _IndirectLightingMix; #else particleColor.rgb += i.shColor.rgb * _IndirectLightingMix; #endif #endif #if defined(LIGHTING) && _EMISSION particleColor.rgb += i.secondColor.rgb; #endif #endif // ================================================================ // Dissolve #if _CFXR_DISSOLVE #if _CFXR_DISSOLVE_ALONG_UV_X half dissolveOffset = tex2D(_DissolveTex, i.uv_random.xy * _DissolveTex_ST.xy + _DissolveTex_ST.zw + frac(_Time.yy * _DissolveScroll.xy)).r * 2.0 - 1.0; half dissolveTex = i.uv_random.x + dissolveOffset * i.custom1.z; #else half dissolveTex = tex2D(_DissolveTex, i.uv_random.xy).r; #endif dissolveTex = _InvertDissolveTex <= 0 ? 1 - dissolveTex : dissolveTex; half dissolveTime = i.custom1.x; half doubleDissolveWidth = 0; if (_DoubleDissolve > 0) doubleDissolveWidth = i.custom1.y; #else half dissolveTex = 0; half dissolveTime = 0; half doubleDissolveWidth = 0; #endif // ================================================================ // #if defined(PASS_SHADOW_CASTER) return frag(i, vpos, particleColor, particleAlpha, dissolveTex, dissolveTime, doubleDissolveWidth); #else return frag(i, particleColor, particleAlpha, dissolveTex, dissolveTime, doubleDissolveWidth); #endif } #endif //-------------------------------------------------------------------------------------------------------------------------------- // PROCEDURAL GLOW //-------------------------------------------------------------------------------------------------------------------------------- #if defined(CFXR_GLOW_SHADER) #include "UnityCG.cginc" #include "UnityStandardUtils.cginc" // -------------------------------- #include "CFXR_SETTINGS.cginc" // -------------------------------- CBUFFER_START(UnityPerMaterial) half _GlowMin; half _GlowMax; half _MaxValue; half _InvertDissolveTex; half _DissolveSmooth; half _HdrMultiply; half _Cutoff; half _SoftParticlesFadeDistanceNear; half _SoftParticlesFadeDistanceFar; half _EdgeFadePow; #if !defined(SHADER_API_GLES) float _ShadowStrength; float4 _DitherCustom_TexelSize; #endif CBUFFER_END sampler2D _DissolveTex; UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); #if !defined(SHADER_API_GLES) sampler3D _DitherMaskLOD; sampler3D _DitherCustom; #endif // -------------------------------- // Input/Output struct appdata { float4 vertex : POSITION; half4 color : COLOR; float4 texcoord : TEXCOORD0; //xy = uv, zw = random float4 texcoord1 : TEXCOORD1; //additional particle data: x = dissolve #if defined(PASS_SHADOW_CASTER) float3 normal : NORMAL; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; // vertex to fragment struct v2f { float4 pos : SV_POSITION; half4 color : COLOR; float4 uv_random : TEXCOORD0; //uv + particle data float4 custom1 : TEXCOORD1; //additional particle data #if !defined(GLOBAL_DISABLE_SOFT_PARTICLES) && ((defined(SOFTPARTICLES_ON) || defined(CFXR_URP) || defined(SOFT_PARTICLES_ORTHOGRAPHIC)) && defined(_FADING_ON)) float4 projPos : TEXCOORD2; #endif UNITY_FOG_COORDS(3) //note: does nothing if fog is not enabled UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // vertex to fragment (shadow caster) struct v2f_shadowCaster { V2F_SHADOW_CASTER_NOPOS half4 color : COLOR; float4 uv_random : TEXCOORD1; //uv + particle data float4 custom1 : TEXCOORD2; //additional particle data UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // -------------------------------- #include "CFXR.cginc" // -------------------------------- // Vertex #if defined(PASS_SHADOW_CASTER) void vertex_program (appdata v, out v2f_shadowCaster o, out float4 opos : SV_POSITION) #else v2f vertex_program (appdata v) #endif { #if !defined(PASS_SHADOW_CASTER) v2f o = (v2f)0; #if defined(CFXR_URP) o = (v2f)0; #else UNITY_INITIALIZE_OUTPUT(v2f, o); #endif #else o = (v2f_shadowCaster)0; #endif UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); #if !defined(PASS_SHADOW_CASTER) o.pos = UnityObjectToClipPos(v.vertex); #endif o.color = GetParticleColor(v.color); o.custom1 = v.texcoord1; GetParticleTexcoords(o.uv_random.xy, o.uv_random.zw, o.custom1.y, v.texcoord, v.texcoord1.y); //o.uv_random = v.texcoord; #if defined(PASS_SHADOW_CASTER) vert(v, o, opos); #else return vert(v, o); #endif } // -------------------------------- // Fragment #if defined(PASS_SHADOW_CASTER) float4 fragment_program (v2f_shadowCaster i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target #else half4 fragment_program (v2f i) : SV_Target #endif { UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); // ================================================================ // Color & Alpha //-------------------------------- // procedural glow float2 uvm = i.uv_random.xy - 0.5; half glow = saturate(1 - ((dot(uvm, uvm) * 4))); #if _CFXR_GLOW_POW_P2 glow = pow(glow, 2); #elif _CFXR_GLOW_POW_P4 glow = pow(glow, 4); #elif _CFXR_GLOW_POW_P8 glow = pow(glow, 8); #endif glow = clamp(lerp(_GlowMin, _GlowMax, glow), 0, _MaxValue) * saturate(glow * 30); half4 mainTex = half4(1, 1, 1, glow); //-------------------------------- #if _CFXR_HDR_BOOST #ifdef UNITY_COLORSPACE_GAMMA _HdrMultiply = LinearToGammaSpaceApprox(_HdrMultiply); #endif mainTex.rgb *= _HdrMultiply * GLOBAL_HDR_MULTIPLIER; #endif half3 particleColor = mainTex.rgb * i.color.rgb; half particleAlpha = mainTex.a * i.color.a; // ================================================================ // Dissolve #if _CFXR_DISSOLVE half dissolveTex = tex2D(_DissolveTex, i.uv_random.xy).r; dissolveTex = _InvertDissolveTex <= 0 ? 1 - dissolveTex : dissolveTex; half dissolveTime = i.custom1.x; #else half dissolveTex = 0; half dissolveTime = 0; #endif // ================================================================ // #if defined(PASS_SHADOW_CASTER) return frag(i, vpos, particleColor, particleAlpha, dissolveTex, dissolveTime, 0.0); #else return frag(i, particleColor, particleAlpha, dissolveTex, dissolveTime, 0.0); #endif } #endif //-------------------------------------------------------------------------------------------------------------------------------- // SCREEN DISTORTION SHADER //-------------------------------------------------------------------------------------------------------------------------------- #if defined(CFXR_SCREEN_DISTORTION_SHADER) #include "UnityCG.cginc" #if defined(CFXR_URP) #include "CFXR_URP.cginc" #endif #include "CFXR_SETTINGS.cginc" // -------------------------------- CBUFFER_START(UnityPerMaterial) half _ScreenDistortionScale; half _Cutoff; half _SoftParticlesFadeDistanceNear; half _SoftParticlesFadeDistanceFar; half _EdgeFadePow; CBUFFER_END sampler2D _ScreenDistortionTex; #if defined(CFXR_URP) sampler2D _CameraOpaqueTexture; #define SampleScreenTexture(uv) tex2Dproj(_CameraOpaqueTexture, uv) #else sampler2D _GrabTexture; #define SampleScreenTexture(uv) tex2Dproj(_GrabTexture, uv) #endif UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); // -------------------------------- // Input/output struct appdata { float4 vertex : POSITION; half4 color : COLOR; float4 texcoord : TEXCOORD0; //xy = uv, zw = random float4 texcoord1 : TEXCOORD1; //additional particle data: x = dissolve, y = animFrame float4 texcoord2 : TEXCOORD2; //additional particle data: second color #if _CFXR_EDGE_FADING float3 normal : NORMAL; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; // vertex to fragment struct v2f { float4 pos : SV_POSITION; half4 color : COLOR; float4 uv_random : TEXCOORD0; //uv + particle data float4 custom1 : TEXCOORD1; //additional particle data float4 grabPassPosition : TEXCOORD2; #if !defined(GLOBAL_DISABLE_SOFT_PARTICLES) && ((defined(SOFTPARTICLES_ON) || defined(CFXR_URP) || defined(SOFT_PARTICLES_ORTHOGRAPHIC)) && defined(_FADING_ON)) float4 projPos : TEXCOORD3; #endif #if !defined(PASS_SHADOW_CASTER) UNITY_FOG_COORDS(4) //note: does nothing if fog is not enabled #endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // -------------------------------- #include "CFXR.cginc" // -------------------------------- // Vertex v2f vertex_program (appdata v) { #if !defined(PASS_SHADOW_CASTER) v2f o = (v2f)0; #if defined(CFXR_URP) o = (v2f)0; #else UNITY_INITIALIZE_OUTPUT(v2f, o); #endif #else o = (v2f_shadowCaster)0; #endif UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); #if !defined(PASS_SHADOW_CASTER) o.pos = UnityObjectToClipPos(v.vertex); o.grabPassPosition = ComputeGrabScreenPos(o.pos); #endif o.color = GetParticleColor(v.color); o.custom1 = v.texcoord1; GetParticleTexcoords(o.uv_random.xy, o.uv_random.zw, o.custom1.y, v.texcoord, v.texcoord1.y); //o.uv_random = v.texcoord; return vert(v, o); } // -------------------------------- // Fragment half4 fragment_program (v2f i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); // ================================================================ // Screen Distortion half4 distortionTex = tex2D(_ScreenDistortionTex, i.uv_random.xy); half particleAlpha = i.color.a * distortionTex.b; half2 screenDistortion = (distortionTex.rg * 2.0 - 1.0) * _ScreenDistortionScale * particleAlpha; float4 grabPosUV = i.grabPassPosition; grabPosUV.xy += screenDistortion; half3 particleColor = SampleScreenTexture(grabPosUV).rgb; #if defined(_DEBUG_VISUALIZE_DISTORTION) return half4(distortionTex.rg, 0, particleAlpha); #endif #if defined(PASS_SHADOW_CASTER) return frag(i, vpos, particleColor, particleAlpha, dissolveTex, dissolveTime, 0.0); #else return frag(i, particleColor, particleAlpha, 0, 0, 0.0); #endif } #endif //-------------------------------------------------------------------------------------------------------------------------------- // PROCEDURAL RING SHADER //-------------------------------------------------------------------------------------------------------------------------------- #if defined(CFXR_PROCEDURAL_RING_SHADER) #include "UnityCG.cginc" #include "UnityStandardUtils.cginc" // -------------------------------- #include "CFXR_SETTINGS.cginc" // -------------------------------- CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; half _InvertDissolveTex; half _DissolveSmooth; half _HdrMultiply; float _RingTopOffset; half _Cutoff; half _SoftParticlesFadeDistanceNear; half _SoftParticlesFadeDistanceFar; half _EdgeFadePow; #if !defined(SHADER_API_GLES) float _ShadowStrength; float4 _DitherCustom_TexelSize; #endif CBUFFER_END sampler2D _MainTex; sampler2D _DissolveTex; UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); #if !defined(SHADER_API_GLES) sampler3D _DitherMaskLOD; sampler3D _DitherCustom; #endif // -------------------------------- // Input/Output struct appdata { float4 vertex : POSITION; half4 color : COLOR; float4 texcoord : TEXCOORD0; //uv + particle data float4 texcoord1 : TEXCOORD1; //additional particle data float4 texcoord2 : TEXCOORD2; //procedural ring data: x = width, y = smooth, z = rotation, w = particle size #if defined(PASS_SHADOW_CASTER) || _CFXR_WORLD_SPACE_RING float3 normal : NORMAL; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; // vertex to fragment struct v2f { float4 pos : SV_POSITION; half4 color : COLOR; float4 uv_uv2 : TEXCOORD0; //uv + particle data float4 ringData : TEXCOORD1; //procedural ring data float4 uvRing_uvCartesian : TEXCOORD2; #if !defined(GLOBAL_DISABLE_SOFT_PARTICLES) && ((defined(SOFTPARTICLES_ON) || defined(CFXR_URP) || defined(SOFT_PARTICLES_ORTHOGRAPHIC)) && defined(_FADING_ON)) float4 projPos : TEXCOORD3; #endif UNITY_FOG_COORDS(4) //note: does nothing if fog is not enabled #if _CFXR_DISSOLVE float4 custom1 : TEXCOORD5; #endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; // vertex to fragment (shadow caster) struct v2f_shadowCaster { V2F_SHADOW_CASTER_NOPOS half4 color : COLOR; float4 uv_uv2 : TEXCOORD1; //uv + particle data float4 ringData : TEXCOORD2; //procedural ring data float4 uvRing_uvCartesian : TEXCOORD3; #if _CFXR_DISSOLVE float4 custom1 : TEXCOORD4; #endif }; // -------------------------------- #include "CFXR.cginc" // -------------------------------- // Vertex #if defined(PASS_SHADOW_CASTER) void vertex_program (appdata v, out v2f_shadowCaster o, out float4 opos : SV_POSITION) #else v2f vertex_program (appdata v) #endif { #if !defined(PASS_SHADOW_CASTER) v2f o = (v2f)0; #if defined(CFXR_URP) o = (v2f)0; #else UNITY_INITIALIZE_OUTPUT(v2f, o); #endif #else o = (v2f_shadowCaster)0; #endif UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //-------------------------------- // procedural ring float ringWidth = v.texcoord2.x; float ringSmooth = v.texcoord2.y; float ringRotation = v.texcoord2.z; float particleSize = v.texcoord2.w; // avoid artifacts when vertex are pushed too much ringWidth = min(particleSize, ringWidth); // constants calculated per vertex o.ringData.x = pow(1 - ringWidth / particleSize, 2); o.ringData.y = 1 - _RingTopOffset; o.ringData.z = ringSmooth / particleSize; // smoothing depends on particle size o.ringData.w = ringRotation; // regular ring UVs float2 uv = v.texcoord.xy + float2(ringRotation, 0); o.uvRing_uvCartesian.xy = 1 - TRANSFORM_TEX(uv, _MainTex); #if _CFXR_WORLD_SPACE_RING // to clip space with width offset v.vertex.xyz = v.vertex.xyz - v.normal.xyz * v.texcoord.y * ringWidth; #if !defined(PASS_SHADOW_CASTER) o.pos = UnityObjectToClipPos(v.vertex); #endif #else // to clip space with width offset float4 m = mul(UNITY_MATRIX_V, v.vertex); m.xy += -v.texcoord.zw * v.texcoord.y * ringWidth; #if !defined(PASS_SHADOW_CASTER) o.pos = mul(UNITY_MATRIX_P, m); #endif #endif //------------------------------------------ /* //v.vertex.xy += -v.texcoord.zw * v.texcoord.y * ringWidth; v.vertex.xy += v.texcoord.zw * v.texcoord.y * 0.5; #if !defined(PASS_SHADOW_CASTER) o.pos = UnityObjectToClipPos(v.vertex); #endif */ //------------------------------------------ // calculate cartesian UVs to accurately calculate ring in fragment shader o.uvRing_uvCartesian.zw = v.texcoord.zw - v.texcoord.zw * v.texcoord.y * ringWidth / particleSize; //-------------------------------- o.color = v.color; o.uv_uv2 = v.texcoord; //-------------------------------- #if _CFXR_DISSOLVE o.custom1 = v.texcoord1; #endif #if defined(PASS_SHADOW_CASTER) vert(v, o, opos); #else return vert(v, o); #endif } // -------------------------------- // Fragment #if defined(PASS_SHADOW_CASTER) float4 fragment_program (v2f_shadowCaster i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target #else half4 fragment_program (v2f i) : SV_Target #endif { UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); // ================================================================ // Color & Alpha //-------------------------------- // procedural ring float b = i.ringData.x; // bottom float t = i.ringData.y; // top float smooth = i.ringData.z; // smoothing float gradient = dot(i.uvRing_uvCartesian.zw, i.uvRing_uvCartesian.zw); float ring = saturate( smoothstep(b, b + smooth, gradient) - smoothstep(t - smooth, t, gradient) ); #if _CFXR_RADIAL_UV // approximate polar coordinates float2 radialUv = float2 ( (atan2(i.uvRing_uvCartesian.z, i.uvRing_uvCartesian.w) / UNITY_PI) * 0.5 + 0.5 + 0.23 - i.ringData.w, (gradient * (1.0 / (t - b)) - (b / (t - b))) * 0.9 - 0.92 + 1 ); radialUv.xy = radialUv.xy * _MainTex_ST.xy + _MainTex_ST.zw; float dx = ddx(i.uvRing_uvCartesian.x); //float dy = ddx(i.uvRing_uvCartesian.x); #define TEX2D_MAIN_TEXCOORD(sampler) tex2Dgrad(sampler, radialUv, dx, dx) #else #define TEX2D_MAIN_TEXCOORD(sampler) tex2D(sampler, i.uvRing_uvCartesian.xy) #endif #if _CFXR_SINGLE_CHANNEL half4 mainTex = half4(1, 1, 1, TEX2D_MAIN_TEXCOORD(_MainTex).r); #else half4 mainTex = TEX2D_MAIN_TEXCOORD(_MainTex); #endif mainTex *= ring; //-------------------------------- half3 particleColor = mainTex.rgb * i.color.rgb; half particleAlpha = mainTex.a * i.color.a; #if _CFXR_HDR_BOOST #ifdef UNITY_COLORSPACE_GAMMA _HdrMultiply = LinearToGammaSpaceApprox(_HdrMultiply); #endif particleColor.rgb *= _HdrMultiply * GLOBAL_HDR_MULTIPLIER; #endif // ================================================================ // Dissolve #if _CFXR_DISSOLVE half dissolveTex = TEX2D_MAIN_TEXCOORD(_DissolveTex).r; dissolveTex = _InvertDissolveTex <= 0 ? 1 - dissolveTex : dissolveTex; half dissolveTime = i.custom1.x; #else half dissolveTex = 0; half dissolveTime = 0; #endif // ================================================================ // #if defined(PASS_SHADOW_CASTER) return frag(i, vpos, particleColor, particleAlpha, dissolveTex, dissolveTime, 0.0); #else return frag(i, particleColor, particleAlpha, dissolveTex, dissolveTime, 0.0); #endif } #endif