1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include "../common/tutorial/tutorial_device.h"
5 
6 namespace embree {
7 
8 #if 0
9   const int numSpheres = 1000;
10   const int numPhi = 5;
11 #else
12   const int numSpheres = 20;
13   const int numPhi = 120;
14   //const int numPhi = 256;
15 #endif
16   const int numTheta = 2 * numPhi;
17 
18   /* scene data */
19   RTCScene  g_scene = nullptr;
20   RTCScene  g_scene_0 = nullptr;
21   RTCScene  g_scene_1 = nullptr;
22   RTCScene  g_scene_2 = nullptr;
23   RTCScene* g_curr_scene = nullptr;
24   Vec3fa position[numSpheres];
25   Vec3fa colors0[numSpheres + 1];
26   Vec3fa colors1[numSpheres/2 + 1];
27   Vec3fa colors2[numSpheres/2 + 1];
28   Vec3fa* colors;
29   float radius[numSpheres];
30   int disabledID = -1;
31   int g_scene_id = 0;
32 
33   /* adds a sphere to the scene */
createSphere(RTCScene scene,RTCBuildQuality quality,const Vec3fa & pos,const float r)34   unsigned int createSphere(RTCScene scene, RTCBuildQuality quality, const Vec3fa& pos, const float r)
35   {
36     /* create a triangulated sphere */
37     RTCGeometry geom = rtcNewGeometry(g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
38     rtcSetGeometryBuildQuality(geom, quality);
39 
40     /* map triangle and vertex buffer */
41     Vertex* vertices = (Vertex*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vertex), numTheta * (numPhi + 1));
42     Triangle* triangles = (Triangle*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(Triangle), 2 * numTheta * (numPhi - 1));
43 
44     /* create sphere geometry */
45     int tri = 0;
46     const float rcpNumTheta = rcp((float)numTheta);
47     const float rcpNumPhi = rcp((float)numPhi);
48     for (int phi = 0; phi <= numPhi; phi++)
49     {
50       for (int theta = 0; theta < numTheta; theta++)
51       {
52         const float phif = phi * float(pi) * rcpNumPhi;
53         const float thetaf = theta * 2.0f * float(pi) * rcpNumTheta;
54         Vertex& v = vertices[phi * numTheta + theta];
55         v.x = pos.x + r * sin(phif) * sin(thetaf);
56         v.y = pos.y + r * cos(phif);
57         v.z = pos.z + r * sin(phif) * cos(thetaf);
58       }
59       if (phi == 0) continue;
60 
61       for (int theta = 1; theta <= numTheta; theta++)
62       {
63         int p00 = (phi - 1) * numTheta + theta - 1;
64         int p01 = (phi - 1) * numTheta + theta % numTheta;
65         int p10 = phi * numTheta + theta - 1;
66         int p11 = phi * numTheta + theta % numTheta;
67 
68         if (phi > 1) {
69           triangles[tri].v0 = p10;
70           triangles[tri].v1 = p01;
71           triangles[tri].v2 = p00;
72           tri++;
73         }
74 
75         if (phi < numPhi) {
76           triangles[tri].v0 = p11;
77           triangles[tri].v1 = p01;
78           triangles[tri].v2 = p10;
79           tri++;
80         }
81       }
82     }
83 
84     rtcCommitGeometry(geom);
85     unsigned int geomID = rtcAttachGeometry(scene, geom);
86     rtcReleaseGeometry(geom);
87     return geomID;
88   }
89 
90   /* adds a ground plane to the scene */
addGroundPlane(RTCScene scene_i)91   unsigned int addGroundPlane(RTCScene scene_i)
92   {
93     /* create a triangulated plane with 2 triangles and 4 vertices */
94     RTCGeometry geom = rtcNewGeometry(g_device, RTC_GEOMETRY_TYPE_TRIANGLE);
95 
96     /* set vertices */
97     Vertex* vertices = (Vertex*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vertex), 4);
98     vertices[0].x = -10; vertices[0].y = -2; vertices[0].z = -10;
99     vertices[1].x = -10; vertices[1].y = -2; vertices[1].z = +10;
100     vertices[2].x = +10; vertices[2].y = -2; vertices[2].z = -10;
101     vertices[3].x = +10; vertices[3].y = -2; vertices[3].z = +10;
102 
103     /* set triangles */
104     Triangle* triangles = (Triangle*)rtcSetNewGeometryBuffer(geom, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(Triangle), 2);
105     triangles[0].v0 = 0; triangles[0].v1 = 1; triangles[0].v2 = 2;
106     triangles[1].v0 = 1; triangles[1].v1 = 3; triangles[1].v2 = 2;
107 
108     rtcCommitGeometry(geom);
109     unsigned int geomID = rtcAttachGeometry(scene_i, geom);
110     rtcReleaseGeometry(geom);
111     return geomID;
112   }
113 
114   /* called by the C++ code for initialization */
device_init(char * cfg)115   extern "C" void device_init(char* cfg)
116   {
117     /* create scene */
118     g_scene_0 = rtcNewScene(g_device);
119     g_scene_1 = rtcNewScene(g_device);
120     g_scene_2 = rtcNewScene(g_device);
121 
122     rtcSetSceneFlags(g_scene_0,RTC_SCENE_FLAG_DYNAMIC | RTC_SCENE_FLAG_ROBUST);
123     rtcSetSceneBuildQuality(g_scene_0,RTC_BUILD_QUALITY_LOW);
124 
125     rtcSetSceneFlags(g_scene_1,RTC_SCENE_FLAG_DYNAMIC | RTC_SCENE_FLAG_ROBUST);
126     rtcSetSceneBuildQuality(g_scene_1,RTC_BUILD_QUALITY_LOW);
127 
128     //rtcSetSceneFlags(g_scene_2,RTC_SCENE_FLAG_DYNAMIC | RTC_SCENE_FLAG_ROBUST);
129     //rtcSetSceneBuildQuality(g_scene_2,RTC_BUILD_QUALITY_LOW);
130 
131     /* create some triangulated spheres */
132     for (int i = 0; i < numSpheres; i++)
133     {
134       const float phi = i * 2.0f * float(pi) / numSpheres;
135       const float r = 2.0f * float(pi) / numSpheres;
136       const Vec3fa p = 2.0f * Vec3fa(sin(phi), 0.0f, -cos(phi));
137       //RTCBuildQuality quality = i%3 == 0 ? RTC_BUILD_QUALITY_MEDIUM : i%3 == 1 ? RTC_BUILD_QUALITY_REFIT : RTC_BUILD_QUALITY_LOW;
138       RTCBuildQuality quality = i % 2 ? RTC_BUILD_QUALITY_REFIT : RTC_BUILD_QUALITY_LOW;
139       //RTCBuildQuality quality = RTC_BUILD_QUALITY_REFIT;
140       //RTCBuildQuality quality = RTC_BUILD_QUALITY_LOW;
141       int id0 = createSphere(g_scene_0, quality, p, r);
142       position[id0] = p;
143       radius[id0] = r;
144       colors0[id0].x = (i % 16 + 1) / 17.0f;
145       colors0[id0].y = (i % 8 + 1) / 9.0f;
146       colors0[id0].z = (i % 4 + 1) / 5.0f;
147       if (i < (numSpheres / 2)) {
148         int id1 = rtcAttachGeometry(g_scene_1, rtcGetGeometry (g_scene_0, id0));
149         colors1[id1] = colors0[id0];
150       }
151       else {
152         int id2 = rtcAttachGeometry(g_scene_2, rtcGetGeometry(g_scene_0, id0));
153         colors2[id2] = colors0[id0];
154       }
155     }
156 
157     /* add ground plane to scene */
158     int id0 = addGroundPlane(g_scene_0);
159     int id1 = rtcAttachGeometry(g_scene_1, rtcGetGeometry(g_scene_0, id0));
160     int id2 = rtcAttachGeometry(g_scene_2, rtcGetGeometry(g_scene_0, id0));
161     colors0[id0] = Vec3fa(1.0f, 1.0f, 1.0f);
162     colors1[id1] = colors0[id0];
163     colors2[id2] = colors0[id0];
164 
165     /* commit changes to scene */
166     rtcCommitScene(g_scene_0);
167     rtcCommitScene(g_scene_1);
168     rtcCommitScene(g_scene_2);
169 
170     /* First render scene1 to check if it got properly
171      * committed even though scene_0 containing all
172      * geometries got already build. */
173     g_scene_id = 1;
174   }
175 
176   /* animates the sphere */
animateSphere(int taskIndex,int threadIndex,Vertex * vertices,const float rcpNumTheta,const float rcpNumPhi,const Vec3fa & pos,const float r,const float f)177   void animateSphere(int taskIndex, int threadIndex, Vertex* vertices,
178                      const float rcpNumTheta,
179                      const float rcpNumPhi,
180                      const Vec3fa& pos,
181                      const float r,
182                      const float f)
183   {
184     int phi = taskIndex;
185     for (unsigned int theta = 0; theta < numTheta; theta++)
186     {
187       Vertex* v = &vertices[phi * numTheta + theta];
188       const float phif = phi * float(pi) * rcpNumPhi;
189       const float thetaf = theta * 2.0f * float(pi) * rcpNumTheta;
190       v->x = pos.x + r * sin(f * phif) * sin(thetaf);
191       v->y = pos.y + r * cos(phif);
192       v->z = pos.z + r * sin(f * phif) * cos(thetaf);
193     }
194   }
195 
196   /* task that renders a single screen tile */
renderPixelStandard(float x,float y,const ISPCCamera & camera,RayStats & stats)197   Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera, RayStats& stats)
198   {
199     /* initialize ray */
200     Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x * camera.xfm.l.vx + y * camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f, inf);
201 
202     /* intersect ray with scene */
203     RTCIntersectContext context;
204     rtcInitIntersectContext(&context);
205     rtcIntersect1(*g_curr_scene, &context, RTCRayHit_(ray));
206     RayStats_addRay(stats);
207 
208     /* shade pixels */
209     Vec3fa color = Vec3fa(0.0f);
210     if (ray.geomID != RTC_INVALID_GEOMETRY_ID)
211     {
212       Vec3fa diffuse = colors[ray.geomID];
213       color = color + diffuse * 0.1f;
214       Vec3fa lightDir = normalize(Vec3fa(-1, -1, -1));
215 
216       /* initialize shadow ray */
217       Ray shadow(ray.org + ray.tfar * ray.dir, neg(lightDir), 0.001f, inf);
218 
219       /* trace shadow ray */
220       rtcOccluded1(*g_curr_scene, &context, RTCRay_(shadow));
221       RayStats_addShadowRay(stats);
222 
223       /* add light contribution */
224       if (shadow.tfar >= 0.0f)
225         color = color + diffuse * clamp(-dot(lightDir, normalize(ray.Ng)), 0.0f, 1.0f);
226     }
227     return color;
228   }
229 
230   /* 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)231   void renderTileStandard(int taskIndex,
232                           int threadIndex,
233                           int* pixels,
234                           const unsigned int width,
235                           const unsigned int height,
236                           const float time,
237                           const ISPCCamera& camera,
238                           const int numTilesX,
239                           const int numTilesY)
240   {
241     const unsigned int tileY = taskIndex / numTilesX;
242     const unsigned int tileX = taskIndex - tileY * numTilesX;
243     const unsigned int x0 = tileX * TILE_SIZE_X;
244     const unsigned int x1 = min(x0 + TILE_SIZE_X, width);
245     const unsigned int y0 = tileY * TILE_SIZE_Y;
246     const unsigned int y1 = min(y0 + TILE_SIZE_Y, height);
247 
248     for (unsigned int y = y0; y < y1; y++) for (unsigned int x = x0; x < x1; x++)
249                                            {
250                                              /* calculate pixel color */
251                                              Vec3fa color = renderPixelStandard((float)x, (float)y, camera, g_stats[threadIndex]);
252 
253                                              /* write color to framebuffer */
254                                              unsigned int r = (unsigned int)(255.0f * clamp(color.x, 0.0f, 1.0f));
255                                              unsigned int g = (unsigned int)(255.0f * clamp(color.y, 0.0f, 1.0f));
256                                              unsigned int b = (unsigned int)(255.0f * clamp(color.z, 0.0f, 1.0f));
257                                              pixels[y * width + x] = (b << 16) + (g << 8) + r;
258                                            }
259   }
260 
261   /* 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)262   void renderTileTask(int taskIndex, int threadIndex, int* pixels,
263                       const unsigned int width,
264                       const unsigned int height,
265                       const float time,
266                       const ISPCCamera& camera,
267                       const int numTilesX,
268                       const int numTilesY)
269   {
270     renderTileStandard(taskIndex, threadIndex, pixels, width, height, time, camera, numTilesX, numTilesY);
271   }
272 
273   /* animates a sphere */
animateSphere(int id,float time)274   void animateSphere(int id, float time)
275   {
276     /* animate vertices */
277     RTCGeometry geom = rtcGetGeometry(g_scene_0, id);
278     Vertex* vertices = (Vertex*)rtcGetGeometryBufferData(geom, RTC_BUFFER_TYPE_VERTEX, 0);
279     const float rcpNumTheta = rcp((float)numTheta);
280     const float rcpNumPhi = rcp((float)numPhi);
281     const Vec3fa pos = position[id];
282     const float r = radius[id];
283     const float f = 2.0f * (1.0f + 0.5f * sin(time));
284 
285     /* loop over all vertices */
286 #if 1 // enables parallel execution
287     parallel_for(size_t(0), size_t(numPhi + 1), [&](const range<size_t>& range) {
288         const int threadIndex = (int)TaskScheduler::threadIndex();
289         for (size_t i = range.begin(); i < range.end(); i++)
290           animateSphere((int)i, threadIndex, vertices, rcpNumTheta, rcpNumPhi, pos, r, f);
291       });
292 #else
293     for (unsigned int phi = 0; phi < numPhi + 1; phi++) for (int theta = 0; theta < numTheta; theta++)
294                                                         {
295                                                           Vertex* v = &vertices[phi * numTheta + theta];
296                                                           const float phif = phi * float(pi) * rcpNumPhi;
297                                                           const float thetaf = theta * 2.0f * float(pi) * rcpNumTheta;
298                                                           v->x = pos.x + r * sin(f * phif) * sin(thetaf);
299                                                           v->y = pos.y + r * cos(phif);
300                                                           v->z = pos.z + r * sin(f * phif) * cos(thetaf);
301                                                         }
302 #endif
303 
304     /* commit mesh */
305     rtcUpdateGeometryBuffer(geom, RTC_BUFFER_TYPE_VERTEX, 0);
306     rtcCommitGeometry(geom);
307   }
308 
renderFrameStandard(int * pixels,const unsigned int width,const unsigned int height,const float time,const ISPCCamera & camera)309   extern "C" void renderFrameStandard(int* pixels,
310                            const unsigned int width,
311                            const unsigned int height,
312                            const float time,
313                            const ISPCCamera & camera)
314   {
315     /* render all pixels */
316     const int numTilesX = (width + TILE_SIZE_X - 1) / TILE_SIZE_X;
317     const int numTilesY = (height + TILE_SIZE_Y - 1) / TILE_SIZE_Y;
318     parallel_for(size_t(0), size_t(numTilesX * numTilesY), [&](const range<size_t>& range) {
319         const int threadIndex = (int)TaskScheduler::threadIndex();
320         for (size_t i = range.begin(); i < range.end(); i++)
321           renderTileTask((int)i, threadIndex, pixels, width, height, time, camera, numTilesX, numTilesY);
322       });
323   }
324 
325   /* 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)326   extern "C" void device_render(int* pixels,
327                                 const unsigned int width,
328                                 const unsigned int height,
329                                 const float time,
330                                 const ISPCCamera & camera)
331   {
332     /* configure rendering of selected scene */
333     switch (g_scene_id)
334     {
335     case 0:
336       g_curr_scene = &g_scene_0;
337       colors = &(colors0[0]);
338       break;
339     case 1:
340       g_curr_scene = &g_scene_1;
341       colors = &(colors1[0]);
342       break;
343     case 2:
344       g_curr_scene = &g_scene_2;
345       colors = &(colors2[0]);
346       break;
347     }
348 
349     /* animate sphere */
350     for (int i = 0; i < numSpheres; i++)
351       animateSphere(i, time + i);
352 
353     /* commit changes to scene */
354     //rtcCommitScene(*g_curr_scene);
355     rtcCommitScene(g_scene_0);
356     rtcCommitScene(g_scene_1);
357     rtcCommitScene(g_scene_2);
358   }
359 
360   /* called by the C++ code for cleanup */
device_cleanup()361   extern "C" void device_cleanup()
362   {
363     rtcReleaseScene(g_scene_0); g_scene_0 = nullptr;
364     rtcReleaseScene(g_scene_1); g_scene_1 = nullptr;
365     rtcReleaseScene(g_scene_2); g_scene_2 = nullptr;
366   }
367 
368 } // namespace embree
369