-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender.cpp
242 lines (222 loc) · 8.98 KB
/
render.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
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include "render.h"
#include <iostream>
#include <algorithm>
#include <cmath>
#include <Eigen/Dense>
#include <glog/logging.h>
using namespace std;
using namespace Eigen;
Render::Render() {
}
Eigen::Vector3f Render::considerFogInfluence(const IntervalIntersectReport &interval_report,
const Eigen::Vector3f &color) {
struct Event {
float t;
int type; // 1 for entering, -1 for exiting
Material *material;
bool operator<(const Event &other) const {
if (t != other.t)
return t > other.t; // Reverse order for integration from infinity to camera
return type < other.type; // Exiting before entering at the same t
}
};
std::vector<Event> events;
// Collect events from all intervals and materials
for (size_t i = 0; i < interval_report.objs_intervals.size(); ++i) {
const DisjointIntervals &intervals = interval_report.objs_intervals[i];
Material *material = interval_report.materials[i];
for (const auto &interval : intervals) {
events.push_back(Event{interval.left, 1, material});
events.push_back(Event{interval.right, -1, material});
}
}
// Sort events in reverse order (from infinity to camera)
std::sort(events.begin(), events.end());
// Initialize intensity at infinity
Eigen::Vector3f I = color;
float last_t = 1e10;
std::set<Material *> active_materials;
for (const auto &e : events) {
float t = e.t;
if (t < 0.0f) {
break;
}
if (t < last_t) {
// Interval between last_t and t
float delta_t = last_t - t;
// Compute combined fog_sigma and fog_color
float sigma = 0.0f;
Eigen::Vector3f sigma_color = Eigen::Vector3f::Zero();
for (auto mat : active_materials) {
sigma += mat->fog_sigma;
sigma_color += mat->fog_sigma * mat->fog_color;
}
Eigen::Vector3f fog_color = Eigen::Vector3f::Ones(); // Default value
if (sigma > 0.0f) {
fog_color = sigma_color / sigma;
}
// Compute transmittance
float transmittance = exp(-sigma * delta_t);
// Update intensity
I = I * transmittance + fog_color * (1.0f - transmittance);
}
// Update active materials
if (e.type == -1) {
CHECK(active_materials.insert(e.material).second);
} else {
CHECK_EQ(active_materials.erase(e.material), 1);
}
last_t = t;
}
// Process interval from t=0 to last_t (camera to last event)
if (last_t > 0.0f) {
float delta_t = last_t - 0.0f;
float sigma = 0.0f;
Eigen::Vector3f sigma_color = Eigen::Vector3f::Zero();
for (auto mat : active_materials) {
sigma += mat->fog_sigma;
sigma_color += mat->fog_sigma * mat->fog_color;
}
Eigen::Vector3f fog_color = Eigen::Vector3f::Ones(); // Default value
if (sigma > 0.0f) {
fog_color = sigma_color / sigma;
}
float transmittance = exp(-sigma * delta_t);
I = I * transmittance + fog_color * (1.0f - transmittance);
}
return I;
}
Eigen::Vector3f Render::getColor(const Scene &scene, const Vector3f &rayO, const Vector3f &rayD, int reflexLeft) {
const float eps = 1e-6;
IntersectReport report;
Material *mt;
IntervalIntersectReport interval_report;
bool intersect = scene.ray_intersect_query(rayO, rayD, report, &mt, &interval_report);
Eigen::Vector3f color = Eigen::Vector3f::Zero();
if (intersect) {
if (mt->random_diffuse_texture) {
Eigen::Vector3f texture_value = mt->random_diffuse_texture->getColor(report.intersect_point.x(),
report.intersect_point.y(),
report.intersect_point.z());
color += lights.ambientColor.cwiseProduct(texture_value);
} else {
color += lights.ambientColor.cwiseProduct(mt->diffuse_color);
}
Vector3f n_to_ray = report.normal;
if (report.normal.dot(rayD) > 0)
n_to_ray = -n_to_ray;
Vector3f offset_intersect = report.intersect_point + eps * n_to_ray;
// sunshine
Vector3f sun_rayO = offset_intersect;
for (Sunshine s : lights.sunshines) {
Vector3f sun_rayD = -s.direction;
if (sun_rayD.dot(n_to_ray) < 0)
continue;
IntersectReport report_sun;
Material *mt2;
IntervalIntersectReport interval_report2;
bool intersect_sun = scene.ray_intersect_query(sun_rayO, sun_rayD, report_sun, &mt2);
if (!intersect_sun) {
color += phongShading(n_to_ray, -rayD, sun_rayD, s.color, *mt);
}
}
Eigen::Vector3f reflex_intensity = Eigen::Vector3f::Zero();
// reflex
if (mt->mirror && reflexLeft > 0) {
Vector3f r = -2.0 * rayD.dot(n_to_ray) * n_to_ray + rayD;
Vector3f reflexD = r;
Vector3f reflexO = offset_intersect;
reflex_intensity = mt->specular_coeff.cwiseProduct(getColor(scene, reflexO, reflexD, reflexLeft - 1));
}
float T = 0.0, R = 1.0;
// refraction
if (mt->transparent && reflexLeft > 0) {
float n1, n2;
if (report.normal.dot(rayD) > 0) {
n1 = mt->relative_refractive_index;
n2 = 1.0;
} else {
n2 = mt->relative_refractive_index;
n1 = 1.0;
}
Vector3f v = -rayD;
Vector3f v_par = v - n_to_ray * (v.dot(n_to_ray));
float sin_i = v_par.norm();
float sin_r = n1 * sin_i / n2;
if (sin_r < 1) {
float cos_i = std::sqrt(1 - sin_i * sin_i);
float cos_r = std::sqrt(1 - sin_r * sin_r);
float n1i = n1 * cos_i;
float n1r = n1 * cos_r;
float n2i = n2 * cos_i;
float n2r = n2 * cos_r;
float Rs = (n1i - n2r) * (n1i - n2r) / ((n1i + n2r) * (n1i + n2r));
float Rp = (n1r - n2i) * (n1r - n2i) / ((n1r + n2i) * (n1r + n2i));
R = 0.5 * (Rs + Rp);
T = 1 - R;
Vector3f p = v.cross(n_to_ray).cross(n_to_ray);
p.normalize();
Vector3f t = -n_to_ray * cos_r + p * sin_r;
Vector3f refractionD = t;
Vector3f refractionO = report.intersect_point - eps * n_to_ray;
color += T * mt->specular_coeff.cwiseProduct(getColor(scene, refractionO, refractionD, reflexLeft - 1));
} else {
R = 1.0;
}
}
color += R * reflex_intensity;
} else {
color = scene.getBackground();
}
if (!interval_report.objs_intervals.empty()) {
color = considerFogInfluence(interval_report, color);
}
return color;
}
Eigen::Vector3f Render::phongShading(const Vector3f &n, const Vector3f &view, const Vector3f &light, const Vector3f &color, const Material &mat) {
Eigen::Vector3f intensity = Eigen::Vector3f::Zero();
intensity += std::max<float>(0.0, light.dot(n)) * color.cwiseProduct(mat.diffuse_color);
if (mat.specular) {
Vector3f r;
r = 2.0 * light.dot(n) * n - light;
// float lambda = 1 - r.dot(view);
// const int gamma = 4;
// float beta = mat.alpha_phong / gamma;
// float tmp = 1 - beta * lambda;
// float tmp2 = tmp * tmp;
// intensity += tmp2*tmp2*mat.specular_coeff*lightIntensity;
intensity += pow(r.dot(view), mat.alpha_phong) * mat.specular_coeff.cwiseProduct(color);
}
return intensity;
}
cv::Mat Render::renderImage(const Camera &cam, const Scene &scene) {
const int H = cam.height, W = cam.width;
const float focal = cam.focal;
const float center_x = W / 2.0;
const float center_y = H / 2.0;
cv::Mat image(H, W, CV_8UC3);
lights = scene.getAllLights();
const Vector3f o = cam.getCameraCenter();
const int reflection = 10;
#pragma omp parallel for schedule(dynamic, 16)
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
Vector3f v;
v[0] = j - center_x;
v[1] = i - center_y;
v[2] = focal;
v.normalize();
v = cam.rotationMatrix() * v;
Eigen::Vector3f color = getColor(scene, o, v, 10);
color.x() = std::clamp(color.x(), 0.0f, 1.0f);
color.y() = std::clamp(color.y(), 0.0f, 1.0f);
color.z() = std::clamp(color.z(), 0.0f, 1.0f);
// BGR order
image.at<cv::Vec3b>(i, j) = cv::Vec3b(
255 * color.z(),
255 * color.y(),
255 * color.x());
}
}
return image;
}