1. 程式人生 > >Monte-Carlo Ray Tracing System (一)原理以及架構設計

Monte-Carlo Ray Tracing System (一)原理以及架構設計

實時全域性光照

對於現在的CG相關行業來說 就如同一個待跨越的聖盃一樣。而在GPU不斷進步的過程中,我們卻對實現全域性光照越來越沒有信心 。效能不夠也是我們最常在嘴上提到的詞語
但是可以說其核心原理早就實現了 在這些年其核心原理並沒有取得很大的突破這也是現階段無法實現實時全域性光照的原因之一。

對待這樣一個系統來說 我們要先從原理說起也就是Monte-Carlo 數值積分。因此第一篇文章著重於演算法和設計 具體的程式碼將不會很多。

Chapter (1)

10x2dx=13

說起
在通常的過程中 對於這樣一個簡單的定積分我們人腦的求解過程是以固定的微分積分公式計算,公式雖然能方便計算出定積分的精確值,但是有一個侷限就是要首先通過不定積分得到被積函式的原函式。有的時候,求原函式是非常困難的,而有的函式,如

f(x)=sinxx

,已經被證明不存在初等原函式,這樣,就無法用Newton-Leibniz公式,只能另想辦法。

我們以y<(x2)作為判斷依據去劃分區域來判斷區域劃分 再通過隨機生成的點去重複的做判斷

當隨機點數量到達一定之後 我們以兩個區域的點的數量作為依據 即可得出結果 且點數越多誤差越小
根據伯努利大數法則:事件發生的頻率依概率收斂於事件的概率p

如下圖:
Monte

而一般來講Monte Carlo方法雖然可以解決很多疑難雜症 但是對於複雜度要求極高的光線追蹤領域 其結果十分驚豔 但並不能夠稱之為一個十分簡潔的演算法

下面我們進入下一章

我們在其他文章中講到了光照模型這一概念 然而應用在傳統的實時渲染領域 光照模型則是一個相對高效但是低質的概念

所在實時渲染領域 其多數是考慮怎麼儘量的使用障眼法去得到一個更逼近數值積分方法的結果 在洪培技術預計算的技術發展方面

類似於UE4的靜態效果 Paris demo 在美術和實時光照技術的雙重作用下 其效果已經達到了現有計算條件下畫質的巔峰
這裡寫圖片描述

但是相比真正的全域性光照,效果仍舊差了一些。

也許會有人說 如此大的代價 去提升那20-30%的畫質 值不值得 ?

當然值得!!

在講解下一章之前我們來了解一下傳統的光柵化渲染技術

什麼是光柵化?什麼是光柵?

光柵是光學中一種常見的概念 意為大量等距平行狹縫
然而在實際中光柵化的意義接近於畫素化,離散化;用已知概念去理解 類似於透過紗窗去看外面的世界


傳統構成三維觀察方法常用的為等軸測投影和透視投影。

首先要討論的是如何把一個三維模型的資料集繪製成相應的模型

這個階段其實在《Real time Rending》這本書和之前的文章裡介紹的很清楚了

渲染管線的基礎結構分為:
這裡寫圖片描述

1.Application應用階段

需要渲染的幾何體從一個固定的資料結構被傳遞到幾何階段。這傳遞過去的東西被稱為圖元,例如點、線、三角形,這些圖元有可能最終顯示到螢幕上。這是應用階段最重要的任務。
由軟體實現的應用階段的問題可能在於,它不能像幾何和光柵化階段那樣劃分為多個子階段。但是,為了提高效能,這一階段經常是由多核並行執行。在設計中,這稱之為超標量體系,

2.Geometry幾何階段

這裡寫圖片描述
在這個階段一般是對模型進行檢視變換 對操作進行響應 對頂點進行著色 投影 裁剪和螢幕對映

相應的例如變換過程如下

這裡寫圖片描述

裁剪過程
這裡寫圖片描述

裁剪之後的影象 還不能用來顯示 現代作業系統的影象大多數執行在視窗之下 所以針對已經計算好的顯示方式來說還需要最後一步 那就是影象幀對螢幕相應區域的對映

過程如下圖:

這裡寫圖片描述

從另一個角度我們也可以考慮到 為什麼全屏執行的遊戲 效果會更好一些 這與省略了對映階段也有著一定的關係

3.Rasterizer光柵器

在這個階段的細分任務中我們算是可以看出這些效果的成因
這裡寫圖片描述

渲染的過程大致相當於:

這裡寫圖片描述

至於牽扯到具體的光效 ,陰影 等資訊著色器就開始擔當大任啦
具體可見:著色器部分

講完了光柵化體系 我們可以看得到 其效果都是由理論模型模擬效果 效率在現在的光柵化晶片加持下 還算不錯 在好的硬體中如GTX1080Ti 甚至能把一個4K 的普遍場景渲染到120Hz

但是

在大多數作品中 我們不可能達到非常好的效果 因為即使類似Unreal Paris demo這種 預渲染的效果 已經計算好了光照 美術和設計還有著色器方面的設計要求實在是太高了

那麼 我們實現實時全域性光照的意義在哪裡?

舉個例子 如果在一個場景之下 我們對一個畫素需要30條光線來收斂 以最小的720p 也就是1280*720解析度 再加上60hz的重新整理率 可以看到每秒鐘需要處理的光線數量達到了16億5000萬條

那我們以一個正常效果的收斂來計算
收斂取樣數為200 1080p解析度 60hz重新整理率
每秒鐘需要處理的光線數量達到了248億

不得不承認

在傳統的SIMD GPU架構上光線追蹤的效率被大大折扣 因此移動GPU巨頭 多年為蘋果設計GPU的Imagination甚至收購了一些企業 製作了光線追蹤加速卡 以至於我們可以在移動端的功耗前提下實現穩定的光線追蹤技術
以下為相應的架構圖

這裡寫圖片描述

而我們再看看SIMD

這裡寫圖片描述

因此實時光線追蹤絕不是遙不可及的技術

但是僅僅這些我們不足以對光線追蹤產生如此大的興趣 因此實時光線追蹤的好處甚至包含了準確反映光的衍射,色散,等等光學特性 這在傳統體系之下幾乎是無法做到的

最終結合計算物理中的流體模擬,動力學模擬,甚至量子物理模擬 在計算機中建立一個完全擬真的世界 永遠是人類為之努力的目標

很慶幸的是 這其中很多技術都取得了關鍵突破

Chapter(2)

1979年,TurnerWhitted在光線投射的基礎上,加入光與物體表面的互動,是光線在物體表面沿著反射,折射以及散射方式上繼續傳播,直到與光源相交這一方法後來也被稱為經典光線跟蹤方法、遞迴式光線追蹤(Recursive Ray Tracing)方法,或 Whitted-style 光線跟蹤方法。

其主要思想是從視點向成像平面上的像素髮射光線,找到與該光線相交的最近物體的交點,如果該點處的表面是散射面,則計算光源直接照射該點產生的顏色;如果該點處表面是鏡面或折射面,則繼續向反射或折射方向跟蹤另一條光線,如此遞迴下去,直到光線逃逸出場景或達到設定的最大遞迴深度。
by淺墨

原理:

我們如果能看到一個物體的某個點 這個點必然反射/折射了光線

而對於光線追蹤這個過程本身來講就像是自然世界的逆過程,朝著我們能看到的所有點發射光線,追蹤次光線(shadow ,reflection ,refraction)。必然能夠回到光源。

這裡寫圖片描述

圖中的幾個部分分別說明了 物件的表示 光線的求解方式
相交的求解方式 等等 我們分公式來舉例說明一下每個公式怎樣用程式碼求解

基礎定義類

三位向量運算類

template<typename T>
class Vec3
{
public:
    T x, y, z;
    Vec3() : x(T(0)), y(T(0)), z(T(0)) {}
    Vec3(T xx) : x(xx), y(xx), z(xx) {}
    Vec3(T xx, T yy, T zz) : x(xx), y(yy), z(zz) {}
    //正規化
    Vec3& normalize()
    {
        T nor2 = length2();
        if (nor2 > 0) {
            T invNor = 1 / sqrt(nor2);
            x *= invNor, y *= invNor, z *= invNor;
        }
        return *this;
    }
    //運算定義
    Vec3<T> operator * (const T &f) const { return Vec3<T>(x * f, y * f, z * f); }
    //標量*向量
    Vec3<T> operator * (const Vec3<T> &v) const { return Vec3<T>(x * v.x, y * v.y, z * v.z); }
    //向量1*向量2
    T dot(const Vec3<T> &v) const { return x * v.x + y * v.y + z * v.z; }
    //點積
    Vec3<T> operator - (const Vec3<T> &v) const { return Vec3<T>(x - v.x, y - v.y, z - v.z); }
    //向量1-向量2
    Vec3<T> operator + (const Vec3<T> &v) const { return Vec3<T>(x + v.x, y + v.y, z + v.z); }
    //向量1+向量2
    Vec3<T>& operator += (const Vec3<T> &v) { x += v.x, y += v.y, z += v.z; return *this; }
    //向量自增
    Vec3<T>& operator *= (const Vec3<T> &v) { x *= v.x, y *= v.y, z *= v.z; return *this; }
    //向量自乘
    Vec3<T> operator - () const { return Vec3<T>(-x, -y, -z); }
    //求負
    T length2() const { return x * x + y * y + z * z; }
    //模^2
    T length() const { return sqrt(length2()); }
    //模
    friend std::ostream & operator << (std::ostream &os, const Vec3<T> &v)
    {
        os << "[" << v.x << " " << v.y << " " << v.z << "]";
        return os;
    }
};

當然 這是較為精簡的寫法和部分運算 下篇文章中 我們將著重來嘗試優化渲染效率和效果 但是其中涉及的複雜運算不利於基礎概念的理解 所以我們用比較基礎的運算來說明

同時按照圖中順序 我們將對這整個過程作一個說明

Sphere / Ray intersection (給出光線和球的表示式 求相交)

Sphere equation/三維向量的球面表示式 可以想象球面點到球心的差的平方為半徑的平方

(p⃗ c⃗ )(p⃗ c⃗ )=r2

    Vec3f center;                           /// position of the sphere
    float radius, radius2;                  /// sphere radius and radius^2
    Vec3f surfaceColor, emissionColor;      /// surface color and emission (light)
    float transparency, reflection;         /// surface transparency and reflectivity
    Sphere(
        const Vec3f &c,
        const float &r,
        const Vec3f &sc,
        const float &refl = 0,
        const float &transp = 0,
        const Vec3f &ec = 0) :
        center(c), radius(r), radius2(r * r), surfaceColor(sc), emissionColor(ec),
        transparency(transp), reflection(refl)
    { /* empty */ }

Ray equation

r⃗ (t)=o⃗ +td⃗ 

這個應該就不用說了 發射點向量和發射的方向向量

僅需要兩個引數

    const Vec3f &rayorig; 
    const Vec3f &raydir;

Intersection

(1)

(o⃗ +td⃗ c⃗ )(o⃗ +td⃗ c⃗ )=r2

or

t2(d⃗ d⃗ )+2(o⃗ c⃗ )td⃗ +(o⃗ c⃗ )(o⃗ c⃗ )r2=0

值得注意的是 intersect是定義在結構體當中的 並非獨立

而最終判斷是否相交需要bool型別做判斷 即判斷給定光線和給定球體是否相交

intersect

    bool intersect(const Vec3f &rayorig, const Vec3f &raydir, float &t0, float &t1) const
    {
        Vec3f l = center - rayorig;
        float tca = l.dot(raydir);
        if (tca < 0) return false;
        float d2 = l.dot(l) - tca * tca;
        if (d2 > radius2) return false;
        float thc = sqrt(radius2 - d2);
        t0 = tca - thc;
        t1 = tca + thc;
        return true;
    }

當然 這僅僅是與球體的相交檢驗 更多的 和各種幾何體和各種網格的檢驗程式碼 我們將在以後的文章中提及

Illumination Equation(光照方程)

在上圖中 Blin-Phone 光照方程如下

I=kaIa+Ii(kd(L⃗ N⃗ )+ks(V⃗ R⃗ )n)+ktIt+krIr

IaKa為遞迴元素

但是我們作為基本傳參的方程樣式應該是渲染方程中的

猛地一看這麼長確實很懵逼 現在市面上很多的書籍教材都不會對引數做詳解
所以就需要我們把這個渲染方程分開來看 看看每一部分到底代表什麼

事實上 我們也可以發現 渲染方程都是分開求解的 最後的結果是所有光照型別部分結果的總和

1. (環境光)

相關推薦

Monte-Carlo Ray Tracing System ()原理以及架構設計

實時全域性光照 對於現在的CG相關行業來說 就如同一個待跨越的聖盃一樣。而在GPU不斷進步的過程中,我們卻對實現全域性光照越來越沒有信心 。效能不夠也是我們最常在嘴上提到的詞語 但是可以說其核心原理早就實現了 在這些年其核心原理並沒有取得很大的突破這也

MySQL主從復制原理以及架構

body 觸發器 新的 dex 延時 -m 加鎖 影響 int 1 復制概述 Mysql內建的復制功能是構建大型,高性能應用程序的基礎。將Mysql的數據分布到多個系統上去,這種分布的機制,是通過將Mysql的某一臺主機的 數據復制到其它主機(slaves)上

運維的天:架構設計、故障處理、人員離職…

高效運維社群致力於陪伴您的職業生涯,與您一起愉快的成長。 作者簡介: 韓曉光 DevOps Master、資訊系統專案管理師、ITIL Foundation、RHCE。GOPS金牌講師、金牌作者。著有《系統運維全面解析:技術、管理與實踐》一書。 本文導讀: 本文以敘事形式濃縮了很多運維場景、技術與

iOS底層原理架構設計

何為架構? 架構(Architecture):軟體開發中的設計方案,類與類之間的關係、模組與模組之間的關係、客戶端與服務端的關係。 經常聽到的架構名詞:MVC、MVP、MVVM、VIPER、CDD、三層架構、四層架構等。 MVC - Apple版 Model

字尾樹系列:概念以及實現原理( the Ukkonen algorithm)

首先說明一下字尾樹系列一共會有三篇文章,本文先介紹基本概念以及如何線性時間內構件字尾樹,第二篇文章會詳細介紹怎麼實現字尾樹(包含實現程式碼),第三篇會著重談一談字尾樹的應用。   本文分為三個部分, 首先介紹一下字尾樹的“前身”– trie樹以及字

關於ssm的工作原理以及相應的功能開發(

SSM框架的Web程式主要用到了三個技術: Spring:用到了註解和自動裝配,就是Spring的兩個精髓IOC(反向控制)和 AOP(面向切面程式設計)。 SpringMVC:用到了MVC模型,將邏輯程式碼放到Controller層處理。 Mybatis:用到了與資料庫打交道的層面,放在所有的

Ray tracing in a weekend(

#include<iostream> #include<fstream> using namespace std; int main() { int nx = 200;//200列 int ny = 100;//100行 ofstream o

Ray tracing in a weekend (十)

Defocus Blur(散焦模糊) 在之前渲染所得的影象中所有物體都是“清晰”的,現在要讓影象更趨近於真實的camera相片,即“有實有虛”。 camera.h #define M_PI 3.1415926 #include"ray.h" #include"

神經網路之神經網路結構與原理以及python實戰

技術交流qq群: 659201069   本系列埔文由淺入深介紹神經網路相關知識,然後深入神經網路核心原理與技術,最後淺出python神經網路程式設計實戰。通過本系列博文,您將徹底理解神經網路的原理以及如何通過python開發可用於生產環境的程式。本博

django開發之許可權管理()——許可權管理詳解(許可權管理原理以及方案)、不使用許可權框架的原始授權方式詳解

知識清單 1.瞭解基於資源的許可權管理方式 2. 掌握許可權資料模型 3. 掌握基於url的許可權管理(不使用許可權框架的情況下實現許可權管理) 許可權管理原理知識 什麼是許可權管理 只要有使用者參與的系統一般都要有許可權管理,許可權管理實現對使用者訪問系統的控制。按照安全規則或安全策略

)H264編碼原理以及I幀B幀P幀

 ---------------------- 前言 -----------------------        H264是新一代的編碼標準,以高壓縮高質量和支援多種網路的流媒體傳輸著稱,在編碼方面,我理解的他的理論依據是:參照一段時間內影象的統計結果表明,在相鄰幾幅

JAVAWEB開發之許可權管理()——許可權管理詳解(許可權管理原理以及方案)、不使用許可權框架的原始授權方式詳解

/* SQLyog v10.2 MySQL - 5.1.72-community : Database - shiro ********************************************************************* */ /*!40101 SET NAMES

文詳解蒙特卡洛(Monte Carlo)法及其應用

概述 蒙特卡羅方法是一種計算方法。原理是通過大量隨機樣本,去了解一個系統,進而得到所要計算的值。 它非常強大和靈活,又相當簡單易懂,很容易實現。對於許多問題來說,它往往是最簡單的計算方法,有時甚至是唯一可行的方法。它誕生於上個世紀40年代美國的"曼哈頓計劃",名字

次搞懂Spring Web零xml配置原理以及父子容器關係

# 前言 在使用Spring和SpringMVC的老版本進行開發時,我們需要配置很多的xml檔案,非常的繁瑣,總是讓使用者自行選擇配置也是非常不好的。基於**約定大於配置**的規定,Spring提供了很多註解幫助我們簡化了大量的xml配置;但是在使用SpringMVC時,我們還會使用到**WEB-INF/we

DEM山體陰影原理以及算法具體解釋

body global 像素 eas 每一個 factor otto con pan 山體陰影原理以及算法具體解釋 山體陰影基本原理:山體陰影是假想一個光源在某個方向和某個太陽高度的模擬下。用過臨近像元的計算來生成一副0-255的灰度圖。 一、山體陰影的主要參數:1、

(9)launcher3 之 外部 更換主題Theme APP demo 實現原理以及demo

解壓 work ace fontsize 思路 con 鎖屏 解壓文件夾 更新 先說下我的思路: luancher3裏面更換圖標的邏輯例如以下: 先從APP資源包裏查詢--數據庫查詢--其它地方查詢ICON 因此,我們僅僅須要把 從數據庫獲取ICON 代碼提前到 從A

java線程總結--synchronized關鍵字,原理以及相關的鎖

public 關鍵字 多線程 java 文章 在多線程編程中,synchronized關鍵字非常常見,當我們需要進行“同步”操作時,我們很多時候需要該該關鍵字對代碼塊或者方法進行鎖定。被synchronized鎖定的代碼塊,只能同時有一條線程訪問該代碼塊。上面是很多人的認識,當然也是我之前

Linux基礎服務_DNS原理以及正反向DNS配置

應用程序 服務器 dns基礎 DNS服務的原理介紹: dns(Domain Name Service,域名解析服務) 為c/s架構的服務 通常默認的監聽的端口為:53/tcp 53/udp 將dns服務實現的應用程序為:bind

tomcat工作原理以及詳解操作

tomcat的工作原理及安裝mkdir /cdrom#創建掛載目錄mount -o loop tomcat.iso /cdromcp -a /cdrom/* .mkdir -p /ly/wwwtar -xf jdk-7u25-linux-i586.gz tar -xf apache-tomcat-7.0.42

ping的原理以及ICMP

都在 發生 傳輸 傳播 ppr nim 同時 工作 con ping 的原理: ping 程序是用來探測主機到主機之間是否可通信,如果不能ping到某臺主機,表明不能和這臺主機建立連接。 ping 使用的是ICMP協議,它發送icmp回送請求消息給目的