1+ //// ACiiL
2+ //// Citations in readme and in source.
3+ //// https://github.com/ACIIL/ACLS-Shader
4+ #include "./ACLS_HELPERS.cginc"
5+
6+ uniform sampler2D _Outline_Sampler; uniform float4 _Outline_Sampler_ST;
7+ uniform Texture2D _MainTex; uniform float4 _MainTex_ST;
8+ uniform Texture2D _OutlineTex; uniform float4 _OutlineTex_ST;
9+ // uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
10+ // uniform sampler2D _OutlineTex; uniform float4 _OutlineTex_ST;
11+
12+ SamplerState sampler_MainTex_trilinear_repeat;
13+
14+ uniform half _shadowCastMin_black;
15+ uniform float4 _Color;
16+ uniform float4 _Outline_Color;
17+
18+ uniform int _outline_mode;
19+ uniform half _Outline_Width;
20+ uniform half _Farthest_Distance;
21+ uniform half _Nearest_Distance;
22+ uniform half _Is_BlendBaseColor;
23+ uniform half _Offset_Z;
24+ uniform int _Is_OutlineTex;
25+
26+ uniform half _indirectAlbedoMaxAveScale;
27+ uniform half _indirectGIDirectionalMix;
28+ uniform half _indirectGIBlur;
29+ uniform half _directLightIntensity;
30+ uniform half _forceLightClamp;
31+
32+
33+
34+ #ifndef NotAlpha
35+ uniform Texture2D _ClippingMask; uniform float4 _ClippingMask_ST;
36+ uniform half _Clipping_Level;
37+ uniform half _Tweak_transparency;
38+ uniform int _Inverse_Clipping;
39+ uniform int _IsBaseMapAlphaAsClippingMask;
40+ #endif
41+
42+
43+
44+ struct VertexInput {
45+ float4 vertex : POSITION ;
46+ float3 normal : NORMAL ;
47+ float2 texcoord0 : TEXCOORD0 ;
48+ UNITY_VERTEX_INPUT_INSTANCE_ID
49+ };
50+
51+ struct VertexOutput {
52+ float4 pos : SV_POSITION ;
53+ float4 worldPos : TEXCOORD0 ;
54+ float2 uv0 : TEXCOORD1 ;
55+ float3 wNormal : TEXCOORD2 ;
56+ float3 dirGI : TEXCOORD3 ;
57+ UNITY_SHADOW_COORDS (4 )
58+ // LIGHTING_COORDS(3,4)
59+ UNITY_FOG_COORDS (5 )
60+ half3 vertexLighting : TEXCOORD6 ;
61+ float outlineThick : TEXCOORD7 ;
62+ UNITY_VERTEX_INPUT_INSTANCE_ID
63+ UNITY_VERTEX_OUTPUT_STEREO
64+ };
65+
66+
67+
68+ //// vert
69+ VertexOutput vert (VertexInput v) {
70+ UNITY_SETUP_INSTANCE_ID (v);
71+ VertexOutput o;
72+ UNITY_INITIALIZE_OUTPUT (VertexOutput, o);
73+ UNITY_TRANSFER_INSTANCE_ID (v, o);
74+ UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO (o);
75+
76+ o.uv0 = v.texcoord0;
77+ o.wNormal = UnityObjectToWorldNormal ( v.normal);
78+ o.worldPos = mul ( unity_ObjectToWorld, v.vertex);
79+ // float3 worldviewPos = float4(0,1,0);
80+ float3 worldviewPos = _WorldSpaceCameraPos;
81+ // float3 worldviewPos = StereoWorldViewPos(); //// wrong stereo for offline offset
82+ float outlineControlTex = tex2Dlod (_Outline_Sampler, float4 (TRANSFORM_TEX (o.uv0, _Outline_Sampler), 0 , 0 )).r;
83+ o.outlineThick = outlineControlTex;
84+ float outlineWidth = saturate ( RemapRange ( (distance (o.worldPos.xyz, worldviewPos.xyz)),
85+ _Farthest_Distance, _Nearest_Distance, 0 , 1 ));
86+ outlineWidth *= outlineControlTex * _Outline_Width * 0.001 ;
87+ float3 posDiff = worldviewPos.xyz - o.worldPos.xyz;
88+ float3 dirView = normalize (posDiff);
89+ float4 viewDirectionVP = mul ( UNITY_MATRIX_VP, float4 ( dirView.xyz, 1 ));
90+ float4 posWorldHull = o.worldPos;
91+ posWorldHull = float4 (posWorldHull.xyz + o.wNormal * outlineWidth, 1 );
92+
93+ UNITY_TRANSFER_FOG (o, o.pos);
94+ UNITY_TRANSFER_FOG (o, UnityWorldToClipPos (posWorldHull));
95+ posWorldHull.xyz = posWorldHull.xyz + dirView * _Offset_Z;
96+ o.pos = UnityWorldToClipPos (posWorldHull);
97+ #ifdef VERTEXLIGHT_ON
98+ float3 vertTo0;
99+ o.vertexLighting = softShade4PointLights_Atten (
100+ unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0
101+ , unity_LightColor
102+ , unity_4LightAtten0
103+ , o.worldPos, o.wNormal, vertTo0);
104+ #endif
105+ #ifdef UNITY_PASS_FORWARDBASE
106+ o.dirGI = GIDominantDir ();
107+ #endif
108+ return o;
109+ }
110+
111+
112+
113+
114+
115+
116+ //// frag
117+ float4 frag (
118+ VertexOutput i,
119+ bool frontFace : SV_IsFrontFace ) : SV_Target {
120+ UNITY_SETUP_INSTANCE_ID (i);
121+ bool isAmbientOnlyMap = !(any (_LightColor0.rgb));
122+ bool isBackFace = !frontFace;
123+ //// dynamic shadow
124+ //// found dynamic shadows dont work in the spatiality of outline hulls.
125+ half shadowAtten = 1 ;
126+ #ifdef DIRECTIONAL
127+ half lightAtten = 1 ;
128+ #else
129+ UNITY_LIGHT_ATTENUATION_NOSHADOW (lightAtten, i, i.worldPos.xyz);
130+ #endif
131+
132+ //// world light albedo
133+ #ifdef UNITY_PASS_FORWARDBASE
134+ //// prepare cubemap albedo support lighting
135+ // half3 refGIcol = shadeSH9LinearAndWhole(float4(normalize(i.wNormal + dEnv.dirViewReflection),1)); //// gi light at a weird angle
136+ // half3 colGIGray = LinearRgbToLuminance_ac(refGIcol);
137+
138+ //// get vertex lighting
139+ half3 vertexLit = i.vertexLighting;
140+ //// build indirect light source
141+ half3 lightIndirectColAve = DecodeLightProbe_average (); //// L0 Average light
142+ half3 lightIndirectColL1 = max (0 , SHEvalDirectL1 (normalize (i.dirGI))); //// L1 raw. Add to L0 as max color of GI
143+ half3 lightIndirectColStatic = 0 , lightIndirectColDir = 0 ;
144+ // if ((_indirectGIDirectionalMix) < 1)
145+ if (true )
146+ {
147+ half3 stackIndirectMaxL0L1 = lightIndirectColL1 + lightIndirectColAve;
148+ half ratioCols = RatioOfColors (stackIndirectMaxL0L1, lightIndirectColAve, _indirectAlbedoMaxAveScale);
149+ lightIndirectColStatic = lerp (stackIndirectMaxL0L1, lightIndirectColAve, ratioCols);
150+ }
151+ if (_indirectGIDirectionalMix > 0 )
152+ {
153+ float4 indirectGIDirectionBlur = float4 (i.wNormal, (_indirectGIBlur + 0.001 ) );
154+ lightIndirectColDir = max (0 , ShadeSH9_ac (indirectGIDirectionBlur)) / (indirectGIDirectionBlur.w);
155+ }
156+ half3 lightIndirectCol = lerp (lightIndirectColStatic, lightIndirectColDir, _indirectGIDirectionalMix);
157+
158+ //// build direct, indirect
159+ half3 lightDirect = _LightColor0.rgb;
160+ half3 lightIndirectSource = (lightIndirectCol);
161+ half3 lightDirectSource = 0 ;
162+ if (isAmbientOnlyMap) //// this setup sucks for preserving Direct light effects
163+ {
164+ if (any (lightIndirectColL1)) //// L1 in pure ambient maps is black. Recover by spliting indirect energy.
165+ {
166+ lightDirectSource = lightIndirectColL1;
167+ }
168+ else
169+ {
170+ lightDirectSource = lightIndirectColAve * .2 ;
171+ lightIndirectSource = lightIndirectColAve * .7 ;
172+ }
173+ }
174+ else
175+ {
176+ lightDirectSource = lightDirect;
177+ }
178+ lightDirectSource = (lightDirectSource + vertexLit) * _directLightIntensity;
179+ lightIndirectSource += vertexLit;
180+
181+ #elif UNITY_PASS_FORWARDADD
182+ float3 lightDirect = _LightColor0.rgb;
183+ lightDirect *= lightAtten;
184+ //// out light source by types
185+ float3 lightDirectSource = lightDirect * _directLightIntensity;
186+ float3 lightIndirectSource = 0 ;
187+ #endif
188+
189+ //// simple light systems reused
190+ // half3 lightSimpleSystem = (lightDirectSource * shadowAtten) + lightIndirectSource;
191+ lightDirect = _LightColor0.rgb;
192+ #ifdef UNITY_PASS_FORWARDBASE
193+ half3 cubeMapAveAlbedo = ((lightDirect * max (_shadowCastMin_black,_LightShadowData.x) * .5 ) + lightDirect ) * .5 + lightIndirectSource;
194+ half lightAverageLum = LinearRgbToLuminance_ac (cubeMapAveAlbedo);
195+ #elif UNITY_PASS_FORWARDADD
196+ half3 cubeMapAveAlbedo = ((lightDirect * max (_shadowCastMin_black,_LightShadowData.x) * .5 ) + lightDirect) * .5 * lightAtten;
197+ half lightAverageLum = LinearRgbToLuminance_ac (cubeMapAveAlbedo);
198+ #endif
199+
200+ //// maintex
201+ UV_DD uv_toon = UVDD ( TRANSFORM_TEX ( i.uv0, _MainTex));
202+ float4 mainTex = _MainTex.SampleGrad (sampler_MainTex_trilinear_repeat, uv_toon.uv, uv_toon.dx, uv_toon.dy);
203+
204+ //// clip & alpha handling. Here so clip() may interrupt flow.
205+ if (!(i.outlineThick)) //// a black mask means nothing
206+ {
207+ clip (-1 );
208+ }
209+ #ifndef NotAlpha
210+ half4 clipMask = _ClippingMask.Sample (sampler_MainTex_trilinear_repeat, TRANSFORM_TEX (i.uv0, _ClippingMask));
211+ half useMainTexAlpha = (_IsBaseMapAlphaAsClippingMask) ? mainTex.a : clipMask.r;
212+ half alpha = (_Inverse_Clipping) ? (1.0 - useMainTexAlpha) : useMainTexAlpha;
213+
214+ half clipTest = (alpha - _Clipping_Level);
215+ clip (clipTest);
216+
217+ #ifndef IsClip
218+ alpha = saturate (alpha + _Tweak_transparency);
219+ #ifdef UseAlphaDither
220+ // dither pattern with some a2c blending.
221+ //// citation to Silent and Xiexe for guidance and research documentation.
222+ //// assumes cutout blending + alpha to coverage. Subtracted alpha must return.
223+ float dither = ScreenDitherToAlphaCutout_ac (screenUV.xy, (1 - alpha));
224+ alpha = alpha - dither;
225+ clip (alpha);
226+ #endif //// UseAlphaDither
227+ alpha = saturate (alpha);
228+ #else //// IsClip
229+ alpha = 1 ;
230+ #endif //// IsClip
231+ #else //// NotAlpha
232+ float alpha = 1 ;
233+ #endif //// NotAlpha
234+
235+ //// albedo mixer
236+ float4 outlineTex = _OutlineTex.SampleGrad (sampler_MainTex_trilinear_repeat, uv_toon.uv, uv_toon.dx, uv_toon.dy);
237+ // float4 outlineTex = tex2D( _OutlineTex, TRANSFORM_TEX( i.uv0, _OutlineTex));
238+ float3 outlineColor = _Outline_Color.rgb;
239+ UNITY_BRANCH
240+ if (_Is_BlendBaseColor)
241+ {
242+ outlineColor *= mainTex.rgb;
243+ }
244+ UNITY_BRANCH
245+ if (_Is_OutlineTex)
246+ {
247+ outlineColor *= outlineTex.rgb;
248+ }
249+ outlineColor *= cubeMapAveAlbedo;
250+
251+ //// color proccessing
252+ if (_forceLightClamp)
253+ {
254+ float sceneIntensity = LinearRgbToLuminance_ac (lightDirectSource + lightIndirectSource); //// grab all light at max potencial
255+ if (sceneIntensity > 1.0 ) //// bloom defaults at > 1.1
256+ {
257+ outlineColor.rgb = outlineColor.rgb / sceneIntensity;
258+ }
259+ }
260+ if (!(_forceLightClamp)) /// non HDR self post pressing, like how Standard cheats on emission.
261+ {
262+ #ifndef UNITY_HDR_ON
263+ //// non HDR maps recurve
264+ float ExposureBias = 2 ;
265+ float3 curr = Uncharted2Tonemap (outlineColor.rgb * ExposureBias);
266+ float3 whiteScale = 1 / Uncharted2Tonemap (11.2 );
267+ outlineColor.rgb = curr * whiteScale;
268+ #endif
269+ }
270+
271+ UNITY_APPLY_FOG ( i.fogCoord, outlineColor);
272+ float4 outlineColorA = float4 (outlineColor, alpha);
273+ return outlineColorA;
274+ }
0 commit comments