第12章 體積散射_第1頁
第12章 體積散射_第2頁
第12章 體積散射_第3頁
第12章 體積散射_第4頁
第12章 體積散射_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第12章 體積散射到目前為止,我們都假定場景中的所有表面都在真空中,這意味者在表面之間的光線的輻射亮度是恒定的。然而,在許多真實世界中的情景中,這個假設(shè)并不精確: 霧和煙對光產(chǎn)生了衰減和散射作用,大氣中的粒子的散射作用使得藍天呈藍色,使得夕陽晚景呈紅色。本章介紹相關(guān)的數(shù)學(xué)知識來描述參與介質(zhì) (participating media-分布于三維空間區(qū)域中的粒子)對光的影響。有了對參與介質(zhì)的效果的模擬,我們就可以渲染場景有霧靄的圖像、穿透云層的光束、子表面的散射 (即光線的出射點跟入射點不同)。本章首先描述了光線的輻射亮度受參與介質(zhì)影響的基本物理過程。然后,我們介紹VolumeRegion基本類,

2、它是描述不同介質(zhì)的接口。為了確定光在場景中的分布的整體效果,我們還需要第17章中所介紹的VolumeIntegrator。12.1 體積散射過程在有參與介質(zhì)的環(huán)境中,有三個主要過程可以影響輻射亮度的分布:吸收(Absorption):由于光能轉(zhuǎn)變成其它形式的能量(如熱)而減弱了輻射亮度。放射(Emission):發(fā)光的粒子增強了環(huán)境中的能量。散射(Scattering):由于光跟粒子的碰撞,在一個方向上傳播的光被散射到其它方向上去。所有這些特性既可以是均質(zhì)的(homogeneous),也可以是非均質(zhì)的(inhomogeneous)。均質(zhì)的特性在給定的一個空間范圍之內(nèi)是一個恒 量,而非均質(zhì)的特性

3、在空間內(nèi)是變化的。下圖顯示了一個體積散射的例子:一個聚光燈照亮了參與介質(zhì),并投射出一個體積陰影(volumetric shadow)。12.1.1 吸收考慮一下火產(chǎn)生的濃煙:煙遮擋了后面的物體,因為煙的顆粒吸收了從物體到觀察者的光線。煙越濃,被吸收的光就越多。下圖顯示了煙的這種特效,其體積密度是由一個模擬煙的精確物理模型生成的。注意地面上的陰影:參與介質(zhì)已經(jīng)吸收了光源和地面之間的光線,從而投射出一個陰影。吸收是通過介質(zhì)的吸收截面a來表述的,它是光線在介質(zhì)中單位距離之內(nèi)被吸收的概率密度。通常情況下,吸收截面隨著位置p和方向的變化而變化,雖然嚴格地講它是關(guān)于位置的函數(shù),但是它通常也是隨光譜變化的量

4、。a的單位是距離的倒數(shù)(m-1)。這意味者a可以取任意正值,并不需要限定在0到1之內(nèi)。下圖顯示了沿著很短一段光線上的吸收效果。在點p上有一定的輻射亮度Li(p, -),我們希望求出在微分體積之內(nèi)被吸收后的出射輻射亮度Lo(p, )。沿光線微分長度dt的輻射亮度變化值可以通過下面的微分方程來表示:    Lo(p, ) Li(p, ) = dLo(p, )= a(p, ) Li(p, ) dt ,也就是說,沿著光線的輻射亮度的微分減少值跟其初始值呈線性關(guān)系。這個微分方程的解實際上是要給出描述光線上被吸收的光的總比率的積分方程。如果我們假定光線以p為起始點在介質(zhì)中沿方向上行進了

5、距離d,則總的吸收比率是:    12.1.2 放射在介質(zhì)中,吸收過程對沿光線的輻射亮度有減弱作用,而放射過程卻有增強作用,原因是由于化學(xué)、熱力學(xué)或核作用將能量轉(zhuǎn)換為可見光。我們記在點p處的方向上單位距離上增加的出射輻射亮度為Lve(p, ),那么有下列微分方程:    dLo(p, ) = Lve(p, ) dt .注意這個方程基于這樣的假定:即出射光Lve是不依賴于入射光Li的。在pbrt的線性光學(xué)的前提下這個假定總是成立的。12.1.3 外散射(out-scattering)和消光 (extinction)在參與介質(zhì)中,第三個光的基本交互作用是散射

6、。當(dāng)一束光穿過一種介質(zhì)中,它可以跟介質(zhì)中的粒子碰撞并被反射到不同的方向上。這對光束的總輻射亮度有兩個效 果:它減弱了光束出離一個微分區(qū)域時的輻射亮度,因為部分光線被反射到其它方向上。這個效果被稱為外散射(out-scattering),即本節(jié)要介紹 的主題。然而,其它光線的輻射亮度也會被加到當(dāng)前的光線的路徑中,這是下一節(jié)要介紹的內(nèi)散射(in-scattering)。單位距離內(nèi)的外散射事件發(fā)生的概率由散射系數(shù)給s給出。跟衰減系數(shù)類似,外散射在微分長度dt上所產(chǎn)生的輻射亮度減少值可以通過下列方程給出:    dLo(p, )= s(p, ) Li(p, ) dt 由吸收和外散射

7、所引起的總輻射亮度的減少是根據(jù)a + s來決定的。這個綜合效果被稱為衰減或消光(extinction)。為了方便起見,我們用衰減系數(shù)t來代表兩個系數(shù)之和:    t(p, ) = a(p, ) + s(p, )有了衰減系數(shù)以后,我們可以得到描述總衰減效果的微分方程:    dLo(p, ) / dt = t(p, ) Li(p, ) 我們通過解這個方程可以得到光束透射率(beam transmittance),它給出了一條光線通過兩個點所傳輸?shù)妮椛淞炼鹊谋嚷剩?#160;   其中d是點p到點p'的距離,是兩點之間的向量的正規(guī)化向量,T

8、r是兩點之間的光束透射率。如果表面上給定方向上的出射輻射亮度是Lo(p, ),那么,通過消光作用之后,在方向上的入射輻射亮度是:    Tr(p p') Lo(p, )光束透射率有兩個很有用的性質(zhì):一個點到它自身的透射率為1,即Tr(p p) = 1;在真空中對于所有點p'都有Tr(p p') = 1。另外,對于所有的介質(zhì),在光線上各點上的透射率有相乘的關(guān)系(例如下面p,p',p''三個點):    Tr(p p'') = Tr(p p') Tr(p' p''

9、)這個性質(zhì)對于體積散射的實現(xiàn)而言非常有用,因為我們可以靠計算相繼點上透射率的乘積逐步地得到沿光線上的許多點上的透射率。在Tr中取負值的指數(shù)被稱為兩點之間的光學(xué)厚度(optical thickness), 用符號來表示:    對于均勻介質(zhì)而言,t為常量,很容易計算出的積分,從而得到Beer定律:    Tr(pp') = etd .11.1.4 內(nèi)散射(In-Scattering)外散射由于向不同方向進行散射的緣故減弱了光線的輻射亮度;與之相反的是,由于其它方向上被散射的光線加入到當(dāng)前光線的方向,內(nèi)散射加強了光線的輻射亮 度。假定粒子之間的間距是

10、它們半徑的數(shù)倍,這樣我們就可以忽略粒子之間的交互作用。在這個假定之下,相函數(shù)p(')表示了在某點上的散射輻射 (scattered radiation)的角分布。它相當(dāng)于體積上的BSDF。然而,這個比擬并不準確,因為相函數(shù)有一個歸一化約束,即對于所有的,滿足下列條件:    這個約束條件意味著相函數(shù)實際上定義了在特定方向上散射的概率分布。內(nèi)散射所增加的總輻射亮度可以由源項S給出,即:    dLo(p, ) = S(p, ) dt它包括了體積放射和內(nèi)散射:    源項的內(nèi)散射部分是單位距離內(nèi)的散射概率s和在該點上所增加的輻射亮

11、度的乘積,所增加的輻射亮度可以通過對入射輻射亮度和相函數(shù) 的乘積進行球面積分得到。注意這個公式跟第5章的散射方程很相似,主要的不同是這里沒有cosine項,因為相函數(shù)使用的是輻射亮度而不是微分輻射照度 (differential irradiance)。12.2 相函數(shù)人們?yōu)榱嗣枋霰砻嫔仙⑸溲芯苛嗽S多BSDF模型,同樣地,人們也開發(fā)了許多相函數(shù)來描述體積散射。其中包括用少數(shù)參數(shù)來做擬合函數(shù)的參數(shù)化模型,還有基于粒子形狀和材質(zhì)(如球形水滴)而推導(dǎo)出的散射輻射分布的解析模型,等等。在大多數(shù)的自然產(chǎn)生的介質(zhì)中,相函數(shù)是關(guān)于兩個方向和'的夾角的一維函數(shù);這樣的介質(zhì)被稱為各向同性的(isotro

12、pic),它們的相函數(shù)常常被 寫成p(cos)。在比較奇異的介質(zhì)中,例如有水晶結(jié)構(gòu)的介質(zhì),它的相函數(shù)是兩個方向的4D函數(shù)。除了前面提到的歸一化性質(zhì)以外,自然生成的介質(zhì)還有一 個重要的性質(zhì),即互反性(reciprocal):兩個方向相互交換后,相函數(shù)值保持不變。注意各向同性的介質(zhì)的互反性很容易從cos(-) = cos()得到。相函數(shù)本身可以是各向同性的(isotropic),也可以是各向異性的(isotropic)的。因為各向同性的相函數(shù)描述的是在各個方向上的均勻散射,因此跟兩個方向都無關(guān)。因為相函數(shù)是歸一化的,因此只有唯一的各向同性函數(shù),且為常量1/4:    P iso

13、tropic(') = 1 / 4 <Volume Scattering Definitions> =    float PhaseIsotropic(const Vector &, const Vector &)         return 1.f / (4.f * M_PI);    本節(jié)下面所介紹的各向異性相函數(shù)描述的是各向同性介質(zhì),因此是用兩個方向的夾角來定義的(如圖)。    跟表面上散射的約定(兩個方向都背離散射點)有所不同的

14、是,這里入射方向是指向散射點的,而出射方向是背離散射點的,這跟相函數(shù)的約定一致。pbrt實現(xiàn)了描述Rayleigh散射和Mie散射的相函數(shù)。Rayleigh模型表示了在地球大氣中極小粒子(如分子)所產(chǎn)生的散射。如果粒子半徑比 光波長小(r/ <  0.05),Rayleigh模型就可以很精確地描述散射光的分布。跟波長相關(guān)的Rayleigh散射也是藍天之所以藍、晚霞之所以紅的原 因。Mie散射基于更一般性的理論:它是從Maxwell方程推導(dǎo)出來的,可以描述的粒子半徑范圍更為寬廣。例如,它可以很好地描述水霧中的天氣。<Volume Scattering Declar

15、ations> =    float PhaseRayleigh(const Vector &w, const Vector &wp);    float PhaseMieHazy(const Vector &w, const Vector &wp);    float PhaseMieMurky(const Vector &w, const Vector &wp);在計算機圖形學(xué)中得到廣泛應(yīng)用的一個相函數(shù)是由Henyey和Greenstein開發(fā)的。這個相函數(shù)很容易和測量出的散射

16、數(shù)據(jù)相擬合。它有一個單一的參數(shù)g(稱為非對稱參數(shù)),用來控制散射光的分布:    pHG(cos ) = (1/4) (1 g2) / (1+ g2 2g(cos )3/2下圖顯示了HenyeyGreenstein相函數(shù),它具有可變的非對稱參數(shù)g,變化范圍是(-1, 1)。負的g值對應(yīng)于向后散射(back-scattering),這時光大多數(shù)會在入射方向上散射(圖中的實線部分對應(yīng)g = -0.35);正的g值對應(yīng)于向前散射(forword-scattering) (圖中的虛線部分對應(yīng)g = 0.67)。g的值越大,散射方向就越靠近- (向后散射)或(向前散射)方向。<

17、Volume Scattering Definitions> +=    float PhaseHG(const Vector &w, const Vector &wp, float g)         float costheta = Dot(w, wp);        return 1.f / (4.f * M_PI) *            (

18、1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f);    非對稱參數(shù)有很嚴格的意義。它是相函數(shù)和-'夾角余弦的乘積的平均值。給定一個任意的相函數(shù),可以用下式計算g:    這樣,對于各向同性相函數(shù)來說,g=0。滿足這個方程的相函數(shù)有任意多個,單獨使用g值不足以唯一地描述一個散射分布。然而。我們將復(fù)雜的散射分布化簡為一個只有一個參數(shù)的模型,這樣做所帶來的方便比可能的精度上的缺失更重要。無法用單一的非對稱參數(shù)描述的更復(fù)雜的相函數(shù)常常用相函數(shù)(如HenyeyGreenstein相函數(shù))的加權(quán)

19、和來表示,其中每個相函數(shù)帶有不同的參數(shù)值:    其中所有的wi的和為1以保證正規(guī)性。Blasi, Le Saec, 和Schlick開發(fā)出了一個HenyeyGreenstein相函數(shù)的很高效的近似表示,由于它的高效性而被廣泛地應(yīng)用于計算機圖形學(xué)領(lǐng)域中:    pSchlick(cos ) = (1/4)(1 k2)/(1 k cos )2其中參數(shù)k跟HenyeyGreenstein中的g項有類似的作用,-1對應(yīng)于向后散射,0對應(yīng)于各向同性散射,1對應(yīng)于向前散射。兩者關(guān)系如下:    k = 1.55g - .55g3<Volu

20、me Scattering Definitions> +=    float PhaseSchlick(const Vector &w, const Vector &wp, float g)         float k = 1.55f * g - .55f * g * g * g;        float kcostheta = k * Dot(w, wp);       

21、60;return 1.f / (4.f * M_PI) *            (1.f - k*k) / (1.f - kcostheta) * (1.f - kcostheta);    12.3 體積區(qū)域接口和均勻介質(zhì)在pbrt中描述體積散射的核心抽象類是VolumeRegion,它是描述場景中一個區(qū)域中的體積散射的接口。在場景中不同的部分,可以使用不同類型的VolumeRegion來描述不同類型的散射。<Volume Scattering Declarations> +=

22、    class COREDLL VolumeRegion     public:        <VolumeRegion Interface>    ;所有的VolumeRegion必須可以計算和軸對齊的世界空間包圍盒,它可以通過函數(shù)VolumeRegion:WorldBound()來得到。跟Shape和Primitive一樣,這個包圍盒可以用來將VolumeRegion放入加速結(jié)構(gòu)。<VolumeRegion Interface> = 

23、;   virtual BBox WorldBound() const = 0;因為VolumeIntegrator需要知道光線在世界空間中穿過體積區(qū)域的參數(shù)范圍,而且世界包圍盒并不一定能夠緊包住體積區(qū)域,所以我們提供了一個 單獨的函數(shù)VolumeRegion:IntersectP(),用來返回光線跟該區(qū)域重疊的那部分光線的參數(shù)t值的范圍。<VolumeRegion Interface> +=    virtual bool IntersectP(const Ray &ray, float *t0, float *t1) const = 0;這

24、個接口有4個函數(shù),分別對應(yīng)于前面介紹的散射性質(zhì)。給定了世界空間的一個點和方 向,VolumeRegion:sigma_a(),VolumeRegion:sigma_s(),VolumeRegion:sigma_Lve() 返回相應(yīng)的吸收、散射和放射性質(zhì)。給定一對方向后,VolumeRegion:p()函數(shù)返回給定點的相函數(shù)值。<VolumeRegion Interface> +=    virtual Spectrum sigma_a(const Point &, const Vector &,      

25、      float time) const = 0;    virtual Spectrum sigma_s(const Point &, const Vector &,            float time) const = 0;    virtual Spectrum Lve(const Point &, const Vector &,      &#

26、160;     float time) const = 0;    virtual float p(const Point &, const Vector &,            const Vector &, float time) const = 0;為了方便,還有一個函數(shù)VolumeRegion:sigma_t()用來返回給定點上的衰減系數(shù)。它的缺省實現(xiàn)是返回a和s的和,但大多數(shù)的實現(xiàn)會重載該函數(shù),直接計算出t。<Volum

27、e Scattering Definitions> +=    Spectrum VolumeRegion:sigma_t(const Point &p, const Vector &w,            float time) const         return sigma_a(p, w, time) + sigma_s(p, w, time);    最后,VolumeRegio

28、n:tau()函數(shù)根據(jù)點ray(ray.mint)和點ray(ray.maxt)來計算體積區(qū)域的光學(xué)厚度。有些實現(xiàn) 可以之間計算出這個值,例如下節(jié)要介紹的HomogeneousVolume,而其它的實現(xiàn)需要Monte Carlo積分來計算。為了方便使用Monte Carlo方法,該函數(shù)使用了兩個可選的參數(shù),step和offset,對于使用封閉形式解的實現(xiàn)而言,可以忽略這兩個參數(shù)。<VolumeRegion Interface> +=    virtual Spectrum tau(const Ray &ray, float step = 1.f,

29、0;       float offset = 0.5) const = 0;11.3.1 均勻體積區(qū)域最簡單的體積表示是HomogeneousVolume,它描述了具有均勻散射性質(zhì)的盒形區(qū)域。它的構(gòu)造器使用了a和s,相函數(shù)的g值,還有放射量 Lve。再加上從世界空間到體積區(qū)域的物體空間的變換還有一個軸對齊的物體空間的包圍盒,就足夠可以描述該區(qū)域的散射性質(zhì)和空間范圍。<HomogeneousVolumeDensity Declarations> =    class HomogeneousVolumeDensit

30、y : public VolumeRegion     public:        <HomogeneousVolumeDensity Public Methods>    private:        <HomogeneousVolumeDensity Private Data>    ;<HomogeneousVolumeDensity Private Data> =

31、60;   Spectrum sig_a, sig_s, le;    float g;    BBox extent;    Transform WorldToVolume;由于包圍盒是定義在物體空間的,所以在WorldBound()函數(shù)中使用到世界空間的變換。<HomogeneousVolumeDensity Public Methods> =    BBox WorldBound() const         return I

32、nverse(WorldToVolume)(extent);    如果區(qū)域的世界空間-物體空間變換包含了旋轉(zhuǎn)操作,那么該區(qū)域在世界空間里就不是軸對齊的了,但我們可以將光線變換到區(qū)域的物體空間中,并求得它們的重疊部分,這樣就可以得到更緊密的光線參數(shù)范圍。<HomogeneousVolumeDensity Public Methods> +=    bool IntersectP(const Ray &r, float *t0, float *t1) const         

33、;Ray ray = WorldToVolume(r);        return extent.IntersectP(ray, t0, t1);    剩下的接口函數(shù)都很簡單。它們都先要驗證給定點是否是在區(qū)域中,如果是的話就返回相應(yīng)的值。這里只列出了sigma_a(),其它的函數(shù)就略去了。<HomogeneousVolumeDensity Public Methods> +=    Spectrum sigma_a(const Point &p, const Vector

34、 &, float) const         return extent.Inside(WorldToVolume(p) ? sig_a : 0.;    由于a和s在整個區(qū)域中是常量,我們可以通過Beer法則以封閉解的形式來計算光學(xué)厚度:<HomogeneousVolumeDensity Public Methods> +=    Spectrum tau(const Ray &ray, float, float) const    

35、0;    float t0, t1;        if (!IntersectP(ray, &t0, &t1) return 0.;        return Distance(ray(t0), ray(t1) * (sig_a + sig_s);    12.4密度可變的體積區(qū)域本章所介紹的其它的體積區(qū)域基于這樣的一個假設(shè):介質(zhì)中的粒子有相同的基本散射性質(zhì),但其密度是隨空間位置變化的。這個假設(shè)所產(chǎn)生的結(jié)

36、論之一就是我們可以 用該點的密度乘以某個基準值來描述體積散射性質(zhì)。例如,我們可以為衰減系數(shù)t設(shè)置基準值為0.2。對于粒子密度為1的區(qū)域,t返回0.2。如果粒子密 度為3,則返回0.6。為了減少重復(fù)性代碼,并令不同的表示將重點放在定義粒子密度的方法上,我們定義了一個DensityRegion類,它定義了一個純虛函數(shù)來獲取一個點上的粒子密度。體積區(qū)域的表示可以繼承DensityRegion,就無需實現(xiàn)相同的邏輯了。<Volume Scattering Declarations> +=    class DensityRegion : public VolumeReg

37、ion     public:        <DensityRegion Public Methods>    protected:        <DensityRegion Protected Data>    ;DensityRegion構(gòu)造器使用了基本散射性質(zhì)的值,并將它們放入相應(yīng)的成員變量中。注意接口聲明了體積區(qū)域-世界空間的變換,但該類存放的是世界空間-體積區(qū)域的變換。<D

38、ensityRegion Protected Data> =    Transform WorldToVolume;    Spectrum sig_a, sig_s, le;    float g;    <DensityRegion Public Methods> =    DensityRegion(const Spectrum &sa, const Spectrum &ss, float gg,      

39、0; const Spectrum &emit, const Transform &VolumeToWorld)            : sig_a(sa), sig_s(ss), le(emit), g(gg),    WorldToVolume(Inverse(VolumeToWorld) 所有DensityRegion的繼承類必須實現(xiàn)DensityRegion:Density(),它返回了體積區(qū)域在物體空間中給定點的密度。該密度用來乘以基本的散射參數(shù),故在任何一

40、點都應(yīng)該是非負數(shù)。<DensityRegion Public Methods> +=    virtual float Density(const Point &Pobj) const = 0;這里只列出DensityRegion:sigma_a()函數(shù)的實現(xiàn),其它類似,從略:<DensityRegion Public Methods> +=    Spectrum sigma_a(const Point &p, const Vector &) const       

41、;  return Density(WorldToVolume(p) * sig_a;    其中一個例外是DensityRegion:p()函數(shù),它并不是用局部的密度乘以相函數(shù)值,因為從點到點的散射變化已經(jīng)由s負責(zé)處理了。<DensityRegion Public Methods> +=    float p(const Point &p, const Vector &w, const Vector &wp) const         

42、return PhaseHG(w, wp, g);    DensityRegion無法實現(xiàn)VolumeRegion:Tau()函數(shù),因為這個函數(shù)基于對VolumeRegion形狀的總體的了解,還要知道其中的密度分布。因此這個方法應(yīng)該由所有的繼承類來實現(xiàn)。12.4.1 三維網(wǎng)格VolumeGrid類將密度存放在一個普通的三維的位置網(wǎng)格中,這跟用2D采樣網(wǎng)格來表示圖像的ImageTexture有些類似。我們通過對這些采樣 值進行插值來計算采樣點之間的位置上的密度。它的構(gòu)造器使用了用戶提供的存放著密度的3D數(shù)組,這就可以允許使用很多類型的數(shù)據(jù)源(物理仿真,CT掃描, 等等)。因

43、為它是DensityRegion的子類,所以用戶也要提供a、s、Lve和g的基準值。<VolumeGrid Declarations> =    class VolumeGrid: public DensityRegion     public:        <VolumeGridDensity Public Methods>    private:        <VolumeGri

44、dDensity Private Data>    ;構(gòu)造器做基本散射參數(shù)的初始化,存儲區(qū)域的物體空間中的包圍盒,并做密度值的局部拷貝。<VolumeGrid Public Methods> =    VolumeGrid (const Spectrum &sa, const Spectrum &ss, float gg,            const Spectrum &emit, const BBox &e, cons

45、t Transform &v2w,        int x, int y, int z, const float *d)        : DensityRegion(sa, ss, gg, emit, v2w), nx(x), ny(y), nz(z), extent(e)         density = new floatnx*ny*nz;      

46、0; memcpy(density, d, nx*ny*nz*sizeof(float);    <VolumeGridPrivate Data>    float *density;    const int nx, ny, nz;    const BBox extent;WorldBound()函數(shù)跟IntersectP()函數(shù)跟前面所介紹的HomogeneousVolume中的類似,從略。VolumeGrid的Density()的任務(wù)是用采樣來重構(gòu)給定點上的密度。<VolumeG

47、ridMethod Definitions> =    float VolumeGrid:Density(const Point &Pobj) const         if (!extent.Inside(Pobj) return 0;        <Compute voxel coordinates and offsets for Pobj>        <

48、;Trilinearly interpolate density values to compute local density>    有了3D空間中一個點的8個采樣值之后,該函數(shù)用三線性插值來計算該點的密度函數(shù)值。首先,要找到整數(shù)坐標(biāo)小于該采樣位置的最近的體積區(qū)域采樣,然后用沿每個軸的麥哈頓距離(Manhattan distance)(dx,dy,dz)來插值。<Compute voxel coordinates and offsets for Pobj> =    float voxx = (Pobj.x - extent.pMi

49、n.x) /        (extent.pMax.x - extent.pMin.x) * nx - .5f;    float voxy = (Pobj.y - extent.pMin.y) /        (extent.pMax.y - extent.pMin.y) * ny - .5f;    float voxz = (Pobj.z - extent.pMin.z) /      

50、  (extent.pMax.z - extent.pMin.z) * nz - .5f;    int vx = Floor2Int(voxx);    int vy = Floor2Int(voxy);    int vz = Floor2Int(voxz);    float dx = voxx - vx, dy = voxy - vy, dz = voxz - vz;我們用這些距離做一系列的Lerp()調(diào)用來估算出采樣點的密度:<Trilinearly interpolate de

51、nsity values to compute local density> =    float d00 = Lerp(dx, D(vx, vy, vz), D(vx+1, vy, vz);    float d10 = Lerp(dx, D(vx, vy+1, vz), D(vx+1, vy+1, vz);    float d01 = Lerp(dx, D(vx, vy, vz+1), D(vx+1, vy, vz+1);    float d11 = Lerp(dx, D(vx, vy+1, vz+1

52、), D(vx+1, vy+1, vz+1);    float d0 = Lerp(dy, d00, d10);    float d1 = Lerp(dy, d01, d11);    return Lerp(dz, d0, d1);工具函數(shù)D()返回給定采樣位置上的密度。它的唯一任務(wù)是使用截取(clamping)方式處理越界的情況,并計算出給定采樣的數(shù)組偏置值。跟MIPMaps不同的是,截取方式幾乎總是我們想要的方式。因為所有的查找點都位于包圍盒之內(nèi),只有在邊界的情況會出現(xiàn)越界。<VolumeGrid Public Met

53、hods> =    float D(int x, int y, int z) const         x = Clamp(x, 0, nx-1);        y = Clamp(y, 0, ny-1);        z = Clamp(z, 0, nz-1);        return densityz*nx*ny +

54、 y*nx + x;    12.4.2 指數(shù)密度另一個很有用的密度類是ExponentialDensity類,它描述了在給定的3D范圍內(nèi)按照關(guān)于高度h的指數(shù)函數(shù)變化的密度分布:        d(h) = a e-bh其中a,b分別是控制總體密度的參數(shù)以及按高度進行衰減的快慢程度的參數(shù)。這個密度函數(shù)是對在地球表面上所觀察到的地球大氣是個很好的模擬(這里忽略了地球的彎曲)。它也可以用于模擬在地平面上的低沉的霧氣。    <ExponentialDensity Declarations>

55、; =    class ExponentialDensity : public DensityRegion     public:        <ExponentialDensity Public Methods>    private:        <ExponentialDensity Private Data>    ;ExponentialDensity的構(gòu)造

56、器使用所傳入的變量來初始化成員函數(shù)。除了要傳入DensityRegion構(gòu)造器的體積散射性質(zhì)外,還有體 積的包圍盒,參數(shù)a和b。這個構(gòu)造器還要用到一個“向上”的向量對體積區(qū)域進行朝向定位,并用來計算點的高度。當(dāng)然,向上向量并非必要(實際上使用世界 -物體變換也可以做到這一點),但在概念上更容易為用戶理解。<ExponentialDensity Public Methods> =    ExponentialDensity(const Spectrum &sa, const Spectrum &ss,     

57、0;  float gg, const Spectrum &emit, const BBox &e,        const Transform &v2w, float aa, float bb,        const Vector &up)    : DensityRegion(sa, ss, gg, emit, v2w), extent(e), a(aa), b(bb)    

58、;     upDir = Normalize(up);    <ExponentialDensity Private Data> =    BBox extent;    float a, b;    Vector upDir;WorldBound()函數(shù)跟IntersectP()函數(shù)跟前面所介紹的HomogeneousVolume中的類似,從略。在物體空間中,給定點的沿“向上”向量的高度可以這樣求得:將從包圍盒的下角(lower corner)到p的向量投影到

59、“向上”向量的方向上,然后求兩個向量的點積即得到高度。如圖:<ExponentialDensity Public Methods> +=    float Density(const Point &Pobj) const         if (!extent.Inside(Pobj) return 0;        float height = Dot(Pobj - extent.pMin, upDir);   

60、     return a * expf(-b * height);    12.5 體積聚合體跟可以存放一組Primitive的Aggregate類一樣,AggregateVolume可以存放一個或多個VolumeRegion。這樣做有兩 個原因:第一,簡化場景以及對VolumeIntegrator的實現(xiàn),因為我們可以只對一個AggregateVolume進行函數(shù)調(diào)用,而無需對場景 中所有的區(qū)域進行循環(huán);第二,AggeragateVolume的實現(xiàn)可以有可能利用3D空間數(shù)據(jù)結(jié)構(gòu)來提升效率,因為我們可以剔除掉里特定光線或查找點 太遠的

61、區(qū)域。這里我們只實現(xiàn)一個簡單的AggregateVolume,它有一個存放場景中所有體積區(qū)域的列表,并在具體的函數(shù)實現(xiàn)中對這些區(qū)域進行循環(huán)。當(dāng)場景中有許多不同的區(qū)域時,這個實現(xiàn)不太高效,如何寫一個高效的實現(xiàn)留做練習(xí)。<Volume Scattering Declarations> +=    class AggregateVolume : public VolumeRegion     public:        <AggregateVolume Public Methods>    private:        <AggregateVolume Private Data>    ;它的構(gòu)造器很簡單,只是拷

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論