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