Advertisement
Delfigamer

ForwardTracer

Dec 10th, 2019
734
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.91 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include "SamplerBase.h"
  4. #include "Camera.h"
  5. #include <array>
  6.  
  7. class BidirSampler: public SamplerBase
  8. {
  9. private:
  10.     struct Event
  11.     {
  12.         FPoint origin;
  13.         FDisp norm;
  14.         FDisp indir;
  15.         FDisp outdir;
  16.         float passrate;
  17.         int face;
  18.     };
  19.  
  20.     struct Emitter
  21.     {
  22.         float fraction;
  23.         float area;
  24.         float power;
  25.         float dens;
  26.     };
  27.  
  28. private:
  29.     Camera camera;
  30.     std::vector<Emitter> emitters;
  31.     std::vector<Event> lightpath;
  32.     std::vector<Event> lenspath;
  33.  
  34.     void PrepareLightStartGenerator();
  35.     void GenerateTriangleInterior(float& u, float& v);
  36.     void GenerateLightSubpath();
  37.     void GenerateLensSubpath(int ix, int iy);
  38.     float Geometric(Event const& from, Event const& to);
  39.     float VisibleGeometric(Event const& from, Event const& to);
  40.     double PathDensity(std::vector<Event*> const& lightpart, std::vector<Event*> const& lenspart);
  41.     double PathFlux(std::vector<Event*> const& path);
  42.     void RecordContribution(FDisp const& dir, float value);
  43.     void RecordToFrame(int x, int y, float value);
  44.  
  45. public:
  46.     BidirSampler(int width, int height);
  47.     ~BidirSampler();
  48.  
  49.     virtual void Iterate() override;
  50. };
  51.  
  52. ////////////////////////////////////////////////////////////////////////////////
  53.  
  54. #include "BidirSampler.h"
  55. #include <cmath>
  56.  
  57. float const passrate = 1.0f;
  58. constexpr float invpi = 0.3183099f;
  59.  
  60. void BidirSampler::PrepareLightStartGenerator()
  61. {
  62.     emitters.resize(scene.FaceCount());
  63.     float totalpower = 0;
  64.     for (int i = 0; i < (int)emitters.size(); ++i) {
  65.         FDisp ab = scene[i].mwt.xunit();
  66.         FDisp ac = scene[i].mwt.yunit();
  67.         FDisp n = cross(ab, ac);
  68.         emitters[i].area = 0.5f * sqrtf(dot(n, n));
  69.         emitters[i].power = scene[i].emissive * emitters[i].area;
  70.         totalpower += emitters[i].power;
  71.     }
  72.     for (int i = 0; i < (int)emitters.size(); ++i) {
  73.         emitters[i].fraction = emitters[i].power / totalpower;
  74.         emitters[i].dens = scene[i].emissive / totalpower;
  75.     }
  76. }
  77.  
  78. void BidirSampler::GenerateTriangleInterior(float& u, float& v)
  79. {
  80.     GenerateTriangle(u);
  81.     u = fabsf(u);
  82.     GenerateUniform(v);
  83.     v *= 1 - u;
  84. }
  85.  
  86. void BidirSampler::GenerateLightSubpath()
  87. {
  88.     constexpr int MaxPathLen = 100;
  89.     TraceRequest tr;
  90.     {
  91.         int ei = 0;
  92.         float q;
  93.         GenerateUniform(q);
  94.         while (ei < (int)emitters.size() - 1 && q >= emitters[ei].fraction) {
  95.             q -= emitters[ei].fraction;
  96.             ei += 1;
  97.         }
  98.         float u;
  99.         float v;
  100.         GenerateTriangleInterior(u, v);
  101.         lightpath.resize(1);
  102.         Event& e = lightpath.front();
  103.         e.face = ei;
  104.         e.origin = scene[ei].mwt * FPoint{ u, v, 0 };
  105.         e.norm = scene[ei].mwt.zunit();
  106.         e.indir = e.norm;
  107.         GenerateLambertian(e.norm, e.outdir);
  108.         e.passrate = 1.0f;
  109.         tr.origin = e.origin;
  110.         tr.dir = e.outdir;
  111.     }
  112.     while (lightpath.size() < MaxPathLen && Trace(tr)) {
  113.         lightpath.emplace_back();
  114.         Event& e = lightpath.back();
  115.         e.origin = tr.hit;
  116.         e.indir = -tr.dir;
  117.         e.face = tr.face;
  118.         tr.origin = tr.hit;
  119.         e.norm = scene[tr.face].mwt.zunit();
  120.         GenerateLambertian(e.norm, tr.dir);
  121.         e.outdir = tr.dir;
  122.         e.passrate = scene[tr.face].albedo;
  123.         {
  124.             float q;
  125.             GenerateUniform(q);
  126.             if (e.passrate <= q) {
  127.                 break;
  128.             }
  129.         }
  130.     }
  131. }
  132.  
  133. void BidirSampler::GenerateLensSubpath(int ix, int iy)
  134. {
  135.     constexpr int MaxPathLen = 1;
  136.     float dx;
  137.     float dy;
  138.     GenerateTriangle(dx);
  139.     GenerateTriangle(dy);
  140.     float cx = 2.0f * (ix + dx + 0.5f) / width - 1.0f;
  141.     float cy = 1.0f - 2.0f * (iy + dx + 0.5f) / height;
  142.     float cu = cx * camera.utan;
  143.     float cv = cy * camera.vtan;
  144.     TraceRequest tr;
  145.     tr.origin = camera.mwc.origin();
  146.     tr.dir = norm(camera.mwc * FDisp{ cu, cv, 1.0f });
  147.     {
  148.         lenspath.resize(1);
  149.         Event& e = lenspath.front();
  150.         e.origin = tr.origin;
  151.         e.norm = camera.mwc.zunit();
  152.         e.outdir = e.norm;
  153.         e.indir = tr.dir;
  154.         e.passrate = 1.0f;
  155.         e.face = -1;
  156.     }
  157.     while (lenspath.size() < MaxPathLen && Trace(tr)) {
  158.         lenspath.emplace_back();
  159.         Event& e = lenspath.back();
  160.         e.origin = tr.hit;
  161.         e.outdir = -tr.dir;
  162.         e.face = tr.face;
  163.         tr.origin = tr.hit;
  164.         e.norm = scene[tr.face].mwt.zunit();
  165.         GenerateLambertian(e.norm, tr.dir);
  166.         e.indir = tr.dir;
  167.         e.passrate = scene[tr.face].albedo;
  168.         {
  169.             float q;
  170.             GenerateUniform(q);
  171.             if (e.passrate <= q) {
  172.                 break;
  173.             }
  174.         }
  175.     }
  176. }
  177.  
  178. float BidirSampler::Geometric(Event const& from, Event const& to)
  179. {
  180.     FDisp delta = to.origin - from.origin;
  181.     FDisp dir = norm(delta);
  182.     float cosa = dot(from.norm, dir);
  183.     float cosb = -dot(to.norm, dir);
  184.     float distsqr = dot(delta, delta);
  185.     return cosa * cosb / distsqr;
  186. }
  187.  
  188. float BidirSampler::VisibleGeometric(Event const& from, Event const& to)
  189. {
  190.     FDisp delta = to.origin - from.origin;
  191.     FDisp dir = norm(delta);
  192.     float cosa = dot(from.norm, dir);
  193.     if (cosa < 0) {
  194.         return 0;
  195.     }
  196.     float cosb = -dot(to.norm, dir);
  197.     if (cosb < 0) {
  198.         return 0;
  199.     }
  200.     if (!scene.Test(from.origin, delta)) {
  201.         return 0;
  202.     }
  203.     float distsqr = dot(delta, delta);
  204.     return cosa * cosb / distsqr;
  205. }
  206.  
  207. double BidirSampler::PathDensity(std::vector<Event*> const& light, std::vector<Event*> const& lens)
  208. {
  209.     double dens = 1.0f;
  210.     if (light.size() >= 1) {
  211.         dens *= emitters[light[0]->face].dens;
  212.     }
  213.     if (light.size() >= 2) {
  214.         dens *= invpi;
  215.         for (int i = 1; i < (int)light.size() - 1; ++i) {
  216.             float geom = Geometric(*light[i], *light[i - 1]);
  217.             float edens = invpi * light[i]->passrate;
  218.             dens *= geom * edens;
  219.         }
  220.         {
  221.             int last = (int)light.size() - 1;
  222.             float geom = Geometric(*light[last], *light[last - 1]);
  223.             dens *= geom;
  224.         }
  225.     }
  226.     if (lens.size() >= 2) {
  227.         {
  228.             float cosa = dot(lens[0]->norm, lens[0]->indir);
  229.             float uvsqr = cosa * cosa;
  230.             dens *= lens[0]->passrate * uvsqr * uvsqr / (4.0f * camera.utan * camera.vtan);
  231.         }
  232.         for (int i = 1; i < (int)lens.size() - 1; ++i) {
  233.             float geom = Geometric(*lens[i], *lens[i - 1]);
  234.             float edens = invpi * lens[i]->passrate;
  235.             dens *= geom * edens;
  236.         }
  237.         {
  238.             int last = (int)lens.size() - 1;
  239.             float geom = Geometric(*lens[last], *lens[last - 1]);
  240.             dens *= geom;
  241.         }
  242.     }
  243.     return dens;
  244. }
  245.  
  246. double BidirSampler::PathFlux(std::vector<Event*> const& path)
  247. {
  248.     if (path.size() < 2) {
  249.         return 0.0f;
  250.     }
  251.     double flux;
  252.     if (path[0]->face >= 0) {
  253.         flux = scene[path[0]->face].emissive;
  254.     } else {
  255.         return 0;
  256.     }
  257.     for (int i = 1; i < (int)path.size() - 1; ++i) {
  258.         float geom = Geometric(*path[i], *path[i - 1]);
  259.         float fs = invpi;
  260.         if (path[i]->face >= 0) {
  261.             fs *= scene[path[i]->face].albedo;
  262.         }
  263.         flux *= geom * fs;
  264.     }
  265.     {
  266.         int last = (int)path.size() - 1;
  267.         FDisp delta = path[last]->origin - path[last - 1]->origin;
  268.         FDisp dir = norm(delta);
  269.         float cosa = dot(path[last]->norm, dir);
  270.         float cosb = -dot(path[last - 1]->norm, dir);
  271.         float distsqr = dot(delta, delta);
  272.         float geom = cosa * cosb / distsqr;
  273.         float uvsqr = cosa * cosa;
  274.         float fs = uvsqr * uvsqr / (4.0f * camera.utan * camera.vtan);
  275.         flux *= geom * fs;
  276.     }
  277.     return flux;
  278. }
  279.  
  280. void BidirSampler::RecordContribution(FDisp const& dir, float value)
  281. {
  282.     FDisp cdir = camera.mcw * dir;
  283.     float cdx, cdy, cdz;
  284.     cdir.unpack(cdx, cdy, cdz);
  285.     if (cdz >= 0) {
  286.         return;
  287.     }
  288.     float cu = cdx / cdz;
  289.     float cv = cdy / cdz;
  290.     float cx = cu / camera.utan;
  291.     float cy = cv / camera.vtan;
  292.     float nx = 0.5f * (1.0f + cx) * width - 0.5f;
  293.     float ny = 0.5f * (1.0f - cy) * height - 0.5f;
  294.     float nfx = floorf(nx);
  295.     float nfy = floorf(ny);
  296.     float dx = nx - nfx;
  297.     float dy = ny - nfy;
  298.     int ix = (int)nfx;
  299.     int iy = (int)nfy;
  300.     RecordToFrame(ix, iy, value * (1 - dx) * (1 - dy));
  301.     RecordToFrame(ix + 1, iy, value * dx * (1 - dy));
  302.     RecordToFrame(ix, iy + 1, value * (1 - dx) * dy);
  303.     RecordToFrame(ix + 1, iy + 1, value * dx * dy);
  304. }
  305.  
  306. void BidirSampler::RecordToFrame(int x, int y, float value)
  307. {
  308.     if (x >= 0 && x < width && y >= 0 && y < height) {
  309.         frame[y * width + x] += value;
  310.     }
  311. }
  312.  
  313. BidirSampler::BidirSampler(int width, int height)
  314.     : SamplerBase(width, height)
  315. {
  316.     float aspect = (float)width / height;
  317.     /*scene.LoadFromT3D("D:\\Program Files (x86)\\Unreal Tournament GOTY\\Maps\\CTF-Coret-FlagRoom.t3d");
  318.     camera = Camera::Targeted(
  319.     FPoint{ -160, 228, 410 },
  320.     FPoint{ 288, -384, 240 },
  321.     1.0f * sqrtf(aspect), 1.0f / sqrtf(aspect));*/
  322.     scene.LoadFromT3D("D:\\Program Files (x86)\\Unreal Tournament GOTY\\Maps\\Box.t3d");
  323.     camera = Camera::Targeted(
  324.         FPoint{ -206, -219, 224 },
  325.         FPoint{ -96, 0, 80 },
  326.         1.0f * sqrtf(aspect), 1.0f / sqrtf(aspect));
  327.     /*camera = Camera::Targeted(
  328.         FPoint{ -50, -80, 224 },
  329.         FPoint{ 0, 0, 80 },
  330.         1.0f * sqrtf(aspect), 1.0f / sqrtf(aspect));*/
  331.     PrepareLightStartGenerator();
  332. }
  333.  
  334. BidirSampler::~BidirSampler()
  335. {
  336. }
  337.  
  338. void BidirSampler::Iterate()
  339. {
  340.     denominator += passrate;
  341.     for (int iy = 0; iy < height; ++iy) {
  342.         for (int ix = 0; ix < width; ++ix) {
  343.             float q;
  344.             GenerateUniform(q);
  345.             if (passrate > q) {
  346.                 GenerateLightSubpath();
  347.                 GenerateLensSubpath(ix, iy);
  348.                 std::vector<Event*> path{ &lenspath[0] };
  349.                 std::vector<Event*> lightsection;
  350.                 std::vector<Event*> lenssection{ &lenspath[0] };
  351.                 for (int i = 0; i < (int)lightpath.size(); ++i) {
  352.                     lightsection.insert(lightsection.end(), &lightpath[i]);
  353.                     path.insert(path.end() - 1, &lightpath[i]);
  354.                     if (VisibleGeometric(*lightsection.back(), *lenssection.back())) {
  355.                         double dens = PathDensity(lightsection, lenssection);
  356.                         if (dens > 0) {
  357.                             double flux = PathFlux(path);
  358.                             if (path.size() >= 2) {
  359.                                 int last = (int)path.size() - 1;
  360.                                 FDisp dir = path[last]->origin - path[last - 1]->origin;
  361.                                 RecordContribution(dir, (float)(flux / dens));
  362.                             }
  363.                         }
  364.                     }
  365.                 }
  366.                 /*GenerateLensSubpath(ix, iy);
  367.                 std::vector<Event*> path;
  368.                 std::vector<Event*> lightsection;
  369.                 std::vector<Event*> lenssection;
  370.                 for (int i = 0; i < (int)lenspath.size(); ++i) {
  371.                     lenssection.insert(lenssection.end(), &lenspath[i]);
  372.                     path.insert(path.begin(), &lenspath[i]);
  373.                     double dens = PathDensity(lightsection, lenssection);
  374.                     if (dens > 0) {
  375.                         double flux = PathFlux(path);
  376.                         if (path.size() >= 2) {
  377.                             int last = (int)path.size() - 1;
  378.                             FDisp dir = path[last]->origin - path[last - 1]->origin;
  379.                             RecordContribution(dir, (float)(flux / dens));
  380.                         }
  381.                     }
  382.                 }*/
  383.             }
  384.         }
  385.     }
  386. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement