Path: blob/master/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp
9913 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#include "bvh_intersector1.h"4#include "node_intersector1.h"5#include "bvh_traverser1.h"67#include "../geometry/intersector_iterators.h"8#include "../geometry/triangle_intersector.h"9#include "../geometry/trianglev_intersector.h"10#include "../geometry/trianglev_mb_intersector.h"11#include "../geometry/trianglei_intersector.h"12#include "../geometry/quadv_intersector.h"13#include "../geometry/quadi_intersector.h"14#include "../geometry/curveNv_intersector.h"15#include "../geometry/curveNi_intersector.h"16#include "../geometry/curveNi_mb_intersector.h"17#include "../geometry/linei_intersector.h"18#include "../geometry/subdivpatch1_intersector.h"19#include "../geometry/object_intersector.h"20#include "../geometry/instance_intersector.h"21#include "../geometry/instance_array_intersector.h"22#include "../geometry/subgrid_intersector.h"23#include "../geometry/subgrid_mb_intersector.h"24#include "../geometry/curve_intersector_virtual.h"2526namespace embree27{28namespace isa29{30template<int N, int types, bool robust, typename PrimitiveIntersector1>31void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::intersect(const Accel::Intersectors* __restrict__ This,32RayHit& __restrict__ ray,33RayQueryContext* __restrict__ context)34{35const BVH* __restrict__ bvh = (const BVH*)This->ptr;3637/* we may traverse an empty BVH in case all geometry was invalid */38if (bvh->root == BVH::emptyNode)39return;4041/* perform per ray precalculations required by the primitive intersector */42Precalculations pre(ray, bvh);4344/* stack state */45StackItemT<NodeRef> stack[stackSize]; // stack of nodes46StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer47StackItemT<NodeRef>* stackEnd = stack+stackSize;48stack[0].ptr = bvh->root;49stack[0].dist = neg_inf;5051if (bvh->root == BVH::emptyNode)52return;5354/* filter out invalid rays */55#if defined(EMBREE_IGNORE_INVALID_RAYS)56if (!ray.valid()) return;57#endif58/* verify correct input */59assert(ray.valid());60assert(ray.tnear() >= 0.0f);61assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));6263/* load the ray into SIMD registers */64TravRay<N,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));6566/* initialize the node traverser */67BVHNNodeTraverser1Hit<N, types> nodeTraverser;6869/* pop loop */70while (true) pop:71{72/* pop next node */73if (unlikely(stackPtr == stack)) break;74stackPtr--;75NodeRef cur = NodeRef(stackPtr->ptr);7677/* if popped node is too far, pop next one */78if (unlikely(*(float*)&stackPtr->dist > ray.tfar))79continue;8081/* downtraversal loop */82while (true)83{84/* intersect node */85size_t mask; vfloat<N> tNear;86STAT3(normal.trav_nodes,1,1,1);87bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);88if (unlikely(!nodeIntersected)) { STAT3(normal.trav_nodes,-1,-1,-1); break; }8990/* if no child is hit, pop next node */91if (unlikely(mask == 0))92goto pop;9394/* select next child and push other children */95nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);96}9798/* this is a leaf node */99assert(cur != BVH::emptyNode);100STAT3(normal.trav_leaves,1,1,1);101size_t num; Primitive* prim = (Primitive*)cur.leaf(num);102size_t lazy_node = 0;103PrimitiveIntersector1::intersect(This, pre, ray, context, prim, num, tray, lazy_node);104tray.tfar = ray.tfar;105106/* push lazy node onto stack */107if (unlikely(lazy_node)) {108stackPtr->ptr = lazy_node;109stackPtr->dist = neg_inf;110stackPtr++;111}112}113}114115template<int N, int types, bool robust, typename PrimitiveIntersector1>116void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::occluded(const Accel::Intersectors* __restrict__ This,117Ray& __restrict__ ray,118RayQueryContext* __restrict__ context)119{120const BVH* __restrict__ bvh = (const BVH*)This->ptr;121122/* we may traverse an empty BVH in case all geometry was invalid */123if (bvh->root == BVH::emptyNode)124return;125126/* early out for already occluded rays */127if (unlikely(ray.tfar < 0.0f))128return;129130/* perform per ray precalculations required by the primitive intersector */131Precalculations pre(ray, bvh);132133/* stack state */134NodeRef stack[stackSize]; // stack of nodes that still need to get traversed135NodeRef* stackPtr = stack+1; // current stack pointer136NodeRef* stackEnd = stack+stackSize;137stack[0] = bvh->root;138139/* filter out invalid rays */140#if defined(EMBREE_IGNORE_INVALID_RAYS)141if (!ray.valid()) return;142#endif143144/* verify correct input */145assert(ray.valid());146assert(ray.tnear() >= 0.0f);147assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f));148149/* load the ray into SIMD registers */150TravRay<N,robust> tray(ray.org, ray.dir, max(ray.tnear(), 0.0f), max(ray.tfar, 0.0f));151152/* initialize the node traverser */153BVHNNodeTraverser1Hit<N, types> nodeTraverser;154155/* pop loop */156while (true) pop:157{158/* pop next node */159if (unlikely(stackPtr == stack)) break;160stackPtr--;161NodeRef cur = (NodeRef)*stackPtr;162163/* downtraversal loop */164while (true)165{166/* intersect node */167size_t mask; vfloat<N> tNear;168STAT3(shadow.trav_nodes,1,1,1);169bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask);170if (unlikely(!nodeIntersected)) { STAT3(shadow.trav_nodes,-1,-1,-1); break; }171172/* if no child is hit, pop next node */173if (unlikely(mask == 0))174goto pop;175176/* select next child and push other children */177nodeTraverser.traverseAnyHit(cur, mask, tNear, stackPtr, stackEnd);178}179180/* this is a leaf node */181assert(cur != BVH::emptyNode);182STAT3(shadow.trav_leaves,1,1,1);183size_t num; Primitive* prim = (Primitive*)cur.leaf(num);184size_t lazy_node = 0;185if (PrimitiveIntersector1::occluded(This, pre, ray, context, prim, num, tray, lazy_node)) {186ray.tfar = neg_inf;187break;188}189190/* push lazy node onto stack */191if (unlikely(lazy_node)) {192*stackPtr = (NodeRef)lazy_node;193stackPtr++;194}195}196}197198template<int N, int types, bool robust, typename PrimitiveIntersector1>199struct PointQueryDispatch200{201typedef typename PrimitiveIntersector1::Precalculations Precalculations;202typedef typename PrimitiveIntersector1::Primitive Primitive;203typedef BVHN<N> BVH;204typedef typename BVH::NodeRef NodeRef;205typedef typename BVH::AABBNode AABBNode;206typedef typename BVH::AABBNodeMB4D AABBNodeMB4D;207208static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store209210static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)211{212const BVH* __restrict__ bvh = (const BVH*)This->ptr;213214/* we may traverse an empty BVH in case all geometry was invalid */215if (bvh->root == BVH::emptyNode)216return false;217218/* stack state */219StackItemT<NodeRef> stack[stackSize]; // stack of nodes220StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer221StackItemT<NodeRef>* stackEnd = stack+stackSize;222stack[0].ptr = bvh->root;223stack[0].dist = neg_inf;224225/* verify correct input */226assert(!(types & BVH_MB) || (query->time >= 0.0f && query->time <= 1.0f));227228/* load the point query into SIMD registers */229TravPointQuery<N> tquery(query->p, context->query_radius);230231/* initialize the node traverser */232BVHNNodeTraverser1Hit<N,types> nodeTraverser;233234bool changed = false;235float cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE236? query->radius * query->radius237: dot(context->query_radius, context->query_radius);238239/* pop loop */240while (true) pop:241{242/* pop next node */243if (unlikely(stackPtr == stack)) break;244stackPtr--;245NodeRef cur = NodeRef(stackPtr->ptr);246247/* if popped node is too far, pop next one */248if (unlikely(*(float*)&stackPtr->dist > cull_radius))249continue;250251/* downtraversal loop */252while (true)253{254/* intersect node */255size_t mask; vfloat<N> tNear;256STAT3(point_query.trav_nodes,1,1,1);257bool nodeIntersected;258if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) {259nodeIntersected = BVHNNodePointQuerySphere1<N, types>::pointQuery(cur, tquery, query->time, tNear, mask);260} else {261nodeIntersected = BVHNNodePointQueryAABB1 <N, types>::pointQuery(cur, tquery, query->time, tNear, mask);262}263if (unlikely(!nodeIntersected)) { STAT3(point_query.trav_nodes,-1,-1,-1); break; }264265/* if no child is hit, pop next node */266if (unlikely(mask == 0))267goto pop;268269/* select next child and push other children */270nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd);271}272273/* this is a leaf node */274assert(cur != BVH::emptyNode);275STAT3(point_query.trav_leaves,1,1,1);276size_t num; Primitive* prim = (Primitive*)cur.leaf(num);277size_t lazy_node = 0;278if (PrimitiveIntersector1::pointQuery(This, query, context, prim, num, tquery, lazy_node))279{280changed = true;281tquery.rad = context->query_radius;282cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE283? query->radius * query->radius284: dot(context->query_radius, context->query_radius);285}286287/* push lazy node onto stack */288if (unlikely(lazy_node)) {289stackPtr->ptr = lazy_node;290stackPtr->dist = neg_inf;291stackPtr++;292}293}294return changed;295}296};297298/* disable point queries for not yet supported geometry types */299template<int N, int types, bool robust>300struct PointQueryDispatch<N, types, robust, VirtualCurveIntersector1> {301static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }302};303304template<int N, int types, bool robust>305struct PointQueryDispatch<N, types, robust, SubdivPatch1Intersector1> {306static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }307};308309template<int N, int types, bool robust>310struct PointQueryDispatch<N, types, robust, SubdivPatch1MBIntersector1> {311static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; }312};313314template<int N, int types, bool robust, typename PrimitiveIntersector1>315bool BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::pointQuery(316const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context)317{318return PointQueryDispatch<N, types, robust, PrimitiveIntersector1>::pointQuery(This, query, context);319}320}321}322323324