【Ray Tracing The Next Week 超詳解】 光線追蹤2-3


 

 Preface

終於到了激動人心的紋理章節了

然鵝,看了下,並不激動

因為我們之前就接觸過

當初有一個 attenuation 嗎?

 

對了,這就是我們的rgb分量過濾器,我們畫出的紅色、藍色、綠色等等,都是通過它來控制的

專業點的詞語叫做rgb衰減比例,比如rtvec(1.,0.,0.),最后呈現出來的是紅色,因為r保留了100%

它是怎么控制的呢,我們來回顧一下這個過程

首先,我們創建一個材質球

后面那個rtvec(0.4,0.2,0.1)就是衰減比例(衰減到原來的百分之。。)

之后

 

進入數據成員中,之后主函數調用lerp的時候

info.materialp->scatter(sight, info, attenuation, scattered))

球體的材質調用scatter函數

即:

沒有絲毫改動地有數據成員傳遞到了attenuation 中

然后用attenuation 做乘法進行rgb衰減,遞歸就不用說了吧,最后遞歸到深處為黑色,不然為背景色

 

為什么要在前言將這個東東,因為

attenuation 所控制形成的物體表面顏色就是最簡單的紋理

 

說白了這章比較簡單,因為下一章是這本書的另外一個高難度章節(分別分布於第二章和第四章) 

所以,中間第三章來點簡單好玩的,過渡一下

 

 先看效果

 

Chapter 3:Solid Textures

 

廢話不多說,先寫一個紋理類

/// texture.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2019.1
// [brief ]        the texture-class for the ray-tracing project
//                from the 《ray tracing the next week》

#pragma once

namespace rt
{

class texture
    {
public:
    
    virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const = 0;
    
    };

}

u 和 v后面用到再講,p就是衰減向量

然后寫一個常量紋理(基礎紋理)

/// constant_tex.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2019.1
// [brief ]        the constant_texture-class for the ray-tracing project
//                from the 《ray tracing the next week》
// -----------------------------------------------------

#pragma once


namespace rt
{
    
class constant_texture :public texture
    {
    public:

        constant_texture() {  }

        constant_texture(const rtvec& color);

        virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;

    public:

        inline const rtvec& color()const { return _color; }

    private:

        rtvec _color;

    };



inline constant_texture::constant_texture(const rtvec& color)
    :_color(color)
    {
    }

rtvec constant_texture::value(rtvar u, rtvar v, const rtvec& p)const
    {
    return _color;
    }

}

 

之后,我們把材質中的rtvec向量改為紋理指針

/// diffuse.hpp
// https://www.cnblogs.com/lv-anchoret/p/10198423.html

// -----------------------------------------------------
// [author]        lv
// [begin ]        2018.12
// [brief ]        one of the materials
// -----------------------------------------------------

#pragma once


namespace rt { class texture; //diffuse material class lambertian : public material { public: lambertian(texture* _tex); virtual bool scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const override; protected: texture* _albedo; }; inline lambertian::lambertian(texture* _tex) :_albedo(_tex) { } bool lambertian::scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const { rtvec target = info._p + info._n + lvgm::random_unit_sphere(); scattered = ray{ info._p, target - info._p }; attenuation = _albedo->value(0.,0.,info._p); return true; } }

 

 之前我們創建的材質球代碼就要改一種風格了

 

把其他的材質類也做相應的改動

 

我們今天最重要的是弄棋盤(checkerboard)紋理

棋盤紋理就是交錯的雙色格子,呈現一定的規律性

所以我們想象一下利用某些映射函數來實現這種類似二值性,且呈現周期性

我們比較容易想到利用正余弦函數,呈現周期性,且值域為【-1,1】是個有界函數

如何體現二值呢,正負嘛,正余弦函數一定關於x軸對稱

如何將物體表面和正余弦函數聯系在一起形成雙色交錯的格子呢

我們采用每個點在3D空間中的位置來將兩者聯系在一起

綜上,如果我們在所有三個維度中相乘某個正余弦函數,那么該公式的符號形成一個棋盤形式

即:rtvar sines = sin(10 * p.x()) * sin(10 * p.y()) * sin(10 * p.z());

 

當然,你也可以試一下sgnx函數,設置一個相關的判別式

 

/// checker_tex.hpp

// -----------------------------------------------------
// [author]        lv
// [begin ]        2019.1
// [brief ]        the checker_texture-class for the ray-tracing project
//                from the 《ray tracing the next week》
// -----------------------------------------------------


#pragma once


namespace rt
{

class checker_texture :public texture
    {
    public:
        checker_texture() {  }

        checker_texture(texture* t1, texture* t2);

        virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;

    private:

        texture* _even;

        texture* _odd;

    };



inline checker_texture::checker_texture(texture * t1, texture * t2)
        :_even(t1)
        , _odd(t2)
    {
    }

rtvec checker_texture::value(rtvar u, rtvar v, const rtvec& p)const
    {
    rtvar sines = sin(30 * p.x()) * sin(30 * p.y()) * sin(30 * p.z());
    if (sines < 0)
        return _odd->value(u, v, p);
    else
        return _even->value(u, v, p);
    }

}

 

我們把大球設置為棋盤紋理

 

就是開篇圖

 

然后,我把判別式中的10改成了30依舊是原圖

10(左)30(右)

 

y = sin(wx + φ)

你可以嘗試改動一下φ參數試一下

 

補充:

使用

使得紋理向屏幕左部偏移了一段距離

 

 

下面是另外一個圖:

隨機球體生成函數改成

 

相機參數依舊是之前的

 

 會得到這樣一個圖

 

 

 

 感謝您的閱讀,生活愉快~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM