yum/3ner

A toon shader for Unity's BIRP.

git clone https://git.yummers.dev/yum/3ner

yumClanker vertex light supportf3918c9

master
9.4 KiB343 linesraw
1#ifndef __3NER_INC
2#define __3NER_INC
3
4#define INCLUDE_UNITY_STANDARD_BRDF_DEPRECATED
5#include "UnityStandardBRDF.cginc"
6#include "UnityDeprecated.cginc"
7#include "UnityCG.cginc"
8#include "UnityLightingCommon.cginc"
9#include "AutoLight.cginc"
10
11#include "brdf.cginc"
12#include "debug.cginc"
13#include "cnlohr.cginc"
14#include "geometry.cginc"
15#include "pbr.cginc"
16#include "lighting.cginc"
17#include "globals.cginc"
18#include "interpolators.cginc"
19#include "instancing.cginc"
20#include "late_pbr.cginc"
21#include "ray_marching.cginc"
22#include "vertex.cginc"
23
24v2f vert(appdata v) {
25#if defined(SHADOW_CASTER_PASS) && !defined(_SHADOW_CASTER)
26  return (v2f) asfloat(-1);
27#endif
28#if defined(OUTLINES_PASS) && !defined(_OUTLINES)
29  return (v2f) asfloat(-1);
30#endif
31
32  v2f o;
33  UNITY_SETUP_INSTANCE_ID(v);
34  UNITY_INITIALIZE_OUTPUT(v2f, o);
35  UNITY_TRANSFER_INSTANCE_ID(v, o);
36  UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
37
38#if defined(OUTLINES_PASS) && defined(_OUTLINES)
39  float thickness = _Outlines_Thickness.SampleLevel(point_repeat_s, v.uv0, 0).r;
40  v.vertex.xyz += v.normal * _Outlines_Width * thickness;
41#endif
42
43#if defined(_VERTEX_DEFORMATION) && ( \
44        defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || \
45        defined(_VERTEX_DEFORMATION_TESSELLATION))
46  o.objPos_orig = v.vertex;
47#endif
48
49  [branch] if (instance_distance_culling()) {
50    return (v2f) asfloat(-1);
51  }
52  instancing_vert(v);
53
54#if defined(_INSTANCE_TEXTURE_OFFSET) && defined(UNITY_INSTANCING_ENABLED)
55  // Early exit custom frustum culling.
56  float3 instanceCenter;
57  if (get_instance_center(instanceCenter)) {
58    float4 instanceClipPos = UnityObjectToClipPos(instanceCenter);
59    instanceClipPos /= instanceClipPos.w;
60    float k = 1.05;
61    if (any(instanceClipPos.xy < -k) || any(instanceClipPos.xy > k)) {
62      return (v2f) asfloat(-1);
63    }
64  }
65#endif
66
67#if defined(_TESSELLATION)
68  o.tpos = v.vertex;
69#endif
70  o.uv01.xy = v.uv0;
71  o.uv01.zw = v.uv1;
72  o.uv23.xy = v.uv2;
73  o.uv23.zw = v.uv3;
74  float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0));
75  o.objPos = v.vertex;
76#if defined(_RAY_MARCHING_BAKED_ORIGINS)
77  o.color = v.color;
78#endif
79
80  // Normal and tangent are in object space to allow for object-space
81  // vertex deformation logic later on. They are converted to world
82  // space inside the fragment shader.
83  o.normal = v.normal;
84  o.tangent = v.tangent;
85#if !defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS)
86  deform_normal(o.objPos, o.normal.xyz, o.tangent.xyz);
87#endif
88  deform(o.objPos);
89
90  propagateObjPos(o);
91
92  UNITY_TRANSFER_LIGHTING(o, v.uv1);
93  UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos);
94#if defined(SHADOW_CASTER_PASS)
95	TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);
96#else
97  TRANSFER_SHADOW(o);
98#endif
99
100  return o;
101}
102
103//ifex _Tessellation_Enabled==0
104struct tess_factors {
105  float edge[3] : SV_TessFactor;
106  float inside : SV_InsideTessFactor;
107};
108
109bool cullPatch(float4 p0, float4 p1, float4 p2, float bias) {
110  return
111    (p0.x < -p0.w - bias && p1.x < -p1.w - bias && p2.x < -p2.w - bias) ||
112    (p0.x > p0.w + bias && p1.x > p1.w + bias && p2.x > p2.w + bias) ||
113    (p0.y < -p0.w - bias && p1.y < -p1.w - bias && p2.y < -p2.w - bias) ||
114    (p0.y > p0.w + bias && p1.y > p1.w + bias && p2.y > p2.w + bias) ||
115    (p0.z < -p0.w - bias && p1.z < -p1.w - bias && p2.z < -p2.w - bias) ||
116    (p0.z > p0.w + bias && p1.z > p1.w + bias && p2.z > p2.w + bias);
117}
118
119// Replaces the existing patch_constant function
120tess_factors patch_constant(InputPatch<v2f, 3> patch) {
121  tess_factors f;
122
123#if defined(_TESSELLATION)
124  float edgeLength = _Tessellation_Factor;
125
126  // Transform object-space positions to clip space
127  float4 p0_clip = UnityObjectToClipPos(float4(patch[0].objPos, 1));
128  float4 p1_clip = UnityObjectToClipPos(float4(patch[1].objPos, 1));
129  float4 p2_clip = UnityObjectToClipPos(float4(patch[2].objPos, 1));
130
131  // Convert to normalized device coordinates (NDC)
132  float3 p0_ndc = p0_clip.xyz / p0_clip.w;
133  float3 p1_ndc = p1_clip.xyz / p1_clip.w;
134  float3 p2_ndc = p2_clip.xyz / p2_clip.w;
135
136  // Convert to screen space (scale by screen dimensions)
137  float2 p0_screen = p0_ndc.xy * _ScreenParams.xy * 0.5f;
138  float2 p1_screen = p1_ndc.xy * _ScreenParams.xy * 0.5f;
139  float2 p2_screen = p2_ndc.xy * _ScreenParams.xy * 0.5f;
140
141  // Calculate screen-space edge lengths in pixels
142  float edge01 = length(p1_screen - p0_screen);
143  float edge12 = length(p2_screen - p1_screen);
144  float edge20 = length(p0_screen - p2_screen);
145
146  // Scale tessellation by screen-space edge length and falloff factor
147  float k = _Tessellation_Falloff_Factor;
148  f.edge[0] = min(_Tessellation_Factor, k * edge12);
149  f.edge[1] = min(_Tessellation_Factor, k * edge20);
150  f.edge[2] = min(_Tessellation_Factor, k * edge01);
151
152  f.inside = (f.edge[0] + f.edge[1] + f.edge[2]) * 0.333333f;
153
154  // Early exit if tessellation is minimal
155  [branch]
156  if (f.inside <= 1.5) {
157    return f;
158  }
159#else
160  f.edge[0] = 1;
161  f.edge[1] = 1;
162  f.edge[2] = 1;
163  f.inside = 1;
164#endif
165
166#if defined(_TESSELLATION)
167  {
168    float4 p0 = patch[0].pos;
169    float4 p1 = patch[1].pos;
170    float4 p2 = patch[2].pos;
171    if (cullPatch(p0, p1, p2, _Tessellation_Frustum_Culling_Bias)) {
172      f.edge[0] = 1;
173      f.edge[1] = 1;
174      f.edge[2] = 1;
175      f.inside = 1;
176    }
177  }
178#endif
179
180  return f;
181}
182
183[UNITY_domain("tri")]
184[UNITY_outputcontrolpoints(3)]
185[UNITY_outputtopology("triangle_cw")]
186[UNITY_partitioning("fractional_odd")]
187[UNITY_patchconstantfunc("patch_constant")]
188v2f hull(
189    InputPatch<v2f, 3> patch,
190    uint id : SV_OutputControlPointID)
191{
192  return patch[id];
193}
194
195[UNITY_domain("tri")]
196v2f domain(
197    tess_factors factors,
198    OutputPatch<v2f, 3> patch,
199    float3 baryc : SV_DomainLocation)
200{
201  UNITY_SETUP_INSTANCE_ID(patch[0]);
202  v2f o = (v2f) 0;
203#define DOMAIN_INTERP(fieldName) \
204  patch[0].fieldName * baryc.x + \
205  patch[1].fieldName * baryc.y + \
206  patch[2].fieldName * baryc.z
207
208  o.uv01      = DOMAIN_INTERP(uv01);
209  o.uv23      = DOMAIN_INTERP(uv23);
210#if defined(_TESSELLATION)
211  o.objPos   = DOMAIN_INTERP(tpos);
212#else
213  o.objPos   = DOMAIN_INTERP(objPos);
214#endif
215
216#if defined(_VERTEX_DEFORMATION) && ( \
217        defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || \
218        defined(_VERTEX_DEFORMATION_TESSELLATION))
219  o.objPos_orig = DOMAIN_INTERP(objPos_orig);
220  o.objPos = o.objPos_orig;
221  deform(o.objPos);
222#endif
223  o.normal = DOMAIN_INTERP(normal);
224  o.tangent = DOMAIN_INTERP(tangent);
225#if defined(_RAY_MARCHING_BAKED_ORIGINS)
226  o.color = DOMAIN_INTERP(color);
227#endif
228#if defined(POINT) || defined(SPOT) || defined(POINT_COOKIE) || defined(DIRECTIONAL_COOKIE)
229  o._LightCoord = DOMAIN_INTERP(_LightCoord);
230#endif
231  o._ShadowCoord = DOMAIN_INTERP(_ShadowCoord);
232
233  propagateObjPos(o);
234
235  UNITY_TRANSFER_INSTANCE_ID(patch[0], o);
236  UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
237  UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos);
238#if defined(SHADOW_CASTER_PASS)
239  o.pos = UnityClipSpaceShadowCasterPos(float4(o.objPos, 1), o.normal);
240  o.pos = UnityApplyLinearShadowBias(o.pos);
241#endif
242  return o;
243}
244//endex
245
246//ifex _Geometry_Shader_Enabled==0
247// maxvertexcount == the number of vertices we create
248[maxvertexcount(3)]
249void geom(triangle v2f tri_in[3],
250  uint pid: SV_PrimitiveID,
251  inout TriangleStream<v2f> tri_out)
252{
253  UNITY_SETUP_INSTANCE_ID(tri_in[0]);
254  v2f v0 = tri_in[0];
255  v2f v1 = tri_in[1];
256  v2f v2 = tri_in[2];
257
258#if defined(_CENTER_OFFSET)
259  float3 n0 = v0.normal;
260  float3 n1 = v1.normal;
261  float3 n2 = v2.normal;
262#if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION)
263  float3 tmp;
264  deform_normal(v0.objPos_orig, n0, tmp);
265  deform_normal(v1.objPos_orig, n1, tmp);
266  deform_normal(v2.objPos_orig, n2, tmp);
267  // the average direction doesn't have to be precise, so don't bother with
268  // normalize().
269  float3 n = (n0 + n1 + n2) * 0.333f;
270#else
271  float3 n = (v0.normal + v1.normal + v2.normal) * 0.333f;
272#endif
273  float height = center_offset(v0.uv01.xy);
274  v0.objPos += n * height;
275  v1.objPos += n * height;
276  v2.objPos += n * height;
277  propagateObjPos(v0);
278  propagateObjPos(v1);
279  propagateObjPos(v2);
280#endif
281
282  // Output transformed geometry.
283  tri_out.Append(v0);
284  tri_out.Append(v1);
285  tri_out.Append(v2);
286  tri_out.RestartStrip();
287}
288//endex
289
290float4 frag_shadow_caster(v2f i) : SV_Target {
291  UNITY_SETUP_INSTANCE_ID(i);
292  return 0;
293}
294
295float4 frag(v2f i, uint facing : SV_IsFrontFace
296    ) : SV_Target {
297  UNITY_SETUP_INSTANCE_ID(i);
298#if defined(_RAY_MARCHING)
299  const bool is_fragment = true;
300  ray_march(i, is_fragment);
301#elif defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS)
302  deform_normal(i.objPos_orig, i.normal, i.tangent.xyz);
303#endif
304
305  // Convert normal and tangent to world space.
306  // `UnityObjectToWorldNormal` normalizes its output.
307  i.normal = UnityObjectToWorldNormal(i.normal);
308  i.tangent.xyz = UnityObjectToWorldNormal(i.tangent.xyz);
309
310  i.normal *= facing ? 1 : -1;
311
312  Pbr pbr = getPbr(i);
313
314  [branch]
315  if (_Mode == 1) {
316    clip(pbr.albedo.a - 0.5);
317  }
318
319  LightData light_data;
320  GetLighting(i, pbr, light_data);
321
322  latePbr(i, light_data, pbr);
323
324  BrdfData bd;
325  float4 lit = brdf(i, pbr, light_data, bd);
326
327#if defined(VERTEXLIGHT_ON) && (defined(FORWARD_BASE_PASS) || defined(OUTLINES_PASS))
328  [loop]
329  for (uint light_index = 0; light_index < 4; ++light_index) {
330    [branch]
331    if (any(unity_LightColor[light_index].rgb > 0)) {
332      LightData vertex_light_data = light_data;
333      GetVertexLighting(i, pbr, light_index, vertex_light_data);
334      BrdfData vertex_bd;
335      lit.rgb += brdf(i, pbr, vertex_light_data, true, vertex_bd).rgb;
336    }
337  }
338#endif
339
340  return apply_debug_view(i, pbr, light_data, bd, lit);
341}
342
343#endif  // __3NER_INC