NLDClient-yudde/ProjectNLD/Assets/Code/Shaders/builtin_shaders-2022.3.17f1/CGIncludes/Tessellation.cginc

134 lines
5.3 KiB
HLSL

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
#ifndef TESSELLATION_CGINC_INCLUDED
#define TESSELLATION_CGINC_INCLUDED
#include "UnityShaderVariables.cginc"
// ---- utility functions
float UnityCalcDistanceTessFactor (float4 vertex, float minDist, float maxDist, float tess)
{
float3 wpos = mul(unity_ObjectToWorld,vertex).xyz;
float dist = distance (wpos, _WorldSpaceCameraPos);
float f = clamp(1.0 - (dist - minDist) / (maxDist - minDist), 0.01, 1.0) * tess;
return f;
}
float4 UnityCalcTriEdgeTessFactors (float3 triVertexFactors)
{
float4 tess;
tess.x = 0.5 * (triVertexFactors.y + triVertexFactors.z);
tess.y = 0.5 * (triVertexFactors.x + triVertexFactors.z);
tess.z = 0.5 * (triVertexFactors.x + triVertexFactors.y);
tess.w = (triVertexFactors.x + triVertexFactors.y + triVertexFactors.z) / 3.0f;
return tess;
}
float UnityCalcEdgeTessFactor (float3 wpos0, float3 wpos1, float edgeLen)
{
// distance to edge center
float dist = distance (0.5 * (wpos0+wpos1), _WorldSpaceCameraPos);
// length of the edge
float len = distance(wpos0, wpos1);
// edgeLen is approximate desired size in pixels
float f = max(len * _ScreenParams.y / (edgeLen * dist), 1.0);
return f;
}
float UnityDistanceFromPlane (float3 pos, float4 plane)
{
float d = dot (float4(pos,1.0f), plane);
return d;
}
// Returns true if triangle with given 3 world positions is outside of camera's view frustum.
// cullEps is distance outside of frustum that is still considered to be inside (i.e. max displacement)
bool UnityWorldViewFrustumCull (float3 wpos0, float3 wpos1, float3 wpos2, float cullEps)
{
float4 planeTest;
// left
planeTest.x = (( UnityDistanceFromPlane(wpos0, unity_CameraWorldClipPlanes[0]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos1, unity_CameraWorldClipPlanes[0]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos2, unity_CameraWorldClipPlanes[0]) > -cullEps) ? 1.0f : 0.0f );
// right
planeTest.y = (( UnityDistanceFromPlane(wpos0, unity_CameraWorldClipPlanes[1]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos1, unity_CameraWorldClipPlanes[1]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos2, unity_CameraWorldClipPlanes[1]) > -cullEps) ? 1.0f : 0.0f );
// top
planeTest.z = (( UnityDistanceFromPlane(wpos0, unity_CameraWorldClipPlanes[2]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos1, unity_CameraWorldClipPlanes[2]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos2, unity_CameraWorldClipPlanes[2]) > -cullEps) ? 1.0f : 0.0f );
// bottom
planeTest.w = (( UnityDistanceFromPlane(wpos0, unity_CameraWorldClipPlanes[3]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos1, unity_CameraWorldClipPlanes[3]) > -cullEps) ? 1.0f : 0.0f ) +
(( UnityDistanceFromPlane(wpos2, unity_CameraWorldClipPlanes[3]) > -cullEps) ? 1.0f : 0.0f );
// has to pass all 4 plane tests to be visible
return !all (planeTest);
}
// ---- functions that compute tessellation factors
// Distance based tessellation:
// Tessellation level is "tess" before "minDist" from camera, and linearly decreases to 1
// up to "maxDist" from camera.
float4 UnityDistanceBasedTess (float4 v0, float4 v1, float4 v2, float minDist, float maxDist, float tess)
{
float3 f;
f.x = UnityCalcDistanceTessFactor (v0,minDist,maxDist,tess);
f.y = UnityCalcDistanceTessFactor (v1,minDist,maxDist,tess);
f.z = UnityCalcDistanceTessFactor (v2,minDist,maxDist,tess);
return UnityCalcTriEdgeTessFactors (f);
}
// Desired edge length based tessellation:
// Approximate resulting edge length in pixels is "edgeLength".
// Does not take viewing FOV into account, just flat out divides factor by distance.
float4 UnityEdgeLengthBasedTess (float4 v0, float4 v1, float4 v2, float edgeLength)
{
float3 pos0 = mul(unity_ObjectToWorld,v0).xyz;
float3 pos1 = mul(unity_ObjectToWorld,v1).xyz;
float3 pos2 = mul(unity_ObjectToWorld,v2).xyz;
float4 tess;
tess.x = UnityCalcEdgeTessFactor (pos1, pos2, edgeLength);
tess.y = UnityCalcEdgeTessFactor (pos2, pos0, edgeLength);
tess.z = UnityCalcEdgeTessFactor (pos0, pos1, edgeLength);
tess.w = (tess.x + tess.y + tess.z) / 3.0f;
return tess;
}
// Same as UnityEdgeLengthBasedTess, but also does patch frustum culling:
// patches outside of camera's view are culled before GPU tessellation. Saves some wasted work.
float4 UnityEdgeLengthBasedTessCull (float4 v0, float4 v1, float4 v2, float edgeLength, float maxDisplacement)
{
float3 pos0 = mul(unity_ObjectToWorld,v0).xyz;
float3 pos1 = mul(unity_ObjectToWorld,v1).xyz;
float3 pos2 = mul(unity_ObjectToWorld,v2).xyz;
float4 tess;
if (UnityWorldViewFrustumCull(pos0, pos1, pos2, maxDisplacement))
{
tess = 0.0f;
}
else
{
tess.x = UnityCalcEdgeTessFactor (pos1, pos2, edgeLength);
tess.y = UnityCalcEdgeTessFactor (pos2, pos0, edgeLength);
tess.z = UnityCalcEdgeTessFactor (pos0, pos1, edgeLength);
tess.w = (tess.x + tess.y + tess.z) / 3.0f;
}
return tess;
}
#endif // TESSELLATION_CGINC_INCLUDED