用多線程為光線追蹤提速

用多線程為光線追蹤提速

在 @miccall 的文章 光線追蹤太慢不想等?用 openGL重現採樣過程 中提到了

要在第一時間得到全圖,然後每次循環都是對全部像素進行採樣,而不是單純的對一個像素循環採樣

我這裡二次封裝了一個DirectX的庫作為預覽窗口,提供實時的效果預覽。

之後我使用了多線程,來提高渲染的速度。目前的速度在我的2.6GHZ的筆記本上渲染一張512*512像素 100spp的圖片需要約2分鐘,而我之前的版本則需要20分鐘。

效果如下

https://www.zhihu.com/video/974684843929509888

具體實現是:

我首先將所有像素數據存成一個浮點型數組, 在預覽的每一幀將浮點數組轉換為byte數組然後賦給DX庫繪製。

這裡使用浮點型數組是為了保留精度。否則顏色會在200spp後失真

多線程掃描,設置16個線程池,然後每個線程執行一個掃描器。這裡第一幀是單獨繪製的,後面採用多線程來糾正像素精度

ThreadPool.SetMaxThreads(16, 16);await Task.Factory.StartNew(delegate { LinearScanner(new ScannerConfig(true, height, width)); });for (var i = 1; i < Samples; i++) ThreadPool.QueueUserWorkItem(LinearScanner, new ScannerConfig(false, height, width));

掃描器

像素緩衝buff 在每次設置的時候都是通過公式

((緩衝中的顏色 x 當前採樣的次數-1) + 新顏色)/ 當前採樣的次數

來矯正採樣顏色的

private void LinearScanner(object o) { var config = (ScannerConfig)o; int n; lock (buff) n = ++NowSample; for (var j = config.h - 1; j >= 0; j--) for (var i = 0; i < config.w; i++) { var color = Diffusing(camera.CreateRay( (i + Random.Range(0, 1f)) * recip_width, (j + Random.Range(0, 1f)) * recip_height), hitableList, 0); SetPixel(i, config.h - j-1,color,n); } } private void SetPixel(int x, int y, Color32 c32,int n) { var i = width * 4 * y + x * 4; var color = (new Color32(buff[i], buff[i + 1] , buff[i + 2] , buff[i + 3]) *(n - 1) + c32) /n; buff[i] = color.r; buff[i + 1] = color.g; buff[i + 2] = color.b; buff[i + 3] = color.a; }

將緩衝中的圖片保存為PNG格式

public void Save() { var pic_buff = preview.Buff; var pic = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); for (var i = 0; i < pic_buff.Length; i+=4) { var c = Color.FromArgb(pic_buff[i+3], pic_buff[i], pic_buff[i+1], pic_buff[i+2]); pic.SetPixel(i % (width*4)/4, i / (width*4), c); } pic.Save("a.png"); }

目前這些內容都在

Asixa/RayTracing-TheNextWeek?

github.com


推薦閱讀:

Ray Marching 101
一款針對離線渲染的基於Nvidia Optix的AI加速降噪工具

TAG:計算機圖形學 | 光線跟蹤 | 渲染器 |