1 /*
2 The MIT License (MIT)
3
4 Copyright (c) 2015 - 2017 Light Transport Entertainment, Inc.
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 */
24
25 #include "render.h"
26
27 #include <algorithm>
28 #include <chrono> // C++11
29 #include <sstream>
30 #include <thread> // C++11
31 #include <vector>
32
33 #include <iostream>
34
35 #include "../../nanort.h"
36 #include "matrix.h"
37
38 #include "trackball.h"
39
40 extern "C" {
41
42 #include "qrcodegen.h"
43
44 } // extern "C"
45
46 namespace example {
47
48 // PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
49 // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
50 // http://www.pcg-random.org/
51 typedef struct {
52 unsigned long long state;
53 unsigned long long inc; // not used?
54 } pcg32_state_t;
55
56 #define PCG32_INITIALIZER \
57 { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
58
pcg32_random(pcg32_state_t * rng)59 float pcg32_random(pcg32_state_t* rng) {
60 unsigned long long oldstate = rng->state;
61 rng->state = oldstate * 6364136223846793005ULL + rng->inc;
62 unsigned int xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
63 unsigned int rot = oldstate >> 59u;
64 unsigned int ret = (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
65
66 return (float)((double)ret / (double)4294967296.0);
67 }
68
pcg32_srandom(pcg32_state_t * rng,uint64_t initstate,uint64_t initseq)69 void pcg32_srandom(pcg32_state_t* rng, uint64_t initstate, uint64_t initseq) {
70 rng->state = 0U;
71 rng->inc = (initseq << 1U) | 1U;
72 pcg32_random(rng);
73 rng->state += initstate;
74 pcg32_random(rng);
75 }
76
77 const float kPI = 3.141592f;
78
79 typedef struct {
80 std::vector<float> vertices;
81 std::vector<float> widths;
82 } Cubes;
83
84 typedef nanort::real3<float> float3;
85
86 // Predefined SAH predicator for cube.
87 class CubePred {
88 public:
CubePred(const float * vertices)89 CubePred(const float* vertices) : axis_(0), pos_(0.0f), vertices_(vertices) {}
90
Set(int axis,float pos) const91 void Set(int axis, float pos) const {
92 axis_ = axis;
93 pos_ = pos;
94 }
95
operator ()(unsigned int i) const96 bool operator()(unsigned int i) const {
97 int axis = axis_;
98 float pos = pos_;
99
100 float3 p0(&vertices_[3 * i]);
101
102 float center = p0[axis];
103
104 return (center < pos);
105 }
106
107 private:
108 mutable int axis_;
109 mutable float pos_;
110 const float* vertices_;
111 };
112
113 class CubeGeometry {
114 public:
CubeGeometry(const float * vertices,const float * widths)115 CubeGeometry(const float* vertices, const float* widths)
116 : vertices_(vertices), widths_(widths) {}
117
118 /// Compute bounding box for `prim_index`th cube.
119 /// This function is called for each primitive in BVH build.
BoundingBox(float3 * bmin,float3 * bmax,unsigned int prim_index) const120 void BoundingBox(float3* bmin, float3* bmax, unsigned int prim_index) const {
121 (*bmin)[0] = vertices_[3 * prim_index + 0] - widths_[prim_index];
122 (*bmin)[1] = vertices_[3 * prim_index + 1] - widths_[prim_index];
123 (*bmin)[2] = vertices_[3 * prim_index + 2] - widths_[prim_index];
124 (*bmax)[0] = vertices_[3 * prim_index + 0] + widths_[prim_index];
125 (*bmax)[1] = vertices_[3 * prim_index + 1] + widths_[prim_index];
126 (*bmax)[2] = vertices_[3 * prim_index + 2] + widths_[prim_index];
127 }
128
129 const float* vertices_;
130 const float* widths_;
131 mutable float3 ray_org_;
132 mutable float3 ray_dir_;
133 mutable nanort::BVHTraceOptions trace_options_;
134 };
135
136 class CubeIntersection {
137 public:
CubeIntersection()138 CubeIntersection() {}
139
140 float normal[3];
141
142 // Required member variables.
143 float t;
144 unsigned int prim_id;
145 };
146
147 template <class I>
148 class CubeIntersector {
149 public:
CubeIntersector(const float * vertices,const float * widths)150 CubeIntersector(const float* vertices, const float* widths)
151 : vertices_(vertices), widths_(widths) {}
152
153 /// Do ray interesection stuff for `prim_index` th primitive and return hit
154 /// distance `t`,
155 /// Returns true if there's intersection.
Intersect(float * t_inout,unsigned int prim_index) const156 bool Intersect(float* t_inout, unsigned int prim_index) const {
157 if ((prim_index < trace_options_.prim_ids_range[0]) ||
158 (prim_index >= trace_options_.prim_ids_range[1])) {
159 return false;
160 }
161
162 const float3 center(&vertices_[3 * prim_index]);
163 const float width = widths_[prim_index];
164
165 const float3 bmin = center - float3(width);
166 const float3 bmax = center + float3(width);
167
168 float tmin, tmax;
169
170 const float min_x = ray_dir_sign_[0] ? bmax[0] : bmin[0];
171 const float min_y = ray_dir_sign_[1] ? bmax[1] : bmin[1];
172 const float min_z = ray_dir_sign_[2] ? bmax[2] : bmin[2];
173 const float max_x = ray_dir_sign_[0] ? bmin[0] : bmax[0];
174 const float max_y = ray_dir_sign_[1] ? bmin[1] : bmax[1];
175 const float max_z = ray_dir_sign_[2] ? bmin[2] : bmax[2];
176
177 // X
178 const float tmin_x = (min_x - ray_org_[0]) * ray_inv_dir_[0];
179 const float tmax_x = (max_x - ray_org_[0]) * ray_inv_dir_[0];
180
181 // Y
182 const float tmin_y = (min_y - ray_org_[1]) * ray_inv_dir_[1];
183 const float tmax_y = (max_y - ray_org_[1]) * ray_inv_dir_[1];
184
185 // Z
186 const float tmin_z = (min_z - ray_org_[2]) * ray_inv_dir_[2];
187 const float tmax_z = (max_z - ray_org_[2]) * ray_inv_dir_[2];
188
189 tmin = nanort::safemax(tmin_z, nanort::safemax(tmin_y, tmin_x));
190 tmax = nanort::safemin(tmax_z, nanort::safemin(tmax_y, tmax_x));
191
192 if (tmin > tmax) {
193 return false;
194 }
195
196 const float t = tmin;
197
198 if (t > (*t_inout)) {
199 return false;
200 }
201
202 (*t_inout) = t;
203
204 return true;
205 }
206
207 /// Returns the nearest hit distance.
GetT() const208 float GetT() const { return t_; }
209
210 /// Update is called when a nearest hit is found.
Update(float t,unsigned int prim_idx) const211 void Update(float t, unsigned int prim_idx) const {
212 t_ = t;
213 prim_id_ = prim_idx;
214 }
215
216 /// Prepare BVH traversal(e.g. compute inverse ray direction)
217 /// This function is called only once in BVH traversal.
PrepareTraversal(const nanort::Ray<float> & ray,const nanort::BVHTraceOptions & trace_options) const218 void PrepareTraversal(const nanort::Ray<float>& ray,
219 const nanort::BVHTraceOptions& trace_options) const {
220 ray_org_[0] = ray.org[0];
221 ray_org_[1] = ray.org[1];
222 ray_org_[2] = ray.org[2];
223
224 ray_dir_[0] = ray.dir[0];
225 ray_dir_[1] = ray.dir[1];
226 ray_dir_[2] = ray.dir[2];
227
228 // FIXME(syoyo): Consider zero div case.
229 ray_inv_dir_[0] = 1.0f / ray.dir[0];
230 ray_inv_dir_[1] = 1.0f / ray.dir[1];
231 ray_inv_dir_[2] = 1.0f / ray.dir[2];
232
233 ray_dir_sign_[0] = ray.dir[0] < 0.0f ? 1 : 0;
234 ray_dir_sign_[1] = ray.dir[1] < 0.0f ? 1 : 0;
235 ray_dir_sign_[2] = ray.dir[2] < 0.0f ? 1 : 0;
236
237 trace_options_ = trace_options;
238 }
239
240 /// Post BVH traversal stuff(e.g. compute intersection point information)
241 /// This function is called only once in BVH traversal.
242 /// `hit` = true if there is something hit.
PostTraversal(const nanort::Ray<float> & ray,bool hit,CubeIntersection * isect) const243 void PostTraversal(const nanort::Ray<float>& ray, bool hit,
244 CubeIntersection* isect) const {
245 if (hit) {
246 // compute normal. there should be valid intersection point.
247 const float3 center(&vertices_[3 * prim_id_]);
248 const float width = widths_[prim_id_];
249
250 const float3 bmin = center - float3(width);
251 const float3 bmax = center + float3(width);
252
253 float tmin, tmax;
254
255 const float min_x = ray_dir_sign_[0] ? bmax[0] : bmin[0];
256 const float min_y = ray_dir_sign_[1] ? bmax[1] : bmin[1];
257 const float min_z = ray_dir_sign_[2] ? bmax[2] : bmin[2];
258 const float max_x = ray_dir_sign_[0] ? bmin[0] : bmax[0];
259 const float max_y = ray_dir_sign_[1] ? bmin[1] : bmax[1];
260 const float max_z = ray_dir_sign_[2] ? bmin[2] : bmax[2];
261
262 // X
263 const float tmin_x = (min_x - ray_org_[0]) * ray_inv_dir_[0];
264
265 // Y
266 const float tmin_y = (min_y - ray_org_[1]) * ray_inv_dir_[1];
267
268 // Z
269 const float tmin_z = (min_z - ray_org_[2]) * ray_inv_dir_[2];
270
271 int axis = 0;
272 tmin = tmin_x;
273 if (tmin < tmin_y) {
274 axis = 1;
275 tmin = tmin_y;
276 }
277 if (tmin < tmin_z) {
278 axis = 2;
279 tmin = tmin_z;
280 }
281
282 isect->t = t_;
283 isect->prim_id = prim_id_;
284
285 isect->normal[0] = 0.0f;
286 isect->normal[1] = 0.0f;
287 isect->normal[2] = 0.0f;
288
289 isect->normal[axis] = ray_dir_sign_[axis] ? 1.0f : -1.0f;
290 }
291 }
292
293 const float* vertices_;
294 const float* widths_;
295 mutable float3 ray_org_;
296 mutable float3 ray_dir_;
297 mutable float3 ray_inv_dir_;
298 mutable int ray_dir_sign_[3];
299 mutable nanort::BVHTraceOptions trace_options_;
300
301 mutable float t_;
302 mutable unsigned int prim_id_;
303 };
304
305 // @fixme { Do not defined as global variable }
306 Cubes gCubes;
307 nanort::BVHAccel<float> gAccel;
308
Lerp3(float3 v0,float3 v1,float3 v2,float u,float v)309 inline float3 Lerp3(float3 v0, float3 v1, float3 v2, float u, float v) {
310 return (1.0f - u - v) * v0 + u * v1 + v * v2;
311 }
312
CalcNormal(float3 & N,float3 v0,float3 v1,float3 v2)313 inline void CalcNormal(float3& N, float3 v0, float3 v1, float3 v2) {
314 float3 v10 = v1 - v0;
315 float3 v20 = v2 - v0;
316
317 N = vcross(v20, v10);
318 N = vnormalize(N);
319 }
320
BuildCameraFrame(float3 * origin,float3 * corner,float3 * u,float3 * v,float quat[4],float eye[3],float lookat[3],float up[3],float fov,int width,int height)321 void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v,
322 float quat[4], float eye[3], float lookat[3], float up[3],
323 float fov, int width, int height) {
324 float e[4][4];
325
326 Matrix::LookAt(e, eye, lookat, up);
327
328 float r[4][4];
329 build_rotmatrix(r, quat);
330
331 float3 lo;
332 lo[0] = lookat[0] - eye[0];
333 lo[1] = lookat[1] - eye[1];
334 lo[2] = lookat[2] - eye[2];
335 float dist = vlength(lo);
336
337 float dir[3];
338 dir[0] = 0.0;
339 dir[1] = 0.0;
340 dir[2] = dist;
341
342 Matrix::Inverse(r);
343
344 float rr[4][4];
345 float re[4][4];
346 float zero[3] = {0.0f, 0.0f, 0.0f};
347 float localUp[3] = {0.0f, 1.0f, 0.0f};
348 Matrix::LookAt(re, dir, zero, localUp);
349
350 // translate
351 re[3][0] += eye[0]; // 0.0; //lo[0];
352 re[3][1] += eye[1]; // 0.0; //lo[1];
353 re[3][2] += (eye[2] - dist);
354
355 // rot -> trans
356 Matrix::Mult(rr, r, re);
357
358 float m[4][4];
359 for (int j = 0; j < 4; j++) {
360 for (int i = 0; i < 4; i++) {
361 m[j][i] = rr[j][i];
362 }
363 }
364
365 float vzero[3] = {0.0f, 0.0f, 0.0f};
366 float eye1[3];
367 Matrix::MultV(eye1, m, vzero);
368
369 float lookat1d[3];
370 dir[2] = -dir[2];
371 Matrix::MultV(lookat1d, m, dir);
372 float3 lookat1(lookat1d[0], lookat1d[1], lookat1d[2]);
373
374 float up1d[3];
375 Matrix::MultV(up1d, m, up);
376
377 float3 up1(up1d[0], up1d[1], up1d[2]);
378
379 // absolute -> relative
380 up1[0] -= eye1[0];
381 up1[1] -= eye1[1];
382 up1[2] -= eye1[2];
383 // printf("up1(after) = %f, %f, %f\n", up1[0], up1[1], up1[2]);
384
385 // Use original up vector
386 // up1[0] = up[0];
387 // up1[1] = up[1];
388 // up1[2] = up[2];
389
390 {
391 float flen =
392 (0.5f * (float)height / tanf(0.5f * (float)(fov * kPI / 180.0f)));
393 float3 look1;
394 look1[0] = lookat1[0] - eye1[0];
395 look1[1] = lookat1[1] - eye1[1];
396 look1[2] = lookat1[2] - eye1[2];
397 // vcross(u, up1, look1);
398 // flip
399 (*u) = nanort::vcross(look1, up1);
400 (*u) = vnormalize((*u));
401
402 (*v) = vcross(look1, (*u));
403 (*v) = vnormalize((*v));
404
405 look1 = vnormalize(look1);
406 look1[0] = flen * look1[0] + eye1[0];
407 look1[1] = flen * look1[1] + eye1[1];
408 look1[2] = flen * look1[2] + eye1[2];
409 (*corner)[0] = look1[0] - 0.5f * (width * (*u)[0] + height * (*v)[0]);
410 (*corner)[1] = look1[1] - 0.5f * (width * (*u)[1] + height * (*v)[1]);
411 (*corner)[2] = look1[2] - 0.5f * (width * (*u)[2] + height * (*v)[2]);
412
413 (*origin)[0] = eye1[0];
414 (*origin)[1] = eye1[1];
415 (*origin)[2] = eye1[2];
416 }
417 }
418
GenerateRay(const float3 & origin,const float3 & corner,const float3 & du,const float3 & dv,float u,float v)419 nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
420 const float3& du, const float3& dv, float u,
421 float v) {
422 float3 dir;
423
424 dir[0] = (corner[0] + u * du[0] + v * dv[0]) - origin[0];
425 dir[1] = (corner[1] + u * du[1] + v * dv[1]) - origin[1];
426 dir[2] = (corner[2] + u * du[2] + v * dv[2]) - origin[2];
427 dir = vnormalize(dir);
428
429 float3 org;
430
431 nanort::Ray<float> ray;
432 ray.org[0] = origin[0];
433 ray.org[1] = origin[1];
434 ray.org[2] = origin[2];
435 ray.dir[0] = dir[0];
436
437 return ray;
438 }
439
GetFilePathExtension(const std::string & FileName)440 static std::string GetFilePathExtension(const std::string& FileName) {
441 if (FileName.find_last_of(".") != std::string::npos)
442 return FileName.substr(FileName.find_last_of(".") + 1);
443 return "";
444 }
445
GenQRData(Cubes * cubes,const std::string & text,float scale)446 bool GenQRData(Cubes* cubes, const std::string& text, float scale) {
447 double bmin[3], bmax[3];
448 bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<double>::max();
449 bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<double>::max();
450
451 cubes->vertices.clear();
452 cubes->widths.clear();
453
454 enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level
455
456 // Make QR Code symbol
457 uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
458 uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
459 bool ok = qrcodegen_encodeText(text.c_str(), tempBuffer, qrcode, errCorLvl,
460 qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
461 qrcodegen_Mask_AUTO, true);
462
463 if (!ok) {
464 std::cerr << "Failed to make QR Code symbol" << std::endl;
465 return false;
466 }
467
468 {
469 int size = qrcodegen_getSize(qrcode);
470 int border = 4;
471 for (int y = -border; y < size + border; y++) {
472 for (int x = -border; x < size + border; x++) {
473 if (qrcodegen_getModule(qrcode, x, y)) {
474 cubes->vertices.push_back(x);
475 cubes->vertices.push_back(y);
476 cubes->vertices.push_back(0.0f); // Z
477
478 cubes->widths.push_back(0.5f);
479 }
480 }
481 }
482 }
483
484 return true;
485 }
486
GenQR(const std::string & text,float scene_scale)487 bool Renderer::GenQR(const std::string& text, float scene_scale) {
488 return GenQRData(&gCubes, text, scene_scale);
489 }
490
BuildBVH()491 bool Renderer::BuildBVH() {
492 if (gCubes.widths.size() < 1) {
493 std::cout << "num_points == 0" << std::endl;
494 return false;
495 }
496
497 std::cout << "[Build BVH] " << std::endl;
498
499 nanort::BVHBuildOptions<float> build_options; // Use default option
500 build_options.cache_bbox = false;
501
502 printf(" BVH build option:\n");
503 printf(" # of leaf primitives: %d\n", build_options.min_leaf_primitives);
504 printf(" SAH binsize : %d\n", build_options.bin_size);
505
506 auto t_start = std::chrono::system_clock::now();
507
508 CubeGeometry cube_geom(&gCubes.vertices.at(0), &gCubes.widths.at(0));
509 CubePred cube_pred(&gCubes.vertices.at(0));
510 bool ret =
511 gAccel.Build(gCubes.widths.size(), cube_geom, cube_pred, build_options);
512 assert(ret);
513
514 auto t_end = std::chrono::system_clock::now();
515
516 std::chrono::duration<double, std::milli> ms = t_end - t_start;
517 std::cout << "BVH build time: " << ms.count() << " [ms]\n";
518
519 nanort::BVHBuildStatistics stats = gAccel.GetStatistics();
520
521 printf(" BVH statistics:\n");
522 printf(" # of leaf nodes: %d\n", stats.num_leaf_nodes);
523 printf(" # of branch nodes: %d\n", stats.num_branch_nodes);
524 printf(" Max tree depth : %d\n", stats.max_tree_depth);
525 float bmin[3], bmax[3];
526 gAccel.BoundingBox(bmin, bmax);
527 printf(" Bmin : %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
528 printf(" Bmax : %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
529
530 return true;
531 }
532
Render(RenderLayer * layer,float quat[4],const RenderConfig & config,std::atomic<bool> & cancelFlag)533 bool Renderer::Render(RenderLayer* layer, float quat[4],
534 const RenderConfig& config,
535 std::atomic<bool>& cancelFlag) {
536 if (!gAccel.IsValid()) {
537 return false;
538 }
539
540 int width = config.width;
541 int height = config.height;
542
543 // camera
544 float eye[3] = {config.eye[0], config.eye[1], config.eye[2]};
545 float look_at[3] = {config.look_at[0], config.look_at[1], config.look_at[2]};
546 float up[3] = {config.up[0], config.up[1], config.up[2]};
547 float fov = config.fov;
548 float3 origin, corner, u, v;
549 BuildCameraFrame(&origin, &corner, &u, &v, quat, eye, look_at, up, fov, width,
550 height);
551
552 auto kCancelFlagCheckMilliSeconds = 300;
553
554 std::vector<std::thread> workers;
555 std::atomic<int> i(0);
556
557 uint32_t num_threads = std::max(1U, std::thread::hardware_concurrency());
558
559 auto startT = std::chrono::system_clock::now();
560
561 // Multi-threaded rendering using C++11 thread.
562 for (auto t = 0; t < num_threads; t++) {
563 workers.emplace_back(std::thread([&, t]() {
564 // Initialize RNG.
565 pcg32_state_t rng;
566 pcg32_srandom(&rng, config.pass,
567 t); // seed = combination of render pass + thread no.
568
569 int y = 0;
570 while ((y = i++) < config.height) {
571 auto currT = std::chrono::system_clock::now();
572
573 std::chrono::duration<double, std::milli> ms = currT - startT;
574 // Check cancel flag
575 if (ms.count() > kCancelFlagCheckMilliSeconds) {
576 if (cancelFlag) {
577 break;
578 }
579 }
580
581 for (int x = 0; x < config.width; x++) {
582 nanort::Ray<float> ray;
583 ray.org[0] = origin[0];
584 ray.org[1] = origin[1];
585 ray.org[2] = origin[2];
586
587 float u0 = pcg32_random(&rng);
588 float u1 = pcg32_random(&rng);
589
590 float3 dir;
591 dir = corner + (float(x) + u0) * u +
592 (float(config.height - y - 1) + u1) * v;
593 dir = vnormalize(dir);
594 ray.dir[0] = dir[0];
595 ray.dir[1] = dir[1];
596 ray.dir[2] = dir[2];
597
598 float kFar = 1.0e+30f;
599 ray.min_t = 0.0f;
600 ray.max_t = kFar;
601
602 CubeIntersector<CubeIntersection> cube_intersector(
603 reinterpret_cast<const float*>(gCubes.vertices.data()),
604 gCubes.widths.data());
605 CubeIntersection isect;
606 bool hit = gAccel.Traverse(ray, cube_intersector, &isect);
607 if (hit) {
608 float3 p;
609 p[0] = ray.org[0] + isect.t * ray.dir[0];
610 p[1] = ray.org[1] + isect.t * ray.dir[1];
611 p[2] = ray.org[2] + isect.t * ray.dir[2];
612
613 layer->position[4 * (y * config.width + x) + 0] = p.x();
614 layer->position[4 * (y * config.width + x) + 1] = p.y();
615 layer->position[4 * (y * config.width + x) + 2] = p.z();
616 layer->position[4 * (y * config.width + x) + 3] = 1.0f;
617
618 layer->varycoord[4 * (y * config.width + x) + 0] = 0.0f;
619 layer->varycoord[4 * (y * config.width + x) + 1] = 0.0f;
620 layer->varycoord[4 * (y * config.width + x) + 2] = 0.0f;
621 layer->varycoord[4 * (y * config.width + x) + 3] = 1.0f;
622
623 unsigned int prim_id = isect.prim_id;
624
625 float3 N;
626 N[0] = isect.normal[0];
627 N[1] = isect.normal[1];
628 N[2] = isect.normal[2];
629
630 layer->normal[4 * (y * config.width + x) + 0] = 0.5 * N[0] + 0.5;
631 layer->normal[4 * (y * config.width + x) + 1] = 0.5 * N[1] + 0.5;
632 layer->normal[4 * (y * config.width + x) + 2] = 0.5 * N[2] + 0.5;
633 layer->normal[4 * (y * config.width + x) + 3] = 1.0f;
634
635 layer->depth[4 * (y * config.width + x) + 0] = isect.t;
636 layer->depth[4 * (y * config.width + x) + 1] = isect.t;
637 layer->depth[4 * (y * config.width + x) + 2] = isect.t;
638 layer->depth[4 * (y * config.width + x) + 3] = 1.0f;
639
640 float diffuse_col[3] = {0.5f, 0.5f, 0.5f};
641
642 // TODO(LTE): Support specular color
643 float specular_col[3] = {0.0f, 0.0f, 0.0f};
644
645 // Simple shading
646 float NdotV = fabsf(vdot(N, dir));
647
648 if (config.pass == 0) {
649 layer->rgba[4 * (y * config.width + x) + 0] =
650 NdotV * diffuse_col[0];
651 layer->rgba[4 * (y * config.width + x) + 1] =
652 NdotV * diffuse_col[1];
653 layer->rgba[4 * (y * config.width + x) + 2] =
654 NdotV * diffuse_col[2];
655 layer->rgba[4 * (y * config.width + x) + 3] = 1.0f;
656 layer->sample_counts[y * config.width + x] =
657 1; // Set 1 for the first pass
658 } else { // additive.
659 layer->rgba[4 * (y * config.width + x) + 0] +=
660 NdotV * diffuse_col[0];
661 layer->rgba[4 * (y * config.width + x) + 1] +=
662 NdotV * diffuse_col[1];
663 layer->rgba[4 * (y * config.width + x) + 2] +=
664 NdotV * diffuse_col[2];
665 layer->rgba[4 * (y * config.width + x) + 3] += 1.0f;
666 layer->sample_counts[y * config.width + x]++;
667 }
668
669 } else {
670 {
671 if (config.pass == 0) {
672 // clear pixel
673 layer->rgba[4 * (y * config.width + x) + 0] = 0.0f;
674 layer->rgba[4 * (y * config.width + x) + 1] = 0.0f;
675 layer->rgba[4 * (y * config.width + x) + 2] = 0.0f;
676 layer->rgba[4 * (y * config.width + x) + 3] = 0.0f;
677 layer->sample_counts[y * config.width + x] =
678 1; // Set 1 for the first pass
679 } else {
680 layer->sample_counts[y * config.width + x]++;
681 }
682
683 // No super sampling
684 layer->normal[4 * (y * config.width + x) + 0] = 0.0f;
685 layer->normal[4 * (y * config.width + x) + 1] = 0.0f;
686 layer->normal[4 * (y * config.width + x) + 2] = 0.0f;
687 layer->normal[4 * (y * config.width + x) + 3] = 0.0f;
688 layer->position[4 * (y * config.width + x) + 0] = 0.0f;
689 layer->position[4 * (y * config.width + x) + 1] = 0.0f;
690 layer->position[4 * (y * config.width + x) + 2] = 0.0f;
691 layer->position[4 * (y * config.width + x) + 3] = 0.0f;
692 layer->depth[4 * (y * config.width + x) + 0] = 0.0f;
693 layer->depth[4 * (y * config.width + x) + 1] = 0.0f;
694 layer->depth[4 * (y * config.width + x) + 2] = 0.0f;
695 layer->depth[4 * (y * config.width + x) + 3] = 0.0f;
696 layer->texcoord[4 * (y * config.width + x) + 0] = 0.0f;
697 layer->texcoord[4 * (y * config.width + x) + 1] = 0.0f;
698 layer->texcoord[4 * (y * config.width + x) + 2] = 0.0f;
699 layer->texcoord[4 * (y * config.width + x) + 3] = 0.0f;
700 layer->varycoord[4 * (y * config.width + x) + 0] = 0.0f;
701 layer->varycoord[4 * (y * config.width + x) + 1] = 0.0f;
702 layer->varycoord[4 * (y * config.width + x) + 2] = 0.0f;
703 layer->varycoord[4 * (y * config.width + x) + 3] = 0.0f;
704 }
705 }
706 }
707 }
708 }));
709 }
710
711 for (auto& t : workers) {
712 t.join();
713 }
714
715 return (!cancelFlag);
716 };
717
718 } // namespace example
719