-
Notifications
You must be signed in to change notification settings - Fork 0
/
Render.h
158 lines (144 loc) · 5.53 KB
/
Render.h
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#ifndef RTSIM_RENDER_H
#define RTSIM_RENDER_H
#define AMBIENT_COEF 0.09
#define DIFFUSE_COEF 1
#define SPECULAR_COEF 1
#define REFLECTION_COEF 0.5
#define INFTY 1e10
#include <iostream>
#include <fstream>
#include <map>
#include "Camera.h"
#include "RGB.h"
#include "Ray.h"
#include "Vector.h"
#include "Scene.h"
using namespace std;
// Prototype
RGB intensity(Scene, Ray, RGB, int);
// Track what objects the ray line will hit
auto hitList(Ray ray, Scene scene) {
// Create map for objects hit and their distance
map<const Object*, double> hit_list;
for (auto object : scene._objects) {
// Find intersections between 0 and infinity
auto intersection = object->intersect(ray, 0, INFTY);
hit_list.insert(make_pair(intersection.second, intersection.first));
}
return hit_list;
}
// Specular scattering
double specular(V3 reflection_ray, V3 source_ray) {
// K_s (v_r . p_rs)^ys I_0
// TODO: add ^ys
auto light_intensity = (dot(unit(source_ray), unit(reflection_ray)));
if (light_intensity < 0) {
// Clamped
light_intensity = 0;
}
return light_intensity;
}
// Diffuse scattering
double diffuse(V3 normal_ray, V3 source_ray) {
// K_d (n_s . p_rs)^yd I_0
// TODO: add ^yd
auto light_intensity = dot(unit(source_ray), unit(normal_ray));
if (light_intensity < 0) {
// Clamped
light_intensity = 0;
}
return light_intensity;
}
// Reflected light recursion
RGB reflected(V3 reflection_ray, P3 reflection_point, Scene scene, RGB pixel_color, int recursion_depth) {
Ray reflected_ray(reflection_point, reflection_ray);
auto hit_list = hitList(reflected_ray, scene);
auto it = min_element(hit_list.begin(), hit_list.end(), [](const pair<const Object*, double> &lhs, const pair<const Object*, double> &rhs) {
// Send objects to infinity if they are not hit
auto l = lhs.second <= 0 ? numeric_limits<double>::max() : lhs.second;
auto r = rhs.second <= 0 ? numeric_limits<double>::max() : rhs.second;
return l < r;
});
const Object* object = it->first;
double t = it->second;
// If an object is not hit, return black
if (t > 0) {
if (recursion_depth > 0) {
// Recursive call
return intensity(scene, reflected_ray, pixel_color, recursion_depth - 1);
} else {
// Return no reflections
return pixel_color;
}
} else {
return pixel_color;
}
}
// Progress indicator
void progress(int j, double height) {
double percent = fabs((j-height) / height) * 100;
int p = static_cast<int>(percent);
cout << "\rRendering scene... " << p << "% complete" << flush;
}
auto get_closest(map<const Object*, double> hit_list) {
auto it = min_element(hit_list.begin(), hit_list.end(), [](pair<const Object *const, double> lhs, pair<const Object *const, double> rhs) {
// Send objects to infinity if they are not hit
auto l = lhs.second < 0 ? numeric_limits <double>::max ( ) : lhs.second;
auto r = rhs.second < 0 ? numeric_limits <double>::max ( ) : rhs.second;
return l < r;
});
return it;
}
RGB intensity(Scene scene, Ray r, RGB pixel_color, int recursion_depth) {
// Generate list of objects hit by ray
auto hit_list = hitList(r, scene);
auto it = get_closest(hit_list);
auto object = it->first;
auto t = it->second;
// If object is in front of camera
if (t > 0.0) {
// Pull t back a little bit to prevent reflections jumping over boundaries due to floating-point errors
V3 p = r(t * 0.999);
// Calculate normal to surface
V3 normal = object->normal(p);
// Loop over all illumination sources
for (auto source: scene._sources) {
// Specular
auto light_vector = (source->_position - p);
auto reflection_ray = unit(reflect(p,normal));
double specular_intensity = object->_reflectivity * specular(reflection_ray, light_vector) * SPECULAR_COEF;
// Diffuse
double diffuse_intensity = (1-object->_reflectivity) * diffuse(normal, light_vector) * DIFFUSE_COEF;
double ambient_intensity = AMBIENT_COEF;
// Reflected
RGB reflected_light = object->_reflectivity * reflected(reflection_ray, p, scene, pixel_color, recursion_depth) * REFLECTION_COEF;
// Add to pixel color
pixel_color += (reflected_light + (((source->_intensity * (specular_intensity + diffuse_intensity)) + ambient_intensity) * object->_color));
}
}
return pixel_color;
}
void render(Camera cam, Scene scene, int recursion_depth) {
// Open ppm file
ofstream output;
output.open ("image.ppm");
// Write header
output << "P3" << endl;
output << cam.image_width << " " << cam.image_height << endl;
output << "255" << endl;
// Loop through each pixel
for (int j = cam.image_height-1; j >=0; --j) {
progress(j, cam.image_height);
for (int i = 0; i < cam.image_width; ++i) {
// Rendering
// Construct ray from bottom left corner of image up to the current i,j
Ray r(cam.origin, cam.lower_left_corner + (double(i) / double(cam.image_width-1)) * cam.horizontal + (double(j) / double(cam.image_height-1)) * cam.vertical - cam.origin);
// Find the closest object
RGB pixel_color = intensity(scene, r, RGB(0, 0, 0), recursion_depth);
// Clamp and write colour
write_RGB(output, pixel_color);
}
}
output.close();
}
#endif //RTSIM_RENDER_H