/
edge.h
303 lines (270 loc) · 11 KB
/
edge.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
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#pragma once
#include "redner.h"
#include "shape.h"
#include "camera.h"
#include "channels.h"
#include "edge_tree.h"
#include <memory>
struct Scene;
struct Edge {
DEVICE Edge() : shape_id(-1), v0(0), v1(0), f0(0), f1(0) {}
DEVICE Edge(int si, int v0, int v1, int f0, int f1) :
shape_id(si),
v0(v0),
v1(v1),
f0(f0),
f1(f1) {}
int shape_id;
int v0, v1;
int f0, f1;
DEVICE inline bool operator==(const Edge &other) const {
return shape_id == other.shape_id &&
v0 == other.v0 && v1 == other.v1 &&
f0 == other.f0 && f1 == other.f1;
}
};
struct PrimaryEdgeRecord {
Edge edge;
Vector2 edge_pt;
};
struct SecondaryEdgeRecord {
Edge edge;
Vector3 edge_pt;
Vector3 mwt;
bool use_nee_ray;
bool is_diffuse_or_glossy;
};
template <typename T>
struct TPrimaryEdgeSample {
T edge_sel;
T t;
};
template <typename T>
struct TSecondaryEdgeSample {
T edge_sel;
T resample_sel;
T bsdf_component;
T t;
};
struct EdgeSampler {
EdgeSampler() {}
EdgeSampler(const std::vector<const Shape*> &shapes,
const Scene &scene);
Buffer<Edge> edges;
Buffer<Real> primary_edges_pmf;
Buffer<Real> primary_edges_cdf;
Buffer<Real> secondary_edges_pmf;
Buffer<Real> secondary_edges_cdf;
// For secondary edges
std::unique_ptr<EdgeTree> edge_tree;
};
using PrimaryEdgeSample = TPrimaryEdgeSample<Real>;
using SecondaryEdgeSample = TSecondaryEdgeSample<Real>;
DEVICE
inline Vector3f get_v0(const Shape *shapes, const Edge &edge) {
return get_vertex(shapes[edge.shape_id], edge.v0);
}
DEVICE
inline Vector3f get_v1(const Shape *shapes, const Edge &edge) {
return get_vertex(shapes[edge.shape_id], edge.v1);
}
DEVICE
inline Vector3f get_non_shared_v0(
const Shape *shapes, const Edge &edge) {
auto ind = get_indices(shapes[edge.shape_id], edge.f0);
for (int i = 0; i < 3; i++) {
if (ind[i] != edge.v0 && ind[i] != edge.v1) {
return get_vertex(shapes[edge.shape_id], ind[i]);
}
}
return get_v0(shapes, edge);
}
DEVICE
inline Vector3f get_non_shared_v1(
const Shape *shapes, const Edge &edge) {
// Unfotunately the below wouldn't work because we sometimes
// merge edge's faces when there are duplicated edges
// auto ind = get_indices(shapes[edge.shape_id], edge.f1);
// for (int i = 0; i < 3; i++) {
// if (ind[i] != edge.v0 && ind[i] != edge.v1) {
// return get_vertex(shapes[edge.shape_id], ind[i]);
// }
// }
// return Vector3{0.f, 0.f, 0.f};
// So we have to go for a slightly more expensive alternative
auto ind = get_indices(shapes[edge.shape_id], edge.f1);
auto v0 = get_v0(shapes, edge);
auto v1 = get_v1(shapes, edge);
for (int i = 0; i < 3; i++) {
auto v = get_vertex(shapes[edge.shape_id], ind[i]);
if (v != v0 && v != v1) {
return v;
}
}
return v1;
}
DEVICE
inline Vector3 get_n0(const Shape *shapes, const Edge &edge) {
auto v0 = Vector3{get_v0(shapes, edge)};
auto v1 = Vector3{get_v1(shapes, edge)};
auto ns_v0 = Vector3{get_non_shared_v0(shapes, edge)};
auto n = cross(v0 - ns_v0, v1 - ns_v0);
auto n_len_sq = length_squared(n);
if (n_len_sq < Real(1e-20)) {
return Vector3{0, 0, 0};
}
n /= sqrt(n_len_sq);
return n;
}
DEVICE
inline Vector3 get_n1(const Shape *shapes, const Edge &edge) {
auto v0 = Vector3{get_v0(shapes, edge)};
auto v1 = Vector3{get_v1(shapes, edge)};
auto ns_v1 = Vector3{get_non_shared_v1(shapes, edge)};
auto n = cross(v1 - ns_v1, v0 - ns_v1);
auto n_len_sq = length_squared(n);
if (n_len_sq < Real(1e-20)) {
return Vector3{0, 0, 0};
}
n /= sqrt(n_len_sq);
return n;
}
DEVICE
inline bool is_silhouette(const Shape *shapes, const Vector3 &p, const Edge &edge) {
auto v0 = Vector3{get_v0(shapes, edge)};
auto v1 = Vector3{get_v1(shapes, edge)};
if (edge.f0 == -1 || edge.f1 == -1) {
// Only adjacent to one face
if (edge.f0 != -1) {
auto ns_v0 = Vector3{get_non_shared_v0(shapes, edge)};
auto n0 = cross(v0 - ns_v0, v1 - ns_v0);
auto n0_len_sq = length_squared(n0);
if (n0_len_sq < Real(1e-20)) {
// Degenerate vertices
return false;
}
}
if (edge.f1 != -1) {
auto ns_v1 = Vector3{get_non_shared_v1(shapes, edge)};
auto n1 = cross(v1 - ns_v1, v0 - ns_v1);
auto n1_len_sq = length_squared(n1);
if (n1_len_sq < Real(1e-20)) {
// Degenerate vertices
return false;
}
}
return true;
}
auto ns_v0 = Vector3{get_non_shared_v0(shapes, edge)};
auto ns_v1 = Vector3{get_non_shared_v1(shapes, edge)};
auto n0 = cross(v0 - ns_v0, v1 - ns_v0);
auto n1 = cross(v1 - ns_v1, v0 - ns_v1);
auto n0_len_sq = length_squared(n0);
auto n1_len_sq = length_squared(n1);
if (n0_len_sq < Real(1e-20) || n1_len_sq < Real(1e-20)) {
// Degenerate vertices
return false;
}
n0 /= sqrt(n0_len_sq);
n1 /= sqrt(n1_len_sq);
if (!has_shading_normals(shapes[edge.shape_id])) {
// If we are not using Phong normal, every edge is silhouette,
// except edges with dihedral angle of 0
if (dot(n0, n1) >= 1 - 1e-6f) {
return false;
}
return true;
}
auto frontfacing0 = dot(p - ns_v0, n0) > 0.f;
auto frontfacing1 = dot(p - ns_v1, n1) > 0.f;
return (frontfacing0 && !frontfacing1) || (!frontfacing0 && frontfacing1);
}
DEVICE
inline bool is_silhouette_dir(const Shape *shapes, const Vector3 &dir, const Edge &edge) {
if (edge.f0 == -1 || edge.f1 == -1) {
// Only adjacent to one face
return true;
}
auto v0 = Vector3{get_v0(shapes, edge)};
auto v1 = Vector3{get_v1(shapes, edge)};
auto ns_v0 = Vector3{get_non_shared_v0(shapes, edge)};
auto ns_v1 = Vector3{get_non_shared_v1(shapes, edge)};
auto n0 = normalize(cross(v0 - ns_v0, v1 - ns_v0));
auto n1 = normalize(cross(v1 - ns_v1, v0 - ns_v1));
if (!has_shading_normals(shapes[edge.shape_id])) {
// If we are not using Phong normal, every edge is silhouette,
// except edges with dihedral angle of 0
if (dot(n0, n1) >= 1 - 1e-6f) {
return false;
}
return true;
}
auto frontfacing0 = dot(dir, n0) > 0.f;
auto frontfacing1 = dot(dir, n1) > 0.f;
return (frontfacing0 && !frontfacing1) || (!frontfacing0 && frontfacing1);
}
DEVICE
inline Real compute_exterior_dihedral_angle(const Shape *shapes, const Edge &edge) {
auto exterior_dihedral = Real(M_PI);
if (edge.f1 != -1) {
auto n0 = get_n0(shapes, edge);
auto n1 = get_n1(shapes, edge);
exterior_dihedral = acos(clamp(dot(n0, n1), Real(-1), Real(1)));
}
return exterior_dihedral;
}
void initialize_ltc_table(bool use_gpu);
void sample_primary_edges(const Scene &scene,
const BufferView<PrimaryEdgeSample> &samples,
const float *d_rendered_image,
const ChannelInfo &channel_info,
BufferView<PrimaryEdgeRecord> edge_records,
BufferView<Ray> rays,
BufferView<RayDifferential> primary_ray_differentials,
BufferView<Vector3> throughputs,
BufferView<Real> channel_multipliers);
void update_primary_edge_weights(const Scene &scene,
const BufferView<PrimaryEdgeRecord> &edge_records,
const BufferView<Intersection> &shading_isects,
const ChannelInfo &channel_info,
BufferView<Vector3> throughputs,
BufferView<Real> channel_multipliers);
void compute_primary_edge_derivatives(const Scene &scene,
const BufferView<PrimaryEdgeRecord> &edge_records,
const BufferView<Real> &edge_contribs,
BufferView<DShape> d_shapes,
DCamera d_camera);
void sample_secondary_edges(const Scene &scene,
const BufferView<int> &active_pixels,
const BufferView<SecondaryEdgeSample> &samples,
const BufferView<Ray> &incoming_rays,
const BufferView<RayDifferential> &incoming_ray_differentials,
const BufferView<Intersection> &shading_isects,
const BufferView<SurfacePoint> &shading_points,
const BufferView<Ray> &nee_rays,
const BufferView<Intersection> &nee_isects,
const BufferView<SurfacePoint> &nee_points,
const BufferView<Vector3> &throughputs,
const BufferView<Real> &min_roughness,
const float *d_rendered_image,
const ChannelInfo &channel_info,
BufferView<SecondaryEdgeRecord> edge_records,
BufferView<Ray> rays,
BufferView<RayDifferential> &bsdf_ray_differentials,
BufferView<Vector3> new_throughputs,
BufferView<Real> edge_min_roughness);
void update_secondary_edge_weights(const Scene &scene,
const BufferView<int> &active_pixels,
const BufferView<SurfacePoint> &shading_points,
const BufferView<Intersection> &edge_isects,
const BufferView<SurfacePoint> &edge_surface_points,
const BufferView<SecondaryEdgeRecord> &edge_records,
BufferView<Vector3> edge_throughputs);
void accumulate_secondary_edge_derivatives(const Scene &scene,
const BufferView<int> &active_pixels,
const BufferView<SurfacePoint> &shading_points,
const BufferView<SecondaryEdgeRecord> &edge_records,
const BufferView<Vector3> &edge_surface_points,
const BufferView<Real> &edge_contribs,
BufferView<SurfacePoint> d_points,
BufferView<DShape> d_shapes);