zoukankan      html  css  js  c++  java
  • 【Ray Tracing The Next Week 超详解】 光线追踪2-9

    我们来整理一下项目的代码

    目录

    ----include

    --hit

    --texture

    --material

    ----RTdef.hpp

    ----ray.hpp

    ----camera.hpp

    ----main.cpp

    3D泛型数学库中的randomfunc.hpp增加了新内容

    #pragma once
    
    #include <lvgm	ype_vec	ype_vec.h>
    #include <random>
    
    namespace lvgm
    {
    
    //@brief:    create a random number that from 0 to 1 completely
    template<typename T = lvgm::precision>
        const T rand01()
            {
            if (typeid(T) == typeid(int))
                {
                std::cerr << "integer doesn't have a random number from 0 to 1
    ";
                throw "integer doesn't have a random number from 0 to 1
    ";
                }
        
            static std::mt19937 mt;
            static std::uniform_real_distribution<T> r;
            return r(mt);
            }
    
    
    //@brief:    find a random point in unit_sphere
    template<typename T = lvgm::precision>
        const lvgm::vec3<T> random_unit_sphere()    
            {
            if (typeid(T) == typeid(int))
                {
                std::cerr << "integer doesn't have a random number from 0 to 1
    ";
                throw "integer doesn't have a random number from 0 to 1
    ";
                }
    
            lvgm::vec3<T> p;
            do
                {
                p = 2.0*lvgm::vec3<T>(rand01(), rand01(), rand01()) - lvgm::vec3<T>(1, 1, 1);
                } while (dot(p, p) >= 1.0);
            return p;
            }
    
    
    //@brief:    find a random point in unit_plane
    template<typename T = lvgm::precision>
        const lvgm::vec2<T> random_unit_plane()            
            {
            if (typeid(T) == typeid(int))
                {
                std::cerr << "integer doesn't have a random number from 0 to 1
    ";
                throw "integer doesn't have a random number from 0 to 1
    ";
                }
    
            lvgm::vec2<T> p;
            do
                {
                p = 2.0*lvgm::vec2<T>(rand01(), rand01()) - lvgm::vec2<T>(1, 1);
                } while (dot(p, p) >= 1.0);
            return p;
            }
    
    //@brief:    generate a list of normalized vector(-1~1)
    template<typename T = precision>
        vec2<T> * random_normalized2D(const size_t size)
            {
            vec2<T> * p = new vec2<T>[size];
            for (int i = 0; i < size; ++i)
                p[i] = vec2<T>( -1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01()).ret_unitization();
            return p;
            }
    
    //@brief:    generate a list of normalized vector(-1~1)
    template<typename T = precision>
        vec3<T> * random_normalized3D(const size_t size)
            {
            vec3<T> * p = new vec3<T>[size];
            for (int i = 0; i < size; ++i)
                p[i] = vec3<T>(-1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01(), -1 + 2 * lvgm::rand01()).ret_unitization();
            return p;
            }
    
    //@brief:    generate a list of normalized vector(-1~1)
    template<typename T = precision>
        T * random_normalized1D(const size_t size)
            {
            T * p = new T[size];
            for (int i = 0; i < size; ++i)
                p[i] = -1 + 2 * lvgm::rand01();
            return p;
            }
    
    //@brief:    make list permute randomly
    template<typename T>
        void permute_method(T * p, size_t n)
            {
            for (int i = n - 1; i; i--)
                {
                size_t tar = int(lvgm::rand01() * (i + 1));
                T t = p[i];
                p[i] = p[tar];
                p[tar] = t;
                }
            }
    
    //@brief:    generate a list of random value(0~n)
    template<typename T = int>
        T * generate_random0n(size_t size)
            {
            int * p = new int[size];
            for (int i = 0; i < 256; ++i)    p[i] = i;
            permute_method(p, 256);
            return p;
            }
    
    }
    randomfunc.hpp

    先说最外面的

    基本和上次的没什么区别https://www.cnblogs.com/lv-anchoret/p/10243553.html

    /// RTdef.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10243553.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1.1
    // [brief ]        the basic concept of rt
    // -----------------------------------------------------
    
    #pragma once
    
    #include <lvgm	ype_vec	ype_vec.h>        //https://www.cnblogs.com/lv-anchoret/p/10163085.html
    #include <lvgmopticsfunc.hpp>            //https://www.cnblogs.com/lv-anchoret/p/10241904.html
    #include <lvgm
    andfunc.hpp>            //https://www.cnblogs.com/lv-anchoret/p/10241904.html
    #include <algorithm>
    
    #define stds std::
    
    namespace rt
    {
        using rtvar = lvgm::precision;
    
        using rtvec = lvgm::vec3<rtvar>;
    
        constexpr static rtvar rtInf() { return static_cast<rtvar>(0x3f3f3f3f); }        //最大值
    
        constexpr rtvar π = 3.1415926;
    
        template<typename T>
        const T& rtmin(const T& a, const T& b)
        {
            return a < b ? a : b;
        }
    
        template<typename T>
        const T& rtmax(const T& a, const T& b)
        {
            return a > b ? a : b;
        }
    
    }
    RTdef.hpp
    /// ray.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10182002.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        the ray-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    #include "RTdef.hpp"
    
    namespace rt
    {
    
    class ray
        {
    public:
        ray()
            :_a{ rtvec() }
            , _b{ rtvec() }
        {  }
    
        ray(const rtvec& a, const rtvec& b, const rtvar time = 0.)
            :_a(a)
            , _b(b)
            ,_time(time)
        {  }
    
        ray(const ray& r)
            :_a(r._a)
            ,_b(r._b)
            ,_time(r._time)
        {    }
    
        inline rtvec origin()const        { return _a; }
    
        inline rtvec direction()const    { return _b; }
    
        inline rtvar time()const        { return _time; }
    
        inline rtvec go(const rtvar t)const { return _a + t * _b; }
    
    private:
        rtvec _a;
    
        rtvec _b;
    
        rtvar _time;
    
        };
    } // rt namespace 
    ray.hpp
    /// camera.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10221058.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        the camera-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of camera class
    
    class camera
        {
    public:
    
        /*
        @brief: the camera constructor
        @param: lookfrom -> the position of eye
                lookat -> the vector of sight's direction
                vup -> the vertical up direction
                vfov -> 相机在垂直方向上关于屏幕岔开的角度
                aspect -> Screen aspect ratio
                focus -> the focal length
                t1 -> Shutter start time
                t2 -> Shutter end time
        */
        camera(rtvec lookfrom, rtvec lookat, rtvec vup, rtvar vfov, rtvar aspect, rtvar aperture, rtvar focus, rtvar t1, rtvar t2);
    
        inline const ray get_ray(const rtvar u, const rtvar v)const;
    
        inline const ray get_ray(const lvgm::vec2<rtvar>& para)const;
    
    public:
        inline const rtvec& eye()const { return _eye; }
    
        inline const rtvec& start()const { return _start; }
    
        inline const rtvec& horizontal()const { return _horizontal; }
    
        inline const rtvec& vertical()const { return _vertical; }
    
        inline const rtvec& u()const { return _u; }
    
        inline const rtvec& v()const { return _v; }
    
        inline const rtvec& w()const { return _w; }
    
        inline const rtvar lens_r()const { return _lens_radius; }
    
    private:
        rtvec _u;
    
        rtvec _v;
    
        rtvec _w;
    
        rtvec _eye;
    
        rtvec _start;        //left-bottom
    
        rtvec _horizontal;
    
        rtvec _vertical;
    
        rtvar _lens_radius;  //the radius of lens
    
        rtvar _time1;
    
        rtvar _time2;
    
        };
    
    
    
    //the implementation of camera class
    
    inline camera::camera(rtvec lookfrom, rtvec lookat, rtvec vup, rtvar vfov, rtvar aspect, rtvar aperture, rtvar focus, rtvar t1, rtvar t2)
        :_eye(lookfrom)
        , _lens_radius(aperture / 2)
        , _time1(t1)
        , _time2(t2)
        {
        rtvar theta = vfov * π / 180;
        rtvar half_height = tan(theta / 2) * focus;
        rtvar half_width = aspect * half_height;
        _w = (lookfrom - lookat).ret_unitization();
        _u = cross(vup, _w).ret_unitization();
        _v = cross(_w, _u);
        
        _start = _eye - half_width * _u - half_height * _v - focus * _w;//高和宽都乘了焦距,w也要乘,不然公式是错的
        _horizontal = 2 * half_width * _u;
        _vertical = 2 * half_height * _v;
        }
    
    inline const ray camera::get_ray(const rtvar u, const rtvar v)const
        {
        rtvec rd = rtvec(_lens_radius * lvgm::random_unit_plane());
        rtvec offset = _u * rd.x() + _v * rd.y();
        rtvar time = _time1 + lvgm::rand01() * (_time2 - _time1);
        return ray{ _eye + offset, _start + u*_horizontal + v*_vertical - (_eye + offset), time };
        }
    
    inline     const ray camera::get_ray(const lvgm::vec2<rtvar>& para)const
        {
        return get_ray(para.u(), para.v()); 
        }
    
    } // rt namespace 
    camera.hpp

     hit

    里面包含的很多物体以及一些变换

    /// RThit.hpp
    //    https://www.cnblogs.com/lv-anchoret/p/10190092.html
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        some intersects
    //                intersections
    //                aabb
    //                bvh
    //                sphere
    //                moving_sphere
    //                rectangle
    //                rectangles
    //                box
    //                translate
    //                rotate
    // -----------------------------------------------------
    
    #pragma once
    
    #include "ray.hpp"
    #include "aabb_box.hpp"
    #include "intersect.hpp"
    
    #include "bvh.hpp"
    #include "intersections.hpp"
    
    #include "sphere.hpp"
    #include "moving_sphere.hpp"
    #include "rectangleBasic.hpp"
    #include "rectangles.hpp"
    #include "rectangle.hpp"
    #include "flip_normal.hpp"
    #include "box.hpp"
    #include "constant_medium.hpp"
    
    #include "translate.hpp"
    #include "rotate.hpp"
    RThit.hpp
    /// intersect.hpp
    //https://www.cnblogs.com/lv-anchoret/p/10190092.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        the intersect-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    class material;
    class aabb;
    
    
    // the infomation of intersection point
    
    struct hitInfo
        {
        lvgm::precision _t;        //ray 中的系数t
        rtvec _p;                //相交点、撞击点
        rtvec _n;                //_p点的表面法线
        material* _materialp;    //材质
        rtvar _u;                //texture-u
        rtvar _v;                //texture-v
        };
    
    
    // the statement of intersect class
    
    class intersect
        {
    public:
        intersect() {  }
    
        /*
        @brief: 撞击函数,求取撞击点相关记录信息
        @param: sight->视线
        系数t的上下界->筛选撞击点
        info->返回撞击点信息
        @retur: 是否存在合法撞击点
        */
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const = 0;
    
        /*
        @brief: get the box of Geometry
        */
        virtual aabb getbox()const = 0;
    
        };
    
    }
    intersect.hpp
    /// aabb.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10284085.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the aabb-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    //the statement of aabb class
    
    class aabb
        {
    public:
        aabb() {  }
    
        /*
        @brief: the box of Geometry
        @param: min -> 盒子坐标最小端
                max -> 盒子坐标最大端
        */
        aabb(const rtvec& min, const rtvec& max);
    
        /*
        @brief: 相交碰撞检测
        @param: sight -> 视线
                解的上下界
        @retur: 是否碰撞相交
        */
        inline bool hit(const ray& sight, rtvar tmin, rtvar tmax)const;
    
        /*
        @brief: 两个包围盒的包围盒
        */
        static aabb _surrounding_box(aabb box1, aabb box2);
        
    public:
    
        inline const rtvec& min()const { return _min; }
    
        inline const rtvec& max()const { return _max; }
    
    private:
        rtvec _min;
    
        rtvec _max;
        };
    
    
    //the implementation of aabb class
    
    inline aabb::aabb(const rtvec& min, const rtvec& max)
        :_min(min)
        ,_max(max)
        {
        }
    
    inline bool aabb::hit(const ray& sight, rtvar tmin, rtvar tmax)const
        {
        for (int i = 0; i < 3; ++i)
            {
            rtvar div = 1.0 / sight.direction()[i];
            rtvar t1 = (_min[i] - sight.origin()[i]) / sight.direction()[i];
            rtvar t2 = (_max[i] - sight.origin()[i]) / sight.direction()[i];
            if (div < 0.)stds swap(t1, t2);
            if (stds min(t2, tmax) <= stds max(t1, tmin))
                return false;
            }
        return true;
        }
    
    aabb aabb::_surrounding_box(aabb box1, aabb box2)
        {
        auto fmin = [](const rtvar a, const rtvar b) {return a < b ? a : b; };
        auto fmax = [](const rtvar a, const rtvar b) {return a > b ? a : b; };
        rtvec min{    fmin(box1.min().x(),box2.min().x()),
                    fmin(box1.min().y(),box2.min().y()),
                    fmin(box1.min().z(),box2.min().z()) };
        rtvec max{    fmax(box1.max().x(),box2.max().x()),
                    fmax(box1.max().y(),box2.max().y()),
                    fmax(box1.max().z(),box2.max().z()) };
        return aabb(min, max);
        }
    
    }  //rt namespace 
    aabb.hpp
    /// bvh.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10284085.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the bvh-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of bvh_node class
    
    class bvh_node :public intersect
        {
    public:
        bvh_node() {  }
    
        /*
        @brief: bvh树
        @param: world -> all Geometry of the scene
                n -> the number of the Geometry
                time1 -> start time
                time2 -> end time
        */
        bvh_node(intersect** world, const int n, const rtvar time1, const rtvar time2);
    
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    private:
        intersect* _left;
    
        intersect* _right;
    
        aabb _box;
    
        };
    
    
    // the implementation of bvh_node class
    
    inline    int _x_cmp(const void * lhs, const void * rhs)
        {
        intersect * lc = *(intersect**)lhs;
        intersect * rc = *(intersect**)rhs;
        aabb lbox = lc->getbox();
        aabb rbox = rc->getbox();
    
        if (lbox.min().x() - rbox.min().x() < 0.)
            return -1;
        else
            return 1;
        }
    
    inline    int _y_cmp(const void * lhs, const void * rhs)
        {
        intersect * lc = *(intersect**)lhs;
        intersect * rc = *(intersect**)rhs;
        aabb lbox = lc->getbox();
        aabb rbox = rc->getbox();
    
        if (lbox.min().y() - rbox.min().y() < 0.)
            return -1;
        else
            return 1;
        }
    
    inline    int _z_cmp(const void * lhs, const void * rhs)
        {
        intersect * lc = *(intersect**)lhs;
        intersect * rc = *(intersect**)rhs;
        aabb lbox = lc->getbox();
        aabb rbox = rc->getbox();
        if (lbox.min().z() - rbox.min().z() < 0.)
            return -1;
        else
            return 1;
        }
    
    inline bvh_node::bvh_node(intersect** world, const int n, const rtvar time1, const rtvar time2)
        {
        int axis = static_cast<int>(3 * lvgm::rand01());
        if (axis == 0)
            qsort(world, n, sizeof(intersect*), _x_cmp);
        else if (axis == 1)
            qsort(world, n, sizeof(intersect*), _y_cmp);
        else
            qsort(world, n, sizeof(intersect*), _z_cmp);
    
        if (n == 1)
            _left = _right = world[0];
        else if (n == 2)
            _left = world[0],
            _right = world[1];
        else
            _left = new bvh_node(world, n / 2, time1, time2),
            _right = new bvh_node(world + n / 2, n - n / 2, time1, time2);
    
        aabb lbox = _left->getbox();
        aabb rbox = _right->getbox();
    
        _box = aabb::_surrounding_box(lbox, rbox);
        }
    
    aabb bvh_node::getbox()const
        {
        return _box;
        }
    
    bool bvh_node::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        if (_box.hit(sight, t_min, t_max))
            {
            hitInfo linfo, rinfo;
            bool lhit = _left->hit(sight, t_min, t_max, linfo);
            bool rhit = _right->hit(sight, t_min, t_max, rinfo);
            if (lhit && rhit)
                {
                if (linfo._t < rinfo._t)
                    info = linfo;
                else
                    info = rinfo;
                return true;
                }
            else if (lhit)
                {
                info = linfo;
                return true;
                }
            else if (rhit)
                {
                info = rinfo;
                return true;
                }
            else 
                return false;
            }
        else 
            return false;
        }
    
    } //rt namespace
    bvh.hpp
    /// intersections.hpp
    //    https://www.cnblogs.com/lv-anchoret/p/10190092.html
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        the intersections-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of intersections class
    
    class intersections :public intersect
        {
    public:
        intersections() {  }
    
    
        /*
        @brief: the list of scene's Geometry
        @param: list -> all Geometry of the scene
                n -> the number of the scene's Geometry
        */    
        intersections(intersect** list, size_t n) :_list(list), _size(n) {  }
            
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override { return aabb(); }
    
    public:
        const size_t get_size()const { return _size; }
    
    private:
        intersect** _list;
    
        size_t _size;
        };
    
    
    
    // the implementation of intersections class
    
    bool intersections::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        hitInfo t_rec;
        bool hitSomething = false;
        rtvar far = t_max;            //刚开始可以看到无限远
        for (int i = 0; i < _size; ++i)
            {
            if (_list[i]->hit(sight, t_min, far, t_rec))
                {
                hitSomething = true;
                far = t_rec._t;            //将上一次的最近撞击点作为视线可达最远处
                info = t_rec;
                }
            }
        return hitSomething;
        }
    
    
    } // rt namespace 
    intersections.hpp
    /// sphere.hpp
    //  https://www.cnblogs.com/lv-anchoret/p/10190092.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the sphere-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    #pragma once
    
    namespace rt
    {
    
    class sphere :public intersect
        {
    public:
        sphere() {  }
    
            /*
            @para1: 球心坐标
            @para2: 球半径
            @para3: 材质
            */
        sphere(const rtvec& h, rtvar r, material* ma);
    
        ~sphere();
            
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
        /*
        获取几何球体中p点对应的2D纹理坐标(u,v)
        */
        static void get_sphere_uv(const rtvec& p, rtvar& u, rtvar& v);
    
    public:
    
        inline const rtvar r()const            { return _radius;    }
    
        inline const rtvec& heart()const    { return _heart;    }
    
        inline const material* get_material()const { return _materialp; }
    
        inline rtvar& r()                    { return _radius;    }
    
        inline rtvec& heart()                { return _heart;    }
    
        inline void set_material(material* m) { _materialp = m; }
    private:
        rtvec _heart;
    
        rtvar _radius;
    
        material* _materialp;
        };
    
    
    inline sphere::sphere(const rtvec& h, rtvar r, material* ma) 
        :_heart(h)
        , _radius(r)
        , _materialp(ma)
        {
        }
    
    inline sphere::~sphere() 
        {
        if (_materialp)
            delete _materialp; 
        }
    
    bool sphere::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvec trace = sight.origin() - _heart;
        rtvar a = dot(sight.direction(), sight.direction());
        rtvar b = 2.0 * dot(trace, sight.direction());
        rtvar c = dot(trace, trace) - _radius * _radius;
        rtvar delt = b*b - 4.0*a*c;
        if (delt > 0)
            {
            info._materialp = _materialp;
            rtvar x = (-b - sqrt(delt)) / (2.0*a);
            if (x < t_max && x > t_min)
                {
                info._t = x;
                info._p = sight.go(x);
                info._n = (info._p - _heart) / _radius;
                get_sphere_uv((info._p - _heart) / _radius, info._u, info._v);        //将撞击点向量规格化
                return true;
                }
            x = (-b + sqrt(delt)) / (2.0*a);
            if (x < t_max && x > t_min)
                {
                info._t = x;
                info._p = sight.go(x);
                info._n = (info._p - _heart) / _radius;
                get_sphere_uv((info._p - _heart) / _radius, info._u, info._v);        //!!!
                return true;
                }
            }
        return false;
        }
    
    aabb sphere::getbox()const
        {
        return aabb(_heart - rtvec(_radius, _radius, _radius), _heart + rtvec(_radius, _radius, _radius));
        }
    
    void sphere::get_sphere_uv(const rtvec& p, rtvar& u, rtvar& v)
        {
        rtvar φ = atan2(p.z(), p.x());
        rtvar θ = asin(p.y());
        u = 1 - (φ + π) / (2 * π);
        v = (θ + π / 2) / π;
        }
    
    } // rt namespace
    sphere.hpp
    /// moving_sphere.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10269488.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the moving_sphere-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    //the statement of moving_shpere class
    
    class moving_sphere :public intersect 
        {
    public:
        moving_sphere() {  }
    
        /*
        @brief: 模拟运动模糊的几何体
        @param: 起始位置的球心
                结束位置的球心
                开始时间
                结束时间
                球体半径
                纹理
        */
        moving_sphere(rtvec heart1, rtvec heart2, rtvar t1, rtvar t2, rtvar r, material* mp);
    
        virtual bool hit(const ray& r, rtvar tmin, rtvar tmax, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
        inline rtvec heart(rtvar t)const;
        
    private:
        rtvec _heart1;
        rtvec _heart2;
        rtvar _time1;
        rtvar _time2;
        rtvar _radius;
        material* _materialp;
        };
    
    
    
    //the implementation of moving_sphere class
    
    inline moving_sphere::moving_sphere(rtvec heart1, rtvec heart2, rtvar t1, rtvar t2, rtvar r, material* mp)
        :_heart1(heart1)
        , _heart2(heart2)
        , _time1(t1)
        , _time2(t2)
        , _radius(r)
        , _materialp(mp)
        {
        }
    
    inline rtvec moving_sphere::heart(rtvar t)const
        {
        return _heart1 + ((t - _time1) / (_time2 - _time1)) * (_heart2 - _heart1);
        }
    
    bool moving_sphere::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvec trace = sight.origin() - heart(sight.time());
        rtvar a = dot(sight.direction(), sight.direction());
        rtvar b = 2.0 * dot(trace, sight.direction());
        rtvar c = dot(trace, trace) - _radius * _radius;
        rtvar delt = b*b - 4.0*a*c;
        if (delt > 0)
            {
            info._materialp = _materialp;
            rtvar x = (-b - sqrt(delt)) / (2.0*a);
            if (x < t_max && x > t_min)
                {
                info._t = x;
                info._p = sight.go(x);
                info._n = (info._p - heart(sight.time())) / _radius;
                return true;
                }
            x = (-b + sqrt(delt)) / (2.0*a);
            if (x < t_max && x > t_min)
                {
                info._t = x;
                info._p = sight.go(x);
                info._n = (info._p - heart(sight.time())) / _radius;
                return true;
                }
            }    
        return false;
        }
    
    aabb moving_sphere::getbox()const
        {
        rtvec delt{ _radius, _radius, _radius };
        return aabb::_surrounding_box(aabb(_heart1 - delt, _heart1 + delt), aabb(_heart2 - delt, _heart2 + delt));
        }
    
    } // rt namespace
    moving_sphere.hpp
    /// constant_medium.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the constant_dedium-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    
    #pragma once
    
    namespace rt
    {
    
    class constant_medium :public intersect
        {
    public:
        /*
        形体
        颗粒浓度
        纹理
        */
        constant_medium(intersect* p, rtvar d, texture* tex);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    public:
        inline const rtvar get_density()const { return _density; }
    
        inline const material* get_material()const { return _materialp; }
    
        inline void set_density(const rtvar density) { _density = density; }
    
        inline void set_material(material* m) { _materialp = m; }
    
    private:
        intersect* _item;
    
        rtvar _density;
    
        material* _materialp;
        };
    
    
    
    inline constant_medium::constant_medium(intersect* p, rtvar d, texture* tex)
        :_item(p)
        ,_density(d)
        ,_materialp(new isotropic(tex))
        {
        }
    
    aabb constant_medium::getbox()const
        {
        return _item->getbox();
        }
    
    bool constant_medium::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const 
        {
        hitInfo info1, info2;
        if (_item->hit(sight, -rtInf(), rtInf(), info1)) {
            if (_item->hit(sight, info1._t + 0.0001, rtInf(), info2)) {
                if (info1._t < t_min)
                    info1._t = t_min;
                if (info2._t > t_max)
                    info2._t = t_max;
                if (info1._t >= info2._t)
                    return false;
                if (info1._t < 0)
                    info1._t = 0;
                float distance_inside_boundary = (info2._t - info1._t)*sight.direction().normal();
                float hit_distance = -(1 / _density)*log(lvgm::rand01());
                if (hit_distance < distance_inside_boundary) {
                    info._t = info1._t + hit_distance / sight.direction().normal();
                    info._p = sight.go(info._t);
                    info._n = rtvec(lvgm::rand01(), lvgm::rand01(), lvgm::rand01());  // arbitrary
                    info._materialp = _materialp;
                    return true;
                    }
                }
            }
        return false;
        }
    
    } // rt namespace
    constant_medium.hpp
    /// flip_normal.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10307569.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the flip_normal-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
        
    class flip_normal: public intersect
        {
    public:
        flip_normal(intersect * p) :_p(p) {  }
        
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override
            {
            if (_p->hit(sight, t_min, t_max, info))
                {
                info._n = -info._n;
                return true;
                }
            return false;
            }
    
        virtual aabb getbox()const override
            {
            return _p->getbox();
            }
    
    private:
        intersect* _p;
        };
    
    } // rt namespace 
    flip_normal.hpp
    /// translate.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10307569.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the translate-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    namespace rt
    {
    
    class translate :public intersect
        {
    public:
        translate(intersect* p, const rtvec& offset);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
        inline const rtvec get_offset()const { return _offset; }
    
        inline void set_offset(const rtvec& f) { _offset = f; }
    
    private:
        intersect* _item;
    
        rtvec _offset;
    
        };
    
    
    
    translate::translate(intersect* p, const rtvec& offset)
        :_item(p)
        , _offset(offset)
        {
        }
    
    bool translate::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        ray movedRay(sight.origin() - _offset, sight.direction(), sight.time());
        if (_item->hit(movedRay, t_min, t_max, info))
            {
            info._p += _offset;
            return true;
            }
        return false;
        }
    
    aabb translate::getbox()const
        {
        aabb box = _item->getbox();
        return aabb(box.min() + _offset, box.max() + _offset);
        }
    
    }// rt namespace
    translate.hpp
    /// rotate.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10307569.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the translate-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    
    namespace rt
    {
    
    // the statement of rotate_y class
    
    class rotate_y :public intersect
        {
    public:
        rotate_y(intersect* p, rtvar angle);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    private:
        intersect* _item;
    
        rtvar _sinθ;
    
        rtvar _cosθ;
    
        aabb _box;
    
        };
    
    // the statement of rotate_x class
    
    class rotate_x :public intersect
        {
    public:
        rotate_x(intersect* p, rtvar angle);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    private:
        intersect* _item;
    
        rtvar _sinθ;
    
        rtvar _cosθ;
    
        aabb _box;
    
        };
    
    // the statement of rotate_z class
    
    class rotate_z :public intersect
        {
    public:
        rotate_z(intersect* p, rtvar angle);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    private:
        intersect* _item;
    
        rtvar _sinθ;
    
        rtvar _cosθ;
    
        aabb _box;
    
        };
    
    
    // the implementation of rotate_y class
    
    rotate_y::rotate_y(intersect* p, rtvar angle)
        :_item(p)
        {
        rtvar radians = (π / 180.) * angle;
        _sinθ = sin(radians);
        _cosθ = cos(radians);
        rtvec min(rtInf(), rtInf(), rtInf());
        rtvec max = -min;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                for (int k = 0; k < 2; ++k)
                    {
                    rtvar x = i * _box.max().x() + (1 - i)*_box.min().x();
                    rtvar y = j * _box.max().y() + (1 - j)*_box.min().y();
                    rtvar z = k * _box.max().z() + (1 - k)*_box.min().z();
                    rtvar newx = _cosθ * x + _sinθ * z;
                    rtvar newz = -_sinθ * x + _cosθ * z;
                    rtvec tester(newx, y, newz);
                    for (int c = 0; c < 3; ++c)
                        {
                        if (tester[c] > max[c])
                            max[c] = tester[c];
                        if (tester[c] < min[c])
                            min[c] = tester[c];
                        }
                    }
        _box = aabb(min, max);
        }
    
    bool rotate_y::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvec eye = sight.origin();
        rtvec direction = sight.direction();
        eye[0] = _cosθ * sight.origin()[0] - _sinθ * sight.origin()[2];
        eye[2] = _sinθ * sight.origin()[0] + _cosθ * sight.origin()[2];
        direction[0] = _cosθ * sight.direction()[0] - _sinθ * sight.direction()[2];
        direction[2] = _sinθ * sight.direction()[0] + _cosθ * sight.direction()[2];
        ray rotatedRay(eye, direction, sight.time());
        if (_item->hit(rotatedRay, t_min, t_max, info))
            {
            rtvec p = info._p;
            rtvec n = info._n;
            p[0] = _cosθ * info._p[0] + _sinθ * info._p[2];
            p[2] = -_sinθ * info._p[0] + _cosθ * info._p[2];
            n[0] = _cosθ * info._n[0] + _sinθ * info._n[2];
            n[2] = -_sinθ * info._n[0] + _cosθ * info._n[2];
            info._p = p;
            info._n = n;
            return true;
            }
        return false;
        }
    
    aabb rotate_y::getbox()const
        {
        return _box;
        }
    
    // the implementation of rotate_x class
    
    rotate_x::rotate_x(intersect* p, rtvar angle)
        :_item(p)
        {
        rtvar radians = (π / 180.) * angle;
        _sinθ = sin(radians);
        _cosθ = cos(radians);
        rtvec min(rtInf(), rtInf(), rtInf());
        rtvec max = -min;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                for (int k = 0; k < 2; ++k)
                    {
                    rtvar x = i * _box.max().x() + (1 - i)*_box.min().x();
                    rtvar y = j * _box.max().y() + (1 - j)*_box.min().y();
                    rtvar z = k * _box.max().z() + (1 - k)*_box.min().z();
                    rtvar newy = _cosθ * x - _sinθ * z;
                    rtvar newz = _sinθ * x + _cosθ * z;
                    rtvec tester(x, newy, newz);
                    for (int c = 0; c < 3; ++c)
                        {
                        if (tester[c] > max[c])
                            max[c] = tester[c];
                        if (tester[c] < min[c])
                            min[c] = tester[c];
                        }
                    }
        _box = aabb(min, max);
        }
    
    bool rotate_x::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvec eye = sight.origin();
        rtvec direction = sight.direction();
        eye[1] = _cosθ * sight.origin()[1] + _sinθ * sight.origin()[2];
        eye[2] = -_sinθ * sight.origin()[1] + _cosθ * sight.origin()[2];
        direction[1] = _cosθ * sight.direction()[1] + _sinθ * sight.direction()[2];
        direction[2] = -_sinθ * sight.direction()[1] + _cosθ * sight.direction()[2];
        ray rotatedRay(eye, direction, sight.time());
        if (_item->hit(rotatedRay, t_min, t_max, info))
            {
            rtvec p = info._p;
            rtvec n = info._n;
            p[1] = _cosθ * info._p[1] - _sinθ * info._p[2];
            p[2] = _sinθ * info._p[1] + _cosθ * info._p[2];
            n[1] = _cosθ * info._n[1] - _sinθ * info._n[2];
            n[2] = _sinθ * info._n[1] + _cosθ * info._n[2];
            info._p = p;
            info._n = n;
            return true;
            }
        return false;
        }
    
    aabb rotate_x::getbox()const
        {
        return _box;
        }
    
    
    // the implementation of rotate_z class
    
    rotate_z::rotate_z(intersect* p, rtvar angle)
        :_item(p)
        {
        rtvar radians = (π / 180.) * angle;
        _sinθ = sin(radians);
        _cosθ = cos(radians);
        rtvec min(rtInf(), rtInf(), rtInf());
        rtvec max = -min;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                for (int k = 0; k < 2; ++k)
                    {
                    rtvar x = i * _box.max().x() + (1 - i)*_box.min().x();
                    rtvar y = j * _box.max().y() + (1 - j)*_box.min().y();
                    rtvar z = k * _box.max().z() + (1 - k)*_box.min().z();
                    rtvar newx = _cosθ * x - _sinθ * y;
                    rtvar newy = _sinθ * x + _cosθ * y;
                    rtvec tester(newx, newy, z);
                    for (int c = 0; c < 3; ++c)
                        {
                        if (tester[c] > max[c])
                            max[c] = tester[c];
                        if (tester[c] < min[c])
                            min[c] = tester[c];
                        }
                    }
        _box = aabb(min, max);
        }
    
    bool rotate_z::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvec eye = sight.origin();
        rtvec direction = sight.direction();
        eye[0] = _cosθ * sight.origin()[0] + _sinθ * sight.origin()[1];
        eye[1] = -_sinθ * sight.origin()[0] + _cosθ * sight.origin()[1];
        direction[0] = _cosθ * sight.direction()[0] + _sinθ * sight.direction()[1];
        direction[1] = -_sinθ * sight.direction()[0] + _cosθ * sight.direction()[1];
        ray rotatedRay(eye, direction, sight.time());
        if (_item->hit(rotatedRay, t_min, t_max, info))
            {
            rtvec p = info._p;
            rtvec n = info._n;
            p[0] = _cosθ * info._p[0] - _sinθ * info._p[1];
            p[1] = _sinθ * info._p[0] + _cosθ * info._p[1];
            n[0] = _cosθ * info._n[0] - _sinθ * info._n[1];
            n[1] = _sinθ * info._n[0] + _cosθ * info._n[1];
            info._p = p;
            info._n = n;
            return true;
            }
        return false;
        }
    
    aabb rotate_z::getbox()const
        {
        return _box;
        }
    
    
    } // rt namespace
    rotate.hpp

    鉴于这个系统的变换均针对运算期的每个点做变换,具体的几何体不变,所以,造成一个问题就是不方便获取变换后的法线等信息,也不利于重置纹理材质等,就长方体而言,比如我想改变某个面的纹理或者材质,就很困难,所以新加了很多接口,但是,这些接口都是统一的,所以又重新整了一个基类,提高代码重用性和可维护性

    但我只改了反转向量,没有对旋转做适应的变动

    /// rectangleBasic.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the rectangle-class for the ray-tracing project
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    class rectangle :public intersect
        {
    public:
        rectangle() {  }
    
        rectangle(rtvar u1, rtvar u2, rtvar v1, rtvar v2, rtvar other, material* mat, rtvec nor)
            :_u1(u1)
            , _u2(u2)
            , _v1(v1)
            , _v2(v2)
            , _materialp(mat)
            , _normal(nor)
        {
        }
    
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override = 0;
    
        virtual aabb getbox()const = 0;
    
    public:
        inline const rtvec Getnormal()const { return _normal; }
    
        inline const lvgm::vec2<lvgm::precision> Urange()const { return lvgm::vec2<lvgm::precision>(rtmin(_u1, _u2), rtmax(_u1, _u2)); }
    
        inline const lvgm::vec2<lvgm::precision> Vrange()const { return lvgm::vec2<lvgm::precision>(rtmin(_v1, _v2), rtmax(_v1, _v2)); }
    
        inline const material* Getmaterial()const { return _materialp; }
    
        inline void flipNormal() { _normal = -_normal; }
    
        inline void setmaterial(material* m) { _materialp = m; }
    
        inline void setnormal(const rtvec& n) { _normal = n; }
    
    protected:
        material* _materialp;
    
        rtvar _u1, _u2;
    
        rtvar _v1, _v2;
    
        rtvar _other;
    
        rtvec _normal;
        };
    
    } // rt namespace 
    rectangleBasic.hpp
    /// rectangles.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the rectangles-class for the ray-tracing project
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    class rectangles:public rectangle
        {
    public:
        rectangles(rectangle** list, size_t n) :_list(list), _size(n) {  }
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override { return aabb(); }
    
    private:
        rectangle** _list;
    
        size_t _size;
        };
    
    
    
        // the implementation of intersections class
    
    bool rectangles::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        hitInfo t_rec;
        bool hitSomething = false;
        rtvar far = t_max;            //刚开始可以看到无限远
        for (int i = 0; i < _size; ++i)
            {
            if (_list[i]->hit(sight, t_min, far, t_rec))
                {
                hitSomething = true;
                far = t_rec._t;            //将上一次的最近撞击点作为视线可达最远处
                info = t_rec;
                }
            }
        return hitSomething;
        }
    
    }
    rectangles.hpp
    /// rectangle.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the rect-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    //the statement of xy_rect class
    
    class xy_rect : public rectangle 
        {
    public:
        xy_rect() {  }
    
        /*
        @brief: the rectangle in the x-y plane
        @param: the boundary of x axis
                the boundary of y axis
                the value of z axis
                the material of rectangle
                flip normal or not
        */
        xy_rect(rtvar x1, rtvar x2, rtvar y1, rtvar y2, rtvar z0, material* mat, bool _flipNormal = false);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
        };
    
    //the statement of xz_rect class
    
    class xz_rect : public rectangle 
        {
    public:
        xz_rect() {  }
    
        /*
        @brief: the rectangle in the x-z plane
        @param: the boundary of x axis
                the boundary of z axis
                the value of y axis
                the material of rectangle
        */
        xz_rect(rtvar x1, rtvar x2, rtvar z1, rtvar z2, rtvar y0, material* mat, bool _flipNormal = false);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
        };
    
    //the statement of yz_rect class
    
    class yz_rect : public rectangle 
        {
    public:
        yz_rect() {  }
    
        /*
        @brief: the rectangle in the y-z plane
        @param: the boundary of y axis
                the boundary of z axis
                the value of x axis
                the material of rectangle
        */
        yz_rect(rtvar y1, rtvar y2, rtvar z1, rtvar z2, rtvar x0, material* mat, bool _flipNormal = false);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
        };
    
    
    
    // the implementation of xy_rect class
    
    inline xy_rect::xy_rect(rtvar x1, rtvar x2, rtvar y1, rtvar y2, rtvar z0, material* mat, bool _flipNormal)
        : rectangle(x1, x2, y1, y2, z0, mat, rtvec(0., 0., 1.))
        {
        if (_flipNormal)flipNormal();
        }
    
    bool xy_rect::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvar t = (_other - sight.origin().z()) / sight.direction().z();
        if (t < t_min || t > t_max)return false;
    
        rtvar x = sight.origin().x() + t*sight.direction().x();
        rtvar y = sight.origin().y() + t*sight.direction().y();
        if (x < _u1 || x > _u2 || y < _v1 || y > _v2)
            return false;
    
        info._u = (x - _u1) / (_u2 - _u1);
        info._v = (y - _v1) / (_v2 - _v1);
        info._t = t;
        info._materialp = _materialp;
        info._p = sight.go(t);
        info._n = rtvec(0, 0, 1);
    
        return true;
        }
    
    aabb xy_rect::getbox()const
        {
        return aabb(rtvec(_u1, _v1, _other - 0.0001), rtvec(_u2, _v2, _other + 0.0001));
        }
    
    
    // the implementation of xz_rect class
    
    inline xz_rect::xz_rect(rtvar x1, rtvar x2, rtvar z1, rtvar z2, rtvar y0, material* mat, bool _flipNormal)
        : rectangle(x1, x2, z1, z2, y0, mat, rtvec(0., 1., 0.))
        {
        if (_flipNormal)flipNormal();
        }
    
    bool xz_rect::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvar t = (_other - sight.origin().y()) / sight.direction().y();
        if (t < t_min || t > t_max)return false;
    
        rtvar x = sight.origin().x() + t*sight.direction().x();
        rtvar z = sight.origin().z() + t*sight.direction().z();
        if (x < _u1 || x > _u2 || z < _v1 || z > _v2)
            return false;
    
        info._u = (x - _u1) / (_u2 - _u1);
        info._v = (z - _v1) / (_v2 - _v1);
        info._t = t;
        info._materialp = _materialp;
        info._p = sight.go(t);
        info._n = rtvec(0, 1, 0);
    
        return true;
        }
    
    aabb xz_rect::getbox()const
        {
        return aabb(rtvec(_u1, _other - 0.0001, _v1), rtvec(_u2, _other + 0.0001, _v2));
        }
    
    // the implementation of yz_rect class
    
    inline yz_rect::yz_rect(rtvar y1, rtvar y2, rtvar z1, rtvar z2, rtvar x0, material* mat, bool _flipNormal)
        : rectangle(y1, y2, z1, z2, x0, mat, rtvec(1., 0., 0.))
        {
        if (_flipNormal)flipNormal();
        }
    
    bool yz_rect::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        rtvar t = (_other - sight.origin().x()) / sight.direction().x();
        if (t < t_min || t > t_max)return false;
    
        rtvar y = sight.origin().y() + t*sight.direction().y();
        rtvar z = sight.origin().z() + t*sight.direction().z();
        if (y < _u1 || y > _u2 || z < _v1 || z > _v2)
            return false;
    
        info._u = (y - _u1) / (_u2 - _u1);
        info._v = (z - _v1) / (_v2 - _v1);
        info._t = t;
        info._materialp = _materialp;
        info._p = sight.go(t);
        info._n = rtvec(1, 0, 0);
    
        return true;
        }
    
    aabb yz_rect::getbox()const
        {
        return aabb(rtvec(_other - 0.0001, _u1, _v1), rtvec(_other + 0.0001, _u2, _v2));
        }
    
    }// rt namespace 
    rectangle.hpp
    /// box.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10307569.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the box-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of box class
    
    class box: public intersect
        {
    public:
        box() {  }
    
        box(const rtvec& pointmin, const rtvec& pointmax, material * mat);
    
        virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const override;
    
        virtual aabb getbox()const override;
    
    public:
        // the normal of xy_rect, the normal's direction is +
        inline const rtvec& xy_n()        const    { return _list[0].Getnormal(); }
    
        // the normal of xy_rect, the normal's direction is -
        inline const rtvec& xy_nflip()    const    { return _list[1].Getnormal(); }
        
        inline const rtvec& xz_n()        const    { return _list[2].Getnormal(); }
    
        inline const rtvec& xz_nflip()    const    { return _list[3].Getnormal(); }
            
        inline const rtvec& yz_n()        const    { return _list[4].Getnormal(); }
    
        inline const rtvec& yz_nflip() const    { return _list[5].Getnormal(); }
    
    
        inline void set_xy_material(material* m) { _list[0].setmaterial(m); }
    
        inline void set_xy_flipmaterial(material* m) { _list[1].setmaterial(m); }
    
        inline void set_xz_material(material* m) { _list[2].setmaterial(m); }
    
        inline void set_xz_flipmaterial(material* m) { _list[3].setmaterial(m); }
    
        inline void set_yz_material(material* m) { _list[4].setmaterial(m); }
    
        inline void set_yz_flipmaterial(material* m) { _list[5].setmaterial(m); }
    
    private:
        rtvec _min;
        
        rtvec _max;
    
        rectangles* _list;
        };
    
    
    
    // the implementation of box class
    
    inline     box::box(const rtvec& pointmin, const rtvec& pointmax, material * mat)
        :_min(pointmin)
        ,_max(pointmax)
        {
        rectangle ** list = new rectangle*[6];
        list[0] = new xy_rect(_min.x(), _max.x(), _min.y(), _max.y(), _max.z(), mat);
        list[1] = new xy_rect(_min.x(), _max.x(), _min.y(), _max.y(), _min.z(), mat, true);
        list[2] = new xz_rect(_min.x(), _max.x(), _min.z(), _max.z(), _max.y(), mat);
        list[3] = new xz_rect(_min.x(), _max.x(), _min.z(), _max.z(), _min.y(), mat, true);
        list[4] = new yz_rect(_min.y(), _max.y(), _min.z(), _max.z(), _max.x(), mat);
        list[5] = new yz_rect(_min.y(), _max.y(), _min.z(), _max.z(), _min.x(), mat, true);
        _list = new rectangles(list, 6);
        }
    
    bool box::hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const
        {
        return _list->hit(sight, t_min, t_max, info);
        }
    
    aabb box::getbox()const
        {
        return aabb(_min, _max);
        }
    
    } // rt namespace 
    box.hpp

     material

    /// RTmaterial.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        some materials
    //                diffuse
    //                metal
    //                dielectric
    //                areaLight
    //                isotropic
    // -----------------------------------------------------
    
    #pragma once
    
    
    #include "E:OpenGL光线追踪code
    ay tracing 1-2
    ay tracing 1-2
    ay.hpp"
    #include "E:OpenGL光线追踪code
    ay tracing 1-2
    ay tracing 1-2includehitintersect.hpp"
    #include "material.hpp"
    
    #include "diffuse.hpp"
    #include "metal.hpp"
    #include "dielectric.hpp"
    #include "light.hpp"
    #include "isotropic.hpp"
    RTmaterial.hpp
    /// material.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        the material-class for the ray-tracing project
    //                from the 《ray tracing in one week》
    // -----------------------------------------------------
    
    #pragma once
    
    namespace rt
    {
    
    // the statement of material class
    
    class material
        {
    public:
    
        /*
        @brief: produce a scattered ray
        @param: InRay -> Incident light
                info -> the information of intersect-point(hit-point)
                attenuation -> when scattered, how much the ray should be attenuated by tis reflectance R
                scattered -> as we talk, it is a new sight; or
                             it is the scattered ray with the intersect-point
        @retur: the function calculate a scattered ray or not
        */
        virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const = 0;
    
    
        /*
        @brief: 自发光
        @param: 纹理所需信息
        @retur: 纹理像素值
        */
        virtual rtvec emitted(rtvar u, rtvar v, const rtvec& p)const { return rtvec(); }
    
        };
    
    }
    material.hpp
    /// 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;
    
    // the statement of lambertian class
    
    class lambertian : public material
        {
    public:
        lambertian(texture* _tex);
    
        virtual bool scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const override;
    
    public:
        const texture* get_texture()const { return _albedo; }
    
        void set_texture(texture* tex) { _albedo = tex; }
    
    protected:
    
        texture* _albedo;
        };
    
    
    
    // the implementation of lambertian class
    
    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(info._u, info._v, info._p);
        return true;
        }
    
    } // rt namespace
    diffuse.hpp
    /// metal.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10206773.html
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2018.12
    // [brief ]        one of the materials
    // -----------------------------------------------------
    
    #pragma once
    
    namespace rt
    {
    
    // the statement of metal class
    
    class metal :public material
        {
    public:
    
        /*
        @param: f -> Fuzzy index
        */
        metal(texture* a, const rtvar f = 0.);
        
        virtual bool scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const override;
    
    public:
        const texture* get_texture()const { return _albedo; }
    
        const rtvar get_fuzz()const { return _fuzz; }
    
        void set_texture(texture* tex) { _albedo = tex; }
    
        void set_fuzz(const rtvar f) { _fuzz = f; }
        
    protected:
    
        texture* _albedo;
    
        rtvar _fuzz;
        };
    
    
    
    inline metal::metal(texture* a, const rtvar f )
        :_albedo(a)
        {
        if (f < 1 && f >= 0)_fuzz = f;
        else _fuzz = 1;
        }
    
    bool metal::scatter(const ray& rIn, const hitInfo& info, rtvec& attenuation, ray& scattered)const
        {
        rtvec target = reflect(rIn.direction().ret_unitization(), info._n);
        scattered = ray{ info._p, target + _fuzz * lvgm::random_unit_sphere() };
        attenuation = _albedo->value(info._u, info._v, info._p);
        return dot(scattered.direction(), info._n) != 0;
        }
    
    } // rt namespace
    metal.hpp
    /// dielectric.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10217719.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        one of the materials
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of dielectric class
    
    class dielectric :public material
        {
        public:
    
            /*
            @param: refractive indices
            */
            dielectric(const rtvar RI) :_RI(RI) {  }
    
            virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const override;
    
        public:
            const rtvar get_refIndex()const { return _RI; }
    
            void set_refIndex(rtvar ri) { _RI = ri; }
    
        protected:
            rtvar _RI;
    
            inline rtvar schlick(const rtvar cosine)const;
        };
    
    
    
    // the implementation of dielectric class
    
    bool dielectric::scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const
        {
        rtvec outward_normal;
        rtvec refracted;
        rtvec reflected = reflect(InRay.direction(), info._n);
        rtvar eta;
        rtvar reflect_prob;
        rtvar cos;
        attenuation = rtvec(1., 1., 1.);
    
        if (dot(InRay.direction(), info._n) > 0)
            {
            outward_normal = -info._n;
            eta = _RI;
            cos = _RI * dot(InRay.direction(), info._n) / InRay.direction().normal();
            }
        else
            {
            outward_normal = info._n;
            eta = 1.0 / _RI;
            cos = -dot(InRay.direction(), info._n) / InRay.direction().normal();
            }
    
        if (refract(InRay.direction(), outward_normal, eta, refracted))
            reflect_prob = schlick(cos);    //如果有折射,计算反射系数
        else
            reflect_prob = 1.0;        //如果没有折射,那么为全反射
    
        if (lvgm::rand01() < reflect_prob)
            scattered = ray(info._p, reflected);
        else
            scattered = ray(info._p, refracted);
    
        return true;
        }
    
    inline rtvar dielectric::schlick(const rtvar cosine)const
        {
        rtvar r0 = (1. - _RI) / (1. + _RI);
        r0 *= r0;
        return r0 + (1 - r0)*pow((1 - cosine), 5);
        }
    
    } // rt namespace 
    dielectric.hpp
    /// light.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the areaLight-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    
    namespace rt
    {
    
    //the statement of areaLight class
    
    class areaLight :public material
        {
    public:
        areaLight() {  }
    
        areaLight(texture* mat) :_emit(mat) {  }
    
        virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const { return false; }
    
        virtual rtvec emitted(rtvar u, rtvar v, const rtvec& p)const { return _emit->value(u, v, p); }
    
    public:
        const texture* get_texture()const { return _emit; }
    
        void set_texture(texture* tex) { _emit = tex; }
    
    private:
        texture* _emit;
        };
    
    } // rt namespace
    light.hpp
    /// isotropic.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the isotropic-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
        class isotropic :public material
        {
        public:
            isotropic(texture* tex) :_albedo(tex) {  }
    
            virtual bool scatter(const ray& InRay, const hitInfo& info, rtvec& attenuation, ray& scattered)const override
            {
                scattered = ray(info._p, lvgm::random_unit_sphere());
                attenuation = _albedo->value(info._u, info._v, info._p);
                return true;
            }
    
        public:
            const texture* get_texture()const { return _albedo; }
    
            void set_texture(texture* tex) { _albedo = tex; }
    
        private:
            texture * _albedo;
        };
    
    } // rt namespace
    isotropic.hpp

     texture

    /// RTtexture.hpp
    
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        some textures
    //                checker
    //                constant
    //                Perlin noise
    //                image
    // -----------------------------------------------------
    
    #pragma once
    
    
    #include "RTdef.hpp"
    
    #include "texture.hpp"
    
    #include "checker_tex.hpp"
    #include "constant_tex.hpp"
    
    #include "Perlin.hpp"
    #include "noise_tex.hpp"
    
    #include "image_tex.hpp"
    RTtexture.hpp
    /// 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;
        
        };
    
    } // rt namespace
    texture.hpp
    /// constant_tex.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10285473.html
    // -----------------------------------------------------
    // [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
    {
    
    // the statement of constant_texture class
        
    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; }
    
        inline void set_color(const rtvec& color) { _color = color; }
    
    private:
    
        rtvec _color;
    
        };
    
    
    
    // the implementation of constant_texture class
    
    inline constant_texture::constant_texture(const rtvec& color)
        :_color(color)
        {
        }
    
    rtvec constant_texture::value(rtvar u, rtvar v, const rtvec& p)const
        {
        return _color;
        }
    
    } // rt namesapce 
    constant_texture .hpp
    /// checker_tex.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10285473.html
    // -----------------------------------------------------
    // [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
    {
    
    // the statement of checker_texture class
    
    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;
    
        };
    
    
    
    // the implementation of checker_texture class
    
    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(10 * p.x() + 2) * sin(10 * p.y() + 2) * sin(10 * p.z() + 2);
        if (sines < 0)
            return _odd->value(u, v, p);
        else
            return _even->value(u, v, p);
        }
    
    } // rt namespace 
    checker_texture.hpp
    /// image_tex.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10295137.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the image_texture-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once 
    
    namespace rt
    {
    
    // the statement of image_texture class
    
    class image_texture: public texture
        {
    public:
        image_texture() {  }
    
        /*
        @param: image -> the rgb list of image texture 
                a  b  -> the size of image texture
        */
        image_texture(unsigned char* image, size_t a, size_t b);
    
        virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;
    
    public:
    
        inline unsigned char* image()const    { return _image; }
    
        inline size_t sizeX()const            { return _sizeX; }
    
        inline size_t sizeY()const            { return _sizeY; }
    
    private:
        unsigned char* _image;
    
        size_t _sizeX;
    
        size_t _sizeY;
        };
    
    
    
    //the implementation of image_texture class
    
    image_texture::image_texture(unsigned char* image, size_t a, size_t b)
        :_image(image)
        ,_sizeX(a)
        ,_sizeY(b)
        {
        }
    
    rtvec image_texture::value(rtvar u, rtvar v, const rtvec& p)const
        {
        int i = u*_sizeX;
        int j = (1 - v)*_sizeY - 0.001;
        if (i < 0)i = 0;
        if (j < 0)j = 0;
        if (i > _sizeX - 1)i = _sizeX - 1;
        if (j > _sizeY - 1)j = _sizeY - 1;
        rtvar r = int(_image[3 * i + 3 * _sizeX*j]) / 255.0;
        rtvar g = int(_image[3 * i + 3 * _sizeX*j + 1]) / 255.0;
        rtvar b = int(_image[3 * i + 3 * _sizeX*j + 2]) / 255.0;
        return rtvec(r, g, b);
        }
    
    } // rt namespace 
    image_texture.hpp
    /// Perlin.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10291292.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the Perlin-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of Perlin class
    
    class Perlin
        {
    public:
    
        /*
        产生噪声值
        */
        inline rtvar noise(const rtvec& p)const;
    
        /*
        @brief: 三线性插值
        @param: list -> 辅助数组
        u v w -> 0~1 的辅助系数
        @retur: 插值结果值
        */
        static rtvar perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w);
    
        /*
        对噪声值进行采样
        */
        inline rtvar turb(const rtvec& p, int depth) const;
    
        inline rtvec* randomvalue()const { return _randomvalue; }
    
        inline int* perm_x()const { return _perm_x; }
    
        inline int* perm_y()const { return _perm_y; }
    
        inline int* perm_z()const { return _perm_z; }
    
    private:
        static rtvec * _randomvalue;
    
        static int * _perm_x;
    
        static int * _perm_y;
    
        static int * _perm_z;
        };
    
    
    
    // the implement of Perlin class
    
    rtvec * Perlin::_randomvalue = lvgm::random_normalized3D(256);
    
    int * Perlin::_perm_x = lvgm::generate_random0n(256);
    
    int * Perlin::_perm_y = lvgm::generate_random0n(256);
    
    int * Perlin::_perm_z = lvgm::generate_random0n(256);
    
    rtvar Perlin::turb(const rtvec& p, int depth = 7) const 
        {
        rtvar accumulate = 0;
        rtvec t = p;
        rtvar weight = 1.0;
        for (int i = 0; i < depth; i++) 
            {
            accumulate += weight*noise(t);
            weight *= 0.5;
            t *= 2;
            }
        return abs(accumulate);
        }
    
    inline rtvar Perlin::noise(const rtvec& p)const
        {
        int i = floor(p.x());
        int j = floor(p.y());
        int k = floor(p.z());
        rtvar u = p.x() - i;
        rtvar v = p.y() - j;
        rtvar w = p.z() - k;
    
        rtvec list[2][2][2];
        for (int a = 0; a < 2; ++a)
            for (int b = 0; b < 2; ++b)
                for (int c = 0; c < 2; ++c)
                    {
                    list[a][b][c] = _randomvalue[_perm_x[(i + a) & 255] ^ _perm_y[(j + b) & 255] ^ _perm_z[(k + c) & 255]];
    #ifdef listtest
                    if (list[a][b][c].x() < 0)stds cout << "list.x < 0 " << stds endl;
                    if (list[a][b][c].y() < 0)stds cout << "list.y < 0 " << stds endl;
                    if (list[a][b][c].z() < 0)stds cout << "list.z < 0 " << stds endl;
    #endif
                    }
        return perlin_interp(list, u, v, w);
        }
    
    rtvar Perlin::perlin_interp(rtvec list[2][2][2], rtvar u, rtvar v, rtvar w)
        {
    #ifdef uvwtest
        if (u < 0)stds cout << "u < 0 " << stds endl;
        if (v < 0)stds cout << "v < 0 " << stds endl;
        if (w < 0)stds cout << "w < 0 " << stds endl;
        if (u > 1)stds cout << "u > 1 " << stds endl;
        if (v > 1)stds cout << "v > 1 " << stds endl;
        if (w > 1)stds cout << "w > 1 " << stds endl;
    #endif
        rtvar uu = u*u*(3 - 2 * u);
        rtvar vv = u*v*(3 - 2 * v);
        rtvar ww = u*w*(3 - 2 * w);
    
        rtvar accumulate = 0;
        for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
                for (int k = 0; k < 2; ++k)
                    {
                    rtvec weight(u - i, v - j, w - k);
                    accumulate +=
                        (i*uu + (1 - i) * (1 - uu))*
                        (j*vv + (1 - j) * (1 - vv))*
                        (k*ww + (1 - k) * (1 - ww))*
                        lvgm::dot(list[i][j][k], weight);
    #ifdef accumulatetest
                    if (accumulate < 0)stds cout << "accumulate < 0 " << stds endl;
    #endif
                    }
        return accumulate;        
        }
    
    } // rt namespace 
    Perlin.hpp
    /// noise_tex.hpp
    // https://www.cnblogs.com/lv-anchoret/p/10291292.html
    // -----------------------------------------------------
    // [author]        lv
    // [begin ]        2019.1
    // [brief ]        the noise_texture-class for the ray-tracing project
    //                from the 《ray tracing the next week》
    // -----------------------------------------------------
    
    #pragma once
    
    
    namespace rt
    {
    
    // the statement of noise_texture class
    
    class noise_texture :public texture
        {
    public:
        noise_texture() {  }
    
        noise_texture(const rtvar scale);    
    
        virtual rtvec value(rtvar u, rtvar v, const rtvec& p)const override;
    
        inline const rtvar get_scale()const { return _scale; }
    
        inline void set_scale(const rtvar s) { _scale = s; }
        
    private:
        Perlin _noise;
    
        rtvar _scale;
        };
    
    
    
    // the implementation of noise_texture class
    
    noise_texture::noise_texture(const rtvar scale)
        :_scale(scale)
        {
        }
    
    rtvec noise_texture::value(rtvar u, rtvar v, const rtvec& p)const
        {
        return rtvec(1., 1., 1.) * 0.5 * (1 + sin(_scale * p.z() + 10 * _noise.noise(p)));
        }
    
    } // rt namespace 
    noise_texture.hpp

    如果有什么问题可以留言

  • 相关阅读:
    PCL配置即常见问题
    opencv2.4.9配置+VS2013
    我的项目配置问题及解决
    Java 8 函数式编程
    leecode刷题(17)-- 实现StrStr
    leecode刷题(16)-- 字符串转换整数
    leecode刷题(15)-- 验证回文字符串
    博客迁移通知
    leecode刷题(14)-- 有效的字母异位词
    leecode刷题(13) -- 字符串中的第一个唯一字符
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/10327509.html
Copyright © 2011-2022 走看看