void BVHNStatistics<N>::statistics(NodeRef node, const float A, size_t& depth) { if (node.isNode()) { numAlignedNodes++; AlignedNode* n = node.node(); bvhSAH += A*travCostAligned; depth = 0; for (size_t i=0; i<N; i++) { if (n->child(i) == BVH::emptyNode) continue; childrenAlignedNodes++; const float Ai = max(0.0f,halfArea(n->extend(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; } else if (node.isUnalignedNode()) { numUnalignedNodes++; UnalignedNode* n = node.unalignedNode(); bvhSAH += A*travCostUnaligned; depth = 0; for (size_t i=0; i<N; i++) { if (n->child(i) == BVH::emptyNode) continue; childrenUnalignedNodes++; const float Ai = max(0.0f,halfArea(n->extend(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; } else if (node.isNodeMB()) { numAlignedNodesMB++; AlignedNodeMB* n = node.nodeMB(); bvhSAH += A*travCostAligned; depth = 0; for (size_t i=0; i<N; i++) { if (n->child(i) == BVH::emptyNode) continue; childrenAlignedNodesMB++; const float Ai = max(0.0f,halfArea(n->extend0(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; } else if (node.isUnalignedNodeMB()) { numUnalignedNodesMB++; UnalignedNodeMB* n = node.unalignedNodeMB(); bvhSAH += A*travCostUnaligned; depth = 0; for (size_t i=0; i<N; i++) { if (n->child(i) == BVH::emptyNode) continue; childrenUnalignedNodesMB++; const float Ai = max(0.0f,halfArea(n->extend0(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; } else if (node.isTransformNode()) { numTransformNodes++; TransformNode* n = node.transformNode(); bvhSAH += A*travCostTransform; depth = 0; const BBox3fa worldBounds = xfmBounds(n->local2world,n->localBounds); const float Ai = max(0.0f,halfArea(worldBounds)); //size_t cdepth; statistics(n->child,Ai,cdepth); //depth=max(depth,cdepth)+1; } else { depth = 0; size_t num; const char* tri = node.leaf(num); if (!num) return; numLeaves++; numPrimBlocks += num; for (size_t i=0; i<num; i++) numPrims += bvh->primTy.size(tri+i*bvh->primTy.bytes); float sah = A * intCost * num; leafSAH += sah; } }
void BVH4Intersector4Hybrid<types,robust,PrimitiveIntersector4>::intersect(bool4* valid_i, BVH4* bvh, Ray4& ray) { /* verify correct input */ bool4 valid0 = *valid_i; #if defined(RTCORE_IGNORE_INVALID_RAYS) valid0 &= ray.valid(); #endif assert(all(valid0,ray.tnear > -FLT_MIN)); assert(!(types & BVH4::FLAG_NODE_MB) || all(valid0,ray.time >= 0.0f & ray.time <= 1.0f)); /* load ray */ Vec3f4 ray_org = ray.org; Vec3f4 ray_dir = ray.dir; float4 ray_tnear = ray.tnear, ray_tfar = ray.tfar; const Vec3f4 rdir = rcp_safe(ray_dir); const Vec3f4 org(ray_org), org_rdir = org * rdir; ray_tnear = select(valid0,ray_tnear,float4(pos_inf)); ray_tfar = select(valid0,ray_tfar ,float4(neg_inf)); const float4 inf = float4(pos_inf); Precalculations pre(valid0,ray); /* compute near/far per ray */ Vec3i4 nearXYZ; nearXYZ.x = select(rdir.x >= 0.0f,int4(0*(int)sizeof(float4)),int4(1*(int)sizeof(float4))); nearXYZ.y = select(rdir.y >= 0.0f,int4(2*(int)sizeof(float4)),int4(3*(int)sizeof(float4))); nearXYZ.z = select(rdir.z >= 0.0f,int4(4*(int)sizeof(float4)),int4(5*(int)sizeof(float4))); /* allocate stack and push root node */ float4 stack_near[stackSizeChunk]; NodeRef stack_node[stackSizeChunk]; stack_node[0] = BVH4::invalidNode; stack_near[0] = inf; stack_node[1] = bvh->root; stack_near[1] = ray_tnear; NodeRef* stackEnd = stack_node+stackSizeChunk; NodeRef* __restrict__ sptr_node = stack_node + 2; float4* __restrict__ sptr_near = stack_near + 2; while (1) pop: { /* pop next node from stack */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; NodeRef cur = *sptr_node; if (unlikely(cur == BVH4::invalidNode)) { assert(sptr_node == stack_node); break; } /* cull node if behind closest hit point */ float4 curDist = *sptr_near; const bool4 active = curDist < ray_tfar; if (unlikely(none(active))) continue; /* switch to single ray traversal */ #if !defined(__WIN32__) || defined(__X86_64__) size_t bits = movemask(active); if (unlikely(__popcnt(bits) <= SWITCH_THRESHOLD)) { for (size_t i=__bsf(bits); bits!=0; bits=__btc(bits,i), i=__bsf(bits)) { BVH4Intersector4Single<types,robust,PrimitiveIntersector4>::intersect1(bvh, cur, i, pre, ray, ray_org, ray_dir, rdir, ray_tnear, ray_tfar, nearXYZ); } ray_tfar = min(ray_tfar,ray.tfar); continue; } #endif while (1) { /* process normal nodes */ if (likely((types & 0x1) && cur.isNode())) { const bool4 valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),4); const Node* __restrict__ const node = cur.node(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->children[i]; if (unlikely(child == BVH4::emptyNode)) break; float4 lnearP; const bool4 lhit = intersect_node<robust>(node,i,org,rdir,org_rdir,ray_tnear,ray_tfar,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); assert(child != BVH4::emptyNode); const float4 childDist = select(lhit,lnearP,inf); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } #if SWITCH_DURING_DOWN_TRAVERSAL == 1 // seems to be the best place for testing utilization if (unlikely(popcnt(ray_tfar > curDist) <= SWITCH_THRESHOLD)) { *sptr_node++ = cur; *sptr_near++ = curDist; goto pop; } #endif } /* process motion blur nodes */ else if (likely((types & 0x10) && cur.isNodeMB())) { const bool4 valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),4); const BVH4::NodeMB* __restrict__ const node = cur.nodeMB(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->child(i); if (unlikely(child == BVH4::emptyNode)) break; float4 lnearP; const bool4 lhit = intersect_node(node,i,org,rdir,org_rdir,ray_tnear,ray_tfar,ray.time,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); assert(child != BVH4::emptyNode); const float4 childDist = select(lhit,lnearP,inf); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } #if SWITCH_DURING_DOWN_TRAVERSAL == 1 // seems to be the best place for testing utilization if (unlikely(popcnt(ray_tfar > curDist) <= SWITCH_THRESHOLD)) { *sptr_node++ = cur; *sptr_near++ = curDist; goto pop; } #endif } else break; }
void BVH4Intersector4Chunk<types,robust,PrimitiveIntersector4>::intersect(sseb* valid_i, BVH4* bvh, Ray4& ray) { /* load ray */ const sseb valid0 = *valid_i; const sse3f rdir = rcp_safe(ray.dir); const sse3f org(ray.org), org_rdir = org * rdir; ssef ray_tnear = select(valid0,ray.tnear,ssef(pos_inf)); ssef ray_tfar = select(valid0,ray.tfar ,ssef(neg_inf)); const ssef inf = ssef(pos_inf); Precalculations pre(valid0,ray); /* allocate stack and push root node */ ssef stack_near[stackSize]; NodeRef stack_node[stackSize]; stack_node[0] = BVH4::invalidNode; stack_near[0] = inf; stack_node[1] = bvh->root; stack_near[1] = ray_tnear; NodeRef* stackEnd = stack_node+stackSize; NodeRef* __restrict__ sptr_node = stack_node + 2; ssef* __restrict__ sptr_near = stack_near + 2; while (1) { /* pop next node from stack */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; NodeRef cur = *sptr_node; if (unlikely(cur == BVH4::invalidNode)) { assert(sptr_node == stack_node); break; } /* cull node if behind closest hit point */ ssef curDist = *sptr_near; if (unlikely(none(ray_tfar > curDist))) continue; while (1) { /* process normal nodes */ if (likely((types & 0x1) && cur.isNode())) { const sseb valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),8); const Node* __restrict__ const node = cur.node(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->children[i]; if (unlikely(child == BVH4::emptyNode)) break; ssef lnearP; const sseb lhit = node->intersect<robust>(i,org,rdir,org_rdir,ray_tnear,ray_tfar,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); const ssef childDist = select(lhit,lnearP,inf); const NodeRef child = node->children[i]; assert(child != BVH4::emptyNode); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } } /* process motion blur nodes */ else if (likely((types & 0x10) && cur.isNodeMB())) { const sseb valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),8); const BVH4::NodeMB* __restrict__ const node = cur.nodeMB(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->child(i); if (unlikely(child == BVH4::emptyNode)) break; ssef lnearP; const sseb lhit = node->intersect(i,org,rdir,org_rdir,ray_tnear,ray_tfar,ray.time,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); assert(child != BVH4::emptyNode); const ssef childDist = select(lhit,lnearP,inf); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } } else break; }
void BVH4Intersector8Chunk<types, robust, PrimitiveIntersector8>::intersect(bool8* valid_i, BVH4* bvh, Ray8& ray) { /* verify correct input */ bool8 valid0 = *valid_i; #if defined(RTCORE_IGNORE_INVALID_RAYS) valid0 &= ray.valid(); #endif assert(all(valid0,ray.tnear > -FLT_MIN)); assert(!(types & BVH4::FLAG_NODE_MB) || all(valid0,ray.time >= 0.0f & ray.time <= 1.0f)); /* load ray */ const Vec3f8 rdir = rcp_safe(ray.dir); const Vec3f8 org(ray.org), org_rdir = org * rdir; float8 ray_tnear = select(valid0,ray.tnear,pos_inf); float8 ray_tfar = select(valid0,ray.tfar ,neg_inf); const float8 inf = float8(pos_inf); Precalculations pre(valid0,ray); /* allocate stack and push root node */ float8 stack_near[stackSize]; NodeRef stack_node[stackSize]; stack_node[0] = BVH4::invalidNode; stack_near[0] = inf; stack_node[1] = bvh->root; stack_near[1] = ray_tnear; NodeRef* stackEnd = stack_node+stackSize; NodeRef* __restrict__ sptr_node = stack_node + 2; float8* __restrict__ sptr_near = stack_near + 2; while (1) { /* pop next node from stack */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; NodeRef cur = *sptr_node; if (unlikely(cur == BVH4::invalidNode)) { assert(sptr_node == stack_node); break; } /* cull node if behind closest hit point */ float8 curDist = *sptr_near; if (unlikely(none(ray_tfar > curDist))) continue; while (1) { /* process normal nodes */ if (likely((types & 0x1) && cur.isNode())) { const bool8 valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),8); const Node* __restrict__ const node = cur.node(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->children[i]; if (unlikely(child == BVH4::emptyNode)) break; float8 lnearP; const bool8 lhit = intersect8_node<robust>(node,i,org,rdir,org_rdir,ray_tnear,ray_tfar,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); assert(child != BVH4::emptyNode); const float8 childDist = select(lhit,lnearP,inf); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } } /* process motion blur nodes */ else if (likely((types & 0x10) && cur.isNodeMB())) { const bool8 valid_node = ray_tfar > curDist; STAT3(normal.trav_nodes,1,popcnt(valid_node),8); const BVH4::NodeMB* __restrict__ const node = cur.nodeMB(); /* pop of next node */ assert(sptr_node > stack_node); sptr_node--; sptr_near--; cur = *sptr_node; curDist = *sptr_near; #pragma unroll(4) for (unsigned i=0; i<BVH4::N; i++) { const NodeRef child = node->child(i); if (unlikely(child == BVH4::emptyNode)) break; float8 lnearP; const bool8 lhit = intersect_node(node,i,org,rdir,org_rdir,ray_tnear,ray_tfar,ray.time,lnearP); /* if we hit the child we choose to continue with that child if it is closer than the current next child, or we push it onto the stack */ if (likely(any(lhit))) { assert(sptr_node < stackEnd); assert(child != BVH4::emptyNode); const float8 childDist = select(lhit,lnearP,inf); sptr_node++; sptr_near++; /* push cur node onto stack and continue with hit child */ if (any(childDist < curDist)) { *(sptr_node-1) = cur; *(sptr_near-1) = curDist; curDist = childDist; cur = child; } /* push hit child onto stack */ else { *(sptr_node-1) = child; *(sptr_near-1) = childDist; } } } } else break; }
void BVH4Intersector1<types,robust,PrimitiveIntersector>::intersect(const BVH4* bvh, Ray& ray) { /*! perform per ray precalculations required by the primitive intersector */ Precalculations pre(ray); BVH4::UnalignedNodeMB::Precalculations pre1(ray); /*! stack state */ StackItemInt32<NodeRef> stack[stackSize]; //!< stack of nodes StackItemInt32<NodeRef>* stackPtr = stack+1; //!< current stack pointer StackItemInt32<NodeRef>* stackEnd = stack+stackSize; stack[0].ptr = bvh->root; stack[0].dist = neg_inf; /*! load the ray into SIMD registers */ const Vec3fa ray_rdir = rcp_safe(ray.dir); const Vec3fa ray_org_rdir = ray.org*ray_rdir; const sse3f org(ray.org.x,ray.org.y,ray.org.z); const sse3f dir(ray.dir.x,ray.dir.y,ray.dir.z); const sse3f rdir(ray_rdir.x,ray_rdir.y,ray_rdir.z); const sse3f org_rdir(ray_org_rdir.x,ray_org_rdir.y,ray_org_rdir.z); const ssef ray_near(ray.tnear); ssef ray_far(ray.tfar); /*! offsets to select the side that becomes the lower or upper bound */ const size_t nearX = ray_rdir.x >= 0.0f ? 0*sizeof(ssef) : 1*sizeof(ssef); const size_t nearY = ray_rdir.y >= 0.0f ? 2*sizeof(ssef) : 3*sizeof(ssef); const size_t nearZ = ray_rdir.z >= 0.0f ? 4*sizeof(ssef) : 5*sizeof(ssef); /* pop loop */ while (true) pop: { /*! pop next node */ if (unlikely(stackPtr == stack)) break; stackPtr--; NodeRef cur = NodeRef(stackPtr->ptr); /*! if popped node is too far, pop next one */ if (unlikely(*(float*)&stackPtr->dist > ray.tfar)) continue; /* downtraversal loop */ while (true) { size_t mask; ssef tNear; /*! stop if we found a leaf node */ if (unlikely(cur.isLeaf(types))) break; STAT3(normal.trav_nodes,1,1,1); /* process standard nodes */ if (likely(cur.isNode(types))) mask = cur.node()->intersect<robust>(nearX,nearY,nearZ,org,rdir,org_rdir,ray_near,ray_far,tNear); /* process motion blur nodes */ else if (likely(cur.isNodeMB(types))) mask = cur.nodeMB()->intersect(nearX,nearY,nearZ,org,rdir,org_rdir,ray_near,ray_far,ray.time,tNear); /*! process nodes with unaligned bounds */ else if (unlikely(cur.isUnalignedNode(types))) mask = cur.unalignedNode()->intersect(org,dir,ray_near,ray_far,tNear); /*! process nodes with unaligned bounds and motion blur */ else if (unlikely(cur.isUnalignedNodeMB(types))) mask = cur.unalignedNodeMB()->intersect(pre1,org,dir,ray_near,ray_far,ray.time,tNear); /*! if no child is hit, pop next node */ const BVH4::BaseNode* node = cur.baseNode(types); if (unlikely(mask == 0)) goto pop; /*! one child is hit, continue with that child */ size_t r = __bscf(mask); if (likely(mask == 0)) { cur = node->child(r); cur.prefetch(types); assert(cur != BVH4::emptyNode); continue; } /*! two children are hit, push far child, and continue with closer child */ NodeRef c0 = node->child(r); c0.prefetch(types); const unsigned int d0 = ((unsigned int*)&tNear)[r]; r = __bscf(mask); NodeRef c1 = node->child(r); c1.prefetch(types); const unsigned int d1 = ((unsigned int*)&tNear)[r]; assert(c0 != BVH4::emptyNode); assert(c1 != BVH4::emptyNode); if (likely(mask == 0)) { assert(stackPtr < stackEnd); if (d0 < d1) { stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; cur = c0; continue; } else { stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; cur = c1; continue; } } /*! Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ assert(stackPtr < stackEnd); stackPtr->ptr = c0; stackPtr->dist = d0; stackPtr++; assert(stackPtr < stackEnd); stackPtr->ptr = c1; stackPtr->dist = d1; stackPtr++; /*! three children are hit, push all onto stack and sort 3 stack items, continue with closest child */ assert(stackPtr < stackEnd); r = __bscf(mask); NodeRef c = node->child(r); c.prefetch(types); unsigned int d = ((unsigned int*)&tNear)[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++; assert(c != BVH4::emptyNode); if (likely(mask == 0)) { sort(stackPtr[-1],stackPtr[-2],stackPtr[-3]); cur = (NodeRef) stackPtr[-1].ptr; stackPtr--; continue; } /*! four children are hit, push all onto stack and sort 4 stack items, continue with closest child */ assert(stackPtr < stackEnd); r = __bscf(mask); c = node->child(r); c.prefetch(types); d = *(unsigned int*)&tNear[r]; stackPtr->ptr = c; stackPtr->dist = d; stackPtr++; assert(c != BVH4::emptyNode); sort(stackPtr[-1],stackPtr[-2],stackPtr[-3],stackPtr[-4]); cur = (NodeRef) stackPtr[-1].ptr; stackPtr--; } /*! this is a leaf node */ assert(cur != BVH4::emptyNode); STAT3(normal.trav_leaves,1,1,1); size_t num; Primitive* prim = (Primitive*) cur.leaf(num); PrimitiveIntersector::intersect(pre,ray,prim,num,bvh->geometry); ray_far = ray.tfar; } AVX_ZERO_UPPER(); }
void BVH4Intersector1<types,robust,PrimitiveIntersector>::occluded(const BVH4* bvh, Ray& ray) { /*! perform per ray precalculations required by the primitive intersector */ Precalculations pre(ray); BVH4::UnalignedNodeMB::Precalculations pre1(ray); /*! stack state */ NodeRef stack[stackSize]; //!< stack of nodes that still need to get traversed NodeRef* stackPtr = stack+1; //!< current stack pointer NodeRef* stackEnd = stack+stackSize; stack[0] = bvh->root; /*! load the ray into SIMD registers */ const Vec3fa ray_rdir = rcp_safe(ray.dir); const Vec3fa ray_org_rdir = ray.org*ray_rdir; const sse3f org(ray.org.x,ray.org.y,ray.org.z); const sse3f dir(ray.dir.x,ray.dir.y,ray.dir.z); const sse3f rdir(ray_rdir.x,ray_rdir.y,ray_rdir.z); const sse3f org_rdir(ray_org_rdir.x,ray_org_rdir.y,ray_org_rdir.z); const ssef ray_near(ray.tnear); ssef ray_far(ray.tfar); /*! offsets to select the side that becomes the lower or upper bound */ const size_t nearX = ray_rdir.x >= 0 ? 0*sizeof(ssef) : 1*sizeof(ssef); const size_t nearY = ray_rdir.y >= 0 ? 2*sizeof(ssef) : 3*sizeof(ssef); const size_t nearZ = ray_rdir.z >= 0 ? 4*sizeof(ssef) : 5*sizeof(ssef); /* pop loop */ while (true) pop: { /*! pop next node */ if (unlikely(stackPtr == stack)) break; stackPtr--; NodeRef cur = (NodeRef) *stackPtr; /* downtraversal loop */ while (true) { size_t mask; ssef tNear; /*! stop if we found a leaf node */ if (unlikely(cur.isLeaf(types))) break; STAT3(shadow.trav_nodes,1,1,1); /* process standard nodes */ if (likely(cur.isNode(types))) mask = cur.node()->intersect<robust>(nearX,nearY,nearZ,org,rdir,org_rdir,ray_near,ray_far,tNear); /* process motion blur nodes */ else if (likely(cur.isNodeMB(types))) mask = cur.nodeMB()->intersect(nearX,nearY,nearZ,org,rdir,org_rdir,ray_near,ray_far,ray.time,tNear); /*! process nodes with unaligned bounds */ else if (unlikely(cur.isUnalignedNode(types))) mask = cur.unalignedNode()->intersect(org,dir,ray_near,ray_far,tNear); /*! process nodes with unaligned bounds and motion blur */ else if (unlikely(cur.isUnalignedNodeMB(types))) mask = cur.unalignedNodeMB()->intersect(pre1,org,dir,ray_near,ray_far,ray.time,tNear); /*! if no child is hit, pop next node */ const BVH4::BaseNode* node = cur.baseNode(types); if (unlikely(mask == 0)) goto pop; /*! one child is hit, continue with that child */ size_t r = __bscf(mask); if (likely(mask == 0)) { cur = node->child(r); cur.prefetch(types); assert(cur != BVH4::emptyNode); continue; } /*! two children are hit, push far child, and continue with closer child */ NodeRef c0 = node->child(r); c0.prefetch(types); const unsigned int d0 = ((unsigned int*)&tNear)[r]; r = __bscf(mask); NodeRef c1 = node->child(r); c1.prefetch(types); const unsigned int d1 = ((unsigned int*)&tNear)[r]; assert(c0 != BVH4::emptyNode); assert(c1 != BVH4::emptyNode); if (likely(mask == 0)) { assert(stackPtr < stackEnd); if (d0 < d1) { *stackPtr = c1; stackPtr++; cur = c0; continue; } else { *stackPtr = c0; stackPtr++; cur = c1; continue; } } assert(stackPtr < stackEnd); *stackPtr = c0; stackPtr++; assert(stackPtr < stackEnd); *stackPtr = c1; stackPtr++; /*! three children are hit */ r = __bscf(mask); cur = node->child(r); cur.prefetch(types); assert(cur != BVH4::emptyNode); if (likely(mask == 0)) continue; assert(stackPtr < stackEnd); *stackPtr = cur; stackPtr++; /*! four children are hit */ cur = node->child(3); cur.prefetch(types); assert(cur != BVH4::emptyNode); } /*! this is a leaf node */ assert(cur != BVH4::emptyNode); STAT3(shadow.trav_leaves,1,1,1); size_t num; Primitive* prim = (Primitive*) cur.leaf(num); if (PrimitiveIntersector::occluded(pre,ray,prim,num,bvh->geometry)) { ray.geomID = 0; break; } } AVX_ZERO_UPPER(); }
void BVH4Statistics::statistics(NodeRef node, const float A, size_t& depth) { if (node.isNode()) { hash += 0x1234; numAlignedNodes++; AlignedNode* n = node.node(); bvhSAH += A*BVH4::travCostAligned; depth = 0; for (size_t i=0; i<BVH4::N; i++) { if (n->child(i) == BVH4::emptyNode) continue; childrenAlignedNodes++; const float Ai = max(0.0f,halfArea(n->extend(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; hash += 0x76767*depth; } else if (node.isUnalignedNode()) { hash += 0x1232344; numUnalignedNodes++; UnalignedNode* n = node.unalignedNode(); bvhSAH += A*BVH4::travCostUnaligned; depth = 0; for (size_t i=0; i<BVH4::N; i++) { if (n->child(i) == BVH4::emptyNode) continue; childrenUnalignedNodes++; const float Ai = max(0.0f,halfArea(n->extend(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; hash += 0x76767*depth; } else if (node.isNodeMB()) { hash += 0xEF343; numAlignedNodesMB++; BVH4::NodeMB* n = node.nodeMB(); bvhSAH += A*BVH4::travCostAligned; depth = 0; for (size_t i=0; i<BVH4::N; i++) { if (n->child(i) == BVH4::emptyNode) continue; childrenAlignedNodesMB++; const float Ai = max(0.0f,halfArea(n->extend0(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; hash += 0x76767*depth; } else if (node.isUnalignedNodeMB()) { hash += 0x1EEF4; numUnalignedNodesMB++; BVH4::UnalignedNodeMB* n = node.unalignedNodeMB(); bvhSAH += A*BVH4::travCostUnaligned; depth = 0; for (size_t i=0; i<BVH4::N; i++) { if (n->child(i) == BVH4::emptyNode) continue; childrenUnalignedNodesMB++; const float Ai = max(0.0f,halfArea(n->extend0(i))); size_t cdepth; statistics(n->child(i),Ai,cdepth); depth=max(depth,cdepth); } depth++; hash += 0x76767*depth; } else { depth = 0; size_t num; const char* tri = node.leaf(num); hash += 0xDD776*num+0x878; if (!num) return; hash += bvh->primTy.hash(tri,num); numLeaves++; numPrims += num; float sah = A * BVH4::intCost * num; bvhSAH += sah; } }