617 lines
22 KiB
Plaintext
617 lines
22 KiB
Plaintext
|
#pragma kernel GPUFrustumCulling
|
||
|
|
||
|
|
||
|
struct IndirectInstanceData
|
||
|
{
|
||
|
float4x4 PositionMatrix;
|
||
|
float4 ControlData;
|
||
|
};
|
||
|
|
||
|
struct IndirectShaderData
|
||
|
{
|
||
|
float4x4 PositionMatrix;
|
||
|
float4x4 InversePositionMatrix;
|
||
|
float4 ControlData;
|
||
|
};
|
||
|
|
||
|
uint _InstanceCount;
|
||
|
bool UseLODs;
|
||
|
bool NoFrustumCulling;
|
||
|
bool ShadowCulling;
|
||
|
|
||
|
//Used for frustum culling
|
||
|
float4 _VS_CameraFrustumPlane0;
|
||
|
float4 _VS_CameraFrustumPlane1;
|
||
|
float4 _VS_CameraFrustumPlane2;
|
||
|
float4 _VS_CameraFrustumPlane3;
|
||
|
float4 _VS_CameraFrustumPlane4;
|
||
|
float4 _VS_CameraFrustumPlane5;
|
||
|
float4 _WorldSpaceCameraPos;
|
||
|
|
||
|
float4 _FloatingOriginOffset;
|
||
|
|
||
|
float3 _LightDirection;
|
||
|
float3 _PlaneOrigin;
|
||
|
float3 _BoundsSize;
|
||
|
|
||
|
|
||
|
//Used for vegetatuion distance culling
|
||
|
float _CullFarStart;
|
||
|
float _CullFarDistance;
|
||
|
float _BoundingSphereRadius;
|
||
|
|
||
|
//Used for LODs
|
||
|
float _LOD1Distance;
|
||
|
float _LOD2Distance;
|
||
|
float _LOD3Distance;
|
||
|
|
||
|
float _LODFactor;
|
||
|
float _LODBias;
|
||
|
float _LODFadeDistance;
|
||
|
int _LODCount;
|
||
|
|
||
|
StructuredBuffer<IndirectInstanceData> SourceShaderDataBuffer;
|
||
|
AppendStructuredBuffer<IndirectShaderData> VisibleBufferLOD0;
|
||
|
AppendStructuredBuffer<IndirectShaderData> VisibleBufferLOD1;
|
||
|
AppendStructuredBuffer<IndirectShaderData> VisibleBufferLOD2;
|
||
|
AppendStructuredBuffer<IndirectShaderData> VisibleBufferLOD3;
|
||
|
|
||
|
AppendStructuredBuffer<IndirectShaderData> ShadowBufferLOD0;
|
||
|
AppendStructuredBuffer<IndirectShaderData> ShadowBufferLOD1;
|
||
|
AppendStructuredBuffer<IndirectShaderData> ShadowBufferLOD2;
|
||
|
AppendStructuredBuffer<IndirectShaderData> ShadowBufferLOD3;
|
||
|
|
||
|
SamplerState _LinearClamp;
|
||
|
|
||
|
// float CalculateLODFade(float cameraDistance, float nextLODDistance)
|
||
|
// {
|
||
|
// float distance = nextLODDistance - cameraDistance;
|
||
|
// if (distance <= _LODFadeDistance)
|
||
|
// {
|
||
|
// return clamp(1 - distance / _LODFadeDistance, 0, 1);
|
||
|
// }
|
||
|
// return 0;
|
||
|
// }
|
||
|
|
||
|
float CalculateLODFadeFirst(float cameraDistance, float nextLODDistance)
|
||
|
{
|
||
|
float distance = nextLODDistance + _LODFadeDistance - cameraDistance;
|
||
|
if (distance <= _LODFadeDistance)
|
||
|
{
|
||
|
return clamp(distance/ _LODFadeDistance, 0, 1) * 2;
|
||
|
return clamp(distance * distance/ _LODFadeDistance, 0, 1);
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
float CalculateLODFadeMiddle(float thisLODDistance, float cameraDistance, float nextLODDistance)
|
||
|
{
|
||
|
if (cameraDistance - thisLODDistance < _LODFadeDistance)
|
||
|
{
|
||
|
float distance = cameraDistance - thisLODDistance;
|
||
|
// return clamp(distance * distance/ _LODFadeDistance, 0, 1);
|
||
|
return clamp(distance/ _LODFadeDistance, 0, 1) * 2;
|
||
|
}
|
||
|
|
||
|
if (nextLODDistance + _LODFadeDistance - cameraDistance <= _LODFadeDistance)
|
||
|
{
|
||
|
float distance = nextLODDistance + _LODFadeDistance - cameraDistance;
|
||
|
|
||
|
//return clamp(distance * distance / _LODFadeDistance, 0, 1);
|
||
|
return clamp(distance/ _LODFadeDistance, 0, 1) * 2;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
float CalculateDistanceFade(float cameraDistance, float cullDistance)
|
||
|
{
|
||
|
float distance = cullDistance - cameraDistance;
|
||
|
if (distance <= _LODFadeDistance)
|
||
|
{
|
||
|
return clamp(1 - distance / _LODFadeDistance, 0, 1);
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
float4x4 inverse(float4x4 input)
|
||
|
{
|
||
|
#define minor(a,b,c) determinant(float3x3(input.a, input.b, input.c))
|
||
|
|
||
|
float4x4 cofactors = float4x4(
|
||
|
minor(_22_23_24, _32_33_34, _42_43_44),
|
||
|
-minor(_21_23_24, _31_33_34, _41_43_44),
|
||
|
minor(_21_22_24, _31_32_34, _41_42_44),
|
||
|
-minor(_21_22_23, _31_32_33, _41_42_43),
|
||
|
|
||
|
-minor(_12_13_14, _32_33_34, _42_43_44),
|
||
|
minor(_11_13_14, _31_33_34, _41_43_44),
|
||
|
-minor(_11_12_14, _31_32_34, _41_42_44),
|
||
|
minor(_11_12_13, _31_32_33, _41_42_43),
|
||
|
|
||
|
minor(_12_13_14, _22_23_24, _42_43_44),
|
||
|
-minor(_11_13_14, _21_23_24, _41_43_44),
|
||
|
minor(_11_12_14, _21_22_24, _41_42_44),
|
||
|
-minor(_11_12_13, _21_22_23, _41_42_43),
|
||
|
|
||
|
-minor(_12_13_14, _22_23_24, _32_33_34),
|
||
|
minor(_11_13_14, _21_23_24, _31_33_34),
|
||
|
-minor(_11_12_14, _21_22_24, _31_32_34),
|
||
|
minor(_11_12_13, _21_22_23, _31_32_33)
|
||
|
);
|
||
|
#undef minor
|
||
|
return transpose(cofactors) / determinant(input);
|
||
|
}
|
||
|
|
||
|
|
||
|
struct Ray
|
||
|
{
|
||
|
float3 origin;
|
||
|
float3 direction;
|
||
|
};
|
||
|
|
||
|
Ray CreateRay(float3 origin, float3 direction)
|
||
|
{
|
||
|
Ray newRay;
|
||
|
newRay.origin = origin;
|
||
|
newRay.direction = direction;
|
||
|
return newRay;
|
||
|
}
|
||
|
|
||
|
struct Bounds
|
||
|
{
|
||
|
float3 center;
|
||
|
float3 extents;
|
||
|
|
||
|
float3 GetMin()
|
||
|
{
|
||
|
return center - extents;
|
||
|
}
|
||
|
|
||
|
float3 GetMax()
|
||
|
{
|
||
|
return center + extents;
|
||
|
}
|
||
|
|
||
|
void SetMinMax(float3 min, float3 max)
|
||
|
{
|
||
|
extents = (max - min) * 0.5f;
|
||
|
center = min + extents;
|
||
|
}
|
||
|
|
||
|
void Encapsulate(float3 targetPoint)
|
||
|
{
|
||
|
SetMinMax(min(GetMin(), targetPoint), max(GetMax(), targetPoint));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
bool IntersectPlane(Ray ray, float3 planeOrigin, out float3 hitPoint)
|
||
|
{
|
||
|
float3 planeNormal = -float3(0, 1, 0);
|
||
|
float denominator = dot(ray.direction, planeNormal);
|
||
|
if (denominator > 0.00001f)
|
||
|
{
|
||
|
float t = dot(planeOrigin - ray.origin, planeNormal) / denominator;
|
||
|
hitPoint = ray.origin + ray.direction * t;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
hitPoint = float3(0, 0, 0);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Bounds GetShadowBounds(Bounds objectBounds, float3 lightDirection, float3 planeOrigin, out bool hitPlane)
|
||
|
{
|
||
|
float3 objectBoundsMin = objectBounds.GetMin();
|
||
|
float3 objectBoundsMax = objectBounds.GetMax();
|
||
|
|
||
|
Ray p0 = CreateRay(float3(objectBoundsMin.x, objectBoundsMax.y, objectBoundsMin.z), lightDirection);
|
||
|
Ray p1 = CreateRay(float3(objectBoundsMin.x, objectBoundsMax.y, 0), lightDirection);
|
||
|
Ray p2 = CreateRay(float3(objectBoundsMax.x, objectBoundsMax.y, objectBoundsMin.z), lightDirection);
|
||
|
Ray p3 = CreateRay(objectBoundsMax, lightDirection);
|
||
|
|
||
|
float3 hitPoint;
|
||
|
hitPlane = false;
|
||
|
|
||
|
if (IntersectPlane(p0, planeOrigin, hitPoint))
|
||
|
{
|
||
|
objectBounds.Encapsulate(hitPoint);
|
||
|
hitPlane = true;
|
||
|
}
|
||
|
|
||
|
if (IntersectPlane(p1, planeOrigin, hitPoint))
|
||
|
{
|
||
|
objectBounds.Encapsulate(hitPoint);
|
||
|
hitPlane = true;
|
||
|
}
|
||
|
|
||
|
if (IntersectPlane(p2, planeOrigin, hitPoint))
|
||
|
{
|
||
|
objectBounds.Encapsulate(hitPoint);
|
||
|
hitPlane = true;
|
||
|
}
|
||
|
|
||
|
if (IntersectPlane(p3, planeOrigin, hitPoint))
|
||
|
{
|
||
|
objectBounds.Encapsulate(hitPoint);
|
||
|
hitPlane = true;
|
||
|
}
|
||
|
|
||
|
return objectBounds;
|
||
|
}
|
||
|
|
||
|
bool TestPlaneIntersection(Bounds bounds, float4 plane)
|
||
|
{
|
||
|
float3 center = bounds.center;
|
||
|
float3 extents = bounds.extents;
|
||
|
|
||
|
float3 planeNormal = plane.xyz;
|
||
|
float planeDistance = plane.w;
|
||
|
|
||
|
float3 absNormal = float3(abs(planeNormal.x), abs(planeNormal.y), abs(planeNormal.z));
|
||
|
float r = extents.x * absNormal.x + extents.y * absNormal.y + extents.z * absNormal.z;
|
||
|
float s = planeNormal.x * center.x + planeNormal.y * center.y + planeNormal.z * center.z;
|
||
|
if (s + r < -planeDistance)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool BoundsIntersectsFrustum(Bounds bounds)
|
||
|
{
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane0) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane1) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane2) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane3) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane4) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (TestPlaneIntersection(bounds, _VS_CameraFrustumPlane5) == false)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool IsShadowVisible(Bounds objectBounds, float3 lightDirection, float3 planeOrigin)
|
||
|
{
|
||
|
bool hitPlane;
|
||
|
Bounds shadowBounds = GetShadowBounds(objectBounds, lightDirection, planeOrigin, hitPlane);
|
||
|
return hitPlane && BoundsIntersectsFrustum(shadowBounds);
|
||
|
}
|
||
|
|
||
|
[numthreads(32, 1, 1)]
|
||
|
void GPUFrustumCulling(uint3 id : SV_DispatchThreadID)
|
||
|
{
|
||
|
uint instanceId = id.x;
|
||
|
if (instanceId < _InstanceCount)
|
||
|
{
|
||
|
IndirectShaderData instanceData;
|
||
|
instanceData.PositionMatrix = SourceShaderDataBuffer[id.x].PositionMatrix;
|
||
|
|
||
|
instanceData.PositionMatrix._m03_m13_m23 += _FloatingOriginOffset.xyz;
|
||
|
|
||
|
float DistanceFalloff = SourceShaderDataBuffer[id.x].ControlData.x;
|
||
|
|
||
|
float itemCullDistance = _CullFarStart * DistanceFalloff;
|
||
|
float lod1Distance = clamp(_LOD1Distance * _LODFactor * _LODBias, 0, _CullFarStart);
|
||
|
float lod2Distance = clamp(_LOD2Distance * _LODFactor * _LODBias, 0, _CullFarStart);
|
||
|
float lod3Distance = clamp(_LOD3Distance * _LODFactor * _LODBias, 0, _CullFarStart);
|
||
|
|
||
|
#define transformPosition mul(instanceData.PositionMatrix, float4(0,0,0,1)).xyz
|
||
|
float3 position = transformPosition + float3(0.0f, _BoundingSphereRadius * 0.5f, 0.0f);
|
||
|
|
||
|
if (NoFrustumCulling)
|
||
|
{
|
||
|
bool useLODFade = true;
|
||
|
float3 itempos = instanceData.PositionMatrix._m03_m13_m23;
|
||
|
float dist = distance(itempos, _WorldSpaceCameraPos.xyz);
|
||
|
if (dist < itemCullDistance)
|
||
|
{
|
||
|
instanceData.InversePositionMatrix = inverse(instanceData.PositionMatrix);
|
||
|
float distanceFade = CalculateDistanceFade(dist, itemCullDistance);
|
||
|
|
||
|
instanceData.ControlData = float4(0, 0, distanceFade, 0);
|
||
|
|
||
|
if (UseLODs)
|
||
|
{
|
||
|
if (_LODCount == 1)
|
||
|
{
|
||
|
lod1Distance = max(lod1Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 2)
|
||
|
{
|
||
|
lod2Distance = max(lod2Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 3)
|
||
|
{
|
||
|
lod3Distance = max(lod3Distance, itemCullDistance);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (dist <= lod1Distance + _LODFadeDistance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, lod1Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
|
||
|
VisibleBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
if (dist <= lod2Distance + _LODFadeDistance && dist > lod1Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod1Distance, dist, lod2Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
lodFadeQuantified = 0;
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 1);
|
||
|
}
|
||
|
VisibleBufferLOD1.Append(instanceData);
|
||
|
}
|
||
|
if (dist <= lod3Distance + _LODFadeDistance && dist > lod2Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod2Distance, dist, lod3Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
lodFadeQuantified = 0.5;
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 2);
|
||
|
}
|
||
|
VisibleBufferLOD2.Append(instanceData);
|
||
|
}
|
||
|
if (dist > lod3Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod3Distance, dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 3);
|
||
|
}
|
||
|
VisibleBufferLOD3.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
VisibleBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
float4 CameraDistances0 = float4(
|
||
|
dot(_VS_CameraFrustumPlane0.xyz, position) + _VS_CameraFrustumPlane0.w,
|
||
|
dot(_VS_CameraFrustumPlane1.xyz, position) + _VS_CameraFrustumPlane1.w,
|
||
|
dot(_VS_CameraFrustumPlane2.xyz, position) + _VS_CameraFrustumPlane2.w,
|
||
|
dot(_VS_CameraFrustumPlane3.xyz, position) + _VS_CameraFrustumPlane3.w
|
||
|
);
|
||
|
|
||
|
float4 CameraDistances1 = float4(
|
||
|
dot(_VS_CameraFrustumPlane4.xyz, position) + _VS_CameraFrustumPlane4.w,
|
||
|
dot(_VS_CameraFrustumPlane5.xyz, position) + _VS_CameraFrustumPlane5.w,
|
||
|
0.0f,
|
||
|
0.0f
|
||
|
);
|
||
|
|
||
|
if (!(all(CameraDistances0 >= -_BoundingSphereRadius)
|
||
|
&& all(CameraDistances1 >= -_BoundingSphereRadius)))
|
||
|
{
|
||
|
if (!ShadowCulling)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
bool useLODFade = true;
|
||
|
float3 itempos = instanceData.PositionMatrix._m03_m13_m23;
|
||
|
float dist = distance(itempos, _WorldSpaceCameraPos.xyz);
|
||
|
|
||
|
if (dist < itemCullDistance)
|
||
|
{
|
||
|
Bounds itemBounds;
|
||
|
itemBounds.center = itempos;
|
||
|
itemBounds.extents = _BoundsSize;
|
||
|
|
||
|
if (IsShadowVisible(itemBounds, _LightDirection, _PlaneOrigin))
|
||
|
{
|
||
|
instanceData.InversePositionMatrix = inverse(instanceData.PositionMatrix);
|
||
|
float distanceFade = CalculateDistanceFade(dist, itemCullDistance);
|
||
|
instanceData.ControlData = float4(0, 0, distanceFade, 0);
|
||
|
|
||
|
if (UseLODs)
|
||
|
{
|
||
|
if (_LODCount == 1)
|
||
|
{
|
||
|
lod1Distance = max(lod1Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 2)
|
||
|
{
|
||
|
lod2Distance = max(lod2Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 3)
|
||
|
{
|
||
|
lod3Distance = max(lod3Distance, itemCullDistance);
|
||
|
}
|
||
|
|
||
|
if (dist <= lod1Distance + _LODFadeDistance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, lod1Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified,
|
||
|
instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
|
||
|
ShadowBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
|
||
|
if (dist <= lod2Distance + _LODFadeDistance && dist > lod1Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod1Distance, dist, lod2Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified,
|
||
|
instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
ShadowBufferLOD1.Append(instanceData);
|
||
|
}
|
||
|
|
||
|
if (dist <= lod3Distance + _LODFadeDistance && dist > lod2Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod2Distance, dist, lod3Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified,
|
||
|
instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
ShadowBufferLOD2.Append(instanceData);
|
||
|
}
|
||
|
|
||
|
if (dist > lod3Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod3Distance, dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified,
|
||
|
instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
ShadowBufferLOD3.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
ShadowBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bool useLODFade = true;
|
||
|
float3 itempos = instanceData.PositionMatrix._m03_m13_m23;
|
||
|
float dist = distance(itempos, _WorldSpaceCameraPos.xyz);
|
||
|
|
||
|
if (dist < itemCullDistance + _LODFadeDistance)
|
||
|
{
|
||
|
instanceData.InversePositionMatrix = inverse(instanceData.PositionMatrix);
|
||
|
float distanceFade = CalculateDistanceFade(dist, itemCullDistance);
|
||
|
instanceData.ControlData = float4(0, 0, distanceFade, 0);
|
||
|
|
||
|
if (UseLODs)
|
||
|
{
|
||
|
if (_LODCount == 1)
|
||
|
{
|
||
|
lod1Distance = max(lod1Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 2)
|
||
|
{
|
||
|
lod2Distance = max(lod2Distance, itemCullDistance);
|
||
|
}
|
||
|
else if (_LODCount == 3)
|
||
|
{
|
||
|
lod3Distance = max(lod3Distance, itemCullDistance);
|
||
|
}
|
||
|
|
||
|
if (dist <= lod1Distance + _LODFadeDistance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, lod1Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
|
||
|
VisibleBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
if (dist <= lod2Distance + _LODFadeDistance && dist > lod1Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod1Distance, dist, lod2Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
lodFadeQuantified = 0;
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 1);
|
||
|
}
|
||
|
VisibleBufferLOD1.Append(instanceData);
|
||
|
}
|
||
|
if (dist <= lod3Distance + _LODFadeDistance && dist > lod2Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod2Distance, dist, lod3Distance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 2);
|
||
|
}
|
||
|
VisibleBufferLOD2.Append(instanceData);
|
||
|
}
|
||
|
if (dist > lod3Distance)
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeMiddle(lod3Distance, dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData =
|
||
|
float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 3);
|
||
|
}
|
||
|
VisibleBufferLOD3.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (useLODFade)
|
||
|
{
|
||
|
float lodFade = CalculateLODFadeFirst(dist, itemCullDistance);
|
||
|
float lodFadeQuantified = 1 - clamp(round(lodFade * 16) / 16, 0.0625, 1);
|
||
|
instanceData.ControlData = float4(lodFade, lodFadeQuantified, instanceData.ControlData.z, 0);
|
||
|
}
|
||
|
VisibleBufferLOD0.Append(instanceData);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|