這是完全可行的,這裏是一些HLSL代碼,它允許執行該操作(並處理在距離相同的情況下擊中兩個三角形的情況)。
我假設你知道如何創建資源(結構化緩衝區)並將它們綁定到計算管道。
此外,我會考慮你的幾何圖形被索引。
的第一步是收集通過測試的三角形。我們將使用追加緩衝區來只推送通過測試的元素,而不是使用「Hit」標誌。
首先創建2個結構化緩衝區(位置和三角形索引),並將模型數據複製到這些緩衝區。
然後創建一個結構化緩衝器,帶有一個可附加無序圖。
進行點擊檢測,可以使用下面的計算代碼:
struct rayHit
{
uint triangleID;
float distanceToTriangle;
};
cbuffer cbRaySettings : register(b0)
{
float3 rayFrom;
float3 rayDir;
uint TriangleCount;
};
StructuredBuffer<float3> positionBuffer : register(t0);
StructuredBuffer<uint3> indexBuffer : register(t1);
AppendStructuredBuffer<rayHit> appendRayHitBuffer : register(u0);
void TestTriangle(float3 p1, float3 p2, float3 p3, out bool hit, out float d)
{
//Perform ray/triangle intersection
hit = false;
d = 0.0f;
}
[numthreads(64,1,1)]
void CS_RayAppend(uint3 tid : SV_DispatchThreadID)
{
if (tid.x >= TriangleCount)
return;
uint3 indices = indexBuffer[tid.x];
float3 p1 = positionBuffer[indices.x];
float3 p2 = positionBuffer[indices.y];
float3 p3 = positionBuffer[indices.z];
bool hit;
float d;
TestTriangle(p1,p2,p3,hit, d);
if (hit)
{
rayHit hitData;
hitData.triangleID = tid.x;
hitData.distanceToTriangle = d;
appendRayHitBuffer.Append(hitData);
}
}
請注意,您需要爲appendRayHitBuffer提供足夠的大小(最壞的情況是三角形數量,例如:每一個三角形被擊中由射線)。
完成此操作後,緩衝區的開始部分包含命中數據,而無序視圖計數通過測試的三角形的數量。
然後,你需要創建一個參數緩存,和一個小字節地址緩衝區(大小爲16,因爲我不認爲運行時將允許12)
你還需要一個小的結構緩衝(一個元素就足夠了),將用於存儲最小距離
使用CopyStructureCount將UnorderedView計數器傳遞到這些緩衝區(請注意,參數緩衝區的第二個和第三個元素需要都設置爲1,因爲它們將作爲參數使用派遣)。
清除小StructuredBuffer緩衝區使用UINT_MAXVALUE,並使用與DispatchIndirect
爭論緩衝我以爲你不會有許多命中,所以下一部分numthreads將被設置爲1,1,1(如果您想要使用更大的組,則需要運行另一個計算着色器來構建參數緩衝區)。
然後找到最小距離:
StructuredBuffer<rayHit> rayHitbuffer : register(t0);
ByteAddressBuffer rayHitCount : register(t1);
RWStructuredBuffer<uint> rwMinBuffer : register(u0);
[numthreads(1,1,1)]
void CS_CalcMin(uint3 tid : SV_DispatchThreadID)
{
uint count = rayHitCount.Load(0);
if (tid.x >= count)
return;
rayHit hit = rayHitbuffer[tid.x];
uint dummy;
InterlockedMin(rwMinBuffer[0],asuint(hit.distanceToTriangle), dummy);
}
由於我們預期命中距離將大於零,我們可以使用asuint和InterlockedMin在該場景中。此外,由於我們使用DispatchIndirect,現在這部分僅適用於之前通過測試的元素。
現在您的單個元素緩衝區中包含的最小距離,而不是指數(或指數)。
最後一部分,我們需要最終提取三角指數是在最低下探距離。
你再次需要一個新的StructuredBuffer與UnorderedView存儲的最低指標。
使用相同的調度參數作爲前(間接),並執行以下操作:
ByteAddressBuffer rayHitCount : register(t1);
StructuredBuffer<uint> MinDistanceBuffer : register(t2);
AppendStructuredBuffer<uint> appendMinHitIndexBuffer : register(u0);
[numthreads(1,1,1)]
void CS_AppendMin(uint3 tid : SV_DispatchThreadID)
{
uint count = rayHitCount.Load(0);
if (tid.x >= count)
return;
rayHit hit = rayHitbuffer[tid.x];
uint minDist = MinDistanceBuffer[0];
uint d = asuint(hit.distanceToTriangle);
if (d == minDist)
{
appendMinHitIndexBuffer.Append(hit.triangleID);
}
}
現在appendMinHitIndexBuffer包含三角指數最爲接近(或幾個,如果你有一個場景),你可以複製它使用一個暫存資源並將您的資源映射爲閱讀。
我記得,有一個*理論上射線的最佳實現 - 三角形相交檢查(布爾不位置),其可以在着色器來實現。讓我看看我能否再次找到它 – Aaron
其實,我發現的所有例子都是CPU端...我想到的算法是[Möller-Trumbore相交算法](https://en.wikipedia.org/維基/ M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm)。我還發現了一個很好的教程鏈接[here](http://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection) – Aaron