yum/3ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum/3ner
f3918c9
master
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