#pragma kernel AddNode #pragma kernel CreateWidth #define NUM_THREAD_X 32 #include "GPUTrailVariablesCS.compute" //////////////////////////////////////////////////////////////////////////////// // AddNode //////////////////////////////////////////////////////////////////////////////// StructuredBuffer _InputBuffer; RWStructuredBuffer _TrailBufferW; RWStructuredBuffer _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 _TrailBuffer; StructuredBuffer _NodeBuffer; RWStructuredBuffer _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; } }