Compare commits
34 Commits
temp-any-i
...
soc-2019-e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
421159e620 | ||
d9d1faef01 | |||
![]() |
4963fc8a70 | ||
![]() |
4b1c544e56 | ||
![]() |
9d602cb3e9 | ||
![]() |
648c053885 | ||
![]() |
8495f9e73d | ||
![]() |
7629463638 | ||
![]() |
137754bba3 | ||
![]() |
cc6c338b25 | ||
![]() |
b11e093bd6 | ||
![]() |
46c0763187 | ||
![]() |
e4b2ae0fb6 | ||
![]() |
209cf2f890 | ||
![]() |
b0f08e8220 | ||
![]() |
c6bc309d0c | ||
![]() |
e0cc40f93c | ||
![]() |
ad6db67771 | ||
![]() |
12ad52c887 | ||
![]() |
0317d3083d | ||
![]() |
e013a24d07 | ||
![]() |
6f25eda4d7 | ||
![]() |
4510849e3d | ||
![]() |
1480ef3107 | ||
![]() |
1671d033d8 | ||
![]() |
3f0a43db2d | ||
![]() |
43b1fc97bd | ||
![]() |
bc98b74829 | ||
![]() |
68d764f93c | ||
![]() |
2ac560181c | ||
![]() |
db229b2380 | ||
![]() |
d40ca519f3 | ||
![]() |
b9928e843d | ||
![]() |
6532a2e695 |
@@ -41,6 +41,7 @@ ExternalProject_Add(external_embree
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH MD5=${EMBREE_HASH}
|
||||
PREFIX ${BUILD_DIR}/embree
|
||||
PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/embree/src/external_embree < ${PATCH_DIR}/embree.diff
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/embree ${DEFAULT_CMAKE_FLAGS} ${EMBREE_EXTRA_ARGS}
|
||||
INSTALL_DIR ${LIBDIR}/embree
|
||||
)
|
||||
|
@@ -2519,7 +2519,7 @@ compile_Embree() {
|
||||
fi
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled results!
|
||||
embree_magic=9
|
||||
embree_magic=11
|
||||
_init_embree
|
||||
|
||||
# Clean install if needed!
|
||||
@@ -2554,6 +2554,9 @@ compile_Embree() {
|
||||
git reset --hard
|
||||
fi
|
||||
|
||||
INFO "Applying patch on to of Embree sources"
|
||||
git apply $SCRIPT_DIR/patches/embree.diff
|
||||
|
||||
# Always refresh the whole build!
|
||||
if [ -d build ]; then
|
||||
rm -rf build
|
||||
|
651
build_files/build_environment/patches/embree.diff
Normal file
651
build_files/build_environment/patches/embree.diff
Normal file
@@ -0,0 +1,651 @@
|
||||
diff --git a/doc/src/api.md b/doc/src/api.md
|
||||
index f190dc160..e77d85cf3 100644
|
||||
--- a/doc/src/api.md
|
||||
+++ b/doc/src/api.md
|
||||
@@ -955,6 +955,11 @@ Embree API Reference
|
||||
```
|
||||
\pagebreak
|
||||
|
||||
+## rtcExtractBVH
|
||||
+``` {include=src/api/rtcExtractBVH.md}
|
||||
+```
|
||||
+\pagebreak
|
||||
+
|
||||
Performance Recommendations
|
||||
===========================
|
||||
|
||||
diff --git a/doc/src/api/rtcExtractBVH.md b/doc/src/api/rtcExtractBVH.md
|
||||
new file mode 100644
|
||||
index 000000000..3c34c0ce2
|
||||
--- /dev/null
|
||||
+++ b/doc/src/api/rtcExtractBVH.md
|
||||
@@ -0,0 +1,94 @@
|
||||
+% rtcExtractBVH(3) | Embree Ray Tracing Kernels 3
|
||||
+
|
||||
+#### NAME
|
||||
+
|
||||
+ rtcExtractBVH - Extract BVH from a scene
|
||||
+
|
||||
+#### SYNOPSIS
|
||||
+
|
||||
+ #include <embree3/rtcore_builder.h>
|
||||
+
|
||||
+ struct BVHPrimitive
|
||||
+ {
|
||||
+ unsigned int geomID;
|
||||
+ unsigned int primID;
|
||||
+ };
|
||||
+
|
||||
+ struct RTCBVHExtractFunction
|
||||
+ {
|
||||
+ void (*expectedSize) (unsigned int num_leaf, unsigned int num_tri, void *userData);
|
||||
+
|
||||
+ void* (*createLeaf) (unsigned int nbPrim, const BVHPrimitive prims[], void *userData);
|
||||
+ void* (*createInstance) (unsigned int nbPrim, const unsigned int geomID[], void *userData);
|
||||
+ void* (*createCurve) (unsigned int nbPrim, const BVHPrimitive prims[], void *userData);
|
||||
+
|
||||
+ void* (*createInnerNode) (unsigned int nbChild, void* children[], void *userData);
|
||||
+
|
||||
+ void (*setAlignedBounds) (void *node, const RTCBounds &bounds, void *userData);
|
||||
+ void (*setLinearBounds) (void *node, const RTCLinearBounds &lbounds, void *userData);
|
||||
+ void (*setUnalignedBounds) (void *node, const RTCAffineSpace &affSpace, void *userData);
|
||||
+ void (*setUnalignedLinearBounds) (void *node, const RTCAffineSpace &affSpace, const RTCBounds &bounds, void *userData);
|
||||
+ };
|
||||
+
|
||||
+ void* rtcExtractBVH(
|
||||
+ RTCScene hscene,
|
||||
+ RTCBVHExtractFunction args,
|
||||
+ void *userData
|
||||
+ );
|
||||
+
|
||||
+#### DESCRIPTION
|
||||
+
|
||||
+The `rtcExtractBVH` function can be used to extract the BVH tree from a scene
|
||||
+that has already been built.
|
||||
+
|
||||
+The `rtcExtractBVH` take the scene to export as parameter as well as a
|
||||
+structure that contain callback function pointers and a user-defined pointer
|
||||
+that is passed to all callback functions when invoked.
|
||||
+All callback functions are typically called from a multiple threads, thus
|
||||
+their implementation must be thread-safe.
|
||||
+
|
||||
+At least 8 callback functions must be registered, which are invoked during
|
||||
+build to create BVH leaf (`createLeaf`, `createInstance` and `createCurve`
|
||||
+member), to create a BVH inner node (`createInnerNode` member) and to set the
|
||||
+bounding boxes of a node (`setAlignedBounds`, `setLinearBounds`,
|
||||
+`setUnalignedBounds` and `setUnalignedLinearBounds` member).
|
||||
+
|
||||
+The function pointer used to preallocate buffer (`expectedSize` member) is
|
||||
+optional and may be `NULL`.
|
||||
+
|
||||
+The `createLeaf`, `createInstance` and `createCurve` callback also gets the
|
||||
+number of primitives for this leaf, and an array of size `nbPrim` of
|
||||
+primitive objects.
|
||||
+
|
||||
+The `createInnerNode` callback gets the number of child, as well as an array
|
||||
+of `nbChild` child previously returned by either `createLeaf`,
|
||||
+`createInstance` or `createCurve`.
|
||||
+
|
||||
+The `setAlignedBounds`, `setLinearBounds`, `setUnalignedBounds` and
|
||||
+`setUnalignedLinearBounds` callback function gets a pointer to the node as
|
||||
+input (`node` argument) as well as the bounds for this node.
|
||||
+
|
||||
+The `setAlignedBounds` callback function take bounds of type `RTCBounds` which
|
||||
+represent an aligned bound box.
|
||||
+
|
||||
+The `setLinearBounds` callback function take bounds of type `RTCLinearBounds`
|
||||
+which represent an aligned bound box that can be linearly interpolated over
|
||||
+time.
|
||||
+
|
||||
+The `setUnalignedBounds` callback function take bounds of type `RTCAffineSpace`
|
||||
+which represent an affine space in which the bound are ((0, 0, 0), (1, 1, 1)).
|
||||
+
|
||||
+The `setUnalignedLinearBounds` callback function take bounds of type
|
||||
+`RTCAffineSpace` and `RTCBounds`. The bound box in the affine space described
|
||||
+by `affSpace` are the linear interpolation between ((0, 0, 0), (1, 1, 1)) and
|
||||
+`bounds`.
|
||||
+
|
||||
+#### EXIT STATUS
|
||||
+
|
||||
+Return the root node, returned by the root `createInnerNode`, or `NULL` if an
|
||||
+error occurred.
|
||||
+On failure an error code is set that can be queried using `rtcDeviceGetError`.
|
||||
+
|
||||
+#### SEE ALSO
|
||||
+
|
||||
+[rtcCommitScene]
|
||||
diff --git a/include/embree3/rtcore_builder.h b/include/embree3/rtcore_builder.h
|
||||
index af84035b0..3f2c4eddf 100644
|
||||
--- a/include/embree3/rtcore_builder.h
|
||||
+++ b/include/embree3/rtcore_builder.h
|
||||
@@ -131,6 +131,35 @@ RTC_API void rtcRetainBVH(RTCBVH bvh);
|
||||
/* Releases the BVH (decrements reference count). */
|
||||
RTC_API void rtcReleaseBVH(RTCBVH bvh);
|
||||
|
||||
+struct BVHPrimitive {
|
||||
+ unsigned int geomID;
|
||||
+ unsigned int primID;
|
||||
+};
|
||||
+
|
||||
+struct RTCBVHExtractFunction
|
||||
+{
|
||||
+ /**
|
||||
+ * Allow to preallocate buffer, is called before everything else
|
||||
+ * Can be NULL if not used
|
||||
+ */
|
||||
+ void (*expectedSize) (unsigned int num_leaf, unsigned int num_tri, void *userData);
|
||||
+
|
||||
+ // Leaf creator function
|
||||
+ void* (*createLeaf) (unsigned int nbPrim, const BVHPrimitive prims[], void *userData);
|
||||
+ void* (*createInstance) (unsigned int nbPrim, const unsigned int geomID[], void *userData);
|
||||
+ void* (*createCurve) (unsigned int nbPrim, const BVHPrimitive prims[], void *userData);
|
||||
+
|
||||
+ // InnerNode creator function
|
||||
+ void* (*createInnerNode) (unsigned int nbChild, void* children[], void *userData);
|
||||
+
|
||||
+ void (*setAlignedBounds) (void *node, const RTCBounds &bounds, void *userData);
|
||||
+ void (*setLinearBounds) (void *node, const RTCLinearBounds &lbounds, void *userData);
|
||||
+ void (*setUnalignedBounds) (void *node, const RTCAffineSpace &affSpace, void *userData);
|
||||
+ void (*setUnalignedLinearBounds) (void *node, const RTCAffineSpace &affSpace, const RTCBounds &bounds, void *userData);
|
||||
+};
|
||||
+
|
||||
+RTC_API void *rtcExtractBVH(RTCScene hscene, RTCBVHExtractFunction args, void *userData);
|
||||
+
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
diff --git a/include/embree3/rtcore_common.h b/include/embree3/rtcore_common.h
|
||||
index 29dfcba11..7eb21c28c 100644
|
||||
--- a/include/embree3/rtcore_common.h
|
||||
+++ b/include/embree3/rtcore_common.h
|
||||
@@ -191,6 +191,13 @@ struct RTC_ALIGN(16) RTCLinearBounds
|
||||
struct RTCBounds bounds1;
|
||||
};
|
||||
|
||||
+/* AffineSpace representation */
|
||||
+struct RTC_ALIGN(16) RTCAffineSpace
|
||||
+{
|
||||
+ float linear[3*3];
|
||||
+ float affine[3];
|
||||
+};
|
||||
+
|
||||
/* Intersection context flags */
|
||||
enum RTCIntersectContextFlags
|
||||
{
|
||||
diff --git a/kernels/bvh/bvh_builder_hair.cpp b/kernels/bvh/bvh_builder_hair.cpp
|
||||
index 14273787f..cad238123 100644
|
||||
--- a/kernels/bvh/bvh_builder_hair.cpp
|
||||
+++ b/kernels/bvh/bvh_builder_hair.cpp
|
||||
@@ -135,8 +135,9 @@ namespace embree
|
||||
#if defined(__AVX__)
|
||||
Builder* BVH8Curve8vBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVHNHairBuilderSAH<8,Curve8v,Line8i>((BVH8*)bvh,scene); }
|
||||
Builder* BVH4Curve8iBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVHNHairBuilderSAH<4,Curve8i,Line8i>((BVH4*)bvh,scene); }
|
||||
-#endif
|
||||
|
||||
+ unsigned int getLine8iPrimId(Line8i *line, unsigned int i) { return line->primID(i); }
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
diff --git a/kernels/common/rtcore_builder.cpp b/kernels/common/rtcore_builder.cpp
|
||||
index 56858294c..6a154881b 100644
|
||||
--- a/kernels/common/rtcore_builder.cpp
|
||||
+++ b/kernels/common/rtcore_builder.cpp
|
||||
@@ -29,8 +29,18 @@
|
||||
#include "../builders/bvh_builder_sah.h"
|
||||
#include "../builders/bvh_builder_morton.h"
|
||||
|
||||
+#include "../bvh/bvh.h"
|
||||
+#include "../geometry/instance.h"
|
||||
+#include "../geometry/trianglev.h"
|
||||
+#include "../geometry/trianglei.h"
|
||||
+#include "../geometry/curveNi.h"
|
||||
+#include "../geometry/curveNi_mb.h"
|
||||
+#include "../geometry/linei.h"
|
||||
+
|
||||
namespace embree
|
||||
{
|
||||
+ DECLARE_ISA_FUNCTION(unsigned int, getLine8iPrimId, Line8i* COMMA unsigned int);
|
||||
+
|
||||
namespace isa // FIXME: support more ISAs for builders
|
||||
{
|
||||
struct BVH : public RefCount
|
||||
@@ -334,92 +344,362 @@ namespace embree
|
||||
return root;
|
||||
}
|
||||
|
||||
- RTC_API void* rtcBuildBVH(const RTCBuildArguments* arguments)
|
||||
- {
|
||||
- BVH* bvh = (BVH*) arguments->bvh;
|
||||
- RTC_CATCH_BEGIN;
|
||||
- RTC_TRACE(rtcBuildBVH);
|
||||
- RTC_VERIFY_HANDLE(bvh);
|
||||
- RTC_VERIFY_HANDLE(arguments);
|
||||
- RTC_VERIFY_HANDLE(arguments->createNode);
|
||||
- RTC_VERIFY_HANDLE(arguments->setNodeChildren);
|
||||
- RTC_VERIFY_HANDLE(arguments->setNodeBounds);
|
||||
- RTC_VERIFY_HANDLE(arguments->createLeaf);
|
||||
-
|
||||
- if (arguments->primitiveArrayCapacity < arguments->primitiveCount)
|
||||
- throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"primitiveArrayCapacity must be greater or equal to primitiveCount")
|
||||
-
|
||||
- /* initialize the allocator */
|
||||
- bvh->allocator.init_estimate(arguments->primitiveCount*sizeof(BBox3fa));
|
||||
- bvh->allocator.reset();
|
||||
-
|
||||
- /* switch between differnet builders based on quality level */
|
||||
- if (arguments->buildQuality == RTC_BUILD_QUALITY_LOW)
|
||||
- return rtcBuildBVHMorton(arguments);
|
||||
- else if (arguments->buildQuality == RTC_BUILD_QUALITY_MEDIUM)
|
||||
- return rtcBuildBVHBinnedSAH(arguments);
|
||||
- else if (arguments->buildQuality == RTC_BUILD_QUALITY_HIGH) {
|
||||
- if (arguments->splitPrimitive == nullptr || arguments->primitiveArrayCapacity <= arguments->primitiveCount)
|
||||
- return rtcBuildBVHBinnedSAH(arguments);
|
||||
- else
|
||||
- return rtcBuildBVHSpatialSAH(arguments);
|
||||
- }
|
||||
- else
|
||||
- throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid build quality");
|
||||
+ template<int N>
|
||||
+ void* createLeaf(const typename BVHN<N>::NodeRef node,
|
||||
+ const PrimitiveType *leafType,
|
||||
+ const RTCBVHExtractFunction args,
|
||||
+ void *userData) {
|
||||
+ size_t nb;
|
||||
+ if(leafType == &Triangle4v::type) {
|
||||
+ Triangle4v *prims = reinterpret_cast<Triangle4v *>(node.leaf(nb));
|
||||
+ BVHPrimitive *primsArray = (BVHPrimitive *)alloca(4 * nb * sizeof(BVHPrimitive));
|
||||
+ unsigned int realNum = 0;
|
||||
+ for(int i = 0; i < nb; ++i) {
|
||||
+ for(size_t j = 0; j < prims[i].size(); j++) {
|
||||
+ primsArray[realNum].geomID = prims[i].geomID(j);
|
||||
+ primsArray[realNum].primID = prims[i].primID(j);
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return args.createLeaf(realNum, primsArray, userData);
|
||||
+ } else if(leafType == &Triangle4i::type) {
|
||||
+ Triangle4i *prims = reinterpret_cast<Triangle4i *>(node.leaf(nb));
|
||||
+ BVHPrimitive *primsArray = (BVHPrimitive *)alloca(4 * nb * sizeof(BVHPrimitive));
|
||||
+ unsigned int realNum = 0;
|
||||
+ for(int i = 0; i < nb; ++i) {
|
||||
+ for(size_t j = 0; j < prims[i].size(); j++) {
|
||||
+ primsArray[realNum].geomID = prims[i].geomID(j);
|
||||
+ primsArray[realNum].primID = prims[i].primID(j);
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return args.createLeaf(realNum, primsArray, userData);
|
||||
+ } else if(leafType == &InstancePrimitive::type) {
|
||||
+ InstancePrimitive *prims = reinterpret_cast<InstancePrimitive *>(node.leaf(nb));
|
||||
+ unsigned int *geomIDs = (unsigned int *)alloca(sizeof(unsigned int)*nb);
|
||||
+ for(int i = 0; i < nb; ++i)
|
||||
+ geomIDs[i] = prims[i].instance->geomID;
|
||||
+
|
||||
+ return args.createInstance(nb, geomIDs, userData);
|
||||
+ } else if(leafType == &Curve8i::type) {
|
||||
+ typedef unsigned char Primitive;
|
||||
+
|
||||
+ Primitive* prim = (Primitive*)node.leaf(nb);
|
||||
+ if(nb == 0) return nullptr;
|
||||
+
|
||||
+ assert(nb == 1);
|
||||
+ Geometry::GType ty = (Geometry::GType)(*prim);
|
||||
+
|
||||
+ BVHPrimitive primsArray[8];
|
||||
+ unsigned int realNum = 0;
|
||||
+
|
||||
+ switch(ty) {
|
||||
+ case Geometry::GTY_FLAT_LINEAR_CURVE: {
|
||||
+ // Access to PrimID from right ISA, otherwise lead to allignement issue
|
||||
+ DEFINE_ISA_FUNCTION(unsigned int, getLine8iPrimId, Line8i* COMMA unsigned int)
|
||||
+ SELECT_SYMBOL_INIT_AVX(getCPUFeatures(), getLine8iPrimId)
|
||||
+
|
||||
+ Line8i *line = reinterpret_cast<Line8i*>(prim);
|
||||
+
|
||||
+ for(size_t i = 0; i < line->m; i++) {
|
||||
+ primsArray[realNum].geomID = line->geomID();
|
||||
+ primsArray[realNum].primID = getLine8iPrimId(line, i);
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ } break;
|
||||
+ case Geometry::GTY_FLAT_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_ROUND_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_FLAT_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_ROUND_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_FLAT_HERMITE_CURVE:
|
||||
+ case Geometry::GTY_ROUND_HERMITE_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_HERMITE_CURVE: {
|
||||
+ Curve8i *curve = reinterpret_cast<Curve8i*>(prim);
|
||||
+ const auto Nb = curve->N;
|
||||
+ for(size_t i = 0; i < Nb; i++) {
|
||||
+ primsArray[realNum].geomID = curve->geomID(Nb);
|
||||
+ primsArray[realNum].primID = curve->primID(Nb)[i];
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ } break;
|
||||
+ default:
|
||||
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "Unexpected curve geom type");
|
||||
+ }
|
||||
+
|
||||
+ return args.createCurve(realNum, primsArray, userData);
|
||||
+ } else if(leafType == &Curve8iMB::type) {
|
||||
+ typedef unsigned char Primitive;
|
||||
+
|
||||
+ Primitive* prim = (Primitive*)node.leaf(nb);
|
||||
+ if(nb == 0) return nullptr;
|
||||
+
|
||||
+ assert(nb == 1);
|
||||
+ Geometry::GType ty = (Geometry::GType)(*prim);
|
||||
+
|
||||
+ BVHPrimitive primsArray[8];
|
||||
+ unsigned int realNum = 0;
|
||||
+
|
||||
+ switch(ty) {
|
||||
+ case Geometry::GTY_FLAT_LINEAR_CURVE: {
|
||||
+ // Access to PrimID from right ISA, otherwise lead to allignement issue
|
||||
+ DEFINE_ISA_FUNCTION(unsigned int, getLine8iPrimId, Line8i* COMMA unsigned int)
|
||||
+ SELECT_SYMBOL_INIT_AVX(getCPUFeatures(), getLine8iPrimId)
|
||||
+
|
||||
+ Line8i *line = reinterpret_cast<Line8i*>(prim);
|
||||
+
|
||||
+ for(size_t i = 0; i < line->m; i++) {
|
||||
+ primsArray[realNum].geomID = line->geomID();
|
||||
+ primsArray[realNum].primID = getLine8iPrimId(line, i);
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ } break;
|
||||
+ case Geometry::GTY_FLAT_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_ROUND_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_BEZIER_CURVE:
|
||||
+ case Geometry::GTY_FLAT_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_ROUND_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_BSPLINE_CURVE:
|
||||
+ case Geometry::GTY_FLAT_HERMITE_CURVE:
|
||||
+ case Geometry::GTY_ROUND_HERMITE_CURVE:
|
||||
+ case Geometry::GTY_ORIENTED_HERMITE_CURVE: {
|
||||
+ Curve8iMB *curve = reinterpret_cast<Curve8iMB*>(prim);
|
||||
+ const auto Nb = curve->N;
|
||||
+ for(size_t i = 0; i < Nb; i++) {
|
||||
+ primsArray[realNum].geomID = curve->geomID(Nb);
|
||||
+ primsArray[realNum].primID = curve->primID(Nb)[i];
|
||||
+ ++realNum;
|
||||
+ }
|
||||
+ } break;
|
||||
+ default:
|
||||
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "Unexpected curve geom type");
|
||||
+ }
|
||||
+
|
||||
+ return args.createCurve(realNum, primsArray, userData);
|
||||
+ } else {
|
||||
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "Unsupported primitive");
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- /* if we are in dynamic mode, then do not clear temporary data */
|
||||
- if (!(arguments->buildFlags & RTC_BUILD_FLAG_DYNAMIC))
|
||||
- {
|
||||
- bvh->morton_src.clear();
|
||||
- bvh->morton_tmp.clear();
|
||||
- }
|
||||
+ inline RTCBounds boundsToRTC(const BBox3fa &bounds) {
|
||||
+ RTCBounds bb;
|
||||
+ bb.lower_x = bounds.lower.x;
|
||||
+ bb.lower_y = bounds.lower.y;
|
||||
+ bb.lower_z = bounds.lower.z;
|
||||
|
||||
- RTC_CATCH_END(bvh->device);
|
||||
- return nullptr;
|
||||
+ bb.upper_x = bounds.upper.x;
|
||||
+ bb.upper_y = bounds.upper.y;
|
||||
+ bb.upper_z = bounds.upper.z;
|
||||
+
|
||||
+ bb.align0 = 0;
|
||||
+ bb.align1 = 1;
|
||||
+
|
||||
+ return bb;
|
||||
}
|
||||
|
||||
- RTC_API void* rtcThreadLocalAlloc(RTCThreadLocalAllocator localAllocator, size_t bytes, size_t align)
|
||||
- {
|
||||
- FastAllocator::CachedAllocator* alloc = (FastAllocator::CachedAllocator*) localAllocator;
|
||||
- RTC_CATCH_BEGIN;
|
||||
- RTC_TRACE(rtcThreadLocalAlloc);
|
||||
- return alloc->malloc0(bytes,align);
|
||||
- RTC_CATCH_END(alloc->alloc->getDevice());
|
||||
- return nullptr;
|
||||
+ template <unsigned int N>
|
||||
+ inline RTCAffineSpace affineSpaceToRTC(const AffineSpace3vf<N> affSpaces, unsigned int i) {
|
||||
+ RTCAffineSpace affSpace;
|
||||
+
|
||||
+ affSpace.affine[0] = affSpaces.p.x[i];
|
||||
+ affSpace.affine[1] = affSpaces.p.y[i];
|
||||
+ affSpace.affine[2] = affSpaces.p.z[i];
|
||||
+
|
||||
+ affSpace.linear[0] = affSpaces.l.vx.x[i];
|
||||
+ affSpace.linear[1] = affSpaces.l.vx.y[i];
|
||||
+ affSpace.linear[2] = affSpaces.l.vx.z[i];
|
||||
+ affSpace.linear[3] = affSpaces.l.vy.x[i];
|
||||
+ affSpace.linear[4] = affSpaces.l.vy.y[i];
|
||||
+ affSpace.linear[5] = affSpaces.l.vy.z[i];
|
||||
+ affSpace.linear[6] = affSpaces.l.vz.x[i];
|
||||
+ affSpace.linear[7] = affSpaces.l.vz.y[i];
|
||||
+ affSpace.linear[8] = affSpaces.l.vz.z[i];
|
||||
+
|
||||
+ return affSpace;
|
||||
}
|
||||
|
||||
- RTC_API void rtcMakeStaticBVH(RTCBVH hbvh)
|
||||
- {
|
||||
- BVH* bvh = (BVH*) hbvh;
|
||||
- RTC_CATCH_BEGIN;
|
||||
- RTC_TRACE(rtcStaticBVH);
|
||||
- RTC_VERIFY_HANDLE(hbvh);
|
||||
- bvh->morton_src.clear();
|
||||
- bvh->morton_tmp.clear();
|
||||
- RTC_CATCH_END(bvh->device);
|
||||
+ template<int N>
|
||||
+ void* recurse(const typename BVHN<N>::NodeRef node,
|
||||
+ const PrimitiveType *leafType,
|
||||
+ const RTCBVHExtractFunction args,
|
||||
+ void *userData) {
|
||||
+ if(node.isLeaf())
|
||||
+ return createLeaf<N>(node, leafType, args, userData);
|
||||
+
|
||||
+ const typename BVHN<N>::BaseNode *bnode = nullptr;
|
||||
+ const typename BVHN<N>::AlignedNode *anode = nullptr;
|
||||
+ const typename BVHN<N>::AlignedNodeMB *anodeMB = nullptr;
|
||||
+ const typename BVHN<N>::AlignedNodeMB4D *anodeMB4D = nullptr;
|
||||
+
|
||||
+ const typename BVHN<N>::UnalignedNode *unanode = nullptr;
|
||||
+ const typename BVHN<N>::UnalignedNodeMB *unanodeMB = nullptr;
|
||||
+
|
||||
+ if(node.isAlignedNode()) {
|
||||
+ anode = node.alignedNode();
|
||||
+ bnode = anode;
|
||||
+ } else if(node.isAlignedNodeMB()) {
|
||||
+ anodeMB = node.alignedNodeMB();
|
||||
+ bnode = anodeMB;
|
||||
+ } else if (node.isAlignedNodeMB4D()) {
|
||||
+ anodeMB4D = node.alignedNodeMB4D();
|
||||
+ anodeMB = anodeMB4D;
|
||||
+ bnode = anodeMB;
|
||||
+ } else if (node.isUnalignedNode()) {
|
||||
+ unanode = node.unalignedNode();
|
||||
+ bnode = unanode;
|
||||
+ } else if (node.isUnalignedNodeMB()) {
|
||||
+ unanodeMB = node.unalignedNodeMB();
|
||||
+ bnode = unanodeMB;
|
||||
+ } else {
|
||||
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "Unknown node type");
|
||||
+ }
|
||||
+
|
||||
+ unsigned int nb = 0;
|
||||
+ void *children[4];
|
||||
+ for(unsigned int i = 0; i < 4; i++) {
|
||||
+ void *child = recurse<N>(bnode->child(i), leafType, args, userData);
|
||||
+ if(child == nullptr) continue;
|
||||
+
|
||||
+ if(anode != nullptr) {
|
||||
+ args.setAlignedBounds(child, boundsToRTC(anode->bounds(i)), userData);
|
||||
+ } else if (anodeMB != nullptr) {
|
||||
+ RTCLinearBounds lb;
|
||||
+ lb.bounds0 = boundsToRTC(anodeMB->bounds0(i));
|
||||
+ lb.bounds1 = boundsToRTC(anodeMB->bounds1(i) - anodeMB->bounds0(i));
|
||||
+
|
||||
+ if (anodeMB4D != nullptr) {
|
||||
+ lb.bounds0.align0 = anodeMB4D->timeRange(i).lower;
|
||||
+ lb.bounds0.align1 = anodeMB4D->timeRange(i).upper;
|
||||
+ }
|
||||
+
|
||||
+ args.setLinearBounds(child, lb, userData);
|
||||
+ } else if(unanode != nullptr) {
|
||||
+ RTCAffineSpace affSpace = affineSpaceToRTC<N>(unanode->naabb, i);
|
||||
+ args.setUnalignedBounds(child, affSpace, userData);
|
||||
+ } else if(unanodeMB != nullptr) {
|
||||
+ RTCAffineSpace affSpace = affineSpaceToRTC<N>(unanodeMB->space0, i);
|
||||
+
|
||||
+ RTCBounds bounds;
|
||||
+ bounds.lower_x = unanodeMB->b1.lower.x[i];
|
||||
+ bounds.lower_y = unanodeMB->b1.lower.y[i];
|
||||
+ bounds.lower_z = unanodeMB->b1.lower.z[i];
|
||||
+
|
||||
+ bounds.upper_x = unanodeMB->b1.upper.x[i];
|
||||
+ bounds.upper_y = unanodeMB->b1.upper.y[i];
|
||||
+ bounds.upper_z = unanodeMB->b1.upper.z[i];
|
||||
+
|
||||
+ args.setUnalignedLinearBounds(child, affSpace, bounds, userData);
|
||||
+ }
|
||||
+
|
||||
+ children[nb++] = child;
|
||||
+ }
|
||||
+
|
||||
+ return args.createInnerNode(nb, children, userData);
|
||||
}
|
||||
|
||||
- RTC_API void rtcRetainBVH(RTCBVH hbvh)
|
||||
- {
|
||||
- BVH* bvh = (BVH*) hbvh;
|
||||
- Device* device = bvh ? bvh->device : nullptr;
|
||||
- RTC_CATCH_BEGIN;
|
||||
- RTC_TRACE(rtcRetainBVH);
|
||||
- RTC_VERIFY_HANDLE(hbvh);
|
||||
- bvh->refInc();
|
||||
- RTC_CATCH_END(device);
|
||||
+ std::vector<void*> prerecurse(Accel *a, RTCBVHExtractFunction args, void *userData) {
|
||||
+ std::vector<void*> nodes;
|
||||
+
|
||||
+ AccelData *ad = a->intersectors.ptr;
|
||||
+ switch(ad->type) {
|
||||
+ case AccelData::TY_BVH4: {
|
||||
+ BVH4 *bvh = dynamic_cast<BVH4 *>(ad);
|
||||
+ BVH4::NodeRef root = bvh->root;
|
||||
+
|
||||
+ void* node = recurse<4>(root, bvh->primTy, args, userData);
|
||||
+ args.setAlignedBounds(node, boundsToRTC(bvh->bounds.bounds()), userData);
|
||||
+ nodes.push_back(node);
|
||||
+ } break;
|
||||
+ case AccelData::TY_BVH8: {
|
||||
+ BVH8 *bvh = dynamic_cast<BVH8 *>(ad);
|
||||
+ BVH8::NodeRef root = bvh->root;
|
||||
+
|
||||
+ void *node = recurse<8>(root, bvh->primTy, args, userData);
|
||||
+ args.setAlignedBounds(node, boundsToRTC(bvh->bounds.bounds()), userData);
|
||||
+ nodes.push_back(node);
|
||||
+ } break;
|
||||
+ case AccelData::TY_ACCELN: {
|
||||
+ AccelN *acceln = dynamic_cast<AccelN *>(ad);
|
||||
+ for (Accel *acc : acceln->accels) {
|
||||
+ auto newNodes = prerecurse(acc, args, userData);
|
||||
+ nodes.insert(nodes.end(), newNodes.begin(), newNodes.end());
|
||||
+ }
|
||||
+ } break;
|
||||
+ default:
|
||||
+ throw_RTCError(RTC_ERROR_INVALID_OPERATION, "Unable to extract something else than BVH4/8 tree");
|
||||
+ }
|
||||
+
|
||||
+ return nodes;
|
||||
}
|
||||
-
|
||||
- RTC_API void rtcReleaseBVH(RTCBVH hbvh)
|
||||
- {
|
||||
- BVH* bvh = (BVH*) hbvh;
|
||||
- Device* device = bvh ? bvh->device : nullptr;
|
||||
+
|
||||
+ RTC_API void *rtcExtractBVH(RTCScene hscene, RTCBVHExtractFunction args, void *userData) {
|
||||
+ Scene* scene = (Scene*) hscene;
|
||||
RTC_CATCH_BEGIN;
|
||||
- RTC_TRACE(rtcReleaseBVH);
|
||||
- RTC_VERIFY_HANDLE(hbvh);
|
||||
- bvh->refDec();
|
||||
- RTC_CATCH_END(device);
|
||||
+ RTC_TRACE(rtcSampleTry);
|
||||
+#if defined(DEBUG)
|
||||
+ RTC_VERIFY_HANDLE(hscene);
|
||||
+#endif
|
||||
+
|
||||
+ if (args.expectedSize != nullptr) {
|
||||
+ /* Defines size and helper macro */
|
||||
+ struct Size {
|
||||
+ unsigned int num_prim = 0;
|
||||
+ unsigned int num_tri = 0;
|
||||
+ };
|
||||
+
|
||||
+#define SIZE(ops) \
|
||||
+ Size* size = reinterpret_cast<Size*>(userData); \
|
||||
+ ops \
|
||||
+ return nullptr;
|
||||
+
|
||||
+#define INC(var, val) size->var += (val);
|
||||
+
|
||||
+
|
||||
+ Size size;
|
||||
+ RTCBVHExtractFunction param;
|
||||
+
|
||||
+ param.createLeaf = [](unsigned int nbPrim, const BVHPrimitive[], void* userData) -> void* {
|
||||
+ SIZE(INC(num_prim, nbPrim) INC(num_tri, 3 * nbPrim))
|
||||
+ };
|
||||
+ param.createInstance = [](unsigned int nbPrim, const unsigned int[], void* userData) -> void* {
|
||||
+ SIZE(INC(num_prim, nbPrim))
|
||||
+ };
|
||||
+ param.createCurve = [](unsigned int nbPrim, const BVHPrimitive[], void* userData) -> void* {
|
||||
+ SIZE(INC(num_prim, nbPrim))
|
||||
+ };
|
||||
+ param.createInnerNode = [](unsigned int, void*[], void* ) -> void* { return nullptr; };
|
||||
+ param.setAlignedBounds = [](void*, const RTCBounds &, void*) {};
|
||||
+ param.setLinearBounds = [](void*, const RTCLinearBounds &, void*) {};
|
||||
+ param.setUnalignedBounds = [](void*, const RTCAffineSpace &, void*) {};
|
||||
+ param.setUnalignedLinearBounds = [](void*, const RTCAffineSpace &, const RTCBounds &, void*) {};
|
||||
+ param.expectedSize = nullptr;
|
||||
+
|
||||
+ prerecurse(scene, param, &size);
|
||||
+ args.expectedSize(size.num_prim, size.num_tri, userData);
|
||||
+ }
|
||||
+
|
||||
+ std::vector<void*> nodes;
|
||||
+
|
||||
+ nodes = prerecurse(scene, args, userData);
|
||||
+
|
||||
+ if(nodes.size() == 0)
|
||||
+ return nullptr;
|
||||
+
|
||||
+ if(nodes.size() == 1)
|
||||
+ return nodes[0];
|
||||
+
|
||||
+ RTCBounds bounds;
|
||||
+ rtcGetSceneBounds(hscene, &bounds);
|
||||
+
|
||||
+ void *root = args.createInnerNode(nodes.size(), nodes.data(), userData);
|
||||
+ args.setAlignedBounds(root, bounds, userData);
|
||||
+ return root;
|
||||
+
|
||||
+ RTC_CATCH_END2(scene);
|
||||
+ return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
@@ -57,6 +57,12 @@ enum_bvh_layouts = (
|
||||
('BVH8', "BVH8", "", 4),
|
||||
)
|
||||
|
||||
enum_bvh_builder = (
|
||||
('INTERNAL', "Internal", "Use old internal BVH builder"),
|
||||
('EMBREE', "Embree", "Use full featured embree (only on CPU)"),
|
||||
('EMBREE_CONVERT', "Embree, then convert", "Use embree, then convert it to BVH2"),
|
||||
)
|
||||
|
||||
enum_bvh_types = (
|
||||
('DYNAMIC_BVH', "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
|
||||
('STATIC_BVH', "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"),
|
||||
@@ -537,11 +543,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
items=enum_bvh_types,
|
||||
default='DYNAMIC_BVH',
|
||||
)
|
||||
use_bvh_embree: BoolProperty(
|
||||
name="Use Embree",
|
||||
description="Use Embree as ray accelerator",
|
||||
default=False,
|
||||
bvh_builder: EnumProperty(
|
||||
name="BVH Builder",
|
||||
description="Choose the BVH builder that will be used",
|
||||
items=enum_bvh_builder,
|
||||
default='INTERNAL',
|
||||
)
|
||||
|
||||
debug_use_spatial_splits: BoolProperty(
|
||||
name="Use Spatial Splits",
|
||||
description="Use BVH spatial splits: longer builder time, faster render",
|
||||
|
@@ -647,17 +647,13 @@ class CYCLES_RENDER_PT_performance_acceleration_structure(CyclesButtonsPanel, Pa
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if _cycles.with_embree:
|
||||
row = col.row()
|
||||
row.active = use_cpu(context)
|
||||
row.prop(cscene, "use_bvh_embree")
|
||||
col.prop(cscene, "bvh_builder")
|
||||
col.prop(cscene, "debug_use_spatial_splits")
|
||||
sub = col.column()
|
||||
sub.active = not cscene.use_bvh_embree or not _cycles.with_embree
|
||||
sub.active = cscene.bvh_builder != 'EMBREE' or not _cycles.with_embree
|
||||
sub.prop(cscene, "debug_use_hair_bvh")
|
||||
sub = col.column()
|
||||
sub.active = not cscene.debug_use_spatial_splits and not cscene.use_bvh_embree
|
||||
sub.active = not cscene.debug_use_spatial_splits and cscene.bvh_builder != 'EMBREE'
|
||||
sub.prop(cscene, "debug_bvh_time_steps")
|
||||
|
||||
|
||||
|
@@ -701,8 +701,14 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
|
||||
}
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
params.bvh_layout = RNA_boolean_get(&cscene, "use_bvh_embree") ? BVH_LAYOUT_EMBREE :
|
||||
params.bvh_layout;
|
||||
switch (RNA_enum_get(&cscene, "bvh_builder")) {
|
||||
case 1:
|
||||
params.bvh_layout = BVH_LAYOUT_EMBREE;
|
||||
break;
|
||||
case 2:
|
||||
params.bvh_layout = BVH_LAYOUT_EMBREE_CONVERTED;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return params;
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ set(SRC
|
||||
bvh_sort.cpp
|
||||
bvh_split.cpp
|
||||
bvh_unaligned.cpp
|
||||
bvh_embree_converter.cpp
|
||||
)
|
||||
|
||||
set(SRC_HEADERS
|
||||
@@ -33,6 +34,7 @@ set(SRC_HEADERS
|
||||
bvh_sort.h
|
||||
bvh_split.h
|
||||
bvh_unaligned.h
|
||||
bvh_embree_converter.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
@@ -51,6 +51,8 @@ const char *bvh_layout_name(BVHLayout layout)
|
||||
return "NONE";
|
||||
case BVH_LAYOUT_EMBREE:
|
||||
return "EMBREE";
|
||||
case BVH_LAYOUT_EMBREE_CONVERTED:
|
||||
return "EMBREE_CONVERTED";
|
||||
case BVH_LAYOUT_ALL:
|
||||
return "ALL";
|
||||
}
|
||||
@@ -105,6 +107,7 @@ BVH *BVH::create(const BVHParams ¶ms, const vector<Object *> &objects)
|
||||
case BVH_LAYOUT_BVH8:
|
||||
return new BVH8(params, objects);
|
||||
case BVH_LAYOUT_EMBREE:
|
||||
case BVH_LAYOUT_EMBREE_CONVERTED:
|
||||
#ifdef WITH_EMBREE
|
||||
return new BVHEmbree(params, objects);
|
||||
#endif
|
||||
|
@@ -94,7 +94,7 @@ void BVH2::pack_aligned_node(int idx,
|
||||
|
||||
int4 data[BVH_NODE_SIZE] = {
|
||||
make_int4(
|
||||
visibility0 & ~PATH_RAY_NODE_UNALIGNED, visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1),
|
||||
visibility0 & ~PATH_RAY_NODE_CLEAR, visibility1 & ~PATH_RAY_NODE_CLEAR, c0, c1),
|
||||
make_int4(__float_as_int(b0.min.x),
|
||||
__float_as_int(b1.min.x),
|
||||
__float_as_int(b0.max.x),
|
||||
@@ -144,8 +144,8 @@ void BVH2::pack_unaligned_node(int idx,
|
||||
float4 data[BVH_UNALIGNED_NODE_SIZE];
|
||||
Transform space0 = BVHUnaligned::compute_node_transform(bounds0, aligned_space0);
|
||||
Transform space1 = BVHUnaligned::compute_node_transform(bounds1, aligned_space1);
|
||||
data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED),
|
||||
__int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED),
|
||||
data[0] = make_float4(__int_as_float((visibility0 & ~PATH_RAY_NODE_CLEAR) | PATH_RAY_NODE_UNALIGNED),
|
||||
__int_as_float((visibility1 & ~PATH_RAY_NODE_CLEAR) | PATH_RAY_NODE_UNALIGNED),
|
||||
__int_as_float(c0),
|
||||
__int_as_float(c1));
|
||||
|
||||
@@ -208,6 +208,7 @@ void BVH2::pack_nodes(const BVHNode *root)
|
||||
pack_leaf(e, leaf);
|
||||
}
|
||||
else {
|
||||
assert(e.node->num_children() == 2);
|
||||
/* inner node */
|
||||
int idx[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
@@ -280,7 +281,10 @@ void BVH2::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility)
|
||||
idx, aligned_space, aligned_space, bbox0, bbox1, c0, c1, visibility0, visibility1);
|
||||
}
|
||||
else {
|
||||
pack_aligned_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
|
||||
pack_aligned_node(idx,
|
||||
bbox0, bbox1,
|
||||
c0, c1,
|
||||
visibility0, visibility1);
|
||||
}
|
||||
|
||||
bbox.grow(bbox0);
|
||||
|
@@ -54,6 +54,7 @@
|
||||
# include "util/util_foreach.h"
|
||||
# include "util/util_logging.h"
|
||||
# include "util/util_progress.h"
|
||||
# include "bvh_embree_converter.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
@@ -286,7 +287,8 @@ int BVHEmbree::rtc_shared_users = 0;
|
||||
thread_mutex BVHEmbree::rtc_shared_mutex;
|
||||
|
||||
BVHEmbree::BVHEmbree(const BVHParams ¶ms_, const vector<Object *> &objects_)
|
||||
: BVH(params_, objects_),
|
||||
: bvh_layout(params_.bvh_layout),
|
||||
BVH2(params_, objects_),
|
||||
scene(NULL),
|
||||
mem_used(0),
|
||||
top_level(NULL),
|
||||
@@ -301,7 +303,11 @@ BVHEmbree::BVHEmbree(const BVHParams ¶ms_, const vector<Object *> &objects_)
|
||||
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
|
||||
thread_scoped_lock lock(rtc_shared_mutex);
|
||||
if (rtc_shared_users == 0) {
|
||||
rtc_shared_device = rtcNewDevice("verbose=0");
|
||||
if(bvh_layout == BVH_LAYOUT_EMBREE_CONVERTED) {
|
||||
rtc_shared_device = rtcNewDevice("verbose=0;hair_accel_mb=bvh4.virtualcurve8imb;");
|
||||
} else {
|
||||
rtc_shared_device = rtcNewDevice("verbose=0;");
|
||||
}
|
||||
/* Check here if Embree was built with the correct flags. */
|
||||
ssize_t ret = rtcGetDeviceProperty(rtc_shared_device, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED);
|
||||
if (ret != 1) {
|
||||
@@ -483,16 +489,21 @@ void BVHEmbree::build(Progress &progress, Stats *stats_)
|
||||
rtcSetSceneProgressMonitorFunction(scene, rtc_progress_func, &progress);
|
||||
rtcCommitScene(scene);
|
||||
|
||||
pack_primitives();
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
delete_rtcScene();
|
||||
stats = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
progress.set_substatus("Packing geometry");
|
||||
pack_nodes(NULL);
|
||||
if(this->bvh_layout == BVH_LAYOUT_EMBREE_CONVERTED) {
|
||||
BVHEmbreeConverter conv(this->scene, this->objects, this->params);
|
||||
conv.fillPack(this->pack);
|
||||
} else {
|
||||
pack_primitives();
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
delete_rtcScene();
|
||||
stats = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
pack_nodes(NULL);
|
||||
}
|
||||
|
||||
stats = NULL;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
# include <embree3/rtcore_scene.h>
|
||||
|
||||
# include "bvh/bvh.h"
|
||||
# include "bvh/bvh2.h"
|
||||
# include "bvh/bvh_params.h"
|
||||
|
||||
# include "util/util_thread.h"
|
||||
@@ -33,10 +34,10 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Mesh;
|
||||
|
||||
class BVHEmbree : public BVH {
|
||||
class BVHEmbree : public BVH2 {
|
||||
public:
|
||||
virtual void build(Progress &progress, Stats *stats) override;
|
||||
virtual ~BVHEmbree();
|
||||
virtual ~BVHEmbree() override;
|
||||
RTCScene scene;
|
||||
static void destroy(RTCScene);
|
||||
|
||||
@@ -64,6 +65,8 @@ class BVHEmbree : public BVH {
|
||||
BVHEmbree *top_level;
|
||||
|
||||
private:
|
||||
BVHLayout bvh_layout;
|
||||
|
||||
void delete_rtcScene();
|
||||
void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh);
|
||||
void update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh);
|
||||
|
897
intern/cycles/bvh/bvh_embree_converter.cpp
Normal file
897
intern/cycles/bvh/bvh_embree_converter.cpp
Normal file
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Copyright 2018, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
|
||||
#include "bvh_embree_converter.h"
|
||||
|
||||
#include "bvh_node.h"
|
||||
#include "render/mesh.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Utility functions */
|
||||
void packPush(PackedBVH *pack, const size_t packIdx,
|
||||
const int object_id, const int prim_id,
|
||||
const int prim_type, const uint visibility,
|
||||
const uint tri_index)
|
||||
{
|
||||
pack->prim_index.resize(packIdx + 1);
|
||||
pack->prim_type.resize(packIdx + 1);
|
||||
pack->prim_object.resize(packIdx + 1);
|
||||
pack->prim_visibility.resize(packIdx + 1);
|
||||
pack->prim_tri_index.resize(packIdx + 1);
|
||||
|
||||
pack->prim_index[packIdx] = prim_id;
|
||||
pack->prim_type[packIdx] = prim_type;
|
||||
pack->prim_object[packIdx] = object_id;
|
||||
pack->prim_visibility[packIdx] = visibility;
|
||||
pack->prim_tri_index[packIdx] = tri_index;
|
||||
|
||||
}
|
||||
|
||||
BoundBox RTCBoundBoxToCCL(const RTCBounds &bound)
|
||||
{
|
||||
return BoundBox(make_float3(bound.lower_x, bound.lower_y, bound.lower_z),
|
||||
make_float3(bound.upper_x, bound.upper_y, bound.upper_z));
|
||||
|
||||
}
|
||||
|
||||
Transform transformSpaceFromBound(const BoundBox &bounds) {
|
||||
Transform space = transform_identity();
|
||||
|
||||
space.x.w -= bounds.min.x;
|
||||
space.y.w -= bounds.min.y;
|
||||
space.z.w -= bounds.min.z;
|
||||
float3 dim = bounds.max - bounds.min;
|
||||
|
||||
return transform_scale(1.0f / max(1e-18f, dim.x),
|
||||
1.0f / max(1e-18f, dim.y),
|
||||
1.0f / max(1e-18f, dim.z)) * space;
|
||||
}
|
||||
|
||||
|
||||
BVHNode *merge(const BVHNode *oldRoot, BVHNode *n0, BVHNode *n1) {
|
||||
BoundBox childBB = merge(n0->bounds, n1->bounds);
|
||||
BVHNode *root = new InnerNode(childBB, n0, n1);
|
||||
|
||||
/* If one of the child has linear bound, take the parents bound */
|
||||
if(n0->deltaBounds != nullptr || n1->deltaBounds != nullptr || n0->is_unaligned || n1->is_unaligned) {
|
||||
root->bounds = oldRoot->bounds;
|
||||
if(oldRoot->deltaBounds != nullptr) root->deltaBounds = new BoundBox(*oldRoot->deltaBounds);
|
||||
if(oldRoot->is_unaligned) root->set_aligned_space(*oldRoot->aligned_space);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
BVHNode *makeBVHTreeFromList(std::deque<BVHNode *> nodes)
|
||||
{
|
||||
BVHNode *ret = nullptr;
|
||||
while(!nodes.empty()) {
|
||||
if(ret == nullptr) {
|
||||
ret = nodes.front();
|
||||
nodes.pop_front();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If it's a leaf or a full node -> create a new parrent */
|
||||
if(ret->is_leaf() || ret->num_children() == 4) {
|
||||
ret = new InnerNode(ret->bounds, &ret, 1);
|
||||
}
|
||||
|
||||
InnerNode *innerNode = dynamic_cast<InnerNode*>(ret);
|
||||
innerNode->children[innerNode->num_children_++] = nodes.front();
|
||||
innerNode->bounds.grow(nodes.front()->bounds);
|
||||
nodes.pop_front();
|
||||
|
||||
if(ret->num_children() == 4) {
|
||||
nodes.push_back(ret);
|
||||
ret = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BVHNode *bvh_shrink(BVHNode *root)
|
||||
{
|
||||
if(root->is_leaf()) {
|
||||
if(root->num_triangles() == 0) // Remove empty leafs
|
||||
return nullptr;
|
||||
else
|
||||
return root;
|
||||
}
|
||||
|
||||
InnerNode *node = dynamic_cast<InnerNode*>(root);
|
||||
|
||||
int num_children = 0;
|
||||
BVHNode* children[4];
|
||||
|
||||
for(int i = 0; i < node->num_children(); ++i) {
|
||||
BVHNode *child = bvh_shrink(node->get_child(i));
|
||||
if(child != nullptr)
|
||||
children[num_children++] = child;
|
||||
}
|
||||
|
||||
if(num_children == 0) {
|
||||
delete root;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(num_children == 1) {
|
||||
delete root;
|
||||
return children[0];
|
||||
}
|
||||
|
||||
// We have 2 node or more, we'll pack them into 2 nodes (to respect BVH2)
|
||||
node->num_children_ = 2;
|
||||
if(num_children == 2) {
|
||||
node->children[0] = children[0];
|
||||
node->children[1] = children[1];
|
||||
return node;
|
||||
}
|
||||
|
||||
node->children[0] = merge(root, children[0], children[1]);
|
||||
|
||||
if(num_children == 3) {
|
||||
node->children[1] = children[2];
|
||||
} else {
|
||||
node->children[1] = merge(root, children[2], children[3]);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
BVHEmbreeConverter::BVHEmbreeConverter(RTCScene scene,
|
||||
std::vector<Object *> objects,
|
||||
const BVHParams ¶ms)
|
||||
: s(scene),
|
||||
objects(objects),
|
||||
params(params)
|
||||
{}
|
||||
|
||||
BVHNode* BVHEmbreeConverter::createLeaf(unsigned int nbPrim,
|
||||
const BVHPrimitive prims[])
|
||||
{
|
||||
const unsigned int from = this->packIdx;
|
||||
|
||||
uint visibility = 0;
|
||||
for(unsigned int i = 0; i < nbPrim; i++) {
|
||||
const unsigned int geom_id = prims[i].geomID;
|
||||
const unsigned int prim_id = prims[i].primID;
|
||||
|
||||
const unsigned int object_id = geom_id / 2;
|
||||
Object *obj = this->objects.at(object_id);
|
||||
Mesh::Triangle tri = obj->mesh->get_triangle(prim_id);
|
||||
|
||||
int prim_type = obj->mesh->has_motion_blur()
|
||||
? PRIMITIVE_MOTION_TRIANGLE
|
||||
: PRIMITIVE_TRIANGLE;
|
||||
|
||||
visibility |= obj->visibility;
|
||||
packPush(this->pack, this->packIdx++,
|
||||
object_id, prim_id,
|
||||
prim_type, obj->visibility,
|
||||
this->pack->prim_tri_verts.size());
|
||||
|
||||
array<float4> *prim_tri_verts = &this->pack->prim_tri_verts;
|
||||
prim_tri_verts->reserve(this->pack->prim_tri_verts.size());
|
||||
float3 *verts = obj->mesh->verts.data();
|
||||
prim_tri_verts->reserve(this->pack->prim_tri_verts.size() + 3);
|
||||
for(int i = 0; i < 3; i++)
|
||||
prim_tri_verts->push_back_reserved(float3_to_float4(verts[tri.v[i]]));
|
||||
}
|
||||
|
||||
return new LeafNode(BoundBox::empty, visibility, from, from + nbPrim);
|
||||
}
|
||||
|
||||
BVHNode* BVHEmbreeConverter::createInstance(unsigned int nbPrim,
|
||||
const unsigned int geomID[])
|
||||
{
|
||||
std::deque<BVHNode *> nodes;
|
||||
|
||||
for(size_t i = 0; i < nbPrim; i++) {
|
||||
uint id = geomID[i] / 2;
|
||||
Object *obj = this->objects.at(id);
|
||||
LeafNode *leafNode = new LeafNode(obj->bounds, obj->visibility,
|
||||
this->packIdx, this->packIdx + 1);
|
||||
|
||||
packPush(this->pack, this->packIdx++,
|
||||
id, -1,
|
||||
PRIMITIVE_NONE, obj->visibility,
|
||||
-1);
|
||||
|
||||
nodes.push_back(leafNode);
|
||||
}
|
||||
|
||||
return makeBVHTreeFromList(nodes);
|
||||
}
|
||||
|
||||
BVHNode* BVHEmbreeConverter::createCurve(unsigned int nbPrim,
|
||||
const BVHPrimitive prims[])
|
||||
{
|
||||
std::deque<BVHNode *> nodes;
|
||||
|
||||
for(unsigned int i = 0; i < nbPrim; i++) {
|
||||
const auto geom_id = prims[i].geomID;
|
||||
const auto prim_id = prims[i].primID;
|
||||
|
||||
const unsigned int object_id = geom_id / 2;
|
||||
Object *obj = this->objects.at(object_id);
|
||||
|
||||
unsigned int curve_id = 0;
|
||||
int segment_id = prim_id;
|
||||
Mesh::Curve curve = obj->mesh->get_curve(0);
|
||||
while(segment_id >= curve.num_segments()) {
|
||||
curve = obj->mesh->get_curve(++curve_id);
|
||||
segment_id -= curve.num_segments();
|
||||
}
|
||||
|
||||
int prim_type = PRIMITIVE_PACK_SEGMENT(obj->mesh->has_motion_blur()
|
||||
? PRIMITIVE_MOTION_CURVE
|
||||
: PRIMITIVE_CURVE, segment_id);
|
||||
|
||||
LeafNode *leafNode = new LeafNode(BoundBox::empty, obj->visibility,
|
||||
this->packIdx, this->packIdx + 1);
|
||||
|
||||
int nbStep = 1;
|
||||
const Attribute *curve_attr_mP = nullptr;
|
||||
if (obj->mesh->has_motion_blur()) {
|
||||
curve_attr_mP = obj->mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
nbStep = obj->mesh->motion_steps;
|
||||
}
|
||||
|
||||
for(int i = 0; i < nbStep; i++) {
|
||||
float4 keys[4];
|
||||
|
||||
curve.cardinal_keys_for_step(
|
||||
obj->mesh->curve_keys.data(),
|
||||
obj->mesh->curve_radius.data(),
|
||||
curve_attr_mP == nullptr ? nullptr : curve_attr_mP->data_float3(),
|
||||
obj->mesh->curve_keys.size(),
|
||||
nbStep, i,
|
||||
max(curve.first_key + segment_id - 1, curve.first_key) - curve.first_key,
|
||||
segment_id, segment_id + 1,
|
||||
min(curve.first_key + segment_id + 2, curve.first_key + curve.num_keys - 1) - curve.first_key,
|
||||
keys
|
||||
);
|
||||
curve.bounds_grow(keys, leafNode->bounds);
|
||||
}
|
||||
|
||||
packPush(this->pack, this->packIdx++,
|
||||
object_id, curve_id,
|
||||
prim_type, obj->visibility, -1);
|
||||
|
||||
nodes.push_back(leafNode);
|
||||
}
|
||||
|
||||
return makeBVHTreeFromList(nodes);
|
||||
}
|
||||
|
||||
|
||||
BVHNode *BVHEmbreeConverter::createInnerNode(unsigned int nbChild,
|
||||
BVHNode *children[])
|
||||
{
|
||||
return new InnerNode(BoundBox::empty, children, nbChild);
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::setAlignedBounds(BVHNode *node, BoundBox bounds)
|
||||
{
|
||||
node->bounds = bounds;
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::setLinearBounds(BVHNode *node, BoundBox bounds, BoundBox deltaBounds)
|
||||
{
|
||||
node->bounds = bounds;
|
||||
node->deltaBounds = new BoundBox(deltaBounds);
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::setUnalignedBounds(BVHNode *node, Transform affSpace)
|
||||
{
|
||||
Transform inv = transform_inverse(affSpace);
|
||||
|
||||
BoundBox bb(transform_point(&inv, make_float3(0)));
|
||||
bb.grow(transform_point(&inv, make_float3(1)));
|
||||
|
||||
node->bounds = bb;
|
||||
node->set_aligned_space(affSpace);
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::setUnalignedLinearBounds(BVHNode *node, Transform affSpace, BoundBox bounds)
|
||||
{
|
||||
Transform inv = transform_inverse(affSpace);
|
||||
|
||||
BoundBox bb(transform_point(&inv, make_float3(0)));
|
||||
bb.grow(transform_point(&inv, make_float3(1)));
|
||||
|
||||
bb.grow(transform_point(&inv, bounds.min));
|
||||
bb.grow(transform_point(&inv, bounds.max));
|
||||
|
||||
node->bounds = bb;
|
||||
node->set_aligned_space(affSpace);
|
||||
node->deltaBounds = new BoundBox(bounds.min,
|
||||
bounds.max - make_float3(1));
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::set_time_bounds(BVHNode *node, float2 time_range)
|
||||
{
|
||||
node->time_from = time_range.x;
|
||||
node->time_to = time_range.y;
|
||||
}
|
||||
|
||||
#define SET_THIS \
|
||||
BVHEmbreeConverter* This = reinterpret_cast<BVHEmbreeConverter*>(userData)
|
||||
#define SET_NODE \
|
||||
BVHNode* Node = reinterpret_cast<BVHNode*>(node)
|
||||
|
||||
BVHNode* BVHEmbreeConverter::getBVH4()
|
||||
{
|
||||
RTCBVHExtractFunction param;
|
||||
param.createLeaf = [](unsigned int nbPrim, const BVHPrimitive prims[], void* userData) -> void* {
|
||||
SET_THIS;
|
||||
return This->createLeaf(nbPrim, prims);
|
||||
};
|
||||
|
||||
param.createInstance = [](unsigned int nbPrim, const unsigned int geomID[], void* userData) -> void* {
|
||||
SET_THIS;
|
||||
return This->createInstance(nbPrim, geomID);
|
||||
};
|
||||
|
||||
param.createCurve = [](unsigned int nbPrim, const BVHPrimitive prims[], void* userData) -> void* {
|
||||
SET_THIS;
|
||||
return This->createCurve(nbPrim, prims);
|
||||
};
|
||||
|
||||
param.createInnerNode = [](unsigned int nbChild, void* children[], void* userData) -> void* {
|
||||
SET_THIS;
|
||||
return This->createInnerNode(nbChild, reinterpret_cast<BVHNode**>(children));
|
||||
};
|
||||
|
||||
param.setAlignedBounds = [](void* node, const RTCBounds &bounds, void* userData) {
|
||||
SET_THIS; SET_NODE;
|
||||
This->setAlignedBounds(Node, RTCBoundBoxToCCL(bounds));
|
||||
};
|
||||
|
||||
param.setLinearBounds = [](void* node, const RTCLinearBounds &lbounds, void* userData) {
|
||||
SET_THIS; SET_NODE;
|
||||
This->setLinearBounds(Node,
|
||||
RTCBoundBoxToCCL(lbounds.bounds0),
|
||||
RTCBoundBoxToCCL(lbounds.bounds1));
|
||||
|
||||
This->set_time_bounds(Node, make_float2(lbounds.bounds0.align0,
|
||||
lbounds.bounds0.align1));
|
||||
};
|
||||
|
||||
param.setUnalignedBounds = [](void* node, const RTCAffineSpace &affSpace, void* userData) {
|
||||
SET_THIS; SET_NODE;
|
||||
Transform tr;
|
||||
tr.x.x = affSpace.linear[0];
|
||||
tr.y.x = affSpace.linear[1];
|
||||
tr.z.x = affSpace.linear[2];
|
||||
tr.x.y = affSpace.linear[3];
|
||||
tr.y.y = affSpace.linear[4];
|
||||
tr.z.y = affSpace.linear[5];
|
||||
tr.x.z = affSpace.linear[6];
|
||||
tr.y.z = affSpace.linear[7];
|
||||
tr.z.z = affSpace.linear[8];
|
||||
|
||||
tr.x.w = affSpace.affine[0];
|
||||
tr.y.w = affSpace.affine[1];
|
||||
tr.z.w = affSpace.affine[2];
|
||||
|
||||
This->setUnalignedBounds(Node, tr);
|
||||
};
|
||||
|
||||
param.setUnalignedLinearBounds = [](void* node, const RTCAffineSpace &affSpace, const RTCBounds &bounds, void* userData) {
|
||||
SET_THIS; SET_NODE;
|
||||
Transform tr;
|
||||
tr.x.x = affSpace.linear[0];
|
||||
tr.y.x = affSpace.linear[1];
|
||||
tr.z.x = affSpace.linear[2];
|
||||
tr.x.y = affSpace.linear[3];
|
||||
tr.y.y = affSpace.linear[4];
|
||||
tr.z.y = affSpace.linear[5];
|
||||
tr.x.z = affSpace.linear[6];
|
||||
tr.y.z = affSpace.linear[7];
|
||||
tr.z.z = affSpace.linear[8];
|
||||
|
||||
tr.x.w = affSpace.affine[0];
|
||||
tr.y.w = affSpace.affine[1];
|
||||
tr.z.w = affSpace.affine[2];
|
||||
|
||||
This->setUnalignedLinearBounds(Node, tr, RTCBoundBoxToCCL(bounds));
|
||||
};
|
||||
|
||||
param.expectedSize = [](unsigned int num_prim, unsigned int num_tri, void* userData) {
|
||||
SET_THIS;
|
||||
This->pack->prim_visibility.reserve(num_prim);
|
||||
This->pack->prim_object.reserve(num_prim);
|
||||
This->pack->prim_type.reserve(num_prim);
|
||||
This->pack->prim_index.reserve(num_prim);
|
||||
This->pack->prim_tri_index.reserve(num_prim);
|
||||
|
||||
This->pack->prim_tri_verts.reserve(num_tri);
|
||||
};
|
||||
|
||||
return reinterpret_cast<BVHNode *>(rtcExtractBVH(this->s, param, this));
|
||||
}
|
||||
|
||||
BVHNode* BVHEmbreeConverter::getBVH2()
|
||||
{
|
||||
BVHNode *root = this->getBVH4();
|
||||
if(root == nullptr) return nullptr;
|
||||
return bvh_shrink(root);
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::pack_instances(size_t nodes_size, size_t leaf_nodes_size, PackedBVH &pack)
|
||||
{
|
||||
/* Adjust primitive index to point to the triangle in the global array, for
|
||||
* meshes with transform applied and already in the top level BVH.
|
||||
*/
|
||||
for (size_t i = 0; i < pack.prim_index.size(); i++)
|
||||
if (pack.prim_index[i] != -1) {
|
||||
if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE)
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset;
|
||||
else
|
||||
pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
|
||||
}
|
||||
|
||||
/* track offsets of instanced BVH data in global array */
|
||||
size_t prim_offset = pack.prim_index.size();
|
||||
size_t nodes_offset = nodes_size;
|
||||
size_t nodes_leaf_offset = leaf_nodes_size;
|
||||
|
||||
/* clear array that gives the node indexes for instanced objects */
|
||||
pack.object_node.clear();
|
||||
|
||||
/* reserve */
|
||||
size_t prim_index_size = pack.prim_index.size();
|
||||
size_t prim_tri_verts_size = pack.prim_tri_verts.size();
|
||||
|
||||
size_t pack_prim_index_offset = prim_index_size;
|
||||
size_t pack_prim_tri_verts_offset = prim_tri_verts_size;
|
||||
size_t pack_nodes_offset = nodes_size;
|
||||
size_t pack_leaf_nodes_offset = leaf_nodes_size;
|
||||
size_t object_offset = 0;
|
||||
|
||||
map<Mesh *, int> mesh_map;
|
||||
|
||||
foreach (Object *ob, objects) {
|
||||
Mesh *mesh = ob->mesh;
|
||||
BVH *bvh = mesh->bvh;
|
||||
|
||||
if (mesh->need_build_bvh()) {
|
||||
if (mesh_map.find(mesh) == mesh_map.end()) {
|
||||
prim_index_size += bvh->pack.prim_index.size();
|
||||
prim_tri_verts_size += bvh->pack.prim_tri_verts.size();
|
||||
nodes_size += bvh->pack.nodes.size();
|
||||
leaf_nodes_size += bvh->pack.leaf_nodes.size();
|
||||
|
||||
mesh_map[mesh] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mesh_map.clear();
|
||||
|
||||
pack.prim_index.resize(prim_index_size);
|
||||
pack.prim_type.resize(prim_index_size);
|
||||
pack.prim_object.resize(prim_index_size);
|
||||
pack.prim_visibility.resize(prim_index_size);
|
||||
pack.prim_tri_verts.resize(prim_tri_verts_size);
|
||||
pack.prim_tri_index.resize(prim_index_size);
|
||||
pack.nodes.resize(nodes_size);
|
||||
pack.leaf_nodes.resize(leaf_nodes_size);
|
||||
pack.object_node.resize(objects.size());
|
||||
|
||||
if (params.num_motion_curve_steps > 0 || params.num_motion_triangle_steps > 0) {
|
||||
pack.prim_time.resize(prim_index_size);
|
||||
}
|
||||
|
||||
int *pack_prim_index = (pack.prim_index.size()) ? &pack.prim_index[0] : nullptr;
|
||||
int *pack_prim_type = (pack.prim_type.size()) ? &pack.prim_type[0] : nullptr;
|
||||
int *pack_prim_object = (pack.prim_object.size()) ? &pack.prim_object[0] : nullptr;
|
||||
uint *pack_prim_visibility = (pack.prim_visibility.size()) ? &pack.prim_visibility[0] : nullptr;
|
||||
float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size()) ? &pack.prim_tri_verts[0] : nullptr;
|
||||
uint *pack_prim_tri_index = (pack.prim_tri_index.size()) ? &pack.prim_tri_index[0] : nullptr;
|
||||
int4 *pack_nodes = (pack.nodes.size()) ? &pack.nodes[0] : nullptr;
|
||||
int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : nullptr;
|
||||
float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : nullptr;
|
||||
|
||||
/* merge */
|
||||
foreach (Object *ob, objects) {
|
||||
Mesh *mesh = ob->mesh;
|
||||
|
||||
/* We assume that if mesh doesn't need own BVH it was already included
|
||||
* into a top-level BVH and no packing here is needed.
|
||||
*/
|
||||
if (!mesh->need_build_bvh()) {
|
||||
pack.object_node[object_offset++] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if mesh already added once, don't add it again, but used set
|
||||
* node offset for this object */
|
||||
map<Mesh *, int>::iterator it = mesh_map.find(mesh);
|
||||
|
||||
if (mesh_map.find(mesh) != mesh_map.end()) {
|
||||
int noffset = it->second;
|
||||
pack.object_node[object_offset++] = noffset;
|
||||
continue;
|
||||
}
|
||||
|
||||
BVH *bvh = mesh->bvh;
|
||||
|
||||
int noffset = nodes_offset;
|
||||
int noffset_leaf = nodes_leaf_offset;
|
||||
int mesh_tri_offset = mesh->tri_offset;
|
||||
int mesh_curve_offset = mesh->curve_offset;
|
||||
|
||||
/* fill in node indexes for instances */
|
||||
if (bvh->pack.root_index == -1)
|
||||
pack.object_node[object_offset++] = -noffset_leaf - 1;
|
||||
else
|
||||
pack.object_node[object_offset++] = noffset;
|
||||
|
||||
mesh_map[mesh] = pack.object_node[object_offset - 1];
|
||||
|
||||
/* merge primitive, object and triangle indexes */
|
||||
if (bvh->pack.prim_index.size()) {
|
||||
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
|
||||
int *bvh_prim_index = &bvh->pack.prim_index[0];
|
||||
int *bvh_prim_type = &bvh->pack.prim_type[0];
|
||||
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0];
|
||||
uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0];
|
||||
float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : nullptr;
|
||||
|
||||
for (size_t i = 0; i < bvh_prim_index_size; i++) {
|
||||
if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset;
|
||||
pack_prim_tri_index[pack_prim_index_offset] = -1;
|
||||
}
|
||||
else {
|
||||
pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
|
||||
pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] +
|
||||
pack_prim_tri_verts_offset;
|
||||
}
|
||||
|
||||
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
|
||||
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
|
||||
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
|
||||
if (bvh_prim_time != nullptr) {
|
||||
pack_prim_time[pack_prim_index_offset] = bvh_prim_time[i];
|
||||
}
|
||||
pack_prim_index_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge triangle vertices data. */
|
||||
if (bvh->pack.prim_tri_verts.size()) {
|
||||
const size_t prim_tri_size = bvh->pack.prim_tri_verts.size();
|
||||
memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset,
|
||||
&bvh->pack.prim_tri_verts[0],
|
||||
prim_tri_size * sizeof(float4));
|
||||
pack_prim_tri_verts_offset += prim_tri_size;
|
||||
}
|
||||
|
||||
/* merge nodes */
|
||||
if (bvh->pack.leaf_nodes.size()) {
|
||||
int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0];
|
||||
size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size();
|
||||
for (size_t i = 0, j = 0; i < leaf_nodes_offset_size; i += BVH_NODE_SIZE_LEAF, j++) {
|
||||
int4 data = leaf_nodes_offset[i];
|
||||
data.x += prim_offset;
|
||||
data.y += prim_offset;
|
||||
pack_leaf_nodes[pack_leaf_nodes_offset] = data;
|
||||
for (int j = 1; j < BVH_NODE_SIZE_LEAF; ++j) {
|
||||
pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j];
|
||||
}
|
||||
pack_leaf_nodes_offset += BVH_NODE_SIZE_LEAF;
|
||||
}
|
||||
}
|
||||
|
||||
if (bvh->pack.nodes.size()) {
|
||||
int4 *bvh_nodes = &bvh->pack.nodes[0];
|
||||
size_t bvh_nodes_size = bvh->pack.nodes.size();
|
||||
|
||||
for (size_t i = 0, j = 0; i < bvh_nodes_size; j++) {
|
||||
size_t nsize = BVH_NODE_SIZE_BASE;
|
||||
if (bvh_nodes[i].x & PATH_RAY_NODE_4D) nsize += BVH_NODE_SIZE_4D;
|
||||
if (bvh_nodes[i].x & PATH_RAY_NODE_MB) nsize += BVH_NODE_SIZE_MOTION_BLUR;
|
||||
if (bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) nsize += BVH_NODE_SIZE_UNALIGNED;
|
||||
|
||||
/* Modify offsets into arrays */
|
||||
int4 data = bvh_nodes[i];
|
||||
data.z += (data.z < 0) ? -noffset_leaf : noffset;
|
||||
data.w += (data.w < 0) ? -noffset_leaf : noffset;
|
||||
pack_nodes[pack_nodes_offset] = data;
|
||||
|
||||
memcpy(&pack_nodes[pack_nodes_offset + 1],
|
||||
&bvh_nodes[i + 1],
|
||||
sizeof(int4) * (nsize - 1));
|
||||
|
||||
pack_nodes_offset += nsize;
|
||||
i += nsize;
|
||||
}
|
||||
}
|
||||
|
||||
nodes_offset += bvh->pack.nodes.size();
|
||||
nodes_leaf_offset += bvh->pack.leaf_nodes.size();
|
||||
prim_offset += bvh->pack.prim_index.size();
|
||||
}
|
||||
}
|
||||
|
||||
void pack_leaf(const BVHStackEntry &e, const LeafNode *leaf, PackedBVH &pack)
|
||||
{
|
||||
assert(e.idx + BVH_NODE_SIZE_LEAF <= pack.leaf_nodes.size());
|
||||
float4 data[BVH_NODE_SIZE_LEAF];
|
||||
memset(data, 0, sizeof(data));
|
||||
if (leaf->num_triangles() == 1 && pack.prim_index[leaf->lo] == -1) {
|
||||
/* object */
|
||||
data[0].x = __int_as_float(~(leaf->lo));
|
||||
data[0].y = __int_as_float(0);
|
||||
}
|
||||
else {
|
||||
/* triangle */
|
||||
data[0].x = __int_as_float(leaf->lo);
|
||||
data[0].y = __int_as_float(leaf->hi);
|
||||
}
|
||||
|
||||
data[0].z = __uint_as_float(leaf->visibility);
|
||||
data[0].w = __uint_as_float(pack.prim_type[leaf->lo]);
|
||||
|
||||
memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4) * BVH_NODE_SIZE_LEAF);
|
||||
}
|
||||
|
||||
void pack_base_node(const int idx, const BVHStackEntry &c0, const BVHStackEntry &c1, uint visibilityFlag, PackedBVH &pack)
|
||||
{
|
||||
assert(idx + BVH_NODE_SIZE_BASE <= pack.nodes.size());
|
||||
|
||||
// Clear visibility flags used for node type, and apply relevant ones
|
||||
uint visibility0 = (c0.node->visibility & ~PATH_RAY_NODE_CLEAR) | visibilityFlag;
|
||||
uint visibility1 = (c1.node->visibility & ~PATH_RAY_NODE_CLEAR) | visibilityFlag;
|
||||
|
||||
int4 data[BVH_NODE_SIZE_BASE] = {
|
||||
make_int4(visibility0, visibility1, c0.encodeIdx(), c1.encodeIdx()),
|
||||
make_int4(__float_as_int(c0.node->bounds.min.x),
|
||||
__float_as_int(c1.node->bounds.min.x),
|
||||
__float_as_int(c0.node->bounds.max.x),
|
||||
__float_as_int(c1.node->bounds.max.x)),
|
||||
make_int4(__float_as_int(c0.node->bounds.min.y),
|
||||
__float_as_int(c1.node->bounds.min.y),
|
||||
__float_as_int(c0.node->bounds.max.y),
|
||||
__float_as_int(c1.node->bounds.max.y)),
|
||||
make_int4(__float_as_int(c0.node->bounds.min.z),
|
||||
__float_as_int(c1.node->bounds.min.z),
|
||||
__float_as_int(c0.node->bounds.max.z),
|
||||
__float_as_int(c1.node->bounds.max.z)),
|
||||
};
|
||||
|
||||
memcpy(&pack.nodes[idx], data, sizeof(int4) * BVH_NODE_SIZE_BASE);
|
||||
}
|
||||
|
||||
void pack_unaligned_node(const int idx, const BVHStackEntry &c0, const BVHStackEntry &c1, uint visibilityFlag, PackedBVH &pack) {
|
||||
assert(idx + BVH_NODE_SIZE_BASE + BVH_NODE_SIZE_UNALIGNED <= pack.nodes.size());
|
||||
|
||||
// Clear visibility flags used for node type, and apply relevant ones
|
||||
uint visibility0 = (c0.node->visibility & ~PATH_RAY_NODE_CLEAR) | visibilityFlag;
|
||||
uint visibility1 = (c1.node->visibility & ~PATH_RAY_NODE_CLEAR) | visibilityFlag;
|
||||
|
||||
float4 data[BVH_NODE_SIZE_BASE + BVH_NODE_SIZE_UNALIGNED];
|
||||
data[0] = make_float4(__int_as_float(visibility0),
|
||||
__int_as_float(visibility1),
|
||||
__int_as_float(c0.encodeIdx()),
|
||||
__int_as_float(c1.encodeIdx()));
|
||||
|
||||
Transform bb0 = c0.node->is_unaligned ? *c0.node->aligned_space
|
||||
: transformSpaceFromBound(c0.node->bounds);
|
||||
Transform bb1 = c1.node->is_unaligned ? *c1.node->aligned_space
|
||||
: transformSpaceFromBound(c1.node->bounds);
|
||||
|
||||
data[1] = bb0.x;
|
||||
data[2] = bb0.y;
|
||||
data[3] = bb0.z;
|
||||
data[4] = bb1.x;
|
||||
data[5] = bb1.y;
|
||||
data[6] = bb1.z;
|
||||
|
||||
memcpy(&pack.nodes[idx], data, sizeof(float4) * (BVH_NODE_SIZE_BASE + BVH_NODE_SIZE_UNALIGNED));
|
||||
}
|
||||
|
||||
void pack_4D_node(const int idx, const BVHNode *c0, const BVHNode *c1, PackedBVH &pack)
|
||||
{
|
||||
assert(idx + BVH_NODE_SIZE_4D <= pack.nodes.size());
|
||||
assert(BVH_NODE_SIZE_4D == 1);
|
||||
|
||||
pack.nodes[idx] = make_int4(__float_as_int(c0->time_from),
|
||||
__float_as_int(c1->time_from),
|
||||
__float_as_int(c0->time_to),
|
||||
__float_as_int(c1->time_to));
|
||||
};
|
||||
|
||||
void pack_MB_node(const int idx, const BoundBox *bb0, const BoundBox *bb1, PackedBVH &pack)
|
||||
{
|
||||
assert(idx + BVH_NODE_SIZE_MOTION_BLUR <= pack.nodes.size());
|
||||
|
||||
if(bb0 == nullptr) bb0 = new BoundBox(make_float3(0));
|
||||
if(bb1 == nullptr) bb1 = new BoundBox(make_float3(0));
|
||||
|
||||
int4 data[BVH_NODE_SIZE_MOTION_BLUR] = {
|
||||
make_int4(__float_as_int(bb0->min.x),
|
||||
__float_as_int(bb1->min.x),
|
||||
__float_as_int(bb0->max.x),
|
||||
__float_as_int(bb1->max.x)),
|
||||
make_int4(__float_as_int(bb0->min.y),
|
||||
__float_as_int(bb1->min.y),
|
||||
__float_as_int(bb0->max.y),
|
||||
__float_as_int(bb1->max.y)),
|
||||
make_int4(__float_as_int(bb0->min.z),
|
||||
__float_as_int(bb1->min.z),
|
||||
__float_as_int(bb0->max.z),
|
||||
__float_as_int(bb1->max.z)),
|
||||
};
|
||||
|
||||
memcpy(&pack.nodes[idx], data, sizeof(int4) * BVH_NODE_SIZE_MOTION_BLUR);
|
||||
}
|
||||
|
||||
int getSize(const BVHNode *e) {
|
||||
int size = BVH_NODE_SIZE_BASE;
|
||||
if(e->has_time_limited()) size += BVH_NODE_SIZE_4D;
|
||||
if(e->has_motion_blur()) size += BVH_NODE_SIZE_MOTION_BLUR;
|
||||
if(e->has_unaligned()) size += BVH_NODE_SIZE_UNALIGNED;
|
||||
return size;
|
||||
}
|
||||
|
||||
void pack_inner(const BVHStackEntry &e, const BVHStackEntry &c0, const BVHStackEntry &c1, PackedBVH &pack)
|
||||
{
|
||||
uint visibility = 0;
|
||||
|
||||
if(e.node->has_time_limited())
|
||||
visibility |= PATH_RAY_NODE_4D;
|
||||
|
||||
if(e.node->has_motion_blur())
|
||||
visibility |= PATH_RAY_NODE_MB;
|
||||
|
||||
if(e.node->has_unaligned())
|
||||
visibility |= PATH_RAY_NODE_UNALIGNED;
|
||||
|
||||
int idx = e.idx;
|
||||
if(e.node->has_unaligned()) {
|
||||
pack_unaligned_node(idx, c0, c1, visibility, pack);
|
||||
idx += BVH_NODE_SIZE_BASE + BVH_NODE_SIZE_UNALIGNED;
|
||||
} else {
|
||||
pack_base_node(idx, c0, c1, visibility, pack);
|
||||
idx += BVH_NODE_SIZE_BASE;
|
||||
}
|
||||
|
||||
if(visibility & PATH_RAY_NODE_MB) {
|
||||
pack_MB_node(idx, c0.node->deltaBounds, c1.node->deltaBounds, pack);
|
||||
idx += BVH_NODE_SIZE_MOTION_BLUR;
|
||||
}
|
||||
|
||||
if(visibility & PATH_RAY_NODE_4D) {
|
||||
pack_4D_node(idx, c0.node, c1.node, pack);
|
||||
idx += BVH_NODE_SIZE_4D;
|
||||
}
|
||||
|
||||
assert(e.idx + getSize(e.node) == idx);
|
||||
}
|
||||
|
||||
void BVHEmbreeConverter::fillPack(PackedBVH &pack) {
|
||||
pack.prim_visibility.clear();
|
||||
pack.prim_object.clear();
|
||||
pack.prim_type.clear();
|
||||
pack.prim_index.clear();
|
||||
pack.prim_tri_index.clear();
|
||||
pack.prim_tri_verts.clear();
|
||||
|
||||
this->pack = &pack;
|
||||
|
||||
BVHNode *root = this->getBVH2();
|
||||
if(root == nullptr) {
|
||||
pack.nodes.clear();
|
||||
pack.leaf_nodes.resize(1);
|
||||
pack.leaf_nodes[0].x = 0;
|
||||
pack.leaf_nodes[0].y = 0;
|
||||
pack.leaf_nodes[0].z = 0;
|
||||
pack.leaf_nodes[0].w = 0;
|
||||
pack.root_index = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
|
||||
const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT);
|
||||
assert(num_leaf_nodes <= num_nodes);
|
||||
const size_t num_inner_nodes = num_nodes - num_leaf_nodes;
|
||||
size_t node_size = num_inner_nodes * BVH_NODE_SIZE_BASE;
|
||||
|
||||
// Additional size for unaligned nodes
|
||||
if (params.use_unaligned_nodes) {
|
||||
const size_t num_unaligned_nodes = root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT);
|
||||
node_size += num_unaligned_nodes * BVH_NODE_SIZE_UNALIGNED;
|
||||
}
|
||||
|
||||
// Additional size for linear bound
|
||||
node_size += root->getSubtreeSize(BVH_STAT_MOTION_BLURED_NODE_COUNT) * BVH_NODE_SIZE_MOTION_BLUR;
|
||||
|
||||
// Additional size for time limits
|
||||
node_size += root->getSubtreeSize(BVH_STAT_4D_NODE_COUNT) * BVH_NODE_SIZE_4D;
|
||||
|
||||
/* Resize arrays */
|
||||
pack.nodes.clear();
|
||||
pack.leaf_nodes.clear();
|
||||
/* For top level BVH, first merge existing BVH's so we know the offsets. */
|
||||
if (params.top_level) {
|
||||
pack_instances(node_size, num_leaf_nodes * BVH_NODE_SIZE_LEAF, pack);
|
||||
}
|
||||
else {
|
||||
pack.nodes.resize(node_size);
|
||||
pack.leaf_nodes.resize(num_leaf_nodes * BVH_NODE_SIZE_LEAF);
|
||||
}
|
||||
|
||||
int nextNodeIdx = 0, nextLeafNodeIdx = 0;
|
||||
|
||||
vector<BVHStackEntry> stack;
|
||||
stack.reserve(BVHParams::MAX_DEPTH * 2);
|
||||
if (root->is_leaf()) {
|
||||
stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++));
|
||||
}
|
||||
else {
|
||||
stack.push_back(BVHStackEntry(root, nextNodeIdx));
|
||||
nextNodeIdx += getSize(root);
|
||||
}
|
||||
|
||||
while (stack.size()) {
|
||||
BVHStackEntry e = stack.back();
|
||||
stack.pop_back();
|
||||
|
||||
if (e.node->is_leaf()) {
|
||||
/* leaf node */
|
||||
const LeafNode *leaf = reinterpret_cast<const LeafNode *>(e.node);
|
||||
pack_leaf(e, leaf, pack);
|
||||
}
|
||||
else {
|
||||
assert(e.node->num_children() == 2);
|
||||
/* inner node */
|
||||
int idx[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (e.node->get_child(i)->is_leaf()) {
|
||||
idx[i] = nextLeafNodeIdx++;
|
||||
}
|
||||
else {
|
||||
idx[i] = nextNodeIdx;
|
||||
nextNodeIdx += getSize(e.node->get_child(i));
|
||||
}
|
||||
}
|
||||
|
||||
stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0]));
|
||||
stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1]));
|
||||
|
||||
pack_inner(e, stack[stack.size() - 2], stack[stack.size() - 1], pack);
|
||||
}
|
||||
}
|
||||
assert(node_size == nextNodeIdx);
|
||||
/* root index to start traversal at, to handle case of single leaf node */
|
||||
pack.root_index = (root->is_leaf()) ? -1 : 0;
|
||||
|
||||
root->deleteSubtree();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_EMBREE */
|
222
intern/cycles/bvh/bvh_embree_converter.h
Normal file
222
intern/cycles/bvh/bvh_embree_converter.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2018, Blender Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BVH_EMBREE_CONVERTER_H__
|
||||
#define __BVH_EMBREE_CONVERTER_H__
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
|
||||
#include <deque>
|
||||
#include <stack>
|
||||
|
||||
#include "render/object.h"
|
||||
#include <embree3/rtcore_builder.h>
|
||||
|
||||
#include "bvh_node.h"
|
||||
|
||||
#include "bvh.h"
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define BVH_NODE_SIZE_LEAF 1
|
||||
#define BVH_NODE_SIZE_BASE 4
|
||||
#define BVH_NODE_SIZE_4D 1
|
||||
#define BVH_NODE_SIZE_MOTION_BLUR 3
|
||||
#define BVH_NODE_SIZE_UNALIGNED 3
|
||||
|
||||
/**
|
||||
* @brief This class implements a converter from Embree internal data structure
|
||||
* to Blender's internal structure
|
||||
*/
|
||||
class BVHEmbreeConverter
|
||||
{
|
||||
public:
|
||||
BVHEmbreeConverter(RTCScene scene,
|
||||
std::vector<Object *> objects,
|
||||
const BVHParams ¶ms);
|
||||
|
||||
BVHNode *getBVH4();
|
||||
BVHNode *getBVH2();
|
||||
|
||||
void fillPack(PackedBVH &pack);
|
||||
private:
|
||||
RTCScene s;
|
||||
std::vector<Object *> objects;
|
||||
const BVHParams ¶ms;
|
||||
PackedBVH *pack;
|
||||
unsigned int packIdx = 0;
|
||||
|
||||
private:
|
||||
BVHNode* createLeaf(unsigned int nbPrim, const BVHPrimitive prims[]);
|
||||
BVHNode* createInstance(unsigned int nbPrim, const unsigned int geomID[]);
|
||||
BVHNode *createCurve(unsigned int nbPrim, const BVHPrimitive prims[]);
|
||||
BVHNode *createInnerNode(unsigned int nbChild, BVHNode *children[]);
|
||||
void setAlignedBounds(BVHNode* node, BoundBox bounds);
|
||||
void setLinearBounds(BVHNode* node, BoundBox bounds, BoundBox deltaBounds);
|
||||
void setUnalignedBounds(BVHNode* node, Transform affSpace);
|
||||
void setUnalignedLinearBounds(BVHNode *node, Transform affSpace, BoundBox bounds);
|
||||
void set_time_bounds(BVHNode* node, float2 time_range);
|
||||
|
||||
void pack_instances(size_t nodes_size,
|
||||
size_t leaf_nodes_size,
|
||||
PackedBVH &pack);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Merge two BVHNode into a tree that contain both of them
|
||||
* @param oldRoot A common ancestor of the two nodes
|
||||
* @param n0 First child
|
||||
* @param n1 Second child
|
||||
* @return A node that contains both child
|
||||
*/
|
||||
BVHNode *merge(const BVHNode *oldRoot, BVHNode *n0, BVHNode *n1);
|
||||
|
||||
/**
|
||||
* @brief Insert a new primitive in packed data
|
||||
* @param pack Pack structure
|
||||
* @param packIdx Index to insert into
|
||||
* @param object_id Object ID
|
||||
* @param prim_id Primitive ID
|
||||
* @param prim_type Primitive type
|
||||
* @param visibility Visibility flag of the primitive
|
||||
* @param tri_index Index for the array containing triangle information
|
||||
*/
|
||||
void packPush(PackedBVH *pack, const size_t packIdx,
|
||||
const int object_id, const int prim_id,
|
||||
const int prim_type, const uint visibility, const uint tri_index);
|
||||
|
||||
/**
|
||||
* @brief Convert embree Bound Box to cycle Bound Box
|
||||
* @param bound Embree Bound Box
|
||||
* @return Cycle Bound Box
|
||||
*/
|
||||
BoundBox RTCBoundBoxToCCL(const RTCBounds &bound);
|
||||
|
||||
/**
|
||||
* @brief Create unaligned space from aligned bounds
|
||||
* @param bounds Aligne bounds box
|
||||
* @return A space in which bounds are [0; 1] on all axis
|
||||
*/
|
||||
Transform transformSpaceFromBound(const BoundBox &bounds);
|
||||
|
||||
/**
|
||||
* @brief Convert a list of BVHNode to a BVH2
|
||||
* Create new nodes if required
|
||||
* @param nodes A list of nodes to insert in the tree
|
||||
* @return A BVH2 containing all provided nodes
|
||||
*/
|
||||
BVHNode *makeBVHTreeFromList(std::deque<BVHNode *> nodes);
|
||||
|
||||
/**
|
||||
* @brief Convert a tree (up to BVH4) to a BVH2
|
||||
* Do not copy node, but update child list: thus every pointer to anywhere in
|
||||
* this tree remain valid
|
||||
* @param root The source BVH tree
|
||||
* @return A BVH2 containg at least all node from the source
|
||||
*/
|
||||
BVHNode *bvh_shrink(BVHNode *root);
|
||||
|
||||
/**
|
||||
* @brief Copute the size for a node
|
||||
* @param e The node to get the size
|
||||
* @return The size used in memory by the node
|
||||
*/
|
||||
int getSize(const BVHNode *e);
|
||||
|
||||
/**
|
||||
* @brief Pack a leaf node
|
||||
* @param e Node entry
|
||||
* @param leaf Leaf node to insert
|
||||
* @param pack Pack structure to fill
|
||||
*/
|
||||
void pack_leaf(const BVHStackEntry &e,
|
||||
const LeafNode *leaf,
|
||||
PackedBVH &pack);
|
||||
|
||||
/**
|
||||
* @brief Pack a generic aligned node
|
||||
* @param idx Index of the node to pack
|
||||
* @param c0 First child of the node
|
||||
* @param c1 Second child of the node
|
||||
* @param visibilityFlag Visibility mask to apply to both node
|
||||
* @param pack Pack structure to fill
|
||||
*
|
||||
* @see pack_unaligned_node
|
||||
*/
|
||||
void pack_base_node(const int idx,
|
||||
const BVHStackEntry &c0,
|
||||
const BVHStackEntry &c1,
|
||||
uint visibilityFlag,
|
||||
PackedBVH &pack);
|
||||
|
||||
/**
|
||||
* @brief Pack an unaligned node
|
||||
* @param idx Index of the node to pack
|
||||
* @param c0 First child of the node
|
||||
* @param c1 Second child of the node
|
||||
* @param visibilityFlag Visibility mask to apply to both node
|
||||
* @param pack Pack structure to fill
|
||||
*
|
||||
* @see pack_unaligned_node
|
||||
*/
|
||||
void pack_unaligned_node(const int idx,
|
||||
const BVHStackEntry &c0,
|
||||
const BVHStackEntry &c1,
|
||||
uint visibilityFlag,
|
||||
PackedBVH &pack);
|
||||
|
||||
/**
|
||||
* @brief Pack additional data for 4D node
|
||||
* @param idx Index to insert data to (should be baseIdx + BVH_NODE_SIZE_BASE)
|
||||
* @param c0 First child of the node
|
||||
* @param c1 Second child of the node
|
||||
* @param pack Pack structure to fill
|
||||
*/
|
||||
void pack_4D_node(const int idx,
|
||||
const BVHNode *c0,
|
||||
const BVHNode *c1,
|
||||
PackedBVH &pack);
|
||||
|
||||
/**
|
||||
* @brief Pack additional data for MB node
|
||||
* Store linear bound box of both children of the node
|
||||
* @param idx Index to insert data to (should be baseIdx + BVH_NODE_SIZE_BASE)
|
||||
* @param c0 First child of the node
|
||||
* @param c1 Second child of the node
|
||||
* @param pack Pack structure to fill
|
||||
*/
|
||||
void pack_MB_node(const int idx,
|
||||
const BoundBox *bb0,
|
||||
const BoundBox *bb1,
|
||||
PackedBVH &pack);
|
||||
|
||||
/**
|
||||
* @brief Pack an inner node
|
||||
* @param e Root node to store
|
||||
* @param c0 First child of the node
|
||||
* @param c1 Second child of the node
|
||||
* @param pack Pack structure to fill
|
||||
*/
|
||||
void pack_inner(const BVHStackEntry &e,
|
||||
const BVHStackEntry &c0,
|
||||
const BVHStackEntry &c1,
|
||||
PackedBVH &pack);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_EMBREE */
|
||||
|
||||
#endif /* __BVH_EMBREE_CONVERTER_H__ */
|
@@ -91,6 +91,14 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const
|
||||
cnt += 1;
|
||||
}
|
||||
return cnt;
|
||||
case BVH_STAT_4D_NODE_COUNT:
|
||||
if(this->has_time_limited())
|
||||
cnt = 1;
|
||||
break;
|
||||
case BVH_STAT_MOTION_BLURED_NODE_COUNT:
|
||||
if(this->has_motion_blur())
|
||||
cnt = 1;
|
||||
break;
|
||||
default:
|
||||
assert(0); /* unknown mode */
|
||||
}
|
||||
@@ -118,7 +126,7 @@ float BVHNode::computeSubtreeSAHCost(const BVHParams &p, float probability) cons
|
||||
for (int i = 0; i < num_children(); i++) {
|
||||
BVHNode *child = get_child(i);
|
||||
SAH += child->computeSubtreeSAHCost(
|
||||
p, probability * child->bounds.safe_area() / bounds.safe_area());
|
||||
p, probability * child->bounds.safe_area() / bounds.safe_area() * (child->time_to - child->time_from) / (time_to - time_from));
|
||||
}
|
||||
|
||||
return SAH;
|
||||
|
@@ -36,6 +36,8 @@ enum BVH_STAT {
|
||||
BVH_STAT_ALIGNED_LEAF_COUNT,
|
||||
BVH_STAT_UNALIGNED_LEAF_COUNT,
|
||||
BVH_STAT_DEPTH,
|
||||
BVH_STAT_4D_NODE_COUNT,
|
||||
BVH_STAT_MOTION_BLURED_NODE_COUNT,
|
||||
};
|
||||
|
||||
class BVHParams;
|
||||
@@ -45,6 +47,7 @@ class BVHNode {
|
||||
virtual ~BVHNode()
|
||||
{
|
||||
delete aligned_space;
|
||||
delete deltaBounds;
|
||||
}
|
||||
|
||||
virtual bool is_leaf() const = 0;
|
||||
@@ -88,6 +91,40 @@ class BVHNode {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_time_limited() const {
|
||||
return this->time_from > 0 || this->time_to < 1;
|
||||
}
|
||||
|
||||
inline bool has_time_limited() const
|
||||
{
|
||||
if (is_leaf()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < num_children(); ++i) {
|
||||
if (get_child(i)->is_time_limited()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool is_motion_blur() const {
|
||||
return this->deltaBounds != nullptr;
|
||||
}
|
||||
|
||||
inline bool has_motion_blur() const
|
||||
{
|
||||
if (is_leaf()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < num_children(); ++i) {
|
||||
if (get_child(i)->is_motion_blur()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Subtree functions
|
||||
int getSubtreeSize(BVH_STAT stat = BVH_STAT_NODE_COUNT) const;
|
||||
float computeSubtreeSAHCost(const BVHParams &p, float probability = 1.0f) const;
|
||||
@@ -110,6 +147,8 @@ class BVHNode {
|
||||
*/
|
||||
Transform *aligned_space;
|
||||
|
||||
BoundBox *deltaBounds;
|
||||
|
||||
float time_from, time_to;
|
||||
|
||||
protected:
|
||||
@@ -118,6 +157,7 @@ class BVHNode {
|
||||
visibility(0),
|
||||
is_unaligned(false),
|
||||
aligned_space(NULL),
|
||||
deltaBounds(NULL),
|
||||
time_from(0.0f),
|
||||
time_to(1.0f)
|
||||
{
|
||||
@@ -128,6 +168,7 @@ class BVHNode {
|
||||
visibility(other.visibility),
|
||||
is_unaligned(other.is_unaligned),
|
||||
aligned_space(NULL),
|
||||
deltaBounds(NULL),
|
||||
time_from(other.time_from),
|
||||
time_to(other.time_to)
|
||||
{
|
||||
|
@@ -338,7 +338,7 @@ class CPUDevice : public Device {
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_EMBREE
|
||||
bvh_layout_mask |= BVH_LAYOUT_EMBREE;
|
||||
bvh_layout_mask |= BVH_LAYOUT_EMBREE | BVH_LAYOUT_EMBREE_CONVERTED;
|
||||
#endif /* WITH_EMBREE */
|
||||
return bvh_layout_mask;
|
||||
}
|
||||
|
@@ -185,7 +185,7 @@ class CUDADevice : public Device {
|
||||
|
||||
virtual BVHLayoutMask get_bvh_layout_mask() const
|
||||
{
|
||||
return BVH_LAYOUT_BVH2;
|
||||
return BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE_CONVERTED;
|
||||
}
|
||||
|
||||
/*#ifdef NDEBUG
|
||||
|
@@ -127,6 +127,7 @@ ccl_device_inline
|
||||
isect_t,
|
||||
node_addr,
|
||||
PATH_RAY_ALL_VISIBILITY,
|
||||
ray->time,
|
||||
dist);
|
||||
#else // __KERNEL_SSE2__
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
@@ -142,6 +143,7 @@ ccl_device_inline
|
||||
shufflexyz,
|
||||
node_addr,
|
||||
PATH_RAY_ALL_VISIBILITY,
|
||||
ray->time,
|
||||
dist);
|
||||
#endif // __KERNEL_SSE2__
|
||||
|
||||
|
@@ -33,39 +33,69 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals *kg,
|
||||
const float3 P,
|
||||
const float3 idir,
|
||||
const float t,
|
||||
const int node_addr,
|
||||
int node_addr,
|
||||
const uint visibility,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
|
||||
/* fetch node data */
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
|
||||
float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr + 1);
|
||||
float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr + 2);
|
||||
float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr + 3);
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
|
||||
float3 c0lo = make_float3(node0.x, node1.x, node2.x);
|
||||
float3 c0hi = make_float3(node0.z, node1.z, node2.z);
|
||||
float3 c1lo = make_float3(node0.y, node1.y, node2.y);
|
||||
float3 c1hi = make_float3(node0.w, node1.w, node2.w);
|
||||
|
||||
if (__float_as_int(cnodes.x) & PATH_RAY_NODE_MB) {
|
||||
float4 node3 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
float4 node4 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
float4 node5 = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
|
||||
float3 c0dlo = make_float3(node3.x, node4.x, node5.x);
|
||||
float3 c0dhi = make_float3(node3.z, node4.z, node5.z);
|
||||
float3 c1dlo = make_float3(node3.y, node4.y, node5.y);
|
||||
float3 c1dhi = make_float3(node3.w, node4.w, node5.w);
|
||||
|
||||
c0lo += rayTime * c0dlo;
|
||||
c0hi += rayTime * c0dhi;
|
||||
c1lo += rayTime * c1dlo;
|
||||
c1hi += rayTime * c1dhi;
|
||||
}
|
||||
|
||||
/* intersect ray against child nodes */
|
||||
float c0lox = (node0.x - P.x) * idir.x;
|
||||
float c0hix = (node0.z - P.x) * idir.x;
|
||||
float c0loy = (node1.x - P.y) * idir.y;
|
||||
float c0hiy = (node1.z - P.y) * idir.y;
|
||||
float c0loz = (node2.x - P.z) * idir.z;
|
||||
float c0hiz = (node2.z - P.z) * idir.z;
|
||||
float c0lox = (c0lo.x - P.x) * idir.x;
|
||||
float c0hix = (c0hi.x - P.x) * idir.x;
|
||||
float c0loy = (c0lo.y - P.y) * idir.y;
|
||||
float c0hiy = (c0hi.y - P.y) * idir.y;
|
||||
float c0loz = (c0lo.z - P.z) * idir.z;
|
||||
float c0hiz = (c0hi.z - P.z) * idir.z;
|
||||
float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
|
||||
float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
|
||||
|
||||
float c1lox = (node0.y - P.x) * idir.x;
|
||||
float c1hix = (node0.w - P.x) * idir.x;
|
||||
float c1loy = (node1.y - P.y) * idir.y;
|
||||
float c1hiy = (node1.w - P.y) * idir.y;
|
||||
float c1loz = (node2.y - P.z) * idir.z;
|
||||
float c1hiz = (node2.w - P.z) * idir.z;
|
||||
float c1lox = (c1lo.x - P.x) * idir.x;
|
||||
float c1hix = (c1hi.x - P.x) * idir.x;
|
||||
float c1loy = (c1lo.y - P.y) * idir.y;
|
||||
float c1hiy = (c1hi.y - P.y) * idir.y;
|
||||
float c1loz = (c1lo.z - P.z) * idir.z;
|
||||
float c1hiz = (c1hi.z - P.z) * idir.z;
|
||||
float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
|
||||
float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
|
||||
|
||||
dist[0] = c0min;
|
||||
dist[1] = c1min;
|
||||
|
||||
if (__float_as_int(cnodes.x) & PATH_RAY_NODE_4D) {
|
||||
float4 timeLimits = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
if(timeLimits.x > rayTime || timeLimits.z < rayTime)
|
||||
c0max = -1.0f;
|
||||
|
||||
if(timeLimits.y > rayTime || timeLimits.w < rayTime)
|
||||
c1max = -1.0f;
|
||||
}
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
/* this visibility test gives a 5% performance hit, how to solve? */
|
||||
return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility)) ? 1 : 0) |
|
||||
@@ -81,14 +111,38 @@ ccl_device_forceinline bool bvh_unaligned_node_intersect_child(KernelGlobals *kg
|
||||
const float t,
|
||||
int node_addr,
|
||||
int child,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr);
|
||||
|
||||
Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child);
|
||||
float3 aligned_dir = transform_direction(&space, dir);
|
||||
float3 aligned_P = transform_point(&space, P);
|
||||
float3 nrdir = -bvh_inverse_direction(aligned_dir);
|
||||
float3 lower_xyz = aligned_P * nrdir;
|
||||
float3 upper_xyz = lower_xyz - nrdir;
|
||||
float3 nrdir = bvh_inverse_direction(aligned_dir);
|
||||
|
||||
float3 lower_xyz;
|
||||
float3 upper_xyz;
|
||||
if (__float_as_int(cnodes.x) & PATH_RAY_NODE_MB) {
|
||||
float4 node3 = kernel_tex_fetch(__bvh_nodes, node_addr + 7);
|
||||
float4 node4 = kernel_tex_fetch(__bvh_nodes, node_addr + 8);
|
||||
float4 node5 = kernel_tex_fetch(__bvh_nodes, node_addr + 9);
|
||||
|
||||
float3 c0dlo = make_float3(node3.x, node4.x, node5.x);
|
||||
float3 c0dhi = make_float3(node3.z, node4.z, node5.z);
|
||||
float3 c1dlo = make_float3(node3.y, node4.y, node5.y);
|
||||
float3 c1dhi = make_float3(node3.w, node4.w, node5.w);
|
||||
|
||||
float3 lowBounds = ((child == 0) ? c0dlo : c1dlo) * rayTime,
|
||||
uppBounds = make_float3(1, 1, 1) + rayTime * (child == 0 ? c0dhi : c1dhi);
|
||||
|
||||
lower_xyz = (lowBounds - aligned_P) * nrdir;
|
||||
upper_xyz = (uppBounds - aligned_P) * nrdir;
|
||||
} else {
|
||||
lower_xyz = aligned_P * -nrdir;
|
||||
upper_xyz = lower_xyz + nrdir;
|
||||
}
|
||||
|
||||
const float near_x = min(lower_xyz.x, upper_xyz.x);
|
||||
const float near_y = min(lower_xyz.y, upper_xyz.y);
|
||||
const float near_z = min(lower_xyz.z, upper_xyz.z);
|
||||
@@ -108,11 +162,12 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg,
|
||||
const float t,
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
int mask = 0;
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, rayTime, &dist[0])) {
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
if ((__float_as_uint(cnodes.x) & visibility))
|
||||
# endif
|
||||
@@ -120,7 +175,7 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals *kg,
|
||||
mask |= 1;
|
||||
}
|
||||
}
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
|
||||
if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, rayTime, &dist[1])) {
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
if ((__float_as_uint(cnodes.y) & visibility))
|
||||
# endif
|
||||
@@ -138,14 +193,15 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg,
|
||||
const float t,
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
|
||||
if (__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
|
||||
return bvh_unaligned_node_intersect(kg, P, dir, idir, t, node_addr, visibility, dist);
|
||||
return bvh_unaligned_node_intersect(kg, P, dir, idir, t, node_addr, visibility, rayTime, dist);
|
||||
}
|
||||
else {
|
||||
return bvh_aligned_node_intersect(kg, P, idir, t, node_addr, visibility, dist);
|
||||
return bvh_aligned_node_intersect(kg, P, idir, t, node_addr, visibility, rayTime, dist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,34 +214,59 @@ int ccl_device_forceinline bvh_aligned_node_intersect(KernelGlobals *kg,
|
||||
const ssef Psplat[3],
|
||||
const ssef idirsplat[3],
|
||||
const shuffle_swap_t shufflexyz[3],
|
||||
const int node_addr,
|
||||
int node_addr,
|
||||
const uint visibility,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
/* Intersect two child bounding boxes, SSE3 version adapted from Embree */
|
||||
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
|
||||
|
||||
/* fetch node data */
|
||||
const ssef *bvh_nodes = (ssef *)kg->__bvh_nodes.data + node_addr;
|
||||
const ssef *bvh_nodes = (ssef *)kg->__bvh_nodes.data;
|
||||
|
||||
/* intersect ray against child nodes */
|
||||
const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
|
||||
const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
|
||||
const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr++);
|
||||
ssef x = bvh_nodes[node_addr++];
|
||||
ssef y = bvh_nodes[node_addr++];
|
||||
ssef z = bvh_nodes[node_addr++];
|
||||
|
||||
if (__float_as_uint(cnodes.x) & PATH_RAY_NODE_MB) {
|
||||
const ssef dx = bvh_nodes[node_addr++];
|
||||
const ssef dy = bvh_nodes[node_addr++];
|
||||
const ssef dz = bvh_nodes[node_addr++];
|
||||
|
||||
x += rayTime * dx;
|
||||
y += rayTime * dy;
|
||||
z += rayTime * dz;
|
||||
}
|
||||
|
||||
/* intersect ray against child nodes */
|
||||
const ssef tminmaxx = (shuffle_swap(x, shufflexyz[0]) - Psplat[0]) * idirsplat[0];
|
||||
const ssef tminmaxy = (shuffle_swap(y, shufflexyz[1]) - Psplat[1]) * idirsplat[1];
|
||||
const ssef tminmaxz = (shuffle_swap(z, shufflexyz[2]) - Psplat[2]) * idirsplat[2];
|
||||
|
||||
/* calculate { c0min, c1min, -c0max, -c1max} */
|
||||
ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
|
||||
const ssef tminmax = minmax ^ pn;
|
||||
const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
|
||||
sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
|
||||
|
||||
dist[0] = tminmax[0];
|
||||
dist[1] = tminmax[1];
|
||||
|
||||
if (__float_as_uint(cnodes.x) & PATH_RAY_NODE_4D) {
|
||||
const ssef timeLimit = bvh_nodes[node_addr++];
|
||||
|
||||
const sseb timeMin = timeLimit < rayTime;
|
||||
const sseb timeMax = timeLimit > rayTime;
|
||||
|
||||
lrhit &= timeMin & shuffle<2, 3, 0, 1>(timeMax);
|
||||
}
|
||||
|
||||
int mask = movemask(lrhit);
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
/* this visibility test gives a 5% performance hit, how to solve? */
|
||||
float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
|
||||
int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility)) ? 1 : 0) |
|
||||
(((mask & 2) && (__float_as_uint(cnodes.y) & visibility)) ? 2 : 0);
|
||||
return cmask;
|
||||
@@ -257,6 +338,7 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg,
|
||||
const shuffle_swap_t shufflexyz[3],
|
||||
const int node_addr,
|
||||
const uint visibility,
|
||||
const float rayTime,
|
||||
float dist[2])
|
||||
{
|
||||
float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
|
||||
@@ -266,7 +348,7 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals *kg,
|
||||
}
|
||||
else {
|
||||
return bvh_aligned_node_intersect(
|
||||
kg, P, dir, tsplat, Psplat, idirsplat, shufflexyz, node_addr, visibility, dist);
|
||||
kg, P, dir, tsplat, Psplat, idirsplat, shufflexyz, node_addr, visibility, rayTime, dist);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(__KERNEL_SSE2__) */
|
||||
|
@@ -122,6 +122,7 @@ ccl_device_inline
|
||||
isect_t,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#else // __KERNEL_SSE2__
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
@@ -137,6 +138,7 @@ ccl_device_inline
|
||||
shufflexyz,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#endif // __KERNEL_SSE2__
|
||||
|
||||
|
@@ -117,6 +117,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
||||
isect->t,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
}
|
||||
#else // __KERNEL_SSE2__
|
||||
@@ -134,6 +135,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
||||
shufflexyz,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
}
|
||||
#endif // __KERNEL_SSE2__
|
||||
|
@@ -118,6 +118,7 @@ ccl_device_inline
|
||||
isect->t,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#else // __KERNEL_SSE2__
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
@@ -133,6 +134,7 @@ ccl_device_inline
|
||||
shufflexyz,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#endif // __KERNEL_SSE2__
|
||||
|
||||
|
@@ -122,6 +122,7 @@ ccl_device_inline
|
||||
isect_t,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#else // __KERNEL_SSE2__
|
||||
traverse_mask = NODE_INTERSECT(kg,
|
||||
@@ -137,6 +138,7 @@ ccl_device_inline
|
||||
shufflexyz,
|
||||
node_addr,
|
||||
visibility,
|
||||
ray->time,
|
||||
dist);
|
||||
#endif // __KERNEL_SSE2__
|
||||
|
||||
|
@@ -319,7 +319,15 @@ enum PathRayFlag {
|
||||
/* Ray is to be terminated. */
|
||||
PATH_RAY_TERMINATE = (PATH_RAY_TERMINATE_IMMEDIATE | PATH_RAY_TERMINATE_AFTER_TRANSPARENT),
|
||||
/* Path and shader is being evaluated for direct lighting emission. */
|
||||
PATH_RAY_EMISSION = (1 << 22)
|
||||
PATH_RAY_EMISSION = (1 << 22),
|
||||
|
||||
/* Special flag to tag 4D BVH nodes (they also carry time bounds). */
|
||||
PATH_RAY_NODE_4D = (1 << 23),
|
||||
|
||||
/* Special flag to tag nodes that can be linearly interpolated */
|
||||
PATH_RAY_NODE_MB = (1 << 24),
|
||||
|
||||
PATH_RAY_NODE_CLEAR = (PATH_RAY_NODE_4D | PATH_RAY_NODE_UNALIGNED | PATH_RAY_NODE_MB),
|
||||
};
|
||||
|
||||
/* Closure Label */
|
||||
@@ -1338,6 +1346,7 @@ typedef enum KernelBVHLayout {
|
||||
BVH_LAYOUT_BVH4 = (1 << 1),
|
||||
BVH_LAYOUT_BVH8 = (1 << 2),
|
||||
BVH_LAYOUT_EMBREE = (1 << 3),
|
||||
BVH_LAYOUT_EMBREE_CONVERTED = (1 << 4),
|
||||
BVH_LAYOUT_DEFAULT = BVH_LAYOUT_BVH8,
|
||||
BVH_LAYOUT_ALL = (unsigned int)(-1),
|
||||
} KernelBVHLayout;
|
||||
|
@@ -1995,6 +1995,10 @@ void MeshManager::device_update_bvh(Device *device,
|
||||
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
if(bparams.bvh_layout == BVH_LAYOUT_EMBREE_CONVERTED) {
|
||||
dscene->data.bvh.bvh_layout = BVH_LAYOUT_BVH2;
|
||||
}
|
||||
|
||||
if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) {
|
||||
dscene->data.bvh.scene = ((BVHEmbree *)bvh)->scene;
|
||||
}
|
||||
|
Reference in New Issue
Block a user