#ifndef __3NER_INC #define __3NER_INC #define INCLUDE_UNITY_STANDARD_BRDF_DEPRECATED #include "UnityStandardBRDF.cginc" #include "UnityDeprecated.cginc" #include "UnityCG.cginc" #include "UnityLightingCommon.cginc" #include "AutoLight.cginc" #include "brdf.cginc" #include "cnlohr.cginc" #include "geometry.cginc" #include "pbr.cginc" #include "lighting.cginc" #include "globals.cginc" #include "interpolators.cginc" #include "ray_marching.cginc" #include "vertex.cginc" #include "impostor.cginc" v2f vert(appdata v) { #if defined(SHADOW_CASTER_PASS) && !defined(_SHADOW_CASTER) return (v2f) asfloat(-1); #endif v2f o; UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_OUTPUT(v2f, o); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); #if defined(_IMPOSTORS) impostor_vert(v.vertex.xyz); #endif #if defined(_TESSELLATION) o.tpos = v.vertex; #endif o.uv01.xy = v.uv0; o.uv01.zw = v.uv1; o.uv23.xy = v.uv2; o.uv23.zw = v.uv3; float3 obj_space_camera_pos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos, 1.0)); o.objPos = v.vertex; #if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) o.objPos_orig = v.vertex; #endif #if defined(_RAY_MARCHING_BAKED_ORIGINS) o.color = v.color; #endif // Normal and tangent are in object space to allow for object-space // vertex deformation logic later on. They are converted to world // space inside the fragment shader. o.normal = v.normal; o.tangent = v.tangent; #if !defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) deform_normal(o.objPos, o.normal.xyz, o.tangent.xyz); #endif deform(o.objPos); propagateObjPos(o); UNITY_TRANSFER_LIGHTING(o, v.uv1); UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos); #if defined(SHADOW_CASTER_PASS) TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); #else TRANSFER_SHADOW(o); #endif return o; } //ifex _Tessellation_Enabled==0 struct tess_factors { float edge[3] : SV_TessFactor; float inside : SV_InsideTessFactor; }; bool cullPatch(float4 p0, float4 p1, float4 p2, float bias) { return (p0.x < -p0.w - bias && p1.x < -p1.w - bias && p2.x < -p2.w - bias) || (p0.x > p0.w + bias && p1.x > p1.w + bias && p2.x > p2.w + bias) || (p0.y < -p0.w - bias && p1.y < -p1.w - bias && p2.y < -p2.w - bias) || (p0.y > p0.w + bias && p1.y > p1.w + bias && p2.y > p2.w + bias) || (p0.z < -p0.w - bias && p1.z < -p1.w - bias && p2.z < -p2.w - bias) || (p0.z > p0.w + bias && p1.z > p1.w + bias && p2.z > p2.w + bias); } // Replaces the existing patch_constant function tess_factors patch_constant(InputPatch patch) { tess_factors f; #if defined(_TESSELLATION) float edgeLength = _Tessellation_Factor; // Transform object-space positions to clip space float4 p0_clip = UnityObjectToClipPos(float4(patch[0].objPos, 1)); float4 p1_clip = UnityObjectToClipPos(float4(patch[1].objPos, 1)); float4 p2_clip = UnityObjectToClipPos(float4(patch[2].objPos, 1)); // Convert to normalized device coordinates (NDC) float3 p0_ndc = p0_clip.xyz / p0_clip.w; float3 p1_ndc = p1_clip.xyz / p1_clip.w; float3 p2_ndc = p2_clip.xyz / p2_clip.w; // Convert to screen space (scale by screen dimensions) float2 p0_screen = p0_ndc.xy * _ScreenParams.xy * 0.5f; float2 p1_screen = p1_ndc.xy * _ScreenParams.xy * 0.5f; float2 p2_screen = p2_ndc.xy * _ScreenParams.xy * 0.5f; // Calculate screen-space edge lengths in pixels float edge01 = length(p1_screen - p0_screen); float edge12 = length(p2_screen - p1_screen); float edge20 = length(p0_screen - p2_screen); // Scale tessellation by screen-space edge length and falloff factor float k = _Tessellation_Falloff_Factor; f.edge[0] = min(_Tessellation_Factor, k * edge12); f.edge[1] = min(_Tessellation_Factor, k * edge20); f.edge[2] = min(_Tessellation_Factor, k * edge01); f.inside = (f.edge[0] + f.edge[1] + f.edge[2]) * 0.333333f; // Early exit if tessellation is minimal [branch] if (f.inside <= 1.5) { return f; } #else f.edge[0] = 1; f.edge[1] = 1; f.edge[2] = 1; f.inside = 1; #endif #if defined(_TESSELLATION) { float4 p0 = patch[0].pos; float4 p1 = patch[1].pos; float4 p2 = patch[2].pos; if (cullPatch(p0, p1, p2, _Tessellation_Frustum_Culling_Bias)) { f.edge[0] = 1; f.edge[1] = 1; f.edge[2] = 1; f.inside = 1; } } #endif return f; } [UNITY_domain("tri")] [UNITY_outputcontrolpoints(3)] [UNITY_outputtopology("triangle_cw")] [UNITY_partitioning("fractional_odd")] [UNITY_patchconstantfunc("patch_constant")] v2f hull( InputPatch patch, uint id : SV_OutputControlPointID) { return patch[id]; } [UNITY_domain("tri")] v2f domain( tess_factors factors, OutputPatch patch, float3 baryc : SV_DomainLocation) { UNITY_SETUP_INSTANCE_ID(patch[0]); v2f o = (v2f) 0; #define DOMAIN_INTERP(fieldName) \ patch[0].fieldName * baryc.x + \ patch[1].fieldName * baryc.y + \ patch[2].fieldName * baryc.z o.uv01 = DOMAIN_INTERP(uv01); o.uv23 = DOMAIN_INTERP(uv23); #if defined(_TESSELLATION) o.objPos = DOMAIN_INTERP(tpos); #else o.objPos = DOMAIN_INTERP(objPos); #endif #if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) o.objPos_orig = DOMAIN_INTERP(objPos_orig); o.objPos = o.objPos_orig; deform(o.objPos); #endif o.normal = DOMAIN_INTERP(normal); o.tangent = DOMAIN_INTERP(tangent); #if defined(_RAY_MARCHING_BAKED_ORIGINS) o.color = DOMAIN_INTERP(color); #endif propagateObjPos(o); UNITY_TRANSFER_INSTANCE_ID(patch[0], o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); #if defined(SHADOW_CASTER_PASS) //TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); #endif return o; } //endex //ifex _Geometry_Shader_Enabled==0 // maxvertexcount == the number of vertices we create [maxvertexcount(3)] void geom(triangle v2f tri_in[3], uint pid: SV_PrimitiveID, inout TriangleStream tri_out) { UNITY_SETUP_INSTANCE_ID(tri_in[0]); v2f v0 = tri_in[0]; v2f v1 = tri_in[1]; v2f v2 = tri_in[2]; #if defined(_CENTER_OFFSET) float3 n0 = v0.normal; float3 n1 = v1.normal; float3 n2 = v2.normal; #if defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) || defined(_VERTEX_DEFORMATION_TESSELLATION) float3 tmp; deform_normal(v0.objPos_orig, n0, tmp); deform_normal(v1.objPos_orig, n1, tmp); deform_normal(v2.objPos_orig, n2, tmp); // the average direction doesn't have to be precise, so don't bother with // normalize(). float3 n = (n0 + n1 + n2) * 0.333f; #else float3 n = (v0.normal + v1.normal + v2.normal) * 0.333f; #endif float height = center_offset(v0.uv01.xy); v0.objPos += n * height; v1.objPos += n * height; v2.objPos += n * height; propagateObjPos(v0); propagateObjPos(v1); propagateObjPos(v2); #endif // Output transformed geometry. tri_out.Append(v0); tri_out.Append(v1); tri_out.Append(v2); tri_out.RestartStrip(); } //endex float4 frag(v2f i, uint facing : SV_IsFrontFace #if defined(_IMPOSTORS) , out float depth : SV_DepthLessEqual #endif ) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); #if defined(SHADOW_CASTER_PASS) return 0; #endif #if defined(_RAY_MARCHING) const bool is_fragment = true; ray_march(i, is_fragment); #elif defined(_VERTEX_DEFORMATION_FRAGMENT_NORMALS) deform_normal(i.objPos_orig, i.normal, i.tangent.xyz); #endif // Convert normal and tangent to world space. i.normal = UnityObjectToWorldNormal(i.normal); i.tangent.xyz = UnityObjectToWorldNormal(i.tangent.xyz); i.normal *= facing ? 1 : -1; Pbr pbr = getPbr(i); #if defined(_IMPOSTORS) i.normal = pbr.normal; i.objPos = pbr.objPos; propagateObjPos(i); float4 imp_clip_pos = UnityObjectToClipPos(i.objPos); depth = imp_clip_pos.z / imp_clip_pos.w; if (false) { depth *= 100; depth *= depth; depth *= depth; depth *= 100; return float4(depth, depth, depth, 1); } if (false) { return float4(i.objPos, 1); } #endif #if defined(_DEBUG_VIEW_UNLIT) return pbr.albedo; #elif defined(_DEBUG_VIEW_WORLD_SPACE_NORMALS) return float4((pbr.normal + 1.0f) * 0.5f, 1); #elif defined(_DEBUG_VIEW_METALLIC_GLOSS) return float4(pbr.metallic, pbr.smoothness, 0, 1); #elif defined(_DEBUG_VIEW_DEPTH) float2 screen_uv = i.pos.xy / _ScreenParams.xy; float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screen_uv); depth = 1.0f - depth; depth *= 100; depth *= depth; depth *= depth; depth *= 100; return float4(depth, depth, depth, 1); #endif LightData light_data; GetLighting(i, pbr, light_data); #if 0 float c = light_data.common.NoV; return float4(c,c,c,1); #endif return brdf(pbr, light_data); } #endif // __3NER_INC