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

    如果有什么问题可以留言

  • 相关阅读:
    堆栈学习
    需要阅读的书籍
    Rust Book Lang Ch.19 Fully Qualified Syntax, Supertraits, Newtype Pattern, type aliases, never type, dynamic sized type
    Rust Lang Book Ch.19 Placeholder type, Default generic type parameter, operator overloading
    Rust Lang Book Ch.19 Unsafe
    Rust Lang Book Ch.18 Patterns and Matching
    Rust Lang Book Ch.17 OOP
    Rust Lang Book Ch.16 Concurrency
    Rust Lang Book Ch.15 Smart Pointers
    HDU3966-Aragorn's Story-树链剖分-点权
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/10327509.html
Copyright © 2011-2022 走看看