c++ - Embree: stream mode - how does gather and scatter work and what are pid and tid?
问题描述
I'm trying to upgrade my application from single ray intersection to stream intersection.
What I don't quite understand is how it's possible that the gather
and scatter
functions shown in the tutorials are even working
The example defines a custom extended ray struct Ray2
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];
};
then it defines an array of these Ray2
structs:
Ray2 primary_stream[TILE_SIZE_X*TILE_SIZE_Y];
this array is set as the userRayExt before calling the intersection method:
primary_context.userRayExt = &primary_stream;
rtcIntersect1M(data.g_scene,&primary_context.context,(RTCRayHit*)&primary_stream,N,sizeof(Ray2));
now, for each ray bundle that embree intersects with geometry, the filter callback is invoked:
/* 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; ui+=1)
{
/* calculate loop and execution mask */
unsigned int vi = ui+0;
if (vi>=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);
}
}
}
the last line of this method is what I don't understand
scatter(ray2->transparency,sizeof(Ray2),pid,rid,T);
I understand what it is SUPPOSED to do. It should update the transparency property of the Ray2
that corresponds to the traced ray with T. But I don't get why/how this works, since the implementation of scatter
looks like this:
inline void scatter(float& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid, float v) {
((float*)(((char*)&ptr) + pid*stride))[rid] = v;
}
I will reformulate this function a bit to better ask my question (but it should be completely equivalent if I'm not mistaken):
inline void scatter(float& ptr, const unsigned int stride, const unsigned int pid, const unsigned int rid, float v) {
float* uptr = ((float*)(((char*)&ptr) + pid*stride));
uptr[rid] = v;
}
So, the first line still makes sense for me. A pointer to the transparency field of the first Ray2 struct is constructed and then incremented by tid * sizeof(Ray2)
- this makes sense as it will land on another transparency
field, since it is incremented by a multiple of sizeof(Ray2)
but then the next line
uptr[rid] = v;
I don't get at all. uptr
is a float pointer, pointing to a transparency field. So unless rid
itself is a multiple of sizeof(Ray2)
, this won't point to a transparency field of one of the rays at all.
pid
and rid
are calculated as
const unsigned int pid = ray->id / 1;
const unsigned int rid = ray->id % 1;
which I find weird. Isn't that always the same as
const unsigned int pid = ray->id;
const unsigned int rid = 0;
?
what are pid
and rid
and why are they computed like this?
解决方案
我自己没有写这个例子,很难猜出它的初衷是什么,但我认为线索恰恰在于你的观察,即对于 rid 和 pid 计算,除以 '1' 的除法/模数是没有意义的。
因此,如果rid 最终总是以“0”结束(因为每个值 mod 1 将是 0 :-/),则uptr[rid] = ...
相当于*uptr = ...
,这实际上是正确的,因为您自己指出它uptr
总是指向有效的透明度。
现在至于为什么代码会做这个令人困惑的 pid/rid 事情?如果我不得不从“Ray2”的命名中猜测,我会假设这个样本的不同版本可能在那个 ray2 结构中使用了两条光线和两个透明度,然后使用 rid/pid 东西来始终选择正确的一个一对。
尽管如此,关于“为什么这完全有效”的原始问题:rid 总是评估为 0,所以它总是直接写入uptr
指向的透明度值。
推荐阅读
- php - [verb]升级到 7.x 后测试中的 Json() 方法不遵守 config('app.url')
- c# - 将列表列表绑定到 DataGridView
- flutter - 用于颤振的 google_fonts 包中的字体是否自动存储在缓存中?
- python - 具有反向引用与用户表相关的其他表的字段集
- python - 如何移动图标?
- php - WooCommerce/Stripe 动作挂钩不起作用
- python-3.x - 如何替换此列表中的 None 值?
- laravel - Laravel - 如何在忘记密码中添加自定义字段
- ipc - macOS 上带有系统扩展的 IPC
- r - 在 R 中按组创建连续年份计数