Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82ac34a2d6 | ||
|
|
e80450780c | ||
|
|
4d0329fe71 | ||
|
|
c3ff7ab7b5 | ||
|
|
b3d327b24e | ||
|
|
969e751525 | ||
|
|
6dc16f6ed2 | ||
|
|
e9c241fe29 | ||
|
|
6cb9789951 | ||
|
|
6a3ebf7871 | ||
|
|
8d3e0ec658 | ||
|
|
a303bccf07 | ||
|
|
905f55ae26 | ||
|
|
fe03dcf15a | ||
|
|
db3a9009c0 | ||
|
|
5b65aa7f74 | ||
|
|
d3c7621b02 | ||
|
|
a095872b94 | ||
|
|
9675800bfd | ||
|
|
02e08538df | ||
|
|
72513cd242 | ||
|
|
212be4e85d | ||
|
|
c2923b8db1 | ||
|
|
c0adf11eca | ||
|
|
ae933bc838 | ||
|
|
68e1be6f74 | ||
|
|
73dbc25652 | ||
|
|
52985f445e | ||
|
|
d6921ccb95 | ||
|
|
29a75f3bc1 | ||
|
|
88932255c0 | ||
|
|
ba9ef506e2 | ||
|
|
0d07cb4c85 | ||
|
|
0ea1424d5c | ||
|
|
d5729dea0f | ||
|
|
08af796183 | ||
|
|
2bbe5f6b95 | ||
|
|
9144d1e922 | ||
|
|
d334b0aa28 | ||
|
|
7eff2b710d | ||
|
|
4635412713 | ||
|
|
79b4d9acd7 | ||
|
|
3ec24c2a76 | ||
|
|
908ecb984f | ||
|
|
152cf7e05e | ||
|
|
09580c66f0 | ||
|
|
f7123c27a5 | ||
|
|
c1406f791c | ||
|
|
8fea89369d | ||
|
|
120f529e21 | ||
|
|
09ac15fbb7 | ||
|
|
9464ea90be | ||
|
|
8f95000bd4 | ||
|
|
caadb6d2c8 | ||
|
|
4830e6667c | ||
|
|
62aba5dc83 | ||
|
|
a018d36d8a | ||
|
|
2a8a3a3cfa | ||
|
|
bb0abc10f6 | ||
|
|
95e6ae6c32 | ||
|
|
ba28fb7200 | ||
|
|
06d1363ec0 |
@@ -53,6 +53,7 @@ enum RTCAlgorithmFlags
|
||||
RTC_INTERSECT16 = (1 << 3), //!< enables the rtcIntersect16 and rtcOccluded16 functions for this scene
|
||||
RTC_INTERPOLATE = (1 << 4), //!< enables the rtcInterpolate function for this scene
|
||||
RTC_INTERSECT_STREAM = (1 << 5), //!< enables the rtcIntersectN and rtcOccludedN functions for this scene
|
||||
RTC_COLLIDE = (1 << 6) //!< enables the rtcCollide function
|
||||
};
|
||||
|
||||
/*! intersection flags */
|
||||
@@ -69,6 +70,10 @@ struct RTCIntersectContext
|
||||
void* userRayExt; //!< can be used to pass extended ray data to callbacks
|
||||
};
|
||||
|
||||
/*! collision callback */
|
||||
struct RTCCollision { unsigned geomID0; unsigned primID0; unsigned geomID1; unsigned primID1; };
|
||||
typedef void (*RTCCollideFunc) (void* userPtr, RTCCollision* collisions, size_t num_collisions);
|
||||
|
||||
/*! \brief Defines an opaque scene type */
|
||||
typedef struct __RTCScene {}* RTCScene;
|
||||
|
||||
@@ -108,6 +113,9 @@ RTCORE_API void rtcCommitThread(RTCScene scene, unsigned int threadID, unsigned
|
||||
* previously to this function. */
|
||||
RTCORE_API void rtcGetBounds(RTCScene scene, RTCBounds& bounds_o);
|
||||
|
||||
/*! Performs collision detection of two scenes */
|
||||
RTCORE_API void rtcCollide (RTCScene scene0, RTCScene scene1, RTCCollideFunc callback, void* userPtr);
|
||||
|
||||
/*! Returns linear AABBs of the scene. The result bounds_o gets filled
|
||||
* with AABBs for time 0 and time 1. rtcCommit has to get called
|
||||
* previously to this function. */
|
||||
|
||||
@@ -74,6 +74,7 @@ SET(EMBREE_LIBRARY_FILES
|
||||
bvh/bvh_builder_subdiv.cpp
|
||||
|
||||
bvh/bvh_intersector1.cpp
|
||||
bvh/bvh_collider.cpp
|
||||
)
|
||||
|
||||
IF (EMBREE_RAY_PACKETS)
|
||||
@@ -90,7 +91,8 @@ ENDIF()
|
||||
SET(EMBREE_LIBRARY_FILES_SSE42
|
||||
geometry/grid_soa.cpp
|
||||
subdiv/subdivpatch1base_eval.cpp
|
||||
bvh/bvh_intersector1.cpp)
|
||||
bvh/bvh_intersector1.cpp
|
||||
bvh/bvh_collider.cpp)
|
||||
|
||||
IF (EMBREE_RAY_PACKETS)
|
||||
SET(EMBREE_LIBRARY_FILES_SSE42 ${EMBREE_LIBRARY_FILES_SSE42}
|
||||
@@ -120,6 +122,7 @@ SET(EMBREE_LIBRARY_FILES_AVX
|
||||
bvh/bvh_builder_instancing.cpp
|
||||
bvh/bvh_builder_subdiv.cpp
|
||||
bvh/bvh_intersector1.cpp
|
||||
bvh/bvh_collider.cpp
|
||||
|
||||
bvh/bvh.cpp
|
||||
bvh/bvh_statistics.cpp)
|
||||
@@ -141,7 +144,8 @@ SET(EMBREE_LIBRARY_FILES_AVX2
|
||||
geometry/grid_soa.cpp
|
||||
subdiv/subdivpatch1base_eval.cpp
|
||||
|
||||
bvh/bvh_intersector1.cpp)
|
||||
bvh/bvh_intersector1.cpp
|
||||
bvh/bvh_collider.cpp)
|
||||
|
||||
IF (EMBREE_RAY_PACKETS)
|
||||
SET(EMBREE_LIBRARY_FILES_AVX2 ${EMBREE_LIBRARY_FILES_AVX2}
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
|
||||
namespace embree
|
||||
{
|
||||
DECLARE_SYMBOL2(Accel::Collider,BVH4ColliderTriangle4v);
|
||||
DECLARE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
|
||||
|
||||
DECLARE_SYMBOL2(Accel::Intersector1,BVH4Line4iIntersector1);
|
||||
DECLARE_SYMBOL2(Accel::Intersector1,BVH4Line4iMBIntersector1);
|
||||
DECLARE_SYMBOL2(Accel::Intersector1,BVH4Bezier1vIntersector1);
|
||||
@@ -268,6 +271,9 @@ namespace embree
|
||||
|
||||
BVH4Factory::BVH4Factory (int features)
|
||||
{
|
||||
SELECT_SYMBOL_DEFAULT_AVX_AVX2(features,BVH4ColliderTriangle4v);
|
||||
SELECT_SYMBOL_DEFAULT_AVX_AVX2(features,BVH4ColliderUserGeom);
|
||||
|
||||
/* select builders */
|
||||
IF_ENABLED_LINES(SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL_AVX512SKX(features,BVH4BuilderTwoLevelLineSegmentsSAH));
|
||||
IF_ENABLED_TRIS (SELECT_SYMBOL_DEFAULT_AVX_AVX512KNL_AVX512SKX(features,BVH4BuilderTwoLevelTriangleMeshSAH));
|
||||
@@ -625,6 +631,7 @@ namespace embree
|
||||
assert(ivariant == IntersectVariant::ROBUST);
|
||||
Accel::Intersectors intersectors;
|
||||
intersectors.ptr = bvh;
|
||||
intersectors.collider = BVH4ColliderTriangle4v;
|
||||
intersectors.intersector1 = BVH4Triangle4vIntersector1Pluecker;
|
||||
intersectors.intersector4 = BVH4Triangle4vIntersector4HybridPluecker;
|
||||
intersectors.intersector8 = BVH4Triangle4vIntersector8HybridPluecker;
|
||||
@@ -831,6 +838,7 @@ namespace embree
|
||||
{
|
||||
Accel::Intersectors intersectors;
|
||||
intersectors.ptr = bvh;
|
||||
intersectors.collider = BVH4ColliderUserGeom;
|
||||
intersectors.intersector1 = BVH4VirtualIntersector1;
|
||||
intersectors.intersector4 = BVH4VirtualIntersector4Chunk;
|
||||
intersectors.intersector8 = BVH4VirtualIntersector8Chunk;
|
||||
|
||||
@@ -110,6 +110,9 @@ namespace embree
|
||||
static void createAccelSetMesh(AccelSet* mesh, AccelData*& accel, Builder*& builder);
|
||||
|
||||
private:
|
||||
DEFINE_SYMBOL2(Accel::Collider,BVH4ColliderTriangle4v);
|
||||
DEFINE_SYMBOL2(Accel::Collider,BVH4ColliderUserGeom);
|
||||
|
||||
DEFINE_SYMBOL2(Accel::Intersector1,BVH4Line4iIntersector1);
|
||||
DEFINE_SYMBOL2(Accel::Intersector1,BVH4Line4iMBIntersector1);
|
||||
DEFINE_SYMBOL2(Accel::Intersector1,BVH4Bezier1vIntersector1);
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
// ======================================================================== //
|
||||
// Copyright 2009-2016 Intel Corporation //
|
||||
// //
|
||||
// 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. //
|
||||
// ======================================================================== //
|
||||
|
||||
#include "bvh_collider.h"
|
||||
#include "../geometry/triangle_triangle_intersector.h"
|
||||
|
||||
namespace embree
|
||||
{
|
||||
namespace isa
|
||||
{
|
||||
#define CSTAT(x)
|
||||
|
||||
size_t parallel_depth_threshold = 6;
|
||||
std::atomic<size_t> bvh_collide_traversal_steps(0);
|
||||
std::atomic<size_t> bvh_collide_leaf_pairs(0);
|
||||
std::atomic<size_t> bvh_collide_leaf_iterations(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections1(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections2(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections3(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections4(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections5(0);
|
||||
std::atomic<size_t> bvh_collide_prim_intersections(0);
|
||||
|
||||
struct Collision
|
||||
{
|
||||
__forceinline Collision() {}
|
||||
|
||||
__forceinline Collision (unsigned geomID0, unsigned primID0, unsigned geomID1, unsigned primID1)
|
||||
: geomID0(geomID0), primID0(primID0), geomID1(geomID1), primID1(primID1) {}
|
||||
|
||||
unsigned geomID0;
|
||||
unsigned primID0;
|
||||
unsigned geomID1;
|
||||
unsigned primID1;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
__forceinline size_t overlap(const BBox3fa& box0, const typename BVHN<N>::AlignedNode& node1)
|
||||
{
|
||||
const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),node1.lower_x);
|
||||
const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),node1.lower_y);
|
||||
const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),node1.lower_z);
|
||||
const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),node1.upper_x);
|
||||
const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),node1.upper_y);
|
||||
const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),node1.upper_z);
|
||||
return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
|
||||
}
|
||||
|
||||
template<int N>
|
||||
__forceinline size_t overlap(const BBox3fa& box0, const BBox<Vec3<vfloat<N>>>& box1)
|
||||
{
|
||||
const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),box1.lower.x);
|
||||
const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),box1.lower.y);
|
||||
const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),box1.lower.z);
|
||||
const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),box1.upper.x);
|
||||
const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),box1.upper.y);
|
||||
const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),box1.upper.z);
|
||||
return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
|
||||
}
|
||||
|
||||
template<int N>
|
||||
__forceinline size_t overlap(const BBox<Vec3<vfloat<N>>>& box0, size_t i, const BBox<Vec3<vfloat<N>>>& box1)
|
||||
{
|
||||
const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x[i]),box1.lower.x);
|
||||
const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y[i]),box1.lower.y);
|
||||
const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z[i]),box1.lower.z);
|
||||
const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x[i]),box1.upper.x);
|
||||
const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y[i]),box1.upper.y);
|
||||
const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z[i]),box1.upper.z);
|
||||
return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
|
||||
}
|
||||
|
||||
bool intersect_triangle_triangle (Scene* scene0, unsigned geomID0, unsigned primID0, Scene* scene1, unsigned geomID1, unsigned primID1)
|
||||
{
|
||||
CSTAT(bvh_collide_prim_intersections1++);
|
||||
const TriangleMesh* mesh0 = scene0->getTriangleMesh(geomID0);
|
||||
const TriangleMesh* mesh1 = scene1->getTriangleMesh(geomID1);
|
||||
const TriangleMesh::Triangle& tri0 = mesh0->triangle(primID0);
|
||||
const TriangleMesh::Triangle& tri1 = mesh1->triangle(primID1);
|
||||
|
||||
/* special culling for scene intersection with itself */
|
||||
if (scene0 == scene1 && geomID0 == geomID1)
|
||||
{
|
||||
/* ignore self intersections */
|
||||
if (primID0 == primID1)
|
||||
return false;
|
||||
}
|
||||
CSTAT(bvh_collide_prim_intersections2++);
|
||||
|
||||
if (scene0 == scene1 && geomID0 == geomID1)
|
||||
{
|
||||
/* ignore intersection with topological neighbors */
|
||||
const vint4 t0(tri0.v[0],tri0.v[1],tri0.v[2],tri0.v[2]);
|
||||
if (any(vint4(tri1.v[0]) == t0)) return false;
|
||||
if (any(vint4(tri1.v[1]) == t0)) return false;
|
||||
if (any(vint4(tri1.v[2]) == t0)) return false;
|
||||
}
|
||||
CSTAT(bvh_collide_prim_intersections3++);
|
||||
|
||||
const Vec3fa a0 = mesh0->vertex(tri0.v[0]);
|
||||
const Vec3fa a1 = mesh0->vertex(tri0.v[1]);
|
||||
const Vec3fa a2 = mesh0->vertex(tri0.v[2]);
|
||||
const Vec3fa b0 = mesh1->vertex(tri1.v[0]);
|
||||
const Vec3fa b1 = mesh1->vertex(tri1.v[1]);
|
||||
const Vec3fa b2 = mesh1->vertex(tri1.v[2]);
|
||||
|
||||
return TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
__forceinline void BVHNColliderTriangle4v<N>::processLeaf(const Triangle4v& __restrict__ tris0, const Triangle4v& __restrict__ tris1)
|
||||
{
|
||||
Collision collisions[4*4];
|
||||
size_t num_collisions = 0;
|
||||
|
||||
size_t size0 = tris0.size();
|
||||
size_t size1 = tris1.size();
|
||||
BBox<Vec3vf4> bounds0(min(tris0.v0,tris0.v1,tris0.v2),max(tris0.v0,tris0.v1,tris0.v2));
|
||||
BBox<Vec3vf4> bounds1(min(tris1.v0,tris1.v1,tris1.v2),max(tris1.v0,tris1.v1,tris1.v2));
|
||||
|
||||
if (size0 < size1)
|
||||
{
|
||||
for (size_t i=0; i<size0; i++)
|
||||
{
|
||||
CSTAT(bvh_collide_leaf_iterations++);
|
||||
size_t mask = movemask(tris1.valid()) & overlap(bounds0,i,bounds1);
|
||||
for (size_t m=mask, j=__bsf(m); m!=0; m=__btc(m,j), j=__bsf(m))
|
||||
{
|
||||
const unsigned geomID0 = tris0.geomID(i);
|
||||
const unsigned primID0 = tris0.primID(i);
|
||||
const unsigned geomID1 = tris1.geomID(j);
|
||||
const unsigned primID1 = tris1.primID(j);
|
||||
if (intersect_triangle_triangle(this->scene0,geomID0,primID0,this->scene1,geomID1,primID1)) {
|
||||
CSTAT(bvh_collide_prim_intersections++);
|
||||
collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t j=0; j<size1; j++)
|
||||
{
|
||||
CSTAT(bvh_collide_leaf_iterations++);
|
||||
size_t mask = movemask(tris0.valid()) & overlap(bounds1,j,bounds0);
|
||||
for (size_t m=mask, i=__bsf(m); m!=0; m=__btc(m,i), i=__bsf(m)) {
|
||||
const unsigned geomID0 = tris0.geomID(i);
|
||||
const unsigned primID0 = tris0.primID(i);
|
||||
const unsigned geomID1 = tris1.geomID(j);
|
||||
const unsigned primID1 = tris1.primID(j);
|
||||
if (intersect_triangle_triangle(this->scene0,geomID0,primID0,this->scene1,geomID1,primID1)) {
|
||||
CSTAT(bvh_collide_prim_intersections++);
|
||||
collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_collisions)
|
||||
this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
__forceinline void BVHNColliderTriangle4v<N>::processLeaf(NodeRef node0, NodeRef node1)
|
||||
{
|
||||
size_t N0; Triangle4v* leaf0 = (Triangle4v*) node0.leaf(N0);
|
||||
size_t N1; Triangle4v* leaf1 = (Triangle4v*) node1.leaf(N1);
|
||||
for (size_t i=0; i<N0; i++)
|
||||
for (size_t j=0; j<N1; j++)
|
||||
processLeaf(leaf0[i],leaf1[j]);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
__forceinline void BVHNColliderUserGeom<N>::processLeaf(NodeRef node0, NodeRef node1)
|
||||
{
|
||||
Collision collisions[16];
|
||||
size_t num_collisions = 0;
|
||||
|
||||
size_t N0; Object* leaf0 = (Object*) node0.leaf(N0);
|
||||
size_t N1; Object* leaf1 = (Object*) node1.leaf(N1);
|
||||
for (size_t i=0; i<N0; i++) {
|
||||
for (size_t j=0; j<N1; j++) {
|
||||
const unsigned geomID0 = leaf0[i].geomID;
|
||||
const unsigned primID0 = leaf0[i].primID;
|
||||
const unsigned geomID1 = leaf1[j].geomID;
|
||||
const unsigned primID1 = leaf1[j].primID;
|
||||
if (this->scene0 == this->scene1 && geomID0 == geomID1 && primID0 == primID1) continue;
|
||||
collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
|
||||
if (num_collisions == 16) {
|
||||
this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
|
||||
num_collisions = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_collisions)
|
||||
this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
void BVHNCollider<N>::collide_recurse(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth)
|
||||
{
|
||||
CSTAT(bvh_collide_traversal_steps++);
|
||||
if (unlikely(ref0.isLeaf())) {
|
||||
if (unlikely(ref1.isLeaf())) {
|
||||
CSTAT(bvh_collide_leaf_pairs++);
|
||||
processLeaf(ref0,ref1);
|
||||
return;
|
||||
} else goto recurse_node1;
|
||||
|
||||
} else {
|
||||
if (unlikely(ref1.isLeaf())) {
|
||||
goto recurse_node0;
|
||||
} else {
|
||||
//if (area(bounds0) > area(bounds1)) {
|
||||
if (depth < parallel_depth_threshold) {
|
||||
goto recurse_node0; // for some reason this parallel work distribution works well
|
||||
}
|
||||
else
|
||||
{
|
||||
if (depth % 2) {
|
||||
goto recurse_node0;
|
||||
} else {
|
||||
goto recurse_node1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
recurse_node0:
|
||||
AlignedNode* node0 = ref0.alignedNode();
|
||||
size_t mask = overlap<N>(bounds1,*node0);
|
||||
//for (size_t m=mask, i=__bsf(m); m!=0; m=__btc(m,i), i=__bsf(m)) {
|
||||
//for (size_t i=0; i<N; i++) {
|
||||
if (depth < parallel_depth_threshold)
|
||||
{
|
||||
parallel_for(size_t(N), [&] ( size_t i ) {
|
||||
if (mask & ( 1 << i)) {
|
||||
node0->child(i).prefetch(BVH_FLAG_ALIGNED_NODE);
|
||||
collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth+1);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t m=mask, i=__bsf(m); m!=0; m=__btc(m,i), i=__bsf(m)) {
|
||||
node0->child(i).prefetch(BVH_FLAG_ALIGNED_NODE);
|
||||
collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth+1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
recurse_node1:
|
||||
AlignedNode* node1 = ref1.alignedNode();
|
||||
size_t mask = overlap<N>(bounds0,*node1);
|
||||
//for (size_t m=mask, i=__bsf(m); m!=0; m=__btc(m,i), i=__bsf(m)) {
|
||||
//for (size_t i=0; i<N; i++) {
|
||||
if (depth < parallel_depth_threshold)
|
||||
{
|
||||
parallel_for(size_t(N), [&] ( size_t i ) {
|
||||
if (mask & ( 1 << i)) {
|
||||
node1->child(i).prefetch(BVH_FLAG_ALIGNED_NODE);
|
||||
collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth+1);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t m=mask, i=__bsf(m); m!=0; m=__btc(m,i), i=__bsf(m)) {
|
||||
node1->child(i).prefetch(BVH_FLAG_ALIGNED_NODE);
|
||||
collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth+1);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template<int N>
|
||||
void BVHNCollider<N>::collide_recurse_entry(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth)
|
||||
{
|
||||
CSTAT(bvh_collide_traversal_steps = 0);
|
||||
CSTAT(bvh_collide_leaf_pairs = 0);
|
||||
CSTAT(bvh_collide_leaf_iterations = 0);
|
||||
CSTAT(bvh_collide_prim_intersections1 = 0);
|
||||
CSTAT(bvh_collide_prim_intersections2 = 0);
|
||||
CSTAT(bvh_collide_prim_intersections3 = 0);
|
||||
CSTAT(bvh_collide_prim_intersections4 = 0);
|
||||
CSTAT(bvh_collide_prim_intersections5 = 0);
|
||||
CSTAT(bvh_collide_prim_intersections = 0);
|
||||
collide_recurse(ref0,bounds0,ref1,bounds1,depth);
|
||||
CSTAT(PRINT(bvh_collide_traversal_steps));
|
||||
CSTAT(PRINT(bvh_collide_leaf_pairs));
|
||||
CSTAT(PRINT(bvh_collide_leaf_iterations));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections1));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections2));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections3));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections4));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections5));
|
||||
CSTAT(PRINT(bvh_collide_prim_intersections));
|
||||
AVX_ZERO_UPPER();
|
||||
}
|
||||
|
||||
|
||||
template<int N>
|
||||
void BVHNColliderTriangle4v<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)
|
||||
{
|
||||
BVHNColliderTriangle4v<N>(bvh0->scene,bvh1->scene,callback,userPtr).
|
||||
collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds(),0);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
void BVHNColliderUserGeom<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)
|
||||
{
|
||||
BVHNColliderUserGeom<N>(bvh0->scene,bvh1->scene,callback,userPtr).
|
||||
collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds(),0);
|
||||
}
|
||||
|
||||
#if !defined (__SSE4_1__)
|
||||
struct collision_regression_test : public RegressionTest
|
||||
{
|
||||
collision_regression_test(const char* name) : RegressionTest(name) {
|
||||
registerRegressionTest(this);
|
||||
}
|
||||
|
||||
bool run ()
|
||||
{
|
||||
bool passed = true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(-0.008815, 0.041848, -2.49875e-06), Vec3fa(-0.008276, 0.053318, -2.49875e-06), Vec3fa(0.003023, 0.048969, -2.49875e-06),
|
||||
Vec3fa(0.00245, 0.037612, -2.49875e-06), Vec3fa(0.01434, 0.042634, -2.49875e-06), Vec3fa(0.013499, 0.031309, -2.49875e-06)) == false;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,1),Vec3fa(0,1,1)) == false;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1,0.1,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1,0.1,-0.1),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(0.5,0,0),Vec3fa(0,0.5,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1,0.1,0),Vec3fa(0.5,0,0),Vec3fa(0,0.5,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1,0.1,0),Vec3fa(0.5,0.1,0),Vec3fa(0.1,0.5,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1,-0.1,0),Vec3fa(0.5,0.1,0),Vec3fa(0.1,0.5,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(-0.1,0.1,0),Vec3fa(0.5,0.1,0),Vec3fa(0.1,0.5,0)) == true;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
|
||||
Vec3fa(-1,1,0) + Vec3fa(0,0,0),Vec3fa(-1,1,0) + Vec3fa(0.1,0,0),Vec3fa(-1,1,0) + Vec3fa(0,0.1,0)) == false;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
|
||||
Vec3fa( 2,0.5,0) + Vec3fa(0,0,0),Vec3fa( 2,0.5,0) + Vec3fa(0.1,0,0),Vec3fa( 2,0.5,0) + Vec3fa(0,0.1,0)) == false;
|
||||
passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
|
||||
Vec3fa(0.5,-2.0f,0) + Vec3fa(0,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0.1,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0.1,0)) == false;
|
||||
return passed;
|
||||
}
|
||||
};
|
||||
|
||||
collision_regression_test collision_regression("collision_regression_test");
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// Collider Definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEFINE_COLLIDER(BVH4ColliderTriangle4v,BVHNColliderTriangle4v<4>);
|
||||
DEFINE_COLLIDER(BVH4ColliderUserGeom,BVHNColliderUserGeom<4>);
|
||||
|
||||
#if defined(__AVX__)
|
||||
DEFINE_COLLIDER(BVH8ColliderTriangle4v,BVHNColliderTriangle4v<8>);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// ======================================================================== //
|
||||
// Copyright 2009-2016 Intel Corporation //
|
||||
// //
|
||||
// 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. //
|
||||
// ======================================================================== //
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bvh.h"
|
||||
#include "../geometry/trianglev.h"
|
||||
#include "../geometry/object.h"
|
||||
|
||||
namespace embree
|
||||
{
|
||||
namespace isa
|
||||
{
|
||||
template<int N>
|
||||
class BVHNCollider
|
||||
{
|
||||
typedef BVHN<N> BVH;
|
||||
typedef typename BVH::NodeRef NodeRef;
|
||||
typedef typename BVH::AlignedNode AlignedNode;
|
||||
|
||||
public:
|
||||
__forceinline BVHNCollider (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
|
||||
: scene0(scene0), scene1(scene1), callback(callback), userPtr(userPtr) {}
|
||||
|
||||
public:
|
||||
virtual void processLeaf(NodeRef leaf0, NodeRef leaf1) = 0;
|
||||
void collide_recurse(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1, size_t depth);
|
||||
void collide_recurse_entry(NodeRef node0, const BBox3fa& bounds0, NodeRef node1, const BBox3fa& bounds1, size_t depth);
|
||||
|
||||
protected:
|
||||
Scene* scene0;
|
||||
Scene* scene1;
|
||||
RTCCollideFunc callback;
|
||||
void* userPtr;
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class BVHNColliderTriangle4v : public BVHNCollider<N>
|
||||
{
|
||||
typedef BVHN<N> BVH;
|
||||
typedef typename BVH::NodeRef NodeRef;
|
||||
typedef typename BVH::AlignedNode AlignedNode;
|
||||
|
||||
__forceinline BVHNColliderTriangle4v (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
|
||||
: BVHNCollider<N>(scene0,scene1,callback,userPtr) {}
|
||||
|
||||
void processLeaf(const Triangle4v& tris0, const Triangle4v& tris1);
|
||||
virtual void processLeaf(NodeRef leaf0, NodeRef leaf1);
|
||||
public:
|
||||
static void collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr);
|
||||
};
|
||||
|
||||
template<int N>
|
||||
class BVHNColliderUserGeom : public BVHNCollider<N>
|
||||
{
|
||||
typedef BVHN<N> BVH;
|
||||
typedef typename BVH::NodeRef NodeRef;
|
||||
typedef typename BVH::AlignedNode AlignedNode;
|
||||
|
||||
__forceinline BVHNColliderUserGeom (Scene* scene0, Scene* scene1, RTCCollideFunc callback, void* userPtr)
|
||||
: BVHNCollider<N>(scene0,scene1,callback,userPtr) {}
|
||||
|
||||
virtual void processLeaf(NodeRef leaf0, NodeRef leaf1);
|
||||
public:
|
||||
static void collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr);
|
||||
};
|
||||
}
|
||||
}
|
||||
+34
-1
@@ -61,6 +61,9 @@ namespace embree
|
||||
ALIGNED_CLASS;
|
||||
public:
|
||||
|
||||
/*! Type of collide function */
|
||||
typedef void (*CollideFunc)(void* bvh0, void* bvh1, RTCCollideFunc callback, void* userPtr);
|
||||
|
||||
/*! Type of intersect function pointer for single rays. */
|
||||
typedef void (*IntersectFunc)(void* ptr, /*!< pointer to user data */
|
||||
RTCRay& ray, /*!< ray to intersect */
|
||||
@@ -121,6 +124,21 @@ namespace embree
|
||||
IntersectContext* context /*!< layout flags */);
|
||||
typedef void (*ErrorFunc) ();
|
||||
|
||||
struct Collider
|
||||
{
|
||||
Collider (ErrorFunc error = nullptr)
|
||||
: collide((CollideFunc)error), name(nullptr) {}
|
||||
|
||||
Collider (CollideFunc collide, const char* name)
|
||||
: collide(collide), name(name) {}
|
||||
|
||||
operator bool() const { return name; }
|
||||
|
||||
public:
|
||||
CollideFunc collide;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
struct Intersector1
|
||||
{
|
||||
Intersector1 (ErrorFunc error = nullptr)
|
||||
@@ -212,10 +230,14 @@ namespace embree
|
||||
: ptr(nullptr) {}
|
||||
|
||||
Intersectors (ErrorFunc error)
|
||||
: ptr(nullptr), intersector1(error), intersector4(error), intersector8(error), intersector16(error), intersectorN(error) {}
|
||||
: ptr(nullptr), collider(error), intersector1(error), intersector4(error), intersector8(error), intersector16(error), intersectorN(error) {}
|
||||
|
||||
void print(size_t ident)
|
||||
{
|
||||
if (collider.name) {
|
||||
for (size_t i=0; i<ident; i++) std::cout << " ";
|
||||
std::cout << "collider = " << collider.name << std::endl;
|
||||
}
|
||||
if (intersector1.name) {
|
||||
for (size_t i=0; i<ident; i++) std::cout << " ";
|
||||
std::cout << "intersector1 = " << intersector1.name << std::endl;
|
||||
@@ -260,6 +282,7 @@ namespace embree
|
||||
|
||||
public:
|
||||
AccelData* ptr;
|
||||
Collider collider;
|
||||
Intersector1 intersector1;
|
||||
Intersector4 intersector4;
|
||||
Intersector4 intersector4_filter;
|
||||
@@ -294,6 +317,12 @@ namespace embree
|
||||
/*! build acceleration structure */
|
||||
virtual void build (size_t threadIndex, size_t threadCount) = 0;
|
||||
|
||||
/*! collides two scenes */
|
||||
__forceinline void collide (Accel* scene0, Accel* scene1, RTCCollideFunc callback, void* userPtr) {
|
||||
assert(intersectors.collider.collide);
|
||||
intersectors.collider.collide(scene0->intersectors.ptr,scene1->intersectors.ptr,callback,userPtr);
|
||||
}
|
||||
|
||||
/*! Intersects a single ray with the scene. */
|
||||
__forceinline void intersect (RTCRay& ray, IntersectContext* context) {
|
||||
assert(intersectors.intersector1.intersect);
|
||||
@@ -411,6 +440,10 @@ namespace embree
|
||||
Intersectors intersectors;
|
||||
};
|
||||
|
||||
#define DEFINE_COLLIDER(symbol,collider) \
|
||||
Accel::Collider symbol((Accel::CollideFunc)collider::collide, \
|
||||
TOSTRING(isa) "::" TOSTRING(symbol));
|
||||
|
||||
#define DEFINE_INTERSECTOR1(symbol,intersector) \
|
||||
Accel::Intersector1 symbol((Accel::IntersectFunc)intersector::intersect, \
|
||||
(Accel::OccludedFunc )intersector::occluded, \
|
||||
|
||||
@@ -303,6 +303,25 @@ namespace embree
|
||||
RTCORE_CATCH_END(scene->device);
|
||||
}
|
||||
|
||||
RTCORE_API void rtcCollide (RTCScene hscene0, RTCScene hscene1, RTCCollideFunc callback, void* userPtr)
|
||||
{
|
||||
Scene* scene0 = (Scene*) hscene0;
|
||||
Scene* scene1 = (Scene*) hscene1;
|
||||
RTCORE_CATCH_BEGIN;
|
||||
RTCORE_TRACE(rtcCollide);
|
||||
#if defined(DEBUG)
|
||||
RTCORE_VERIFY_HANDLE(hscene0);
|
||||
RTCORE_VERIFY_HANDLE(hscene1);
|
||||
if (scene0->isModified()) throw_RTCError(RTC_INVALID_OPERATION,"scene got not committed");
|
||||
if (scene1->isModified()) throw_RTCError(RTC_INVALID_OPERATION,"scene got not committed");
|
||||
if (scene0->device != scene1->device) throw_RTCError(RTC_INVALID_OPERATION,"scenes are from different devices");
|
||||
#endif
|
||||
if (!isCollidable(scene0->aflags)) throw_RTCError(RTC_INVALID_OPERATION,"rtcCollide not supported for this scene");
|
||||
if (!isCollidable(scene1->aflags)) throw_RTCError(RTC_INVALID_OPERATION,"rtcCollide not supported for this scene");
|
||||
scene0->collide(scene0,scene1,callback,userPtr);
|
||||
RTCORE_CATCH_END(scene0->device);
|
||||
}
|
||||
|
||||
RTCORE_API void rtcIntersect (RTCScene hscene, RTCRay& ray)
|
||||
{
|
||||
Scene* scene = (Scene*) hscene;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace embree
|
||||
__forceinline bool isIntersect4Mode(RTCAlgorithmFlags flags) { return (flags & RTC_INTERSECT4) != 0; }
|
||||
__forceinline bool isIntersect8Mode(RTCAlgorithmFlags flags) { return (flags & RTC_INTERSECT8) != 0; }
|
||||
__forceinline bool isIntersect16Mode(RTCAlgorithmFlags flags) { return (flags & RTC_INTERSECT16) != 0; }
|
||||
__forceinline bool isCollidable(RTCAlgorithmFlags flags) { return (flags & RTC_COLLIDE) != 0; }
|
||||
|
||||
/*! decoding of intersection flags */
|
||||
__forceinline bool isCoherent (RTCIntersectFlags flags) { return (flags & RTC_INTERSECT_INCOHERENT) == 0; }
|
||||
|
||||
@@ -96,7 +96,16 @@ namespace embree
|
||||
#if defined(EMBREE_GEOMETRY_TRIANGLES)
|
||||
if (device->tri_accel == "default")
|
||||
{
|
||||
if (isStatic()) {
|
||||
/* choose special accel if we need to collide the scene */
|
||||
if (isCollidable(aflags))
|
||||
{
|
||||
if (isStatic()) {
|
||||
accels.add(device->bvh4_factory->BVH4Triangle4v(this,BVH4Factory::BuildVariant::STATIC,BVH4Factory::IntersectVariant::ROBUST));
|
||||
} else {
|
||||
accels.add(device->bvh4_factory->BVH4Triangle4v(this,BVH4Factory::BuildVariant::DYNAMIC,BVH4Factory::IntersectVariant::ROBUST));
|
||||
}
|
||||
}
|
||||
else if (isStatic()) {
|
||||
int mode = 2*(int)isCompact() + 1*(int)isRobust();
|
||||
switch (mode) {
|
||||
case /*0b00*/ 0:
|
||||
@@ -155,7 +164,8 @@ namespace embree
|
||||
else if (device->tri_accel == "qbvh4.triangle4i") accels.add(device->bvh4_factory->BVH4QuantizedTriangle4i(this));
|
||||
|
||||
#if defined (__TARGET_AVX__)
|
||||
else if (device->tri_accel == "bvh8.triangle4") accels.add(device->bvh8_factory->BVH8Triangle4 (this));
|
||||
else if (device->tri_accel == "bvh8.triangle4") accels.add(device->bvh8_factory->BVH8Triangle4(this));
|
||||
else if (device->tri_accel == "bvh8.triangle4v") accels.add(device->bvh8_factory->BVH8Triangle4v(this));
|
||||
else if (device->tri_accel == "bvh8.triangle4i") accels.add(device->bvh8_factory->BVH8Triangle4i(this));
|
||||
else if (device->tri_accel == "qbvh8.triangle4i") accels.add(device->bvh8_factory->BVH8QuantizedTriangle4i(this));
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// ======================================================================== //
|
||||
// Copyright 2009-2016 Intel Corporation //
|
||||
// //
|
||||
// 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. //
|
||||
// ======================================================================== //
|
||||
|
||||
#include "primitive.h"
|
||||
|
||||
namespace embree
|
||||
{
|
||||
namespace isa
|
||||
{
|
||||
struct TriangleTriangleIntersector
|
||||
{
|
||||
__forceinline static float T(float pa0, float pa1, float da0, float da1) {
|
||||
return pa0 + (pa1-pa0)*da0/(da0-da1);
|
||||
}
|
||||
|
||||
__forceinline static bool point_line_side(const Vec2f& p, const Vec2f& a0, const Vec2f& a1) {
|
||||
return det(p-a0,a0-a1) >= 0.0f;
|
||||
}
|
||||
|
||||
__forceinline static bool point_inside_triangle(const Vec2f& p, const Vec2f& a, const Vec2f& b, const Vec2f& c)
|
||||
{
|
||||
const bool pab = point_line_side(p,a,b);
|
||||
const bool pbc = point_line_side(p,b,c);
|
||||
const bool pca = point_line_side(p,c,a);
|
||||
return pab == pbc && pab == pca;
|
||||
}
|
||||
|
||||
__forceinline static bool intersect_line_line(const Vec2f& a0, const Vec2f& a1, const Vec2f& b0, const Vec2f& b1)
|
||||
{
|
||||
const bool different_sides0 = point_line_side(b0,a0,a1) != point_line_side(b1,a0,a1);
|
||||
const bool different_sides1 = point_line_side(a0,b0,b1) != point_line_side(a1,b0,b1);
|
||||
return different_sides0 && different_sides1;
|
||||
}
|
||||
|
||||
__forceinline static bool intersect_triangle_triangle (const Vec2f& a0, const Vec2f& a1, const Vec2f& a2,
|
||||
const Vec2f& b0, const Vec2f& b1, const Vec2f& b2)
|
||||
{
|
||||
const bool a01_b01 = intersect_line_line(a0,a1,b0,b1);
|
||||
if (a01_b01) return true;
|
||||
const bool a01_b12 = intersect_line_line(a0,a1,b1,b2);
|
||||
if (a01_b12) return true;
|
||||
const bool a01_b20 = intersect_line_line(a0,a1,b2,b0);
|
||||
if (a01_b20) return true;
|
||||
const bool a12_b01 = intersect_line_line(a1,a2,b0,b1);
|
||||
if (a12_b01) return true;
|
||||
const bool a12_b12 = intersect_line_line(a1,a2,b1,b2);
|
||||
if (a12_b12) return true;
|
||||
const bool a12_b20 = intersect_line_line(a1,a2,b2,b0);
|
||||
if (a12_b20) return true;
|
||||
const bool a20_b01 = intersect_line_line(a2,a0,b0,b1);
|
||||
if (a20_b01) return true;
|
||||
const bool a20_b12 = intersect_line_line(a2,a0,b1,b2);
|
||||
if (a20_b12) return true;
|
||||
const bool a20_b20 = intersect_line_line(a2,a0,b2,b0);
|
||||
if (a20_b20) return true;
|
||||
|
||||
bool a_in_b = point_inside_triangle(a0,b0,b1,b2) && point_inside_triangle(a1,b0,b1,b2) && point_inside_triangle(a2,b0,b1,b2);
|
||||
if (a_in_b) return true;
|
||||
|
||||
bool b_in_a = point_inside_triangle(b0,a0,a1,a2) && point_inside_triangle(b1,a0,a1,a2) && point_inside_triangle(b2,a0,a1,a2);
|
||||
if (b_in_a) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool intersect_triangle_triangle (const Vec3fa& a0, const Vec3fa& a1, const Vec3fa& a2,
|
||||
const Vec3fa& b0, const Vec3fa& b1, const Vec3fa& b2)
|
||||
{
|
||||
const float eps = 1E-5f;
|
||||
|
||||
/* calculate triangle planes */
|
||||
const Vec3fa Na = cross(a1-a0,a2-a0);
|
||||
const float Ca = dot(Na,a0);
|
||||
const Vec3fa Nb = cross(b1-b0,b2-b0);
|
||||
const float Cb = dot(Nb,b0);
|
||||
|
||||
/* project triangle A onto plane B */
|
||||
const float da0 = dot(Nb,a0)-Cb;
|
||||
const float da1 = dot(Nb,a1)-Cb;
|
||||
const float da2 = dot(Nb,a2)-Cb;
|
||||
if (max(da0,da1,da2) < -eps) return false;
|
||||
if (min(da0,da1,da2) > +eps) return false;
|
||||
//CSTAT(bvh_collide_prim_intersections4++);
|
||||
|
||||
/* project triangle B onto plane A */
|
||||
const float db0 = dot(Na,b0)-Ca;
|
||||
const float db1 = dot(Na,b1)-Ca;
|
||||
const float db2 = dot(Na,b2)-Ca;
|
||||
if (max(db0,db1,db2) < -eps) return false;
|
||||
if (min(db0,db1,db2) > +eps) return false;
|
||||
//CSTAT(bvh_collide_prim_intersections5++);
|
||||
|
||||
if (unlikely((da0 == 0.0f && da1 == 0.0f && da2 == 0.0f) ||
|
||||
(db0 == 0.0f && db1 == 0.0f && db2 == 0.0f)))
|
||||
{
|
||||
const size_t dz = maxDim(Na);
|
||||
const size_t dx = (dz+1)%3;
|
||||
const size_t dy = (dx+1)%3;
|
||||
const Vec2f A0(a0[dx],a0[dy]);
|
||||
const Vec2f A1(a1[dx],a1[dy]);
|
||||
const Vec2f A2(a2[dx],a2[dy]);
|
||||
const Vec2f B0(b0[dx],b0[dy]);
|
||||
const Vec2f B1(b1[dx],b1[dy]);
|
||||
const Vec2f B2(b2[dx],b2[dy]);
|
||||
return intersect_triangle_triangle(A0,A1,A2,B0,B1,B2);
|
||||
}
|
||||
|
||||
const Vec3fa D = cross(Na,Nb);
|
||||
const float pa0 = dot(D,a0);
|
||||
const float pa1 = dot(D,a1);
|
||||
const float pa2 = dot(D,a2);
|
||||
const float pb0 = dot(D,b0);
|
||||
const float pb1 = dot(D,b1);
|
||||
const float pb2 = dot(D,b2);
|
||||
|
||||
BBox1f ba = empty;
|
||||
if (min(da0,da1) <= 0.0f && max(da0,da1) >= 0.0f && abs(da0-da1) > 0.0f) ba.extend(T(pa0,pa1,da0,da1));
|
||||
if (min(da1,da2) <= 0.0f && max(da1,da2) >= 0.0f && abs(da1-da2) > 0.0f) ba.extend(T(pa1,pa2,da1,da2));
|
||||
if (min(da2,da0) <= 0.0f && max(da2,da0) >= 0.0f && abs(da2-da0) > 0.0f) ba.extend(T(pa2,pa0,da2,da0));
|
||||
|
||||
BBox1f bb = empty;
|
||||
if (min(db0,db1) <= 0.0f && max(db0,db1) >= 0.0f && abs(db0-db1) > 0.0f) bb.extend(T(pb0,pb1,db0,db1));
|
||||
if (min(db1,db2) <= 0.0f && max(db1,db2) >= 0.0f && abs(db1-db2) > 0.0f) bb.extend(T(pb1,pb2,db1,db2));
|
||||
if (min(db2,db0) <= 0.0f && max(db2,db0) >= 0.0f && abs(db2-db0) > 0.0f) bb.extend(T(pb2,pb0,db2,db0));
|
||||
|
||||
return conjoint(ba,bb);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ ADD_SUBDIRECTORY(motion_blur_geometry)
|
||||
ADD_SUBDIRECTORY(interpolation)
|
||||
ADD_SUBDIRECTORY(convert)
|
||||
ADD_SUBDIRECTORY(curve_geometry)
|
||||
ADD_SUBDIRECTORY(collide)
|
||||
|
||||
IF (EMBREE_RAY_PACKETS)
|
||||
ADD_SUBDIRECTORY(viewer_stream)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
## ======================================================================== ##
|
||||
## Copyright 2009-2016 Intel Corporation ##
|
||||
## ##
|
||||
## 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. ##
|
||||
## ======================================================================== ##
|
||||
|
||||
ADD_EXECUTABLE(collide collide.cpp collide_device.cpp ../common/tutorial/application.cpp)
|
||||
TARGET_LINK_LIBRARIES(collide embree tutorial image tutorial_device noise)
|
||||
SET_PROPERTY(TARGET collide PROPERTY FOLDER tutorials)
|
||||
INSTALL(TARGETS collide DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT examples)
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
// ======================================================================== //
|
||||
// Copyright 2009-2016 Intel Corporation //
|
||||
// //
|
||||
// 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. //
|
||||
// ======================================================================== //
|
||||
|
||||
#include "../common/tutorial/tutorial.h"
|
||||
#include "../common/tutorial/statistics.h"
|
||||
#include <set>
|
||||
#include "../../common/sys/mutex.h"
|
||||
#include "../common/core/ray.h"
|
||||
#include "../../kernels/geometry/triangle_triangle_intersector.h"
|
||||
|
||||
namespace embree
|
||||
{
|
||||
RTCDevice g_device = nullptr;
|
||||
RTCScene g_scene = nullptr;
|
||||
std::shared_ptr<TutorialScene> g_tutorial_scene = nullptr;
|
||||
size_t cur_time = 0;
|
||||
std::vector<std::shared_ptr<TutorialScene>> g_animation;
|
||||
std::set<std::pair<unsigned,unsigned>> collision_candidates;
|
||||
//RTCScene g_scene0 = nullptr;
|
||||
//RTCScene g_scene1 = nullptr;
|
||||
//TutorialScene g_tutorial_scene0;
|
||||
//TutorialScene g_tutorial_scene1;
|
||||
//std::set<std::pair<unsigned,unsigned>> set0;
|
||||
//std::set<std::pair<unsigned,unsigned>> set1;
|
||||
bool use_user_geometry = false;
|
||||
|
||||
size_t skipBenchmarkRounds = 0;
|
||||
size_t numBenchmarkRounds = 0;
|
||||
std::atomic<size_t> numTotalCollisions(0);
|
||||
SpinLock mutex;
|
||||
|
||||
bool intersect_triangle_triangle (TutorialScene* scene0, unsigned geomID0, unsigned primID0, TutorialScene* scene1, unsigned geomID1, unsigned primID1)
|
||||
{
|
||||
//CSTAT(bvh_collide_prim_intersections1++);
|
||||
const TutorialScene::TriangleMesh* mesh0 = (TutorialScene::TriangleMesh*) scene0->geometries[geomID0].ptr;
|
||||
const TutorialScene::TriangleMesh* mesh1 = (TutorialScene::TriangleMesh*) scene1->geometries[geomID1].ptr;
|
||||
const TutorialScene::Triangle& tri0 = mesh0->triangles[primID0];
|
||||
const TutorialScene::Triangle& tri1 = mesh1->triangles[primID1];
|
||||
|
||||
/* special culling for scene intersection with itself */
|
||||
if (scene0 == scene1 && geomID0 == geomID1)
|
||||
{
|
||||
/* ignore self intersections */
|
||||
if (primID0 == primID1)
|
||||
return false;
|
||||
}
|
||||
//CSTAT(bvh_collide_prim_intersections2++);
|
||||
|
||||
if (scene0 == scene1 && geomID0 == geomID1)
|
||||
{
|
||||
/* ignore intersection with topological neighbors */
|
||||
const vint4 t0(tri0.v0,tri0.v1,tri0.v2,tri0.v2);
|
||||
if (any(vint4(tri1.v0) == t0)) return false;
|
||||
if (any(vint4(tri1.v1) == t0)) return false;
|
||||
if (any(vint4(tri1.v2) == t0)) return false;
|
||||
}
|
||||
//CSTAT(bvh_collide_prim_intersections3++);
|
||||
|
||||
const Vec3fa a0 = mesh0->positions[tri0.v0];
|
||||
const Vec3fa a1 = mesh0->positions[tri0.v1];
|
||||
const Vec3fa a2 = mesh0->positions[tri0.v2];
|
||||
const Vec3fa b0 = mesh1->positions[tri1.v0];
|
||||
const Vec3fa b1 = mesh1->positions[tri1.v1];
|
||||
const Vec3fa b2 = mesh1->positions[tri1.v2];
|
||||
|
||||
return isa::TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);
|
||||
}
|
||||
|
||||
void CollideFunc (void* userPtr, RTCCollision* collisions, size_t num_collisions)
|
||||
{
|
||||
if (use_user_geometry)
|
||||
{
|
||||
for (size_t i=0; i<num_collisions;)
|
||||
{
|
||||
bool intersect = intersect_triangle_triangle(g_tutorial_scene.get(),collisions[i].geomID0,collisions[i].primID0,
|
||||
g_tutorial_scene.get(),collisions[i].geomID1,collisions[i].primID1);
|
||||
if (intersect) i++;
|
||||
else collisions[i] = collisions[--num_collisions];
|
||||
}
|
||||
}
|
||||
|
||||
if (num_collisions == 0)
|
||||
return;
|
||||
|
||||
if (numBenchmarkRounds)
|
||||
return;
|
||||
|
||||
//numTotalCollisions+=num_collisions;
|
||||
|
||||
Lock<SpinLock> lock(mutex);
|
||||
for (size_t i=0; i<num_collisions; i++)
|
||||
{
|
||||
const unsigned geomID0 = collisions[i].geomID0;
|
||||
const unsigned primID0 = collisions[i].primID0;
|
||||
const unsigned geomID1 = collisions[i].geomID1;
|
||||
const unsigned primID1 = collisions[i].primID1;
|
||||
//PRINT4(geomID0,primID0,geomID1,primID1);
|
||||
collision_candidates.insert(std::make_pair(geomID0,primID0));
|
||||
collision_candidates.insert(std::make_pair(geomID1,primID1));
|
||||
//set0.insert(std::make_pair(geomID0,primID0));
|
||||
//set1.insert(std::make_pair(geomID1,primID1));
|
||||
|
||||
#if 0
|
||||
/* verify result */
|
||||
Ref<TutorialScene::TriangleMesh> mesh0 = g_tutorial_scene->geometries[geomID0].dynamicCast<TutorialScene::TriangleMesh>();
|
||||
TutorialScene::Triangle tri0 = mesh0->triangles[primID0];
|
||||
BBox3fa bounds0 = empty;
|
||||
bounds0.extend(mesh0->positions[tri0.v0]);
|
||||
bounds0.extend(mesh0->positions[tri0.v1]);
|
||||
bounds0.extend(mesh0->positions[tri0.v2]);
|
||||
|
||||
Ref<TutorialScene::TriangleMesh> mesh1 = g_tutorial_scene->geometries[geomID1].dynamicCast<TutorialScene::TriangleMesh>();
|
||||
TutorialScene::Triangle tri1 = mesh1->triangles[primID1];
|
||||
BBox3fa bounds1 = empty;
|
||||
bounds1.extend(mesh1->positions[tri1.v0]);
|
||||
bounds1.extend(mesh1->positions[tri1.v1]);
|
||||
bounds1.extend(mesh1->positions[tri1.v2]);
|
||||
|
||||
if (disjoint(bounds0,bounds1))
|
||||
std::cout << "WARNING: bounds do not overlap!" << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void triangle_bounds_func(void* userPtr,
|
||||
void* geomUserPtr,
|
||||
size_t item,
|
||||
RTCBounds* bounds_o)
|
||||
{
|
||||
const unsigned geomID = (unsigned) (size_t) geomUserPtr;
|
||||
const TutorialScene::TriangleMesh* mesh = (TutorialScene::TriangleMesh*) g_tutorial_scene->geometries[geomID].ptr;
|
||||
const TutorialScene::Triangle& tri = mesh->triangles[item];
|
||||
BBox3fa bounds = empty;
|
||||
bounds.extend(mesh->positions[tri.v0]);
|
||||
bounds.extend(mesh->positions[tri.v1]);
|
||||
bounds.extend(mesh->positions[tri.v2]);
|
||||
*(BBox3fa*) bounds_o = bounds;
|
||||
}
|
||||
|
||||
void triangle_intersect_func(void* geomUserPtr, RTCRay& ray, size_t primID)
|
||||
{
|
||||
const unsigned geomID = (unsigned) (size_t) geomUserPtr;
|
||||
const TutorialScene::TriangleMesh* mesh = (TutorialScene::TriangleMesh*) g_tutorial_scene->geometries[geomID].ptr;
|
||||
const TutorialScene::Triangle& tri = mesh->triangles[primID];
|
||||
const Vec3fa v0 = mesh->positions[tri.v0];
|
||||
const Vec3fa v1 = mesh->positions[tri.v1];
|
||||
const Vec3fa v2 = mesh->positions[tri.v2];
|
||||
const Vec3fa e1 = v0-v1;
|
||||
const Vec3fa e2 = v2-v0;
|
||||
const Vec3fa Ng = cross(e1,e2);
|
||||
|
||||
/* calculate denominator */
|
||||
const Vec3fa O = Vec3fa(ray.org);
|
||||
const Vec3fa D = Vec3fa(ray.dir);
|
||||
const Vec3fa C = v0 - O;
|
||||
const Vec3fa R = cross(D,C);
|
||||
const float den = dot(Ng,D);
|
||||
const float rcpDen = rcp(den);
|
||||
|
||||
/* perform edge tests */
|
||||
const float u = dot(R,e2)*rcpDen;
|
||||
const float v = dot(R,e1)*rcpDen;
|
||||
|
||||
/* perform backface culling */
|
||||
bool valid = (den != 0.0f) & (u >= 0.0f) & (v >= 0.0f) & (u+v<=1.0f);
|
||||
if (likely(!valid)) return;
|
||||
|
||||
/* perform depth test */
|
||||
const float t = dot(Vec3fa(Ng),C)*rcpDen;
|
||||
valid &= (t > ray.tnear) & (t < ray.tfar);
|
||||
if (likely(!valid)) return;
|
||||
|
||||
/* update hit */
|
||||
ray.tfar = t;
|
||||
ray.u = u;
|
||||
ray.v = v;
|
||||
ray.geomID = geomID;
|
||||
ray.primID = primID;
|
||||
ray.Ng = Ng;
|
||||
}
|
||||
|
||||
struct Tutorial : public TutorialApplication
|
||||
{
|
||||
bool pause;
|
||||
|
||||
Tutorial()
|
||||
: TutorialApplication("collide",FEATURE_RTCORE), pause(false)//, use_user_geometry(false)
|
||||
{
|
||||
registerOption("i", [this] (Ref<ParseStream> cin, const FileName& path) {
|
||||
FileName filename = path + cin->getFileName();
|
||||
Ref<SceneGraph::Node> scene = SceneGraph::load(filename);
|
||||
std::shared_ptr<TutorialScene> tscene(new TutorialScene);
|
||||
tscene->add(scene,TutorialScene::INSTANCING_NONE);
|
||||
g_animation.push_back(tscene);
|
||||
}, "-i <filename>: parses scene from <filename>");
|
||||
|
||||
registerOption("benchmark", [this] (Ref<ParseStream> cin, const FileName& path) {
|
||||
skipBenchmarkRounds = cin->getInt();
|
||||
numBenchmarkRounds = cin->getInt();
|
||||
interactive = false;
|
||||
}, "--benchmark <N> <M>: enabled benchmark mode, skips N collisions, measures M collisions");
|
||||
|
||||
registerOption("use-user-geometry", [this] (Ref<ParseStream> cin, const FileName& path) {
|
||||
use_user_geometry = true;
|
||||
}, "--use-user-geometry: use user geometries for collision detection");
|
||||
|
||||
registerOption("use-triangle-geometry", [this] (Ref<ParseStream> cin, const FileName& path) {
|
||||
use_user_geometry = false;
|
||||
}, "--use-triangle-geometry: use triangle geometries for collision detection");
|
||||
}
|
||||
|
||||
unsigned int convertTriangleMesh(Ref<TutorialScene::TriangleMesh> mesh, RTCScene scene_out)
|
||||
{
|
||||
RTCGeometryFlags gflags;
|
||||
if (g_animation.size() == 1) gflags = RTC_GEOMETRY_STATIC;
|
||||
else gflags = RTC_GEOMETRY_DYNAMIC;
|
||||
|
||||
if (use_user_geometry)
|
||||
{
|
||||
unsigned int geomID = rtcNewUserGeometry3 (scene_out, gflags, mesh->triangles.size(), 1);
|
||||
rtcSetUserData(scene_out,geomID,(void*)(size_t)geomID);
|
||||
rtcSetBoundsFunction2 (scene_out, geomID, triangle_bounds_func, nullptr);
|
||||
rtcSetIntersectFunction (scene_out, geomID, triangle_intersect_func);
|
||||
return geomID;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int geomID = rtcNewTriangleMesh (scene_out, gflags, mesh->triangles.size(), mesh->numVertices, 1);
|
||||
rtcSetBuffer(scene_out, geomID, RTC_VERTEX_BUFFER, mesh->positions.data(), 0, sizeof(Vec3fa ));
|
||||
rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER , mesh->triangles.data(), 0, sizeof(TutorialScene::Triangle));
|
||||
return geomID;
|
||||
}
|
||||
}
|
||||
|
||||
RTCScene convertScene(std::shared_ptr<TutorialScene> scene_in)
|
||||
{
|
||||
RTCSceneFlags sflags;
|
||||
if (g_animation.size() == 1) sflags = RTC_SCENE_STATIC;
|
||||
else sflags = RTC_SCENE_DYNAMIC;
|
||||
RTCScene scene_out = rtcDeviceNewScene(g_device,sflags,RTC_INTERSECT1 | RTC_COLLIDE);
|
||||
|
||||
for (unsigned int i=0; i<scene_in->geometries.size(); i++)
|
||||
{
|
||||
if (Ref<TutorialScene::TriangleMesh> mesh = scene_in->geometries[i].dynamicCast<TutorialScene::TriangleMesh>()) {
|
||||
unsigned int geomID MAYBE_UNUSED = convertTriangleMesh(mesh, scene_out);
|
||||
assert(geomID == i);
|
||||
}
|
||||
else assert(false);
|
||||
}
|
||||
|
||||
rtcCommit(scene_out);
|
||||
return scene_out;
|
||||
}
|
||||
|
||||
void updateTriangleMesh(Ref<TutorialScene::TriangleMesh> mesh, RTCScene scene_out, unsigned geomID)
|
||||
{
|
||||
if (!use_user_geometry) {
|
||||
rtcSetBuffer(scene_out, geomID, RTC_VERTEX_BUFFER, mesh->positions.data(), 0, sizeof(Vec3fa ));
|
||||
rtcSetBuffer(scene_out, geomID, RTC_INDEX_BUFFER , mesh->triangles.data(), 0, sizeof(TutorialScene::Triangle));
|
||||
}
|
||||
rtcUpdate(scene_out, geomID);
|
||||
}
|
||||
|
||||
void updateScene(std::shared_ptr<TutorialScene> scene_in, RTCScene scene_out)
|
||||
{
|
||||
for (unsigned int i=0; i<scene_in->geometries.size(); i++)
|
||||
{
|
||||
if (Ref<TutorialScene::TriangleMesh> mesh = scene_in->geometries[i].dynamicCast<TutorialScene::TriangleMesh>()) {
|
||||
updateTriangleMesh(mesh, scene_out, i);
|
||||
}
|
||||
else assert(false);
|
||||
}
|
||||
|
||||
rtcCommit(scene_out);
|
||||
}
|
||||
|
||||
void updateScene()
|
||||
{
|
||||
g_tutorial_scene = g_animation[cur_time];
|
||||
cur_time = (cur_time+1)%g_animation.size();
|
||||
|
||||
if (g_scene == nullptr)
|
||||
g_scene = convertScene(g_tutorial_scene);
|
||||
else if (g_animation.size() > 1)
|
||||
updateScene(g_tutorial_scene,g_scene);
|
||||
}
|
||||
|
||||
void keyboardFunc(unsigned char key, int x, int y)
|
||||
{
|
||||
if (key == ' ') pause = !pause;
|
||||
else TutorialApplication::keyboardFunc(key,x,y);
|
||||
}
|
||||
|
||||
void render(unsigned* pixels, const unsigned width, const unsigned height, const float time, const ISPCCamera& camera)
|
||||
{
|
||||
//for (volatile int i=0; i<10000000; i++);
|
||||
if (!pause) updateScene();
|
||||
else PRINT(cur_time);
|
||||
collision_candidates.clear();
|
||||
rtcCollide(g_scene,g_scene,CollideFunc,nullptr);
|
||||
device_render(pixels,width,height,time,camera);
|
||||
}
|
||||
|
||||
void benchmark()
|
||||
{
|
||||
Statistics stat0;
|
||||
Statistics stat1;
|
||||
size_t numTotalRounds = skipBenchmarkRounds + numBenchmarkRounds;
|
||||
for (size_t i=0; i<skipBenchmarkRounds; i++)
|
||||
{
|
||||
updateScene();
|
||||
//double t0 = getSeconds();
|
||||
numTotalCollisions = 0;
|
||||
rtcCollide(g_scene,g_scene,CollideFunc,nullptr);
|
||||
//double t1 = getSeconds();
|
||||
//float dt = float(t1-t0);
|
||||
//std::cout << "round [" << std::setw(3) << i << " / " << std::setw(3) << numTotalRounds << "]: " << std::setw(8) << 1000.0f*dt << " ms (skipped)" << std::endl << std::flush;
|
||||
//if (benchmarkSleep) sleepSeconds(0.1);
|
||||
}
|
||||
|
||||
for (size_t i=skipBenchmarkRounds; i<numTotalRounds; i++)
|
||||
{
|
||||
double t0 = getSeconds();
|
||||
updateScene();
|
||||
double t1 = getSeconds();
|
||||
numTotalCollisions = 0;
|
||||
rtcCollide(g_scene,g_scene,CollideFunc,nullptr);
|
||||
double t2 = getSeconds();
|
||||
|
||||
float dt0 = float(t1-t0);
|
||||
float dt1 = float(t2-t1);
|
||||
stat0.add(dt0);
|
||||
stat1.add(dt1);
|
||||
//if (benchmarkSleep) sleepSeconds(0.1);
|
||||
}
|
||||
|
||||
std::cout << "Scene Update: min = " << std::setw(8) << 1000.0f*stat0.getMin() << " ms, "
|
||||
<< "avg = " << std::setw(8) << 1000.0f*stat0.getAvg() << " ms, "
|
||||
<< "max = " << std::setw(8) << 1000.0f*stat0.getMax() << " ms " << std::endl;
|
||||
std::cout << "Collision Detection: min = " << std::setw(8) << 1000.0f*stat1.getMin() << " ms, "
|
||||
<< "avg = " << std::setw(8) << 1000.0f*stat1.getAvg() << " ms, "
|
||||
<< "max = " << std::setw(8) << 1000.0f*stat1.getMax() << " ms " << std::endl;
|
||||
/*std::cout << "Per Collision ( " << numTotalCollisions << " collisions ):" << std::endl;
|
||||
std::cout << " min = " << std::setw(8) << 1E9f*stat.getMin()/float(numTotalCollisions) << " ns, "
|
||||
<< "avg = " << std::setw(8) << 1E9f*stat.getAvg()/float(numTotalCollisions) << " ns, "
|
||||
<< "max = " << std::setw(8) << 1E9f*stat.getMax()/float(numTotalCollisions) << " ns" << std::endl;*/
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) try
|
||||
{
|
||||
/* parse command line options */
|
||||
parseCommandLine(argc,argv);
|
||||
|
||||
/* test if user has set two scenes */
|
||||
if (g_animation.size() == 0)
|
||||
throw std::runtime_error("you have to specify at least one scene");
|
||||
|
||||
/* initialize ray tracing core */
|
||||
g_device = rtcNewDevice(rtcore.c_str());
|
||||
//error_handler(rtcDeviceGetError(g_device));
|
||||
|
||||
if (numBenchmarkRounds)
|
||||
benchmark();
|
||||
else
|
||||
run(argc,argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cout << "Error: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...) {
|
||||
std::cout << "Error: unknown exception caught." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
return embree::Tutorial().main(argc,argv);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// ======================================================================== //
|
||||
// Copyright 2009-2016 Intel Corporation //
|
||||
// //
|
||||
// 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. //
|
||||
// ======================================================================== //
|
||||
|
||||
#include "../common/math/random_sampler.h"
|
||||
#include "../common/core/differential_geometry.h"
|
||||
#include "../common/tutorial/tutorial_device.h"
|
||||
#include "../common/tutorial/scene_device.h"
|
||||
#include <set>
|
||||
|
||||
namespace embree {
|
||||
|
||||
extern RTCDevice g_device;
|
||||
extern RTCScene g_scene;
|
||||
extern std::set<std::pair<unsigned,unsigned>> collision_candidates;
|
||||
|
||||
/* task that renders a single screen tile */
|
||||
Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera)
|
||||
{
|
||||
/* initialize ray */
|
||||
RTCRay ray;
|
||||
ray.org = Vec3fa(camera.xfm.p);
|
||||
ray.dir = Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz));
|
||||
ray.tnear = 0.0f;
|
||||
ray.tfar = inf;
|
||||
ray.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
ray.mask = -1;
|
||||
ray.time = 0.0f;
|
||||
|
||||
/* intersect ray with scene */
|
||||
rtcIntersect(g_scene,ray);
|
||||
|
||||
/* shade background black */
|
||||
if (ray.geomID == RTC_INVALID_GEOMETRY_ID) {
|
||||
return Vec3fa(0.0f);
|
||||
}
|
||||
|
||||
/* shade all rays that hit something */
|
||||
Vec3fa color(0,0,0);
|
||||
color = Vec3fa(1.0f,0.0f,0.0f);
|
||||
if (collision_candidates.find(std::make_pair(ray.geomID,ray.primID)) != collision_candidates.end())
|
||||
color = Vec3fa(1.0f,1.0f,0.0f);
|
||||
|
||||
return color*abs(dot(neg(ray.dir),normalize(ray.Ng)));
|
||||
}
|
||||
|
||||
/* renders a single screen tile */
|
||||
void renderTileStandard(int taskIndex,
|
||||
int* pixels,
|
||||
const unsigned int width,
|
||||
const unsigned int height,
|
||||
const float time,
|
||||
const ISPCCamera& camera,
|
||||
const int numTilesX,
|
||||
const int numTilesY)
|
||||
{
|
||||
const int t = taskIndex;
|
||||
const unsigned int tileY = t / numTilesX;
|
||||
const unsigned int tileX = t - tileY * numTilesX;
|
||||
const unsigned int x0 = tileX * TILE_SIZE_X;
|
||||
const unsigned int x1 = min(x0+TILE_SIZE_X,width);
|
||||
const unsigned int y0 = tileY * TILE_SIZE_Y;
|
||||
const unsigned int y1 = min(y0+TILE_SIZE_Y,height);
|
||||
|
||||
for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
|
||||
{
|
||||
Vec3fa color = renderPixelStandard((float)x,(float)y,camera);
|
||||
|
||||
/* write color to framebuffer */
|
||||
unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f));
|
||||
unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f));
|
||||
unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f));
|
||||
pixels[y*width+x] = (b << 16) + (g << 8) + r;
|
||||
}
|
||||
}
|
||||
|
||||
/* task that renders a single screen tile */
|
||||
void renderTileTask (int taskIndex, int* pixels,
|
||||
const unsigned int width,
|
||||
const unsigned int height,
|
||||
const float time,
|
||||
const ISPCCamera& camera,
|
||||
const int numTilesX,
|
||||
const int numTilesY)
|
||||
{
|
||||
renderTile(taskIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
|
||||
}
|
||||
|
||||
/* called by the C++ code for initialization */
|
||||
extern "C" void device_init (char* cfg)
|
||||
{
|
||||
/* set error handler */
|
||||
rtcDeviceSetErrorFunction(g_device,error_handler);
|
||||
|
||||
/* set start render mode */
|
||||
renderTile = renderTileStandard;
|
||||
}
|
||||
|
||||
/* called by the C++ code to render */
|
||||
extern "C" void device_render (int* pixels,
|
||||
const unsigned int width,
|
||||
const unsigned int height,
|
||||
const float time,
|
||||
const ISPCCamera& camera)
|
||||
{
|
||||
/* render image */
|
||||
const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X;
|
||||
const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y;
|
||||
parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range<size_t>& range) {
|
||||
for (size_t i=range.begin(); i<range.end(); i++)
|
||||
renderTileTask((int)i,pixels,width,height,time,camera,numTilesX,numTilesY);
|
||||
});
|
||||
}
|
||||
|
||||
/* called by the C++ code for cleanup */
|
||||
extern "C" void device_cleanup ()
|
||||
{
|
||||
rtcDeleteScene (g_scene); g_scene = nullptr;
|
||||
rtcDeleteDevice(g_device); g_device = nullptr;
|
||||
}
|
||||
|
||||
} // namespace embree
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../common/sys/platform.h"
|
||||
#include "../../common/sys/sysinfo.h"
|
||||
#include "../../common/sys/ref.h"
|
||||
#include "../../common/sys/vector.h"
|
||||
#include "../../common/math/vec2.h"
|
||||
|
||||
@@ -51,6 +51,10 @@ namespace embree
|
||||
Triangle (unsigned v0, unsigned v1, unsigned v2, unsigned materialID)
|
||||
: v0(v0), v1(v1), v2(v2), materialID(materialID) {}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& cout, const Triangle& tri) {
|
||||
return cout << "Triangle (" << tri.v0 << ", " << tri.v1 << ", " << tri.v2 << ")";
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned v0, v1, v2, materialID;
|
||||
};
|
||||
|
||||
@@ -377,7 +377,7 @@ namespace embree
|
||||
for (size_t i=0; i<skipBenchmarkFrames; i++)
|
||||
{
|
||||
double t0 = getSeconds();
|
||||
device_render(pixels,width,height,0.0f,ispccamera);
|
||||
render(pixels,width,height,0.0f,ispccamera);
|
||||
double t1 = getSeconds();
|
||||
std::cout << "frame [" << std::setw(3) << i << " / " << std::setw(3) << numTotalFrames << "]: " << std::setw(8) << 1.0/(t1-t0) << " fps (skipped)" << std::endl << std::flush;
|
||||
if (benchmarkSleep) sleepSeconds(0.1);
|
||||
@@ -386,7 +386,7 @@ namespace embree
|
||||
for (size_t i=skipBenchmarkFrames; i<numTotalFrames; i++)
|
||||
{
|
||||
double t0 = getSeconds();
|
||||
device_render(pixels,width,height,0.0f,ispccamera);
|
||||
render(pixels,width,height,0.0f,ispccamera);
|
||||
double t1 = getSeconds();
|
||||
|
||||
float fr = float(1.0/(t1-t0));
|
||||
@@ -431,7 +431,7 @@ namespace embree
|
||||
{
|
||||
resize(width,height);
|
||||
ISPCCamera ispccamera = camera.getISPCCamera(width,height);
|
||||
device_render(pixels,width,height,0.0f,ispccamera);
|
||||
render(pixels,width,height,0.0f,ispccamera);
|
||||
Ref<Image> image = new Image4uc(width, height, (Col4uc*)pixels);
|
||||
storeImage(image, fileName);
|
||||
}
|
||||
@@ -530,7 +530,7 @@ namespace embree
|
||||
if (state == GLUT_UP)
|
||||
{
|
||||
mouseMode = 0;
|
||||
if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == GLUT_ACTIVE_SHIFT)
|
||||
if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_SHIFT))
|
||||
{
|
||||
ISPCCamera ispccamera = camera.getISPCCamera(width,height);
|
||||
Vec3fa p; bool hit = device_pick(float(x),float(y),ispccamera,p);
|
||||
@@ -580,7 +580,7 @@ namespace embree
|
||||
|
||||
/* render image using ISPC */
|
||||
double t0 = getSeconds();
|
||||
device_render(pixels,width,height,float(time0-t0),ispccamera);
|
||||
render(pixels,width,height,float(time0-t0),ispccamera);
|
||||
double dt0 = getSeconds()-t0;
|
||||
|
||||
/* draw pixels to screen */
|
||||
@@ -665,6 +665,10 @@ namespace embree
|
||||
TutorialApplication::instance->idleFunc();
|
||||
}
|
||||
|
||||
void TutorialApplication::render(unsigned* pixels, const unsigned width, const unsigned height, const float time, const ISPCCamera& camera) {
|
||||
device_render(pixels,width,height,time,camera);
|
||||
}
|
||||
|
||||
void TutorialApplication::run(int argc, char** argv)
|
||||
{
|
||||
/* initialize ray tracing core */
|
||||
|
||||
@@ -72,6 +72,9 @@ namespace embree
|
||||
virtual void displayFunc(void);
|
||||
virtual void reshapeFunc(int width, int height);
|
||||
virtual void idleFunc();
|
||||
|
||||
public:
|
||||
virtual void render(unsigned* pixels, const unsigned width, const unsigned height, const float time, const ISPCCamera& camera);
|
||||
|
||||
public:
|
||||
std::string tutorialName;
|
||||
|
||||
Reference in New Issue
Block a user