2016-10-21 118 views
2

我最近完成轉換的使用D3DXIntersect找到射線/網格交點到DirectX 11,支持DirectX 9應用程序,因爲D3DXIntersect不提供DX11,我寫我自己的代碼來尋找交集,它只是在網格中的所有三角形上循環並對它們進行測試,以跟蹤最接近原點的點。這是在CPU端完成的,並且可以通過GUI進行拾取,但我有另一部分應用程序根據幾個不同的視點從現有的一個創建新的網格,我需要檢查每個三角形的視線在網格中多次。這變得很慢。的射線/網格的DirectX 11計算着色器相交

是否有意義使用DX11計算着色器(從做它的CPU上即會有一個顯著加速)這樣做呢?我搜索了互聯網,但找不到現有的例子。

假如答案是肯定的,這裏是我想到的辦法:

  • 啓動一個線程用於每個三角形在我的網
  • 每個線程計算在該三角形一擊的距離,或在未命中時返回最大浮點數。將每個線程的一個值存儲在緩衝區中。
  • 然後做一個減少並返回最小值(非負值)。

我希望我能夠訪問DirectX中的CUDA Thrust之類的東西,因爲我認爲編碼減少會是一種痛苦。這就是爲什麼我問,所以我不會爲了一件事而做一堆工作!

+0

我記得,有一個*理論上射線的最佳實現 - 三角形相交檢查(布爾不位置),其可以在着色器來實現。讓我看看我能否再次找到它 – Aaron

+0

其實,我發現的所有例子都是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

回答

0

這是完全可行的,這裏是一些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包含三角指數最爲接近(或幾個,如果你有一個場景),你可以複製它使用一個暫存資源並將您的資源映射爲閱讀。

相關問題