You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
312 lines
11 KiB
312 lines
11 KiB
#pragma kernel CSMain
|
|
${VFXPragmaOnlyRenderers}
|
|
${VFXPragmaRequire}
|
|
|
|
${VFXGlobalInclude}
|
|
${VFXGlobalDeclaration}
|
|
|
|
#ifdef VFX_IS_RAYTRACED
|
|
#pragma multi_compile _ VFX_COMPUTE_AABBS
|
|
#endif
|
|
|
|
#if USE_MULTI_COMPILE_XR_IN_OUTPUT_UPDATE
|
|
#pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
|
|
#endif
|
|
|
|
#if HAS_STRIPS
|
|
StructuredBuffer<uint> stripDataBuffer;
|
|
#endif
|
|
|
|
${VFXInclude("Shaders/VFXParticleCommon.template")}
|
|
|
|
ByteAddressBuffer attributeBuffer;
|
|
|
|
#if VFX_FEATURE_MOTION_VECTORS
|
|
RWByteAddressBuffer elementToVFXBuffer;
|
|
#endif
|
|
|
|
#if VFX_FEATURE_SORT
|
|
struct Kvp
|
|
{
|
|
float sortKey;
|
|
uint index;
|
|
};
|
|
#define IndirectOutputType Kvp
|
|
#else
|
|
#define IndirectOutputType uint
|
|
#endif
|
|
|
|
#if INDIRECT_BUFFER_COUNT > 0
|
|
RWStructuredBuffer<IndirectOutputType> outputBuffer0;
|
|
#endif
|
|
#if INDIRECT_BUFFER_COUNT > 1
|
|
RWStructuredBuffer<IndirectOutputType> outputBuffer1;
|
|
#endif
|
|
#if INDIRECT_BUFFER_COUNT > 2
|
|
RWStructuredBuffer<IndirectOutputType> outputBuffer2;
|
|
#endif
|
|
#if INDIRECT_BUFFER_COUNT > 3
|
|
RWStructuredBuffer<IndirectOutputType> outputBuffer3;
|
|
#endif
|
|
#if INDIRECT_BUFFER_COUNT > 4
|
|
#error Too many indirect buffers defined.
|
|
#endif
|
|
|
|
CBUFFER_START(updateParamsConst)
|
|
uint dispatchWidth;
|
|
${VFXInstancingConstants}
|
|
float3 cameraXRSettings;
|
|
CBUFFER_END
|
|
|
|
${VFXPerPassInclude}
|
|
|
|
${VFXGeneratedBlockFunction}
|
|
|
|
#if VFX_FEATURE_FRUSTUM_CULL || VFX_FEATURE_LOD
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl"
|
|
|
|
bool IsSphereOutsideFrustum(float3 pos, float radius, float4 frustumPlanes[6])
|
|
{
|
|
bool outside = false;
|
|
[unroll]
|
|
for (int i = 0; i < 6; ++i)
|
|
outside = outside || DistanceFromPlane(pos, frustumPlanes[i]) < -radius;
|
|
return outside;
|
|
}
|
|
#endif
|
|
|
|
#if HAS_STRIPS
|
|
${VFXDeclareGetStripTangent}
|
|
#endif
|
|
|
|
${VFXDeclareAppendOutputIndirectBuffer}
|
|
|
|
[numthreads(NB_THREADS_PER_GROUP,1,1)]
|
|
void CSMain(uint3 groupId : SV_GroupID,
|
|
uint3 groupThreadId : SV_GroupThreadID)
|
|
{
|
|
uint id = GetThreadId(groupId, groupThreadId, dispatchWidth);
|
|
|
|
${VFXInitInstancingCompute}
|
|
|
|
${VFXLoadContextData}
|
|
uint systemSeed = contextData.systemSeed;
|
|
uint nbMax = contextData.maxParticleCount;
|
|
|
|
if (index < nbMax)
|
|
{
|
|
${VFXLoadGraphValues}
|
|
|
|
#if VFX_LOCAL_SPACE
|
|
${VFXLoadParameter:{localToWorld}}
|
|
vfxLocalToWorld = localToWorld;
|
|
|
|
${VFXLoadParameter:{worldToLocal}}
|
|
vfxWorldToLocal = worldToLocal;
|
|
#else
|
|
vfxWorldToLocal = k_identity4x4;
|
|
vfxLocalToWorld = k_identity4x4;
|
|
#endif
|
|
|
|
VFXAttributes attributes = (VFXAttributes)0;
|
|
VFXSourceAttributes sourceAttributes = (VFXSourceAttributes)0;
|
|
${VFXLoadAttributes:{alive}}
|
|
#if HAS_STRIPS
|
|
// For strips, we need to render the entire strip, even if some particles are dead.
|
|
const StripData stripData = GetStripDataFromParticleIndex(index, instanceIndex);
|
|
InitStripAttributes(index, attributes, stripData);
|
|
uint relativeIndexInStrip = GetRelativeIndex(index, stripData);
|
|
if (relativeIndexInStrip < stripData.nextIndex)
|
|
#else
|
|
if (attributes.alive)
|
|
#endif
|
|
{
|
|
${VFXLoadAttributes:{(?!(alive))(\b\w)}}
|
|
${VFXProcessBlocks}
|
|
|
|
#if !HAS_STRIPS
|
|
// Recheck alive as blocks can set it to false for manual culling.
|
|
// Test will be stripped if it's not the case anyway.
|
|
if (attributes.alive)
|
|
#endif
|
|
{
|
|
${VFXLoadSize}
|
|
float3 center = attributes.position;
|
|
#if HAS_STRIPS
|
|
// Add an epsilon so that size is never 0 for strips
|
|
size3.x += size3.x < 0.0f ? -VFX_EPSILON : VFX_EPSILON;
|
|
size3.y += size3.y < 0.0f ? -VFX_EPSILON : VFX_EPSILON;
|
|
size3.z += size3.z < 0.0f ? -VFX_EPSILON : VFX_EPSILON;
|
|
|
|
if (relativeIndexInStrip < stripData.nextIndex - 1)
|
|
{
|
|
uint nextIndex = GetParticleIndex(relativeIndexInStrip + 1,stripData);
|
|
center = (center + GetParticlePosition(nextIndex, instanceIndex)) * 0.5f;
|
|
size3 += abs(center - attributes.position) * sign(size3);
|
|
}
|
|
#endif
|
|
float4x4 elementToVFX = GetElementToVFXMatrix(
|
|
attributes.axisX,
|
|
attributes.axisY,
|
|
attributes.axisZ,
|
|
float3(attributes.angleX,attributes.angleY,attributes.angleZ),
|
|
float3(attributes.pivotX,attributes.pivotY,attributes.pivotZ),
|
|
size3,
|
|
center);
|
|
|
|
#if VFX_FEATURE_FRUSTUM_CULL || VFX_FEATURE_LOD
|
|
#if VFX_WORLD_SPACE
|
|
float4x4 elementToWorld = elementToVFX;
|
|
elementToWorld._m03_m13_m23 = GetCameraRelativePositionWS(elementToWorld._m03_m13_m23);
|
|
#else
|
|
float4x4 elementToWorld = mul(GetObjectToWorldMatrix(),elementToVFX);
|
|
#endif
|
|
|
|
float xAxisSqrLength = dot(elementToWorld._m00_m10_m20, elementToWorld._m00_m10_m20);
|
|
float yAxisSqrLength = dot(elementToWorld._m01_m11_m21, elementToWorld._m01_m11_m21);
|
|
float zAxisSqrLength = dot(elementToWorld._m02_m12_m22, elementToWorld._m02_m12_m22);
|
|
float radius = 0.5f * sqrt(xAxisSqrLength + yAxisSqrLength + zAxisSqrLength);
|
|
|
|
${VFXLoadParameter:{radiusScale}}
|
|
radius *= radiusScale;
|
|
|
|
#if VFX_FEATURE_FRUSTUM_CULL
|
|
if (IsSphereOutsideFrustum(elementToWorld._m03_m13_m23, radius, _FrustumPlanes))
|
|
return;
|
|
#endif
|
|
#endif
|
|
|
|
#if INDIRECT_BUFFER_COUNT > 0
|
|
#if VFX_FEATURE_LOD
|
|
uint outputIndex = ~0u;
|
|
#if !VFX_FEATURE_FRUSTUM_CULL
|
|
// If particle is out of frustum and frustum culling is disabled, use the lowest LOD
|
|
// This is useful for shadow passes for instance to avoid out of frustum particles to be culled from shadows
|
|
if (IsSphereOutsideFrustum(elementToWorld._m03_m13_m23, radius, _FrustumPlanes))
|
|
outputIndex = INDIRECT_BUFFER_COUNT - 1;
|
|
else
|
|
#endif
|
|
{
|
|
float viewZ = mul(GetWorldToViewMatrix(), float4(elementToWorld._m03_m13_m23, 1)).z;
|
|
float4x4 centeredProjMatrix = GetViewToHClipMatrix();
|
|
centeredProjMatrix._13_14_23_24 = 0.0f; //Cancels the jittering and/or the eye offset when in VR
|
|
float4 clip = mul(centeredProjMatrix, float4(radius, radius, viewZ, 1));
|
|
float lodValue = max(abs(clip.x),abs(clip.y)) * rcp(max(VFX_EPSILON, clip.w));
|
|
|
|
${VFXLoadParameter:{lodValues}}
|
|
|
|
for (uint i = 0; i < INDIRECT_BUFFER_COUNT; ++i)
|
|
if (lodValue > lodValues[i])
|
|
{
|
|
outputIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
#elif INDIRECT_BUFFER_COUNT == 1
|
|
uint outputIndex = 0;
|
|
#else
|
|
uint outputIndex = attributes.meshIndex;
|
|
#endif
|
|
if (outputIndex >= INDIRECT_BUFFER_COUNT)
|
|
return;
|
|
|
|
|
|
#if VFX_FEATURE_SORT
|
|
${VFXFeedSortingKeys}
|
|
#else
|
|
uint output = index;
|
|
#endif
|
|
|
|
if (outputIndex == 0)
|
|
{
|
|
AppendOutputBuffer(outputBuffer0, output, instanceActiveIndex);
|
|
}
|
|
#if INDIRECT_BUFFER_COUNT > 1
|
|
else if (outputIndex == 1)
|
|
{
|
|
AppendOutputBuffer(outputBuffer1, output, instanceActiveIndex);
|
|
}
|
|
#if INDIRECT_BUFFER_COUNT > 2
|
|
else if (outputIndex == 2)
|
|
{
|
|
AppendOutputBuffer(outputBuffer2, output, instanceActiveIndex);
|
|
}
|
|
#if INDIRECT_BUFFER_COUNT > 3
|
|
else if (outputIndex == 3)
|
|
{
|
|
AppendOutputBuffer(outputBuffer3, output, instanceActiveIndex);
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if VFX_FEATURE_MOTION_VECTORS
|
|
uint offsetedIndex = (RAW_CAPACITY * instanceIndex) + index;
|
|
#ifdef VFX_FEATURE_MOTION_VECTORS_VERTS
|
|
uint viewTotal = asuint(cameraXRSettings.x);
|
|
uint viewCount = asuint(cameraXRSettings.y);
|
|
uint viewOffset = asuint(cameraXRSettings.z);
|
|
uint elementToVFXIndex = offsetedIndex * (VFX_FEATURE_MOTION_VECTORS_VERTS * 2 * viewTotal + 1);
|
|
#else
|
|
uint elementToVFXIndex = offsetedIndex * 13;
|
|
#endif
|
|
${VFXLoadParameter:{currentFrameIndex}}
|
|
elementToVFXBuffer.Store(elementToVFXIndex++ << 2, attributes.alive ? asuint(currentFrameIndex) : 0u);
|
|
#ifdef VFX_FEATURE_MOTION_VECTORS_VERTS
|
|
elementToVFXIndex += viewOffset * viewCount * VFX_FEATURE_MOTION_VECTORS_VERTS * 2;
|
|
${VFXLoadParameter:{targetOffset}}
|
|
${VFXMotionVectorVerts}
|
|
#ifdef USING_STEREO_MATRICES
|
|
if (viewCount == 2)
|
|
{
|
|
float4 stereoOffset = float4(GetWorldStereoOffset(), 0.0f);
|
|
UNITY_UNROLL
|
|
for (int itIndexVert = 0; itIndexVert < VFX_FEATURE_MOTION_VECTORS_VERTS; ++itIndexVert)
|
|
{
|
|
float4 vertPosWorld = float4(TransformPositionVFXToWorld(verts[itIndexVert]), 1.0f);
|
|
vertPosWorld.xyz = VFXTransformPositionWorldToCameraRelative(vertPosWorld.xyz);
|
|
float4 vertPosA = mul(GetNonJitteredViewProjMatrix(0), vertPosWorld);
|
|
float4 vertPosB = mul(GetNonJitteredViewProjMatrix(1), vertPosWorld + stereoOffset);
|
|
elementToVFXBuffer.Store4(elementToVFXIndex << 2, asuint(float4(vertPosA.xy / vertPosA.w, vertPosB.xy / vertPosB.w)));
|
|
elementToVFXIndex += 4; // 1 vert * 2 floats * 2 views
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
UNITY_UNROLL
|
|
for (int itIndexVert = 0; itIndexVert < VFX_FEATURE_MOTION_VECTORS_VERTS - 1; itIndexVert += 2)
|
|
{
|
|
float4 vertPosA = TransformPositionVFXToNonJitteredClip(verts[itIndexVert]);
|
|
float4 vertPosB = TransformPositionVFXToNonJitteredClip(verts[itIndexVert + 1]);
|
|
elementToVFXBuffer.Store4(elementToVFXIndex << 2, asuint(float4(vertPosA.xy / vertPosA.w, vertPosB.xy / vertPosB.w)));
|
|
elementToVFXIndex += 4; // 2 verts * 2 floats
|
|
}
|
|
if (VFX_FEATURE_MOTION_VECTORS_VERTS % 2 == 1)
|
|
{
|
|
int itIndexVert = VFX_FEATURE_MOTION_VECTORS_VERTS - 1;
|
|
float4 vertPos = TransformPositionVFXToNonJitteredClip(verts[itIndexVert]);
|
|
elementToVFXBuffer.Store2(elementToVFXIndex << 2, asuint(vertPos.xy / vertPos.w));
|
|
elementToVFXIndex += 2; // 1 verts * 2 floats
|
|
}
|
|
}
|
|
#else
|
|
UNITY_UNROLL
|
|
for (int itIndexMatrixRow = 0; itIndexMatrixRow < 3; ++itIndexMatrixRow)
|
|
{
|
|
float4 value = elementToVFX[itIndexMatrixRow] * attributes.alive;
|
|
elementToVFXBuffer.Store4(elementToVFXIndex << 2, asuint(value));
|
|
elementToVFXIndex += 4; // 1 row * 4 floats
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
#if VFX_COMPUTE_AABBS
|
|
${VFXLoadSizeRT}
|
|
int rayTracingDecimationFactor = VFX_RT_DECIMATION_FACTOR;
|
|
FillAabbBuffer(attributes, size3, index, instanceIndex, rayTracingDecimationFactor);
|
|
#endif
|
|
}
|
|
}
|