Files
2026-07-13 13:13:17 +08:00

244 lines
7.8 KiB
HLSL

#include "shared/point.hlsl"
#include "shared/quat-functions.hlsl"
#include "shared/pbr.hlsl"
cbuffer Params : register(b0)
{
float StepCount;
float DecayW;
float Extend;
float SpreadColor;
float SpreadColorShift;
}
StructuredBuffer<Point> SourcePoints : t0;
StructuredBuffer<PbrVertex> Vertices : t1;
StructuredBuffer<int3> Indices : t2;
RWStructuredBuffer<Point> ResultPoints : u0;
// Casual Moller-Trumbore GPU Ray-Triangle Intersection Routine
// bool intersectMT(
// float3 orig, float3 dir,
// float3 v0, float3 v1, float3 v2,
// out float3 baryzentricUVW,
// out float t)
// {
// float3 e1 = v1 - v0;
// float3 e2 = v2 - v0;
// float3 normal = normalize(cross(e1, e2));
// float b = dot(normal, dir);
// float3 w0 = orig - v0;
// float a = -dot(normal, w0);
// t = a / b;
// float3 p = orig + t * dir;
// float uu, vv, uv, wu, wv, inverseD;
// //float2 baryzentricUV = 0;
// uu = dot(e1, e1);
// uv = dot(e1, e2);
// vv = dot(e2, e2);
// float3 w = p - v0;
// wu = dot(w, e1);
// wv = dot(w, e2);
// inverseD = uv * uv - uu * vv;
// inverseD = 1.0f / inverseD;
// float u = (uv * wv - vv * wu) * inverseD;
// if (u < 0.0f || u > 1.0f)
// //return -1.0f;
// return false;
// float v = (uv * wu - uu * wv) * inverseD;
// if (v < 0.0f || (u + v) > 1.0f)
// return false;
// //return -1.0f;
// baryzentricUVW = float3(u,v, 1-u-v).xzz;
// return true;
// }
static const float kEpsilon = 0.0001;
// From https://graphicscodex.courses.nvidia.com/app.html?page=_rn_rayCst#section4.2
bool intersect(
float3 orig, float3 dir,
float3 v0, float3 v1, float3 v2,
out float3 b,
out float t)
{
// Edge vectors
float3 e_1 = v1 - v0;
float3 e_2 = v2 - v0;
// Face normal
float3 n = normalize(cross(e_1, e_2));
float3 q = cross(dir, e_2);
float a = dot(e_1, q);
// Backfacing / nearly parallel, or close to the limit of precision?
if ((dot(n, dir) >= 0) || (abs(a) <= kEpsilon))
return false;
float3 s = (orig - v0) / a;
float3 r = cross(s, e_1);
b[0] = dot(s, q);
b[1] = dot(r, dir);
b[2] = 1.0f - b[0] - b[1];
t = dot(e_2, r);
// Intersected inside triangle?
return ((b[0] >= 0) && (b[1] >= 0) && (b[2] >= 0) && (t >= 0));
}
static const float NaN = sqrt(-1);
static const int RAY_THREAD_COUNT = 8;
static const int FACE_THREAD_COUNT = 512 / RAY_THREAD_COUNT;
groupshared int BestHitIntDistances[RAY_THREAD_COUNT];
groupshared int BestHitIndices[RAY_THREAD_COUNT];
groupshared float3 BestHitPositions[RAY_THREAD_COUNT];
groupshared float2 BestHitBaryUV[RAY_THREAD_COUNT];
[numthreads(RAY_THREAD_COUNT, FACE_THREAD_COUNT, 1)] void main(uint3 i : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID)
{
uint rayCount, stride;
SourcePoints.GetDimensions(rayCount, stride);
uint faceCount;
Indices.GetDimensions(faceCount, stride);
uint rayId = i.x;
uint rayThreadId = GTid.x;
uint faceThreadId = i.y;
uint stepCount = (uint)StepCount; // including separator
uint rayGroupStartIndex = i.x * stepCount;
Point p = SourcePoints[i.x];
// Write ray start and seperator
ResultPoints[rayGroupStartIndex + 0] = p;
ResultPoints[rayGroupStartIndex + stepCount - 1].Scale = NaN;
float3 rayOrigin = p.Position;
float3 rayDirection = qRotateVec3(float3(0, 0, 1), p.Rotation);
float fx1 = p.FX1;
int _bestHitIndex = -1;
float3 _bestHitPosition = rayOrigin + rayDirection * Extend;
float2 _bestHitBaryUv = 0;
for (uint stepIndex = 1; stepIndex < (stepCount - 1); stepIndex++)
{
if (faceThreadId == 0)
{
if (rayId < rayCount)
{
BestHitIntDistances[rayThreadId] = 99999999;
BestHitIndices[rayThreadId] = -1;
BestHitPositions[rayThreadId] = rayOrigin + rayDirection * Extend;
_bestHitIndex = -1;
_bestHitPosition = rayOrigin + rayDirection * Extend;
_bestHitBaryUv = 0;
}
}
GroupMemoryBarrierWithGroupSync();
int faceGroupCount = faceCount / FACE_THREAD_COUNT;
for (uint faceGroupStartIndex = 0; faceGroupStartIndex < faceCount; faceGroupStartIndex += FACE_THREAD_COUNT)
{
uint faceId = faceThreadId + faceGroupStartIndex;
if (faceId < faceCount)
{
int3 f = Indices[faceId];
float3 bary;
float t;
if (intersect(
rayOrigin,
rayDirection,
Vertices[f[0]].Position,
Vertices[f[1]].Position,
Vertices[f[2]].Position,
bary,
t))
{
float org;
int intt = t * 1000;
InterlockedMin(BestHitIntDistances[rayThreadId], intt, org);
if (org > intt)
{
BestHitIndices[rayThreadId] = faceId;
BestHitBaryUV[rayThreadId] = bary.zx;
BestHitPositions[rayThreadId] = rayOrigin + rayDirection * t;
_bestHitIndex = faceId;
_bestHitBaryUv = bary.zx;
_bestHitPosition = rayOrigin + rayDirection * t;
}
}
}
// GroupMemoryBarrierWithGroupSync();
}
GroupMemoryBarrierWithGroupSync();
_bestHitIndex = BestHitIndices[rayThreadId];
if (_bestHitIndex < 0)
{
rayOrigin += rayDirection * Extend;
ResultPoints[rayGroupStartIndex + stepIndex].Rotation = p.Rotation;
ResultPoints[rayGroupStartIndex + stepIndex].Position = rayOrigin;
ResultPoints[rayGroupStartIndex + stepIndex].Scale = p.Scale;
ResultPoints[rayGroupStartIndex + stepIndex].FX2 = p.FX2;
ResultPoints[rayGroupStartIndex + stepIndex].Color = p.Color;
ResultPoints[rayGroupStartIndex + stepIndex].Position = rayOrigin;
ResultPoints[rayGroupStartIndex + stepIndex].FX1 = fx1;
}
else
{
_bestHitPosition = BestHitPositions[rayThreadId];
rayOrigin = _bestHitPosition;
ResultPoints[rayGroupStartIndex + stepIndex].Position = rayOrigin;
ResultPoints[rayGroupStartIndex + stepIndex].Rotation = p.Rotation;
ResultPoints[rayGroupStartIndex + stepIndex].FX1 = fx1;
ResultPoints[rayGroupStartIndex + stepIndex].Scale = p.Scale;
ResultPoints[rayGroupStartIndex + stepIndex].FX2 = p.FX2;
ResultPoints[rayGroupStartIndex + stepIndex].Color = p.Color;
float3 n0 = normalize(Vertices[Indices[_bestHitIndex][0]].Normal);
float3 n1 = normalize(Vertices[Indices[_bestHitIndex][1]].Normal);
float3 n2 = normalize(Vertices[Indices[_bestHitIndex][2]].Normal);
_bestHitBaryUv = BestHitBaryUV[rayThreadId]; // <----
float u = _bestHitBaryUv.x;
float v = _bestHitBaryUv.y;
float3 n = normalize(u * n0 + v * n1 + (1 - u - v) * n2);
fx1 *= DecayW;
// rayDirection= reflect( rayDirection, n * 1);
float3 I = rayDirection;
// float3 R = I - 2* ( dot(n,I)* n);
float phi = acos(dot(n, I));
phi += (fx1 - SpreadColorShift) * SpreadColor;
float3 R = I - 2 * cos(phi) * n;
rayDirection = R;
// rayDirection= reflect( rayDirection, n);
}
GroupMemoryBarrierWithGroupSync();
ResultPoints[rayGroupStartIndex + stepCount - 1].Scale = NaN;
}
}