《用兩天學(xué)習(xí)光線追蹤》1.項目介紹和ppm圖片輸出

本項目參考自教程《Ray Tracing in One Weekend》,在跑通了所有例子之后,加上了自己的理解寫成筆記,項目使用CPU多線程提速,并增加了GUI進度顯示。
項目鏈接:https://github.com/maijiaquan/ray-tracing-with-imgui

目錄:
《用兩天學(xué)習(xí)光線追蹤》1.項目介紹和ppm圖片輸出
《用兩天學(xué)習(xí)光線追蹤》2.射線、簡單相機和背景輸出
《用兩天學(xué)習(xí)光線追蹤》3.球體和表面法向量
《用兩天學(xué)習(xí)光線追蹤》4.封裝成類
《用兩天學(xué)習(xí)光線追蹤》5.抗鋸齒
《用兩天學(xué)習(xí)光線追蹤》6.漫反射材質(zhì)
《用兩天學(xué)習(xí)光線追蹤》7.反射向量和金屬材質(zhì)
《用兩天學(xué)習(xí)光線追蹤》8.折射向量和電介質(zhì)
《用兩天學(xué)習(xí)光線追蹤》9.可放置相機
《用兩天學(xué)習(xí)光線追蹤》10.散焦模糊


項目介紹

本項目使用了ImGUI的圖形化界面框架,使用官方自帶的一個OpenGL2的例子,目的是用直接繪制的方法,在屏幕上逐像素輸出整張圖片。目前在MacOS(Xcode 10.3)和Windows(Visual Studio 2015)環(huán)境中上能順利運行,其他環(huán)境待測試。

因為大家的主要目的是學(xué)習(xí)光線追蹤,所以環(huán)境搭建、GUI、圖片光柵化輸出、多線程的具體實現(xiàn)等,就不在這里細述,有興趣的朋友們可以看我的代碼實現(xiàn)。每一節(jié)的代碼都會基于上一節(jié)進行增改,最終實現(xiàn)效果如下:

image

本節(jié)目標(biāo)

在300x150的屏幕上輸出一張插值漸變的圖片,并保存為ppm格式,如下圖所示:

image

本節(jié)代碼:main1.cpp


多線程

由于用CPU跑光線追蹤很慢,所以用多線程來提速。假設(shè)CPU是雙核的,則理論上能提速一倍。
為了演示一下多線程,這里特地調(diào)整了每個線程的運行速度,并一次性創(chuàng)建了50個線程(假裝CPU有50個核),每個線程繪制完一行之后,跳到下50行繼續(xù)繪制。圖片的寬高為300x150,則每個線程要繪制3行。最下面一行的線程速度最快,越往上速度遞減的話,就會有如下效果:


image

PPM格式概要和存儲

ppm是一種直接存儲RGB顏色值的文件格式,第一行是p3,表示顏色值用ASCII存。第二行是圖像的寬和高。接下來是每一行按順序存放的顏色值。

本項目會將所有的輸出圖片保存為ppm格式,由于本項目支持實時顯示,關(guān)于如何打開ppm圖片的問題本文不再贅述,網(wǎng)上可找到大量解決辦法。


本節(jié)核心代碼

向量類vec3的具體實現(xiàn):vec3.h

對于像素點的繪制,我直接封裝了一個函數(shù):

void DrawPixel(x, y, r, g, b); //在屏幕上坐標(biāo)為(x,y)的位置上,繪制顏色值為(r,g,b)的一個像素

因為是一個簡單的漸變圖片,所以直接用行和列的下標(biāo)插值的方式來直接賦值RGB,代碼如下:

int nx = 300;
int ny = 150;
void RayTracing()
{
    for (int y = ny - 1; y >= 0; y --)
    {
        for (int x = 0; x < nx; x++)
        {
            vec3 col(float(x) / float(nx), float(y) / float(ny), 0.8);
            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            DrawPixel(x, y, ir, ig, ib);
        }
    }
}

如果要寫成多線程,則可以將上面代碼改成下面的樣子:

void RayTracingInOneThread(int k)   //繪制一個線程
{
    for (int y = ny-k; y >= 0; y -= numThread)  //ny為屏幕的高
    {
        for (int x = 0; x < nx; x++)    //nx為屏幕的寬
        {
            vec3 col(float(x) / float(nx), float(y) / float(ny), 0.8);
            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            DrawPixel(x, y, ir, ig, ib);
        }
    }
}

void RayTracing()
{
    vector<thread> threads; //多線程
    for (int k = 0; k < numThread; k++)
    {
        threads.push_back(thread(RayTracingInOneThread, k)); 
    }
    for (auto &thread : threads)
    {
        thread.join();
    }
}

注意:本項目的入口函數(shù)為RayTracing()。由于默認(rèn)使用多線程,入口函數(shù)會分發(fā)到若干個線程里面執(zhí)行,每個線程對應(yīng)的函數(shù)為RayTracingInOneThread(int k)。如果實在無法理解這個函數(shù)的行為,可以粗暴假設(shè)k=1numThread=1,當(dāng)作是單線程來理解。


參考資料:《Ray Tracing in One Weekend》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 全局光照:光線追蹤、路徑追蹤與GI技術(shù)進化編年史 轉(zhuǎn)發(fā)一篇關(guān)于全局光照的文章,寫的很好,普及下概念。 全局光照(G...
    雄關(guān)漫道從頭越閱讀 2,198評論 2 12
  • Problem Formulation Ray Tracing的目標(biāo)是生成一張包含場景內(nèi)物體,具有真實感的圖像,因...
    Manster閱讀 9,296評論 4 8
  • 身為一個計算機圖形學(xué)領(lǐng)域的小白,最近由于課程的緣故學(xué)習(xí)了一些光線追蹤方面的知識,并實現(xiàn)了基本的代碼,現(xiàn)在分享給大家...
    金戈大王閱讀 3,921評論 7 12
  • 生活對每個人何曾溫柔過,它的不溫柔總是推陳出新,無從選擇,更無法逃避。不是每個人都會經(jīng)歷人生的地震海嘯,希望劇烈的...
    孫華翎閱讀 193評論 0 0
  • 我本來可以很快樂的
    初夏未夏閱讀 201評論 0 0

友情鏈接更多精彩內(nèi)容