1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include "intersection_filter_device.h"
5 
6 namespace embree {
7 
8 RTCScene g_scene = nullptr;
9 TutorialData data;
10 
11 // FIXME: fast path for occlusionFilter
12 
13 /******************************************************************************************/
14 /*                             Standard Mode                                              */
15 /******************************************************************************************/
16 
17 #define HIT_LIST_LENGTH 16
18 
19 /* extended ray structure that includes total transparency along the ray */
20 struct Ray2
21 {
22   Ray ray;
23 
24   // ray extensions
25   float transparency; //!< accumulated transparency value
26 
27   // we remember up to 16 hits to ignore duplicate hits
28   unsigned int firstHit, lastHit;
29   unsigned int hit_geomIDs[HIT_LIST_LENGTH];
30   unsigned int hit_primIDs[HIT_LIST_LENGTH];
31 };
32 
RTCRayHit_(Ray2 & ray)33 inline RTCRayHit* RTCRayHit_(Ray2& ray)
34 {
35   RTCRayHit* ray_ptr = (RTCRayHit*)&ray;
36   return ray_ptr;
37 }
38 
RTCRay_(Ray2 & ray)39 inline RTCRay* RTCRay_(Ray2& ray)
40 {
41   RTCRay* ray_ptr = (RTCRay*)&ray;
42   return ray_ptr;
43 }
44 
45 /* 3D procedural transparency */
transparencyFunction(Vec3fa & h)46 inline float transparencyFunction(Vec3fa& h)
47 {
48   float v = abs(sin(4.0f*h.x)*cos(4.0f*h.y)*sin(4.0f*h.z));
49   float T = clamp((v-0.1f)*3.0f,0.0f,1.0f);
50   return T;
51   //return 0.5f;
52 }
53 
54 
55 /* task that renders a single screen tile */
renderPixelStandard(const TutorialData & data,int x,int y,int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera,RayStats & stats)56 void renderPixelStandard(const TutorialData& data,
57                          int x, int y,
58                          int* pixels,
59                          const unsigned int width,
60                          const unsigned int height,
61                          const float time,
62                          const ISPCCamera& camera, RayStats& stats)
63 {
64   float weight = 1.0f;
65   Vec3fa color = Vec3fa(0.0f);
66 
67   IntersectContext context;
68   InitIntersectionContext(&context);
69 
70   /* initialize ray */
71   Ray2 primary;
72   init_Ray(primary.ray,Vec3fa(camera.xfm.p), Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f, inf);
73   primary.ray.id = 0; // needs to encode rayID for filter
74   primary.transparency = 0.0f;
75 
76 
77   while (true)
78   {
79     context.userRayExt = &primary;
80 
81     /* intersect ray with scene */
82     rtcIntersect1(data.g_scene,&context.context,RTCRayHit_(primary));
83     RayStats_addRay(stats);
84 
85     /* shade pixels */
86     if (primary.ray.geomID == RTC_INVALID_GEOMETRY_ID)
87       break;
88 
89     float opacity = 1.0f-primary.transparency;
90     Vec3fa diffuse = data.colors[primary.ray.primID];
91     Vec3fa La = diffuse*0.5f;
92     color = color + weight*opacity*La;
93     Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1));
94 
95     /* initialize shadow ray */
96     Ray2 shadow;
97     init_Ray(shadow.ray, primary.ray.org + primary.ray.tfar*primary.ray.dir, neg(lightDir), 0.001f, inf);
98     shadow.ray.id = 0; // needs to encode rayID for filter
99     shadow.transparency = 1.0f;
100     shadow.firstHit = 0;
101     shadow.lastHit = 0;
102     context.userRayExt = &shadow;
103 
104     /* trace shadow ray */
105     rtcOccluded1(data.g_scene,&context.context,RTCRay_(shadow));
106     RayStats_addShadowRay(stats);
107 
108     /* add light contribution */
109     if (shadow.ray.tfar >= 0.0f) {
110       Vec3fa Ll = diffuse*shadow.transparency*clamp(-dot(lightDir,normalize(primary.ray.Ng)),0.0f,1.0f);
111       color = color + weight*opacity*Ll;
112     }
113 
114     /* shoot transmission ray */
115     weight *= primary.transparency;
116     primary.ray.tnear() = 1.001f*primary.ray.tfar;
117     primary.ray.tfar = (float)(inf);
118     primary.ray.geomID = RTC_INVALID_GEOMETRY_ID;
119     primary.ray.primID = RTC_INVALID_GEOMETRY_ID;
120     primary.transparency = 0.0f;
121   }
122 
123   /* write color to framebuffer */
124   unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f));
125   unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f));
126   unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f));
127   pixels[y*width+x] = (b << 16) + (g << 8) + r;
128 }
129 
130 /* renders a single screen tile */
renderTileStandard(int taskIndex,int threadIndex,int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera,const int numTilesX,const int numTilesY)131 void renderTileStandard(int taskIndex,
132                         int threadIndex,
133                         int* pixels,
134                         const unsigned int width,
135                         const unsigned int height,
136                         const float time,
137                         const ISPCCamera& camera,
138                         const int numTilesX,
139                         const int numTilesY)
140 {
141   const unsigned int tileY = taskIndex / numTilesX;
142   const unsigned int tileX = taskIndex - tileY * numTilesX;
143   const unsigned int x0 = tileX * TILE_SIZE_X;
144   const unsigned int x1 = min(x0+TILE_SIZE_X,width);
145   const unsigned int y0 = tileY * TILE_SIZE_Y;
146   const unsigned int y1 = min(y0+TILE_SIZE_Y,height);
147 
148   for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
149   {
150     renderPixelStandard(data,x,y,pixels,width,height,time,camera,g_stats[threadIndex]);
151   }
152 }
153 
154 /******************************************************************************************/
155 /*                               Stream Mode                                              */
156 /******************************************************************************************/
157 
gather(float & ptr,const unsigned int stride,const unsigned int pid,const unsigned int rid)158 inline float gather(float& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid)
159 {
160   float* uptr = (float*) (((char*)&ptr) + pid*stride);
161   return uptr[rid];
162 }
163 
gather(unsigned int & ptr,const unsigned int stride,const unsigned int pid,const unsigned int rid)164 inline unsigned int gather(unsigned int& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid)
165 {
166   unsigned int* uptr = (unsigned int*) (((char*)&ptr) + pid*stride);
167   return uptr[rid];
168 }
169 
gather(unsigned int & ptr,const unsigned int idx,const unsigned int stride,const unsigned int pid,const unsigned int rid)170 inline unsigned int gather(unsigned int& ptr, const unsigned int idx, const unsigned int stride, const unsigned int pid, const unsigned int rid)
171 {
172   unsigned int* uptr = (unsigned int*) (((char*)&ptr) + pid*stride);
173   return uptr[rid + 1*idx];
174 }
175 
scatter(float & ptr,const unsigned int stride,const unsigned int pid,const unsigned int rid,float v)176 inline void scatter(float& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid, float v) {
177   ((float*)(((char*)&ptr) + pid*stride))[rid] = v;
178 }
179 
scatter(unsigned int & ptr,const unsigned int stride,const unsigned int pid,const unsigned int rid,unsigned int v)180 inline void scatter(unsigned int& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid, unsigned int v) {
181   ((unsigned int*)(((char*)&ptr) + pid*stride))[rid] = v;
182 }
183 
scatter(unsigned int & ptr,const unsigned int idx,const unsigned int stride,const unsigned int pid,const unsigned int rid,unsigned int v)184 inline void scatter(unsigned int& ptr, const unsigned int idx, const unsigned int stride, const unsigned int pid, const unsigned int rid, unsigned int v) {
185   ((unsigned int*)(((char*)&ptr) + pid*stride))[rid+1*idx] = v;
186 }
187 
188 
189 /* intersection filter function for single rays and packets */
intersectionFilter(const RTCFilterFunctionNArguments * args)190 void intersectionFilter(const RTCFilterFunctionNArguments* args)
191 {
192   /* avoid crashing when debug visualizations are used */
193   if (args->context == nullptr) return;
194 
195   assert(args->N == 1);
196   int* valid = args->valid;
197   const IntersectContext* context = (const IntersectContext*) args->context;
198   Ray* ray = (Ray*)args->ray;
199   //RTCHit* hit = (RTCHit*)args->hit;
200 
201   /* ignore inactive rays */
202   if (valid[0] != -1) return;
203 
204   /* calculate transparency */
205   Vec3fa h = ray->org + ray->dir  * ray->tfar;
206   float T = transparencyFunction(h);
207 
208   /* ignore hit if completely transparent */
209   if (T >= 1.0f)
210     valid[0] = 0;
211   /* otherwise accept hit and remember transparency */
212   else
213   {
214     Ray2* eray = (Ray2*) context->userRayExt;
215     eray->transparency = T;
216   }
217 }
218 
219 /* intersection filter function for streams of general packets */
intersectionFilterN(const RTCFilterFunctionNArguments * args)220 void intersectionFilterN(const RTCFilterFunctionNArguments* args)
221 {
222   int* valid = args->valid;
223   const IntersectContext* context = (const IntersectContext*) args->context;
224   struct RTCRayHitN* rayN = (struct RTCRayHitN*)args->ray;
225   //struct RTCHitN* hitN = args->hit;
226   const unsigned int N = args->N;
227 
228   /* avoid crashing when debug visualizations are used */
229   if (context == nullptr) return;
230 
231   /* iterate over all rays in ray packet */
232   for (unsigned int ui=0; ui<N; ui+=1)
233   {
234     /* calculate loop and execution mask */
235     unsigned int vi = ui+0;
236     if (vi>=N) continue;
237 
238     /* ignore inactive rays */
239     if (valid[vi] != -1) continue;
240 
241     /* read ray/hit from ray structure */
242     RTCRayHit rtc_ray = rtcGetRayHitFromRayHitN(rayN,N,ui);
243     Ray* ray = (Ray*)&rtc_ray;
244 
245     /* calculate transparency */
246     Vec3fa h = ray->org + ray->dir  * ray->tfar;
247     float T = transparencyFunction(h);
248 
249     /* ignore hit if completely transparent */
250     if (T >= 1.0f)
251       valid[vi] = 0;
252     /* otherwise accept hit and remember transparency */
253     else
254     {
255       /* decode ray IDs */
256       const unsigned int pid = ray->id / 1;
257       const unsigned int rid = ray->id % 1;
258       Ray2* ray2 = (Ray2*) context->userRayExt;
259       assert(ray2);
260       scatter(ray2->transparency,sizeof(Ray2),pid,rid,T);
261     }
262   }
263 }
264 
265 /* occlusion filter function for single rays and packets */
occlusionFilter(const RTCFilterFunctionNArguments * args)266 void occlusionFilter(const RTCFilterFunctionNArguments* args)
267 {
268   /* avoid crashing when debug visualizations are used */
269   if (args->context == nullptr) return;
270 
271   assert(args->N == 1);
272   int* valid = args->valid;
273   const IntersectContext* context = (const IntersectContext*) args->context;
274   Ray* ray = (Ray*)args->ray;
275   RTCHit* hit = (RTCHit*)args->hit;
276 
277   /* ignore inactive rays */
278   if (valid[0] != -1) return;
279 
280   Ray2* ray2 = (Ray2*) context->userRayExt;
281   assert(ray2);
282 
283   for (unsigned int i=ray2->firstHit; i<ray2->lastHit; i++) {
284     unsigned slot= i%HIT_LIST_LENGTH;
285     if (ray2->hit_geomIDs[slot] == hit->geomID && ray2->hit_primIDs[slot] == hit->primID) {
286       valid[0] = 0; return; // ignore duplicate intersections
287     }
288   }
289   /* store hit in hit list */
290   unsigned int slot = ray2->lastHit%HIT_LIST_LENGTH;
291   ray2->hit_geomIDs[slot] = hit->geomID;
292   ray2->hit_primIDs[slot] = hit->primID;
293   ray2->lastHit++;
294   if (ray2->lastHit - ray2->firstHit >= HIT_LIST_LENGTH)
295     ray2->firstHit++;
296 
297   Vec3fa h = ray->org + ray->dir * ray->tfar;
298 
299   /* calculate and accumulate transparency */
300   float T = transparencyFunction(h);
301   T *= ray2->transparency;
302   ray2->transparency = T;
303   if (T != 0.0f)
304     valid[0] = 0;
305 }
306 
307 /* intersection filter function for streams of general packets */
occlusionFilterN(const RTCFilterFunctionNArguments * args)308 void occlusionFilterN(const RTCFilterFunctionNArguments* args)
309 {
310   int* valid = args->valid;
311   const IntersectContext* context = (const IntersectContext*) args->context;
312   struct RTCRayHitN* rayN = (struct RTCRayHitN*)args->ray;
313   struct RTCHitN* hitN = args->hit;
314   const unsigned int N = args->N;
315 
316   /* avoid crashing when debug visualizations are used */
317   if (context == nullptr) return;
318 
319   /* iterate over all rays in ray packet */
320   for (unsigned int ui=0; ui<N; ui+=1)
321   {
322     /* calculate loop and execution mask */
323     unsigned int vi = ui+0;
324     if (vi>=N) continue;
325 
326     /* ignore inactive rays */
327     if (valid[vi] != -1) continue;
328 
329     /* read ray/hit from ray structure */
330     RTCRayHit rtc_ray = rtcGetRayHitFromRayHitN(rayN,N,ui);
331     Ray* ray = (Ray*)&rtc_ray;
332 
333     RTCHit hit = rtcGetHitFromHitN(hitN,N,ui);
334     const unsigned int hit_geomID = hit.geomID;
335     const unsigned int hit_primID = hit.primID;
336 
337     /* decode ray IDs */
338     const unsigned int pid = ray->id / 1;
339     const unsigned int rid = ray->id % 1;
340     Ray2* ray2 = (Ray2*) context->userRayExt;
341     assert(ray2);
342 
343     /* The occlusion filter function may be called multiple times with
344      * the same hit. We remember the last N hits, and skip duplicates. */
345     unsigned int ray2_firstHit = gather(ray2->firstHit,sizeof(Ray2),pid,rid);
346     unsigned int ray2_lastHit =  gather(ray2->lastHit ,sizeof(Ray2),pid,rid);
347     for (unsigned int i=ray2_firstHit; i<ray2_lastHit; i++)
348     {
349       unsigned int slot= i%HIT_LIST_LENGTH;
350       unsigned int last_geomID = gather(ray2->hit_geomIDs[0],slot,sizeof(Ray2),pid,rid);
351       unsigned int last_primID = gather(ray2->hit_primIDs[0],slot,sizeof(Ray2),pid,rid);
352       if (last_geomID == hit_geomID && last_primID == hit_primID) {
353         valid[vi] = 0; break; // ignore duplicate intersections
354       }
355     }
356     if (!valid[vi]) continue;
357 
358     /* store hit in hit list */
359     unsigned int slot = ray2_lastHit%HIT_LIST_LENGTH;
360     scatter(ray2->hit_geomIDs[0],slot,sizeof(Ray2),pid,rid,hit_geomID);
361     scatter(ray2->hit_primIDs[0],slot,sizeof(Ray2),pid,rid,hit_primID);
362     ray2_lastHit++;
363     scatter(ray2->lastHit,sizeof(Ray2),pid,rid,ray2_lastHit);
364     if (ray2_lastHit - ray2_firstHit >= HIT_LIST_LENGTH)
365       scatter(ray2->firstHit,sizeof(Ray2),pid,rid,ray2_firstHit+1);
366 
367     /* calculate transparency */
368     Vec3fa h = ray->org + ray->dir * ray->tfar;
369     float T = transparencyFunction(h);
370 
371     /* accumulate transparency and store inside ray extensions */
372     T *= gather(ray2->transparency,sizeof(Ray2),pid,rid);
373     scatter(ray2->transparency,sizeof(Ray2),pid,rid,T);
374 
375     /* reject a hit if not fully opqaue */
376     if (T != 0.0f)
377       valid[vi] = 0;
378   }
379 }
380 
381 /* renders a single screen tile */
renderTileStandardStream(int taskIndex,int threadIndex,int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera,const int numTilesX,const int numTilesY)382 void renderTileStandardStream(int taskIndex,
383                               int threadIndex,
384                               int* pixels,
385                               const unsigned int width,
386                               const unsigned int height,
387                               const float time,
388                               const ISPCCamera& camera,
389                               const int numTilesX,
390                               const int numTilesY)
391 {
392   const unsigned int tileY = taskIndex / numTilesX;
393   const unsigned int tileX = taskIndex - tileY * numTilesX;
394   const unsigned int x0 = tileX * TILE_SIZE_X;
395   const unsigned int x1 = min(x0+TILE_SIZE_X,width);
396   const unsigned int y0 = tileY * TILE_SIZE_Y;
397   const unsigned int y1 = min(y0+TILE_SIZE_Y,height);
398 
399   RayStats& stats = g_stats[threadIndex];
400 
401   Ray2 primary_stream[TILE_SIZE_X*TILE_SIZE_Y];
402   Ray2 shadow_stream[TILE_SIZE_X*TILE_SIZE_Y];
403   Vec3fa color_stream[TILE_SIZE_X*TILE_SIZE_Y];
404   float weight_stream[TILE_SIZE_X*TILE_SIZE_Y];
405   bool valid_stream[TILE_SIZE_X*TILE_SIZE_Y];
406 
407   /* generate stream of primary rays */
408   int N = 0;
409   int numActive = 0;
410   for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
411   {
412     /* ISPC workaround for mask == 0 */
413 
414 
415     /* initialize variables */
416     numActive++;
417     color_stream[N] = Vec3fa(0.0f);
418     weight_stream[N] = 1.0f;
419     bool mask = 1; { valid_stream[N] = mask; }
420 
421     /* initialize ray */
422     Ray2& primary = primary_stream[N];
423     mask = 1; { // invalidates inactive rays
424       primary.ray.tnear() = mask ? 0.0f         : (float)(pos_inf);
425       primary.ray.tfar  = mask ? (float)(inf) : (float)(neg_inf);
426     }
427     init_Ray(primary.ray, Vec3fa(camera.xfm.p), Vec3fa(normalize((float)x*camera.xfm.l.vx + (float)y*camera.xfm.l.vy + camera.xfm.l.vz)), primary.ray.tnear(), primary.ray.tfar);
428 
429     primary.ray.id = N*1 + 0;
430     primary.transparency = 0.0f;
431 
432     N++;
433     RayStats_addRay(stats);
434   }
435 
436   Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1));
437 
438   while (numActive)
439   {
440     /* trace rays */
441     IntersectContext primary_context;
442     InitIntersectionContext(&primary_context);
443     primary_context.context.flags = g_iflags_coherent;
444     primary_context.userRayExt = &primary_stream;
445     rtcIntersect1M(data.g_scene,&primary_context.context,(RTCRayHit*)&primary_stream,N,sizeof(Ray2));
446 
447     /* terminate rays and update color */
448     N = -1;
449     for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
450     {
451       N++;
452       /* ISPC workaround for mask == 0 */
453 
454 
455       /* invalidate shadow rays by default */
456       Ray2& shadow = shadow_stream[N];
457       {
458         shadow.ray.tnear() = (float)(pos_inf);
459         shadow.ray.tfar  = (float)(neg_inf);
460       }
461 
462       /* ignore invalid rays */
463       if (valid_stream[N] == false) continue;
464 
465       /* terminate rays that hit nothing */
466       if (primary_stream[N].ray.geomID == RTC_INVALID_GEOMETRY_ID) {
467         valid_stream[N] = false;
468         continue;
469       }
470 
471       /* update color */
472       Ray2& primary = primary_stream[N];
473       float opacity = 1.0f-primary.transparency;
474       Vec3fa diffuse = data.colors[primary.ray.primID];
475       Vec3fa La = diffuse*0.5f;
476       color_stream[N] = color_stream[N] + weight_stream[N]*opacity*La;
477 
478       /* initialize shadow ray */
479       bool mask = 1; {
480         shadow.ray.tnear() = mask ? 0.001f       : (float)(pos_inf);
481         shadow.ray.tfar  = mask ? (float)(inf) : (float)(neg_inf);
482       }
483       init_Ray(shadow.ray, primary.ray.org + primary.ray.tfar*primary.ray.dir, neg(lightDir), shadow.ray.tnear(), shadow.ray.tfar);
484       shadow.ray.id = N*1 + 0;
485       shadow.transparency = 1.0f;
486       shadow.firstHit = 0;
487       shadow.lastHit = 0;
488       RayStats_addShadowRay(stats);
489     }
490     N++;
491 
492     /* trace shadow rays */
493     IntersectContext shadow_context;
494     InitIntersectionContext(&shadow_context);
495     shadow_context.context.flags = g_iflags_coherent;
496     shadow_context.userRayExt = &shadow_stream;
497     rtcOccluded1M(data.g_scene,&shadow_context.context,(RTCRay*)&shadow_stream,N,sizeof(Ray2));
498 
499     /* add light contribution and generate transmission ray */
500     N = -1;
501     numActive = 0;
502     for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
503     {
504       N++;
505       /* ISPC workaround for mask == 0 */
506 
507 
508       /* invalidate rays by default */
509       Ray2& primary = primary_stream[N];
510       float primary_tfar = primary.ray.tfar;
511       {
512         primary.ray.tnear() = (float)(pos_inf);
513         primary.ray.tfar  = (float)(neg_inf);
514       }
515 
516       /* ignore invalid rays */
517       if (valid_stream[N] == false) continue;
518       numActive++;
519 
520       /* add light contrinution */
521       float opacity = 1.0f-primary.transparency;
522       Vec3fa diffuse = data.colors[primary.ray.primID];
523       Ray2& shadow = shadow_stream[N];
524       if (shadow.ray.tfar >= 0.0f) {
525         Vec3fa Ll = diffuse*shadow.transparency*clamp(-dot(lightDir,normalize(primary.ray.Ng)),0.0f,1.0f);
526         color_stream[N] = color_stream[N] + weight_stream[N]*opacity*Ll;
527       }
528 
529       /* initialize transmission ray */
530       weight_stream[N] *= primary.transparency;
531       bool mask = 1; {
532         primary.ray.tnear() = mask ? 1.001f*primary_tfar : (float)(pos_inf);
533         primary.ray.tfar  = mask ? (float)(inf)        : (float)(neg_inf);
534       }
535       primary.ray.geomID = RTC_INVALID_GEOMETRY_ID;
536       primary.ray.primID = RTC_INVALID_GEOMETRY_ID;
537       primary.transparency = 0.0f;
538       RayStats_addRay(stats);
539     }
540     N++;
541   }
542 
543   /* framebuffer writeback */
544   N = 0;
545   for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
546   {
547     /* ISPC workaround for mask == 0 */
548 
549 
550     /* write color to framebuffer */
551     unsigned int r = (unsigned int) (255.0f * clamp(color_stream[N].x,0.0f,1.0f));
552     unsigned int g = (unsigned int) (255.0f * clamp(color_stream[N].y,0.0f,1.0f));
553     unsigned int b = (unsigned int) (255.0f * clamp(color_stream[N].z,0.0f,1.0f));
554     pixels[y*width+x] = (b << 16) + (g << 8) + r;
555     N++;
556   }
557 }
558 
559 /******************************************************************************************/
560 /*                              Scene Creation                                            */
561 /******************************************************************************************/
562 
563 #define NUM_VERTICES 8
564 #define NUM_QUAD_INDICES 24
565 #define NUM_TRI_INDICES 36
566 #define NUM_QUAD_FACES 6
567 #define NUM_TRI_FACES 12
568 
569 __aligned(16) float cube_vertices[NUM_VERTICES][4] =
570 {
571   { -1, -1, -1, 0 },
572   { -1, -1, +1, 0 },
573   { -1, +1, -1, 0 },
574   { -1, +1, +1, 0 },
575   { +1, -1, -1, 0 },
576   { +1, -1, +1, 0 },
577   { +1, +1, -1, 0 },
578   { +1, +1, +1, 0 },
579 };
580 
581 unsigned int cube_quad_indices[NUM_QUAD_INDICES] = {
582   0, 1, 3, 2,
583   5, 4, 6, 7,
584   0, 4, 5, 1,
585   6, 2, 3, 7,
586   0, 2, 6, 4,
587   3, 1, 5, 7
588 };
589 
590 unsigned int cube_tri_indices[NUM_TRI_INDICES] = {
591   0, 1, 2,  2, 1, 3,
592   5, 4, 7,  7, 4, 6,
593   0, 4, 1,  1, 4, 5,
594   6, 2, 7,  7, 2, 3,
595   0, 2, 4,  4, 2, 6,
596   3, 1, 7,  7, 1, 5
597 };
598 
599 unsigned int cube_quad_faces[NUM_QUAD_FACES] = {
600   4, 4, 4, 4, 4, 4
601 };
602 
603 /* adds a cube to the scene */
addCube(RTCScene scene_i,const Vec3fa & offset,const Vec3fa & scale,float rotation)604 unsigned int addCube (RTCScene scene_i, const Vec3fa& offset, const Vec3fa& scale, float rotation)
605 {
606   /* create a triangulated cube with 12 triangles and 8 vertices */
607   RTCGeometry geom = rtcNewGeometry (g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
608   //rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, cube_vertices,     0, sizeof(Vec3fa  ), NUM_VERTICES);
609   Vec3fa* ptr = (Vec3fa*) rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vec3fa), NUM_VERTICES);
610   for (unsigned int i=0; i<NUM_VERTICES; i++) {
611     float x = cube_vertices[i][0];
612     float y = cube_vertices[i][1];
613     float z = cube_vertices[i][2];
614     Vec3fa vtx = Vec3fa(x,y,z);
615     ptr[i] = Vec3fa(offset+LinearSpace3fa::rotate(Vec3fa(0,1,0),rotation)*LinearSpace3fa::scale(scale)*vtx);
616   }
617   rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, cube_tri_indices, 0, 3*sizeof(unsigned int), NUM_TRI_FACES);
618 
619   /* create per-triangle color array */
620   data.colors = (Vec3fa*) alignedMalloc(12*sizeof(Vec3fa),16);
621   data.colors[0] = Vec3fa(1,0,0); // left side
622   data.colors[1] = Vec3fa(1,0,0);
623   data.colors[2] = Vec3fa(0,1,0); // right side
624   data.colors[3] = Vec3fa(0,1,0);
625   data.colors[4] = Vec3fa(0.5f);  // bottom side
626   data.colors[5] = Vec3fa(0.5f);
627   data.colors[6] = Vec3fa(1.0f);  // top side
628   data.colors[7] = Vec3fa(1.0f);
629   data.colors[8] = Vec3fa(0,0,1); // front side
630   data.colors[9] = Vec3fa(0,0,1);
631   data.colors[10] = Vec3fa(1,1,0); // back side
632   data.colors[11] = Vec3fa(1,1,0);
633 
634   /* set intersection filter for the cube */
635   if (g_mode == MODE_NORMAL && nativePacketSupported(g_device))
636   {
637     rtcSetGeometryIntersectFilterFunction(geom,intersectionFilter);
638     rtcSetGeometryOccludedFilterFunction(geom,occlusionFilter);
639   }
640   else
641   {
642     rtcSetGeometryIntersectFilterFunction(geom,intersectionFilterN);
643     rtcSetGeometryOccludedFilterFunction(geom,occlusionFilterN);
644   }
645 
646   rtcCommitGeometry(geom);
647   unsigned int geomID = rtcAttachGeometry(scene_i,geom);
648   rtcReleaseGeometry(geom);
649   return geomID;
650 }
651 
652 /* adds a cube to the scene */
addSubdivCube(RTCScene scene_i)653 unsigned int addSubdivCube (RTCScene scene_i)
654 {
655   RTCGeometry geom = rtcNewGeometry(g_device, RTC_GEOMETRY_TYPE_SUBDIVISION);
656   rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, cube_vertices,      0, sizeof(Vec3fa),       NUM_VERTICES);
657   rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX,  0, RTC_FORMAT_UINT,   cube_quad_indices,  0, sizeof(unsigned int), NUM_QUAD_INDICES);
658   rtcSetSharedGeometryBuffer(geom, RTC_BUFFER_TYPE_FACE,   0, RTC_FORMAT_UINT,   cube_quad_faces,    0, sizeof(unsigned int), NUM_QUAD_FACES);
659 
660   float* level = (float*) rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_LEVEL, 0, RTC_FORMAT_FLOAT, sizeof(float), NUM_QUAD_INDICES);
661   for (unsigned int i=0; i<NUM_QUAD_INDICES; i++) level[i] = 4;
662 
663   /* create face color array */
664   data.colors = (Vec3fa*) alignedMalloc(6*sizeof(Vec3fa),16);
665   data.colors[0] = Vec3fa(1,0,0); // left side
666   data.colors[1] = Vec3fa(0,1,0); // right side
667   data.colors[2] = Vec3fa(0.5f);  // bottom side
668   data.colors[3] = Vec3fa(1.0f);  // top side
669   data.colors[4] = Vec3fa(0,0,1); // front side
670   data.colors[5] = Vec3fa(1,1,0); // back side
671 
672   /* set intersection filter for the cube */
673   if (g_mode == MODE_NORMAL && nativePacketSupported(g_device))
674   {
675     rtcSetGeometryIntersectFilterFunction(geom,intersectionFilter);
676     rtcSetGeometryOccludedFilterFunction(geom,occlusionFilter);
677   }
678   else
679   {
680     rtcSetGeometryIntersectFilterFunction(geom,intersectionFilterN);
681     rtcSetGeometryOccludedFilterFunction(geom,occlusionFilterN);
682   }
683 
684   rtcCommitGeometry(geom);
685   unsigned int geomID = rtcAttachGeometry(scene_i,geom);
686   rtcReleaseGeometry(geom);
687   return geomID;
688 }
689 
690 /* adds a ground plane to the scene */
addGroundPlane(RTCScene scene_i)691 unsigned int addGroundPlane (RTCScene scene_i)
692 {
693   /* create a triangulated plane with 2 triangles and 4 vertices */
694   RTCGeometry geom = rtcNewGeometry (g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
695 
696   /* set vertices */
697   Vertex* vertices = (Vertex*) rtcSetNewGeometryBuffer(geom,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,sizeof(Vertex),4);
698   vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10;
699   vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10;
700   vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10;
701   vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10;
702 
703   /* set triangles */
704   Triangle* triangles = (Triangle*) rtcSetNewGeometryBuffer(geom,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,sizeof(Triangle),2);
705   triangles[0].v0 = 0; triangles[0].v1 = 1; triangles[0].v2 = 2;
706   triangles[1].v0 = 1; triangles[1].v1 = 3; triangles[1].v2 = 2;
707 
708   rtcCommitGeometry(geom);
709   unsigned int geomID = rtcAttachGeometry(scene_i,geom);
710   rtcReleaseGeometry(geom);
711   return geomID;
712 }
713 
714 /* called by the C++ code for initialization */
device_init(char * cfg)715 extern "C" void device_init (char* cfg)
716 {
717   /* create scene */
718   g_scene = data.g_scene = rtcNewScene(g_device);
719   rtcSetSceneBuildQuality(data.g_scene, RTC_BUILD_QUALITY_HIGH); // high quality mode to test if we filter out duplicated intersections
720 
721   /* add cube */
722   addCube(data.g_scene,Vec3fa(0.0f,0.0f,0.0f),Vec3fa(10.0f,1.0f,1.0f),45.0f);
723   //addSubdivCube(data.g_scene);
724 
725   /* add ground plane */
726   addGroundPlane(data.g_scene);
727 
728   /* commit changes to scene */
729   rtcCommitScene (data.g_scene);
730 }
731 
732 /* task that renders a single screen tile */
renderTileTask(int taskIndex,int threadIndex,int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera,const int numTilesX,const int numTilesY)733 void renderTileTask (int taskIndex, int threadIndex, int* pixels,
734                          const unsigned int width,
735                          const unsigned int height,
736                          const float time,
737                          const ISPCCamera& camera,
738                          const int numTilesX,
739                          const int numTilesY)
740 {
741   if (g_mode == MODE_NORMAL)
742     renderTileStandard(taskIndex,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
743   else
744     renderTileStandardStream(taskIndex,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
745 }
746 
renderFrameStandard(int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera)747 extern "C" void renderFrameStandard (int* pixels,
748                           const unsigned int width,
749                           const unsigned int height,
750                           const float time,
751                           const ISPCCamera& camera)
752 {
753   const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X;
754   const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y;
755   parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range<size_t>& range) {
756     const int threadIndex = (int)TaskScheduler::threadIndex();
757     for (size_t i=range.begin(); i<range.end(); i++)
758       renderTileTask((int)i,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
759   });
760 }
761 
762 /* called by the C++ code to render */
device_render(int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera)763 extern "C" void device_render (int* pixels,
764                            const unsigned int width,
765                            const unsigned int height,
766                            const float time,
767                            const ISPCCamera& camera)
768 {
769 }
770 
771 /* called by the C++ code for cleanup */
device_cleanup()772 extern "C" void device_cleanup ()
773 {
774   TutorialData_Destructor(&data);
775 }
776 
777 } // namespace embree
778