2014-10-03 38 views
2

所以我試圖使用openCL實現光線/路徑跟蹤器,它看起來非常簡單 - 編寫一個跟蹤單個光線/像素/等路徑的內核並讓它執行並行多條射線。openCL光線跟蹤和分支內核代碼問題

但是,當遍歷一個場景時,單個射線會有相當多的方向。例如,根據擊中物體的材質,射線可以反射或折射。另外,不同的材質需要不同的着色算法。例如,如果一個場景對象需要cook-torrance着色器,而另一個場景對象需要病毒各向異性着色器,則需要在內核中調用不同的着色函數。

根據我一直在閱讀的內容,在內部使用分支代碼的內核是不可取的,因爲它會影響性能。但是如果我基於每條射線並行化我的代碼,這在射線追蹤器中似乎是不可避免的。

因此,「分支」代碼結構真的是內核性能的一大障礙嗎?如果是這樣,我會怎樣去構建我的代碼來解決這個問題?

+0

而不是分支,將數組元素中的「1」保存爲「要分支」(「0」表示不分支)並對數組進行排序,使得所有分支彼此相鄰,無分支「 0「是彼此相鄰的,所以SIMD得到了它想要的和更快的,因爲所有元素在多遍(迭代)中做同樣的事情(只有分支或只有非分支)而不是假遞歸性(以性能指數方式殺死性能)。單個基數排序通行證可以做到這一點。我的意思是,在第二遍中,內核尋找「1」來分支並繼續追蹤光束,「0」結束並獲得像素的顏色。 – 2014-10-04 11:19:27

+0

我還是有點困惑。首先,當你說使用「多次傳遞」時,你的意思是不同的內核調用?在哪裏進行射線分類,在內核或主機上進行?如果它在主機上,會不會導致性能下降?在任何情況下仍然不確定整個控制流程。就像你說的在內核1中有一道光線緩衝區,追蹤它們直到它們碰到某物,然後根據它們擊中的位置,再次追蹤等將它們分成內核2和3? – user1855952 2014-10-04 20:04:03

回答

2

第一遍(1M射線),無符號的字符陣列(或甚至壓縮單位)

ray 0  ------------------ render end --------------> 0  \ 
    ray 1  ------------------ surface ---------------> 1  \ 
    ray 2  ------------------ surface ---------------> 1  }-- bad for SIMD 
    ray 3  ------------------ render end --------------> 0 /
    ray 4  ------------------ surface ---------------> 1 /
    ... 
    ... 
    ray 1M ... 

分選(高速緩存或復此重複使用折射和反射)與表面類型 (存在/不存在的)和表面位置(時間一致性)

ray 1 \ 
    ray 2 -------------------- all surfaces --------------> 1 good for simd 
    ray 4/
    ray 0 \ 
    ray x -------------------- all render end ------------> 0 good for simd 
    ray 3/

    second pass (refraction) (1M rays) 

    ray 1 ..................... refract ...................> cast a new ray 
    ray 2 ..................... refract ...................> cast a new ray 
    ray 4 ..................... refract ...................> cast a new ray 
    ray 0 .................... no new ray casting .........> offload some other work/draw 
    ray x .................... no new ray casting .........> offload some other work/draw 
    ray 3 .................... no new ray casting .........> offload some other work/draw 

    third pass (reflection) (1M rays) 

    ray 1 ..................... reflect...................> cast a new ray 
    ray 2 ..................... reflect...................> cast a new ray 
    ray 4 ..................... reflect...................> cast a new ray 
    ray 0 .................... no new ray casting .........> offload some other work/draw 
    ray x .................... no new ray casting .........> offload some other work/draw 
    ray 3 .................... no new ray casting .........> offload some other work/draw 

現在有兩組1M射線,每次迭代時加倍。所以如果你有256M元素的空間,你應該能夠投射光線,直到深度7或8.所有這些都可以通過適當的索引在單個陣列上完成。

+0

感謝這個想出來的答案。這肯定給我一個我需要做的開始參考(不知何故,我將不得不從外部推斷如何不僅反射/折射,而且還有多個着色算法,不同形狀類型的相交測試等)。 – user1855952 2014-10-06 09:35:25

+0

對於單內核版本,您可以從每個工作組的單音像素開始,然後在該單個工作組中分支並生成光線(refr/refl),直到工作組無法拍攝它的深度爲6-7(128/256條光線)再重複下一個像素的處理,這樣的內核會很慢,但是我可以說內核啓動開銷會很小。使用全球記憶,你可以輕鬆擁有30-40的深度。 – 2014-10-06 10:02:03

+0

此方法的實現是否存在? – runeks 2015-02-25 13:10:40