-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathScene.cpp
executable file
·132 lines (110 loc) · 3.66 KB
/
Scene.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
// Created by Göksu Güvendiren on 2019-05-14.
//
#include "Scene.hpp"
#include "Material.hpp"
void Scene::buildBVH() {
printf(" - Generating BVH...\n\n");
this->bvh = new BVHAccel(objects, 1, BVHAccel::SplitMethod::NAIVE);
}
Intersection Scene::intersect(const Ray &ray) const {
return this->bvh->Intersect(ray);
}
void Scene::sampleLight(Intersection &pos, float &pdf) const {
float emit_area_sum = 0;
for(uint32_t k = 0; k < objects.size(); ++k) {
if(objects[k]->hasEmit()) {
emit_area_sum += objects[k]->getArea();
}
}
float p = get_random_float() * emit_area_sum;
emit_area_sum = 0;
for(uint32_t k = 0; k < objects.size(); ++k) {
if(objects[k]->hasEmit()) {
emit_area_sum += objects[k]->getArea();
if(p <= emit_area_sum) {
objects[k]->Sample(pos, pdf);
break;
}
}
}
}
bool Scene::trace(
const Ray &ray,
const std::vector<Object *> &objects,
float &tNear, uint32_t &index, Object **hitObject) {
*hitObject = nullptr;
for(uint32_t k = 0; k < objects.size(); ++k) {
float tNearK = kInfinity;
uint32_t indexK;
Vector2f uvK;
if(objects[k]->intersect(ray, tNearK, indexK) && tNearK < tNear) {
*hitObject = objects[k];
tNear = tNearK;
index = indexK;
}
}
return (*hitObject != nullptr);
}
// Implementation of Path Tracing
Vector3f Scene::castRay(const Ray &ray, int depth) const {
// Russian Roulette termination
if(depth > maxDepth) {
return Vector3f(0.0f);
}
// Find intersection with the scene
Intersection intersection = intersect(ray);
if(!intersection.happened) {
return this->backgroundColor;
}
// If the intersected object is a light source, return its emission
if(intersection.m->hasEmission()) {
return intersection.m->getEmission();
}
Vector3f L_dir(0.0f); // Direct lighting
Vector3f L_indir(0.0f);// Indirect lighting
// ----- Direct Lighting -----
// Sample a point on the light source
Intersection light_inter;
float pdf_light = 0.0f;
sampleLight(light_inter, pdf_light);
// Compute the direction from the intersection point to the light sample
Vector3f p = intersection.coords;
Vector3f x = light_inter.coords;
Vector3f ws = normalize(x - p);
// Check if the light is visible from the intersection point
Ray shadowRay(p, ws);
Intersection shadow_inter = intersect(shadowRay);
// If the shadow ray hits the light source directly
if(shadow_inter.happened && (shadow_inter.coords - x).norm() < EPSILON) {
Vector3f N = intersection.normal;
Vector3f NN = light_inter.normal;
Vector3f emit = light_inter.emit;
// Compute BRDF, cosine terms, and the squared distance
Vector3f f = intersection.m->eval(ray.direction, ws, N);
float cosTheta = dotProduct(ws, N);
float cosTheta_x = dotProduct(-ws, NN);
float distance_squared = (x - p).norm();
distance_squared *= distance_squared;
// Accumulate direct lighting
L_dir = emit * f * cosTheta * cosTheta_x / (distance_squared * pdf_light);
}
// ----- Indirect Lighting -----
if(get_random_float() < RussianRoulette) {
Vector3f N = intersection.normal;
Vector3f wi = intersection.m->sample(ray.direction, N);
float pdf = intersection.m->pdf(ray.direction, wi, N);
if(pdf > EPSILON) {
Ray newRay(p, wi);
Intersection new_intersection = intersect(newRay);
// Only consider non-emitting surfaces for indirect lighting
if(new_intersection.happened && !new_intersection.m->hasEmission()) {
Vector3f f = intersection.m->eval(ray.direction, wi, N);
float cosTheta = dotProduct(wi, N);
// Recursively compute indirect lighting
L_indir = castRay(newRay, depth + 1) * f * cosTheta / (pdf * RussianRoulette);
}
}
}
return L_dir + L_indir;
}