<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

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

       

       Preface

      博主剛放假回家就進(jìn)了醫(yī)院,今天剛完事兒,來續(xù)寫第二本書

       

       

       Ready

      我們來總結(jié)一下上一本書的筆記中我們的一些規(guī)定

      1. 數(shù)學(xué)表達(dá)式

      我們采用小寫粗黑體代表向量,大寫粗黑體代表矩陣,其他代表標(biāo)量

      2.我們將eye(or camera)發(fā)出的光線稱為視線(sight)

      3.我們目前將所有的非特定(不專屬于任何一個類)的通用物理數(shù)學(xué)運(yùn)算函數(shù)封裝到泛型庫中,并以lvgm命名空間限定,暫時不準(zhǔn)備劃分子命名空間

      4.我們寫庫,擬采用全hpp書寫,因.h和.cpp之間關(guān)于父類純虛函數(shù)的子類相關(guān)聲明與實(shí)現(xiàn)出現(xiàn)了無法鏈接的神奇編譯錯誤,問過很多大佬,最后還是采用hpp

       

      基礎(chǔ)工程代碼見第一本書總結(jié)篇

       

       Chapter 1  Motion Blur

      今天先來一個開胃菜,一個簡單易懂的技術(shù)——運(yùn)動模糊

       先看效果

      好像我們之前也提到過類似的模糊,例如:散焦模糊(defucos blur

      它和今天的模糊還是有一定區(qū)別的,從物理成因上講,defucos是因為未正確對焦,如果沒有玩過生活中的相機(jī)也沒關(guān)系,大家都用手機(jī)拍過照吧,有些時候,手機(jī)相機(jī)打開對著拍攝對象,屏幕中的物體或字跡的邊緣是模糊的,通常我們會做一個動作,即,點(diǎn)一下屏幕(會出現(xiàn)一個小框),然后圖像就會變清晰(邊緣明顯)

      運(yùn)動模糊的意思是,現(xiàn)實(shí)世界中,相機(jī)快門開啟的時間間隔內(nèi),相機(jī)內(nèi)物體發(fā)生了位移,畫面最后呈現(xiàn)出來的像素,是移動過程中像素的平均值。它不是由相機(jī)造成的,而是由物體運(yùn)動狀態(tài)造成的形狀模糊,比如,你拍攝一張正在下落小球的照片,它所造成的模糊是在段時間內(nèi)停留在歷史軌跡中的重影

      弄清楚這個,就開始我們的正題

      如何模擬真實(shí)生活中的運(yùn)動模糊,我們先來回顧一下光線追蹤的過程

      1. 我們選定屏幕中的一個位置,作為待計算的像素點(diǎn)

      2. 從eye發(fā)出一條視線指向該上述位置周圍的采樣點(diǎn)

      3. 如果中途有物體相交,那么根據(jù)物體表面材質(zhì)進(jìn)行視線計算

      3. 至多遞歸計算50次,確定該位置的一個采樣值

      4. 該位置周圍采樣100次,計算均值作為該位置的最終像素值

       

      那么我們看一下上述過程中,需要改動哪些地方以支持模擬物體的運(yùn)動模糊行為

      首先,我們只需要模擬相機(jī)快門開啟的時間間隔內(nèi)的物體運(yùn)動情況,所以,物體一定有一個運(yùn)動的起點(diǎn)和終點(diǎn)位置

      如果是球體,我們用球心代表運(yùn)動的位置(heart1,heart2),另外相機(jī)時間間隔是一段時間,需要起止時間點(diǎn)確定(time1,time2)

      其次,我們模擬物體運(yùn)動模糊,還要根據(jù)相機(jī)原理:畫面最后呈現(xiàn)出來的像素,是移動過程中像素的平均值

      所以,我們依舊采用隨機(jī)取樣,我們之前已經(jīng)確定采樣像素點(diǎn)為100個,采樣周圍點(diǎn)是為了抗鋸齒,這一節(jié)我們更重要的是要采樣物體的運(yùn)動位置

      我們有物體運(yùn)動的起止位置和起止時間點(diǎn)(確定運(yùn)動時間間隔),所以我們?nèi)?~1的隨機(jī)數(shù)作為物體從heart1到heart2運(yùn)動路徑長度比例,進(jìn)而確定物體在該隨機(jī)時刻的具體位置heart,我們?nèi)《鄠€隨機(jī)時間進(jìn)行采樣,之后再進(jìn)行均值處理,作為移動過程中像素的平均值

      完成上述理論,還需在光線追蹤過程中下手

      第一步就不用說了,就是確定屏幕位置

      第二步就很重要了,視線發(fā)出就要接觸物體,也就是說視線產(chǎn)生就要確定該時刻的物體具體位置,因為它要和物體進(jìn)行相交計算,所以,視線承擔(dān)著記錄當(dāng)前時間點(diǎn)的作用

      而我們還需要做運(yùn)動位置采樣,所以,eye需要發(fā)出多條視線,基于不同的隨機(jī)時間,這樣我們就做到了根據(jù)不同的隨機(jī)時間發(fā)出多條采樣視線對物體的運(yùn)動位置進(jìn)行采樣

      我們不妨把抗鋸齒的采樣和運(yùn)動位置采樣視線生成放在一起

      ray.hpp

      /// ray.h
      
      // -----------------------------------------------------
      // [author]        lv
      // [begin ]        2019.1
      // [brief ]        the ray-class for the ray-tracing project
      //                from the 《ray tracing The Next week》
      // -----------------------------------------------------
      #pragma once
      
      #include "RTdef.h"
      
      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)
              {    }
      
              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;
      
          };
      }

       

      camera.hpp

       

       

       這樣,我們就做好了產(chǎn)生記錄隨機(jī)時間的視線

      接下來就是采樣了

      main.cpp

       

      我們再來說第三步,視線和物體的相交計算

      這個是最重要的,我們要 根據(jù)視線記錄的隨機(jī)時間,來確定物體的輪廓,然后進(jìn)行計算交點(diǎn)

      顯然,我們不能用之前的sphere了

      下面是我們新寫的moving_sphere

      /// moving_sphere.h
      
      // -----------------------------------------------------
      // [author]        lv
      // [begin ]        2019.1
      // [brief ]        the moving_sphere-class for the ray-tracing project
      //                from the 《ray tracing in one week》
      // -----------------------------------------------------
      
      #pragma once
      #include "ray.h"
      #include "intersect.h"
      
      namespace rt
      {
      
      class moving_sphere :public intersect
          {
      public:
          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)
              {
              }
      
          virtual bool hit(const ray& r, rtvar tmin, rtvar tmax, hitInfo& info)const override;
      
          inline rtvec heart(rtvar t)const
              {
              return _heart1 + ((t - _time1) / (_time2 - _time1)) * (_heart2 - _heart1);
              }
      
      private:
          rtvec _heart1;
          rtvec _heart2;
          rtvar _time1;
          rtvar _time2;
          rtvar _radius;
          material* _materialp;
          };
      
      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;
      }
      
      }

       

       我們用vec3 heart(time);來計算某個隨機(jī)時間某個物體從開始位置向終止位置運(yùn)動time時間之后的具體位置

      第四步和第五步就不說了,都是上述過程的重復(fù)自動計算

       

      下面是開篇圖片中球體參數(shù)設(shè)置

       

      intersect* random_sphere()
      {
          int cnt = 50000;
          intersect **list = new intersect*[cnt + 1];
          list[0] = new sphere(rtvec(0, -1000, 0), 1000, new lambertian(rtvec(0.5, 0.5, 0.5)));
          int size = 1;
          for (int a = -10; a < 10; ++a)
              for (int b = -10; b < 10; ++b)
              {
                  rtvar choose_mat = lvgm::rand01();
                  rtvec center(a + 0.9 * lvgm::rand01(), 0.2, b + 0.9*lvgm::rand01());
                  if ((center - rtvec(4, 0.2, 0)).normal()>0.9)
                  {
                      if (choose_mat < 0.75)
                          list[size++] = new moving_sphere(center, center + rtvec(0, 0.5*lvgm::rand01(), 0), 0., 1., 0.2,
                              new lambertian(rtvec(lvgm::rand01()*lvgm::rand01(), lvgm::rand01()*lvgm::rand01(), lvgm::rand01()*lvgm::rand01())));
      
                      else if (choose_mat < 0.9)
                          list[size++] = new sphere(center, 0.2,
                              new metal(rtvec(0.5*(1 + lvgm::rand01()), 0.5*(1 + lvgm::rand01()), 0.5*(1 + lvgm::rand01())), 0.5*lvgm::rand01()));
      
                      else
                          list[size++] = new sphere(center, 0.2,
                              new dielectric(1.5));
                  }
              }
      
          list[size++] = new sphere(rtvec(0, 1, 0), 1.0, new dielectric(1.5));
          list[size++] = new sphere(rtvec(-4, 1, 0), 1.0, new lambertian(rtvec(0.4, 0.2, 0.1)));
          list[size++] = new sphere(rtvec(4, 1, 0), 1.0, new metal(rtvec(0.7, 0.6, 0.5), 0.));
      
          return new intersections(list, size);
      }

       相機(jī)參數(shù)設(shè)置

      rtvec lookfrom(13, 2, 3);
      rtvec lookat(0, 0, 0);
      float dist_to_focus = 10.0;
      float aperture = 0.0;
      camera cma(lookfrom, lookat, rtvec(0, 1, 0), 20, rtvar(W) / rtvar(H), aperture, 0.7*dist_to_focus, 0., 1.);

       

      還有水平運(yùn)動模糊的圖片正在渲染中,完成之后會貼在下面

       

      ******************* 更新分割線 *************************

      一個大球的水平運(yùn)動模糊

       

      此外你可以控制起止時間間隔或者起止位置遠(yuǎn)近來調(diào)整小球運(yùn)動模糊的速度

      如果把上一張圖中運(yùn)動大球的運(yùn)動距離改為0.5長度,也就是

      new moving_sphere(rtvec(-4.5, 1, 0.65), rtvec(-4.5,1,0.15)......
      會得到下圖(球的數(shù)量和尺寸都改小了點(diǎn))
      代碼參見(http://www.rzrgm.cn/lv-anchoret/p/10284085.html 末尾)

      另外,之前的運(yùn)動球過多,各種球體的比例也做了調(diào)整(第一張圖)

      intersect* random_sphere()
      {
          int cnt = 50000;
          intersect **list = new intersect*[cnt + 1];
          list[0] = new sphere(rtvec(0, -1000, 0), 1000, new lambertian(rtvec(0.5, 0.5, 0.5)));
          int size = 1;
          for (int a = -10; a < 10; ++a)
              for (int b = -10; b < 10; ++b)
              {
                  rtvar choose_mat = lvgm::rand01();
                  rtvec center(a + 0.9 * lvgm::rand01(), 0.2, b + 0.9*lvgm::rand01());
                  if ((center - rtvec(4, 0.2, 0)).normal()>0.9)
                  {
                      if (choose_mat < 0.55)
                          list[size++] = new moving_sphere(center, center + rtvec(0, 0.5*lvgm::rand01(), 0), 0., 1., 0.2,
                              new lambertian(rtvec(lvgm::rand01()*lvgm::rand01(), lvgm::rand01()*lvgm::rand01(), lvgm::rand01()*lvgm::rand01())));
      
                      else if (choose_mat < 0.85)
                          list[size++] = new sphere(center, 0.2,
                              new metal(rtvec(0.5*(1 + lvgm::rand01()), 0.5*(1 + lvgm::rand01()), 0.5*(1 + lvgm::rand01())), 0.5*lvgm::rand01()));
      
                      else
                          list[size++] = new sphere(center, 0.2,
                              new dielectric(1.5));
                  }
              }
      
          list[size++] = new sphere(rtvec(0, 1, 0), 1.0, new dielectric(1.5));
          list[size++] = new moving_sphere(rtvec(-4.5, 1, 0.95), rtvec(-4,1,0.1), 0., 1., 1.0, 
              new lambertian(rtvec(0.4, 0.2, 0.1)));
          list[size++] = new sphere(rtvec(4, 1, 0), 1.0, new metal(rtvec(0.7, 0.6, 0.5), 0.));
      
          return new intersections(list, size);
      }

       

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

      posted @ 2019-01-14 22:42  林-兮  閱讀(2885)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 国产jjizz女人多水喷水| 国产亚洲精品成人av一区| 国产精品一区二区久久岳| 亚洲 制服 丝袜 无码| 国产成人精品区一区二区| 午夜免费无码福利视频麻豆| 欧美 变态 另类 人妖| 欧美成人精品手机在线| 视频一区二区三区自拍偷拍| 中文字幕乱码人妻二区三区| 国产丰满乱子伦无码专区| 免费av深夜在线观看| 亚洲人成电影网站 久久影视| 国产一区二区午夜福利久久| 精品无码人妻| 九九视频热最新在线视频| 色综合热无码热国产| 起碰免费公开97在线视频| 国产av精品一区二区三区| 护士的小嫩嫩好紧好爽| 国产69成人精品视频免费| 久久综合九色综合97欧美| 末发育娇小性色xxxxx视频| 丰满的人妻hd高清日本| 人人澡人摸人人添| 性欧美vr高清极品| 伊人av超碰伊人久久久| 亚洲午夜天堂| 熟女系列丰满熟妇AV| 熟女精品国产一区二区三区| 国精品无码一区二区三区在线看| 人妻熟女一区无中文字幕| 亚洲精品一区二区18禁| 中文无码高潮到痉挛在线视频| 亚洲精品成人片在线观看精品字幕| 欧美成人精品手机在线| 亚洲日韩图片专区第1页 | 精品乱码一区二区三四五区| 樱桃视频影院在线播放| 无码伊人久久大杳蕉中文无码| 国产不卡一区不卡二区|