// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #include "intersection_filter_device.h" namespace embree { RTCScene g_scene = nullptr; TutorialData data; // FIXME: fast path for occlusionFilter /******************************************************************************************/ /* Standard Mode */ /******************************************************************************************/ #define HIT_LIST_LENGTH 16 /* extended ray structure that includes total transparency along the ray */ struct Ray2 { Ray ray; // ray extensions float transparency; //!< accumulated transparency value // we remember up to 16 hits to ignore duplicate hits unsigned int firstHit, lastHit; unsigned int hit_geomIDs[HIT_LIST_LENGTH]; unsigned int hit_primIDs[HIT_LIST_LENGTH]; }; inline RTCRayHit* RTCRayHit_(Ray2& ray) { RTCRayHit* ray_ptr = (RTCRayHit*)&ray; return ray_ptr; } inline RTCRay* RTCRay_(Ray2& ray) { RTCRay* ray_ptr = (RTCRay*)&ray; return ray_ptr; } /* 3D procedural transparency */ inline float transparencyFunction(Vec3fa& h) { float v = abs(sin(4.0f*h.x)*cos(4.0f*h.y)*sin(4.0f*h.z)); float T = clamp((v-0.1f)*3.0f,0.0f,1.0f); return T; //return 0.5f; } /* task that renders a single screen tile */ void 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) { float weight = 1.0f; Vec3fa color = Vec3fa(0.0f); IntersectContext context; InitIntersectionContext(&context); /* initialize ray */ Ray2 primary; 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); primary.ray.id = 0; // needs to encode rayID for filter primary.transparency = 0.0f; while (true) { context.userRayExt = &primary; /* intersect ray with scene */ rtcIntersect1(data.g_scene,&context.context,RTCRayHit_(primary)); RayStats_addRay(stats); /* shade pixels */ if (primary.ray.geomID == RTC_INVALID_GEOMETRY_ID) break; float opacity = 1.0f-primary.transparency; Vec3fa diffuse = data.colors[primary.ray.primID]; Vec3fa La = diffuse*0.5f; color = color + weight*opacity*La; Vec3fa lightDir = normalize(Vec3fa(-1,-1,-1)); /* initialize shadow ray */ Ray2 shadow; init_Ray(shadow.ray, primary.ray.org + primary.ray.tfar*primary.ray.dir, neg(lightDir), 0.001f, inf); shadow.ray.id = 0; // needs to encode rayID for filter shadow.transparency = 1.0f; shadow.firstHit = 0; shadow.lastHit = 0; context.userRayExt = &shadow; /* trace shadow ray */ rtcOccluded1(data.g_scene,&context.context,RTCRay_(shadow)); RayStats_addShadowRay(stats); /* add light contribution */ if (shadow.ray.tfar >= 0.0f) { Vec3fa Ll = diffuse*shadow.transparency*clamp(-dot(lightDir,normalize(primary.ray.Ng)),0.0f,1.0f); color = color + weight*opacity*Ll; } /* shoot transmission ray */ weight *= primary.transparency; primary.ray.tnear() = 1.001f*primary.ray.tfar; primary.ray.tfar = (float)(inf); primary.ray.geomID = RTC_INVALID_GEOMETRY_ID; primary.ray.primID = RTC_INVALID_GEOMETRY_ID; primary.transparency = 0.0f; } /* write color to framebuffer */ unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f)); unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f)); unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f)); pixels[y*width+x] = (b << 16) + (g << 8) + r; } /* renders a single screen tile */ void 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) { const unsigned int tileY = taskIndex / numTilesX; const unsigned int tileX = taskIndex - tileY * numTilesX; const unsigned int x0 = tileX * TILE_SIZE_X; const unsigned int x1 = min(x0+TILE_SIZE_X,width); const unsigned int y0 = tileY * TILE_SIZE_Y; const unsigned int y1 = min(y0+TILE_SIZE_Y,height); for (unsigned int y=y0; ycontext == nullptr) return; assert(args->N == 1); int* valid = args->valid; const IntersectContext* context = (const IntersectContext*) args->context; Ray* ray = (Ray*)args->ray; //RTCHit* hit = (RTCHit*)args->hit; /* ignore inactive rays */ if (valid[0] != -1) return; /* calculate transparency */ Vec3fa h = ray->org + ray->dir * ray->tfar; float T = transparencyFunction(h); /* ignore hit if completely transparent */ if (T >= 1.0f) valid[0] = 0; /* otherwise accept hit and remember transparency */ else { Ray2* eray = (Ray2*) context->userRayExt; eray->transparency = T; } } /* intersection filter function for streams of general packets */ void intersectionFilterN(const RTCFilterFunctionNArguments* args) { int* valid = args->valid; const IntersectContext* context = (const IntersectContext*) args->context; struct RTCRayHitN* rayN = (struct RTCRayHitN*)args->ray; //struct RTCHitN* hitN = args->hit; const unsigned int N = args->N; /* avoid crashing when debug visualizations are used */ if (context == nullptr) return; /* iterate over all rays in ray packet */ for (unsigned int ui=0; ui=N) continue; /* ignore inactive rays */ if (valid[vi] != -1) continue; /* read ray/hit from ray structure */ RTCRayHit rtc_ray = rtcGetRayHitFromRayHitN(rayN,N,ui); Ray* ray = (Ray*)&rtc_ray; /* calculate transparency */ Vec3fa h = ray->org + ray->dir * ray->tfar; float T = transparencyFunction(h); /* ignore hit if completely transparent */ if (T >= 1.0f) valid[vi] = 0; /* otherwise accept hit and remember transparency */ else { /* decode ray IDs */ const unsigned int pid = ray->id / 1; const unsigned int rid = ray->id % 1; Ray2* ray2 = (Ray2*) context->userRayExt; assert(ray2); scatter(ray2->transparency,sizeof(Ray2),pid,rid,T); } } } /* occlusion filter function for single rays and packets */ void occlusionFilter(const RTCFilterFunctionNArguments* args) { /* avoid crashing when debug visualizations are used */ if (args->context == nullptr) return; assert(args->N == 1); int* valid = args->valid; const IntersectContext* context = (const IntersectContext*) args->context; Ray* ray = (Ray*)args->ray; RTCHit* hit = (RTCHit*)args->hit; /* ignore inactive rays */ if (valid[0] != -1) return; Ray2* ray2 = (Ray2*) context->userRayExt; assert(ray2); for (unsigned int i=ray2->firstHit; ilastHit; i++) { unsigned slot= i%HIT_LIST_LENGTH; if (ray2->hit_geomIDs[slot] == hit->geomID && ray2->hit_primIDs[slot] == hit->primID) { valid[0] = 0; return; // ignore duplicate intersections } } /* store hit in hit list */ unsigned int slot = ray2->lastHit%HIT_LIST_LENGTH; ray2->hit_geomIDs[slot] = hit->geomID; ray2->hit_primIDs[slot] = hit->primID; ray2->lastHit++; if (ray2->lastHit - ray2->firstHit >= HIT_LIST_LENGTH) ray2->firstHit++; Vec3fa h = ray->org + ray->dir * ray->tfar; /* calculate and accumulate transparency */ float T = transparencyFunction(h); T *= ray2->transparency; ray2->transparency = T; if (T != 0.0f) valid[0] = 0; } /* intersection filter function for streams of general packets */ void occlusionFilterN(const RTCFilterFunctionNArguments* args) { int* valid = args->valid; const IntersectContext* context = (const IntersectContext*) args->context; struct RTCRayHitN* rayN = (struct RTCRayHitN*)args->ray; struct RTCHitN* hitN = args->hit; const unsigned int N = args->N; /* avoid crashing when debug visualizations are used */ if (context == nullptr) return; /* iterate over all rays in ray packet */ for (unsigned int ui=0; ui=N) continue; /* ignore inactive rays */ if (valid[vi] != -1) continue; /* read ray/hit from ray structure */ RTCRayHit rtc_ray = rtcGetRayHitFromRayHitN(rayN,N,ui); Ray* ray = (Ray*)&rtc_ray; RTCHit hit = rtcGetHitFromHitN(hitN,N,ui); const unsigned int hit_geomID = hit.geomID; const unsigned int hit_primID = hit.primID; /* decode ray IDs */ const unsigned int pid = ray->id / 1; const unsigned int rid = ray->id % 1; Ray2* ray2 = (Ray2*) context->userRayExt; assert(ray2); /* The occlusion filter function may be called multiple times with * the same hit. We remember the last N hits, and skip duplicates. */ unsigned int ray2_firstHit = gather(ray2->firstHit,sizeof(Ray2),pid,rid); unsigned int ray2_lastHit = gather(ray2->lastHit ,sizeof(Ray2),pid,rid); for (unsigned int i=ray2_firstHit; ihit_geomIDs[0],slot,sizeof(Ray2),pid,rid); unsigned int last_primID = gather(ray2->hit_primIDs[0],slot,sizeof(Ray2),pid,rid); if (last_geomID == hit_geomID && last_primID == hit_primID) { valid[vi] = 0; break; // ignore duplicate intersections } } if (!valid[vi]) continue; /* store hit in hit list */ unsigned int slot = ray2_lastHit%HIT_LIST_LENGTH; scatter(ray2->hit_geomIDs[0],slot,sizeof(Ray2),pid,rid,hit_geomID); scatter(ray2->hit_primIDs[0],slot,sizeof(Ray2),pid,rid,hit_primID); ray2_lastHit++; scatter(ray2->lastHit,sizeof(Ray2),pid,rid,ray2_lastHit); if (ray2_lastHit - ray2_firstHit >= HIT_LIST_LENGTH) scatter(ray2->firstHit,sizeof(Ray2),pid,rid,ray2_firstHit+1); /* calculate transparency */ Vec3fa h = ray->org + ray->dir * ray->tfar; float T = transparencyFunction(h); /* accumulate transparency and store inside ray extensions */ T *= gather(ray2->transparency,sizeof(Ray2),pid,rid); scatter(ray2->transparency,sizeof(Ray2),pid,rid,T); /* reject a hit if not fully opqaue */ if (T != 0.0f) valid[vi] = 0; } } /* renders a single screen tile */ void 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) { const unsigned int tileY = taskIndex / numTilesX; const unsigned int tileX = taskIndex - tileY * numTilesX; const unsigned int x0 = tileX * TILE_SIZE_X; const unsigned int x1 = min(x0+TILE_SIZE_X,width); const unsigned int y0 = tileY * TILE_SIZE_Y; const unsigned int y1 = min(y0+TILE_SIZE_Y,height); RayStats& stats = g_stats[threadIndex]; Ray2 primary_stream[TILE_SIZE_X*TILE_SIZE_Y]; Ray2 shadow_stream[TILE_SIZE_X*TILE_SIZE_Y]; Vec3fa color_stream[TILE_SIZE_X*TILE_SIZE_Y]; float weight_stream[TILE_SIZE_X*TILE_SIZE_Y]; bool valid_stream[TILE_SIZE_X*TILE_SIZE_Y]; /* generate stream of primary rays */ int N = 0; int numActive = 0; for (unsigned int y=y0; y= 0.0f) { Vec3fa Ll = diffuse*shadow.transparency*clamp(-dot(lightDir,normalize(primary.ray.Ng)),0.0f,1.0f); color_stream[N] = color_stream[N] + weight_stream[N]*opacity*Ll; } /* initialize transmission ray */ weight_stream[N] *= primary.transparency; bool mask = 1; { primary.ray.tnear() = mask ? 1.001f*primary_tfar : (float)(pos_inf); primary.ray.tfar = mask ? (float)(inf) : (float)(neg_inf); } primary.ray.geomID = RTC_INVALID_GEOMETRY_ID; primary.ray.primID = RTC_INVALID_GEOMETRY_ID; primary.transparency = 0.0f; RayStats_addRay(stats); } N++; } /* framebuffer writeback */ N = 0; for (unsigned int y=y0; y& range) { const int threadIndex = (int)TaskScheduler::threadIndex(); for (size_t i=range.begin(); i