Aetheria/Assets/Plugins/GPUTrail/Shaders/GPUTrailIndirect.compute

139 lines
4.1 KiB
Text
Raw Normal View History

#pragma kernel AddNode
#pragma kernel CreateWidth
#define NUM_THREAD_X 32
#include "GPUTrailVariablesCS.compute"
////////////////////////////////////////////////////////////////////////////////
// AddNode
////////////////////////////////////////////////////////////////////////////////
StructuredBuffer<InputData> _InputBuffer;
RWStructuredBuffer<Trail> _TrailBufferW;
RWStructuredBuffer<Node> _NodeBufferW;
[numthreads(NUM_THREAD_X,1,1)]
void AddNode (uint3 id : SV_DispatchThreadID)
{
uint trailIdx = id.x;
if ( trailIdx < _TrailNum )
{
Trail trail = _TrailBufferW[trailIdx];
uint totalInputNum = trail.totalInputNum;
bool isFirst = (totalInputNum==0);
InputData inputData = _InputBuffer[trailIdx];
if ( isFirst || (_MinNodeDistance <= distance(inputData.pos, _NodeBufferW[calcNodeIdx(trailIdx, totalInputNum-1)].pos)))
{
Node node;
node.pos = inputData.pos;
node.time = _Time;
node.color = inputData.color;
uint nodeIdx = calcNodeIdx(trailIdx, totalInputNum);
_NodeBufferW[nodeIdx] = node;
trail.startTime = isFirst ? _Time : trail.startTime;
trail.totalInputNum++;
_TrailBufferW[trailIdx] = trail;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// CreateWidth
////////////////////////////////////////////////////////////////////////////////
StructuredBuffer<Trail> _TrailBuffer;
StructuredBuffer<Node> _NodeBuffer;
RWStructuredBuffer<Vertex> _VertexBuffer;
uint calcPrevIdxInTrail(uint idx)
{
return (idx + _NodeNumPerTrail-1) % _NodeNumPerTrail;
}
uint calcNextIdxInTrail(uint idx)
{
return (idx + 1) % _NodeNumPerTrail;
}
uint calcNodeIdxFromInTrail(uint trailIdx, uint idxInTrail)
{
return trailIdx * _NodeNumPerTrail + idxInTrail;
}
Node getNode(uint trailIdx, uint idxInTrail, uint totalInputNum)
{
idxInTrail = min(idxInTrail, totalInputNum-1); // 未使用ノードのIdxが指定されたら最新のノードを返す
return _NodeBuffer[calcNodeIdxFromInTrail(trailIdx, idxInTrail)];
}
float3 calcNodeDir(uint trailIdx, uint nodeIdxInTrail, uint totalInputNum)
{
float3 dirPrev = float3(0,0,0);
float3 dirNext = float3(0,0,0);
float3 pos = getNode(trailIdx, nodeIdxInTrail, totalInputNum).pos;
uint prevIdxInTrail = calcPrevIdxInTrail(nodeIdxInTrail);
uint inputIdxInTrail = calcPrevIdxInTrail(totalInputNum);
bool prevEnable = (prevIdxInTrail != inputIdxInTrail) && (prevIdxInTrail < totalInputNum);
if ( prevEnable )
{
dirPrev = normalize(pos - getNode(trailIdx, prevIdxInTrail, totalInputNum).pos);
}
bool nextEnable = nodeIdxInTrail!= inputIdxInTrail;
if ( nextEnable )
{
uint nextIdxInTrail = calcNextIdxInTrail(nodeIdxInTrail);
dirNext = normalize(getNode(trailIdx, nextIdxInTrail, totalInputNum).pos - pos);
}
return normalize(dirPrev + dirNext);
}
[numthreads(NUM_THREAD_X,1,1)]
void CreateWidth (uint3 id : SV_DispatchThreadID)
{
uint nodeIdx = id.x;
uint trailIdx = nodeIdx / _NodeNumPerTrail;
if ( trailIdx < _TrailNum )
{
Trail trail = _TrailBuffer[trailIdx];
uint totalInputNum = trail.totalInputNum;
uint nodeIdxInTrail = nodeIdx % _NodeNumPerTrail;
Vertex v0 = GetDefaultVertex();
Vertex v1 = GetDefaultVertex();
{
Node node = getNode(trailIdx, nodeIdxInTrail, totalInputNum);
float life = min(_Life, _Time - trail.startTime);
float rate = life <= 0 ? 1 : max(0, 1 - ((_Time - node.time) / life));
float3 pos = node.pos;
float3 dir = calcNodeDir(trailIdx, nodeIdxInTrail, totalInputNum);
float3 toCameraDir = calcToCameraDir(pos);
float3 right = normalize(cross(dir, toCameraDir)) * lerp(_EndWidth, _StartWidth, rate) * 0.5f;
v0.pos = pos - right;
v0.uv = float2(rate, 0);
v0.color = node.color;
v1.pos = pos + right;
v1.uv = float2(rate, 1);
v1.color = node.color;
}
uint startIdxInTrail = (totalInputNum <= _NodeNumPerTrail) ? 0 : calcNextIdxInTrail(totalInputNum-1);
uint nodeIdxFromStartInTrail = ((nodeIdxInTrail + _NodeNumPerTrail) - startIdxInTrail) % _NodeNumPerTrail;
uint drawIdx = calcNodeIdxFromInTrail(trailIdx, nodeIdxFromStartInTrail);
uint vIdx = drawIdx * 2;
_VertexBuffer[vIdx] = v0;
_VertexBuffer[vIdx+1] = v1;
}
}