collect some more statistics, code for fitting SAH cost constants to empirical measurements

metadata
Wenzel Jakob 2010-10-12 23:47:15 +02:00
parent efb75bbf7b
commit 5feb7753d8
7 changed files with 451 additions and 120 deletions

View File

@ -33,6 +33,9 @@ public:
/// Initialize with the identity matrix
Matrix4x4();
/// Initialize the matrix with constant entries
Matrix4x4(Float value);
/// Unserialize a matrix from a stream
Matrix4x4(Stream *stream);
@ -228,6 +231,31 @@ public:
dest.z = m_invTransform->m[0][2] * v.x + m_invTransform->m[1][2] * v.y
+ m_invTransform->m[2][2] * v.z;
}
/// 4D matrix-vector multiplication
inline Vector4 operator()(const Vector4 &v) const {
Float x = m_transform->m[0][0] * v.x + m_transform->m[0][1] * v.y
+ m_transform->m[0][2] * v.z + m_transform->m[0][3] * v.w;
Float y = m_transform->m[1][0] * v.x + m_transform->m[1][1] * v.y
+ m_transform->m[1][2] * v.z + m_transform->m[1][3] * v.w;
Float z = m_transform->m[2][0] * v.x + m_transform->m[2][1] * v.y
+ m_transform->m[2][2] * v.z + m_transform->m[2][3] * v.w;
Float w = m_transform->m[3][0] * v.x + m_transform->m[3][1] * v.y
+ m_transform->m[3][2] * v.z + m_transform->m[3][3] * v.w;
return Vector4(x,y,z,w);
}
/// 4D matrix-vector multiplication
inline void operator()(const Vector4 &v, Vector4 &dest) const {
dest.x = m_transform->m[0][0] * v.x + m_transform->m[0][1] * v.y
+ m_transform->m[0][2] * v.z + m_transform->m[0][3] * v.w;
dest.y = m_transform->m[1][0] * v.x + m_transform->m[1][1] * v.y
+ m_transform->m[1][2] * v.z + m_transform->m[1][3] * v.w;
dest.z = m_transform->m[2][0] * v.x + m_transform->m[2][1] * v.y
+ m_transform->m[2][2] * v.z + m_transform->m[2][3] * v.w;
dest.w = m_transform->m[3][0] * v.x + m_transform->m[3][1] * v.y
+ m_transform->m[3][2] * v.z + m_transform->m[3][3] * v.w;
}
/// Transform a ray. Assumes that there is no scaling
inline void operator()(const Ray &a, Ray &b) const {

View File

@ -24,7 +24,7 @@
#include <boost/tuple/tuple.hpp>
/// Activate lots of extra checks
#define MTS_KD_DEBUG 1
//#define MTS_KD_DEBUG 1
/** Compile-time KD-tree depth limit. Allows to put certain
data structures on the stack */
@ -584,7 +584,7 @@ public:
inline size_type getMaxDepth() const {
return m_maxDepth;
}
/**
* \brief Specify whether or not to use primitive clipping will
* be used in the tree construction.
@ -680,7 +680,7 @@ public:
inline bool getExactPrimitiveThreshold() const {
return m_exactPrimThreshold;
}
/**
* \brief Return whether or not the kd-tree has been built
*/
@ -689,9 +689,29 @@ public:
}
/**
* \brief Build a KD-tree over supplied geometry
* \brief Intersect a ray against all primitives stored in the kd-tree
*/
void build() {
bool rayIntersect(const Ray &ray, Intersection &its) const;
/**
* \brief Test a ray for intersection against all primitives stored in the kd-tree
*/
bool rayIntersect(const Ray &ray) const;
/**
* \brief Empirically find the best traversal and intersection cost values
*
* This is done by running the traversal code on random rays and fitting
* the SAH cost model to the collected statistics.
*/
void findCosts(Float &traversalCost, Float &intersectionCost);
protected:
/**
* \brief Build a KD-tree over the supplied geometry
*
* To be called by the subclass.
*/
void buildInternal() {
if (isBuilt())
Log(EError, "The kd-tree has already been built!");
@ -806,6 +826,10 @@ public:
Float expPrimitivesIntersected = 0;
Float sahCost = 0;
size_type nodePtr = 0, indexPtr = 0;
size_type maxPrimsInLeaf = 0;
const size_type primBucketCount = 16;
size_type primBuckets[primBucketCount];
memset(primBuckets, 0, sizeof(size_type)*primBucketCount);
m_nodes = static_cast<KDNode *> (allocAligned(
sizeof(KDNode) * (ctx.innerNodeCount + ctx.leafNodeCount)));
@ -829,7 +853,11 @@ public:
expLeavesVisited += aabb.getSurfaceArea();
expPrimitivesIntersected += weightedSA;
sahCost += weightedSA * m_intersectionCost;
if (primCount < primBucketCount)
primBuckets[primCount]++;
if (primCount > maxPrimsInLeaf)
maxPrimsInLeaf = primCount;
const BlockedVector<index_type, MTS_KD_BLOCKSIZE_IDX> &indices
= context->indices;
for (size_type idx = primStart; idx<primEnd; ++idx)
@ -898,7 +926,7 @@ public:
expLeavesVisited /= rootSA;
expPrimitivesIntersected /= rootSA;
sahCost /= rootSA;
/* Slightly enlarge the bounding box
(necessary e.g. when the scene is planar) */
m_aabb.min -= (m_aabb.max-m_aabb.min) * Epsilon
@ -906,18 +934,33 @@ public:
m_aabb.max += (m_aabb.max-m_aabb.min) * Epsilon
+ Vector(Epsilon, Epsilon, Epsilon);
Log(EDebug, "Detailed kd-tree statistics:");
Log(EDebug, " Inner nodes : %i", ctx.innerNodeCount);
Log(EDebug, " Leaf nodes : %i", ctx.leafNodeCount);
Log(EDebug, " Nonempty leaf nodes : %i", ctx.nonemptyLeafNodeCount);
Log(EDebug, "Structural kd-tree statistics:");
Log(EDebug, " Parallel work units : " SIZE_T_FMT,
m_interface.threadMap.size());
Log(EDebug, " Node storage cost : %s",
memString(nodePtr * sizeof(KDNode)).c_str());
Log(EDebug, " Index storage cost : %s",
memString(indexPtr * sizeof(index_type)).c_str());
Log(EDebug, " Parallel work units : " SIZE_T_FMT,
m_interface.threadMap.size());
Log(EDebug, " Inner nodes : %i", ctx.innerNodeCount);
Log(EDebug, " Leaf nodes : %i", ctx.leafNodeCount);
Log(EDebug, " Nonempty leaf nodes : %i", ctx.nonemptyLeafNodeCount);
std::ostringstream oss;
oss << " Leaf node histogram : ";
for (int i=0; i<primBucketCount; i++) {
oss << i << "(" << primBuckets[i] << ") ";
if ((i+1)%4==0 && i+1<primBucketCount) {
Log(EDebug, "%s", oss.str().c_str());
oss.str("");
oss << " ";
}
}
Log(EDebug, "%s", oss.str().c_str());
Log(EDebug, "");
Log(EDebug, "Qualitative kd-tree statistics:");
Log(EDebug, " Retracted splits : %i", ctx.retractedSplits);
Log(EDebug, " Pruned primitives : %i", ctx.pruned);
Log(EDebug, " Largest leaf node : %i primitives",
maxPrimsInLeaf);
Log(EDebug, " Avg. prims/nonempty leaf : %.2f",
ctx.primIndexCount / (Float) ctx.nonemptyLeafNodeCount);
Log(EDebug, " Expected traversals/ray : %.2f", expTraversalSteps);
@ -927,16 +970,6 @@ public:
Log(EDebug, "");
}
/**
* \brief Intersect a ray against all primitives stored in the kd-tree
*/
bool rayIntersect(const Ray &ray, Intersection &its) const;
/**
* \brief Test a ray for intersection against all primitives stored in the kd-tree
*/
bool rayIntersect(const Ray &ray) const;
protected:
/// Primitive classification during tree-construction
enum EClassificationResult {
@ -1366,7 +1399,7 @@ protected:
inline const Derived *cast() const {
return static_cast<const Derived *>(this);
}
/**
* \brief Create an edge event list for a given list of primitives.
*
@ -2449,8 +2482,6 @@ protected:
template<bool shadowRay> FINLINE bool rayIntersectHavran(const Ray &ray,
Float mint, Float maxt, Float &t, void *temp) const {
KDStackEntryHavran stack[MTS_KD_MAXDEPTH];
const KDNode * __restrict farChild,
* __restrict currNode = m_nodes;
#if 0
static const int prevAxisTable[] = { 2, 0, 1 };
static const int nextAxisTable[] = { 1, 2, 0 };
@ -2470,11 +2501,13 @@ protected:
stack[exPt].t = maxt;
stack[exPt].p = ray(maxt);
stack[exPt].node = NULL;
const KDNode * __restrict currNode = m_nodes;
while (currNode != NULL) {
while (EXPECT_TAKEN(!currNode->isLeaf())) {
const Float splitVal = (Float) currNode->getSplit();
const int axis = currNode->getAxis();
const KDNode * __restrict farChild;
if (stack[enPt].p[axis] <= splitVal) {
if (stack[exPt].p[axis] <= splitVal) {
@ -2558,7 +2591,7 @@ protected:
EIntersectionResult result = cast()->intersect(ray,
primIdx, searchStart, searchEnd, t, temp);
if (result == EYes) {
if (shadowRay)
return true;
@ -2584,6 +2617,131 @@ protected:
return false;
}
/**
* \brief Internal kd-tree traversal implementation (Havran variant)
*
* This method is almost identical to \ref rayIntersectHavran, except
* that it additionally returns statistics on the number of traversed
* nodes, intersected shapes, as well as the time taken to do this
* (measured using rtdsc).
*/
FINLINE boost::tuple<bool, uint32_t, uint32_t, uint64_t>
rayIntersectHavranCollectStatistics(const Ray &ray,
Float mint, Float maxt, Float &t, void *temp) const {
KDStackEntryHavran stack[MTS_KD_MAXDEPTH];
/* Set up the entry point */
uint32_t enPt = 0;
stack[enPt].t = mint;
stack[enPt].p = ray(mint);
/* Set up the exit point */
uint32_t exPt = 1;
stack[exPt].t = maxt;
stack[exPt].p = ray(maxt);
stack[exPt].node = NULL;
uint32_t numTraversals = 0;
uint32_t numIntersections = 0;
uint64_t timer = rdtsc();
const KDNode * __restrict currNode = m_nodes;
while (currNode != NULL) {
while (EXPECT_TAKEN(!currNode->isLeaf())) {
const Float splitVal = (Float) currNode->getSplit();
const int axis = currNode->getAxis();
const KDNode * __restrict farChild;
++numTraversals;
if (stack[enPt].p[axis] <= splitVal) {
if (stack[exPt].p[axis] <= splitVal) {
/* Cases N1, N2, N3, P5, Z2 and Z3 (see thesis) */
currNode = currNode->getLeft();
continue;
}
/* Typo in Havran's thesis:
(it specifies "stack[exPt].p == splitVal", which
is clearly incorrect) */
if (stack[enPt].p[axis] == splitVal) {
/* Case Z1 */
currNode = currNode->getRight();
continue;
}
/* Case N4 */
currNode = currNode->getLeft();
farChild = currNode + 1; // getRight()
} else { /* stack[enPt].p[axis] > splitVal */
if (splitVal < stack[exPt].p[axis]) {
/* Cases P1, P2, P3 and N5 */
currNode = currNode->getRight();
continue;
}
/* Case P4 */
farChild = currNode->getLeft();
currNode = farChild + 1; // getRight()
}
/* Cases P4 and N4 -- calculate the distance to the split plane */
t = (splitVal - ray.o[axis]) * ray.dRcp[axis];
/* Set up a new exit point */
const uint32_t tmp = exPt++;
if (exPt == enPt) /* Do not overwrite the entry point */
++exPt;
KDAssert(exPt < MTS_KD_MAX_DEPTH);
stack[exPt].prev = tmp;
stack[exPt].t = t;
stack[exPt].node = farChild;
stack[exPt].p = ray(t);
stack[exPt].p[axis] = splitVal;
}
#if defined(SINGLE_PRECISION)
const Float eps = 1e-3;
#else
const Float eps = 1e-5;
#endif
const Float m_eps = 1-eps, p_eps = 1+eps;
/* Floating-point arithmetic.. - use both absolute and relative
epsilons when looking for intersections in the subinterval */
const Float searchStart = std::max(mint, stack[enPt].t * m_eps - eps);
Float searchEnd = std::min(maxt, stack[exPt].t * p_eps + eps);
/* Reached a leaf node */
bool foundIntersection = false;
for (unsigned int entry=currNode->getPrimStart(),
last = currNode->getPrimEnd(); entry != last; entry++) {
const index_type primIdx = m_indices[entry];
++numIntersections;
EIntersectionResult result = cast()->intersect(ray,
primIdx, searchStart, searchEnd, t, temp);
if (result == EYes) {
searchEnd = t;
foundIntersection = true;
}
}
if (foundIntersection)
return boost::make_tuple(true, numTraversals,
numIntersections, rdtsc() - timer);
/* Pop from the stack and advance to the next node on the interval */
enPt = exPt;
currNode = stack[exPt].node;
exPt = stack[enPt].prev;
}
return boost::make_tuple(false, numTraversals,
numIntersections, rdtsc() - timer);
}
struct KDStackEntry {
const KDNode * __restrict node;
Float mint, maxt;
@ -2735,6 +2893,94 @@ template <typename Derived> bool GenericKDTree<Derived>::rayIntersect(
}
return false;
}
template <typename Derived> void GenericKDTree<Derived>::findCosts(
Float &traversalCost, Float &intersectionCost) {
ref<Random> random = new Random();
uint32_t temp[MTS_KD_INTERSECTION_TEMP];
BSphere bsphere = m_aabb.getBSphere();
const size_t nRays = 10000000, warmup = nRays/4;
Vector *A = new Vector[nRays-warmup];
Float *b = new Float[nRays-warmup];
size_t nIntersections = 0, idx = 0;
for (size_t i=0; i<nRays; ++i) {
Point2 sample1(random->nextFloat(), random->nextFloat()),
sample2(random->nextFloat(), random->nextFloat());
Point p1 = bsphere.center + squareToSphere(sample1) * bsphere.radius;
Point p2 = bsphere.center + squareToSphere(sample2) * bsphere.radius;
Ray ray(p1, normalize(p2-p1));
Float mint, maxt, t;
if (ray.mint > mint) mint = ray.mint;
if (ray.maxt < maxt) maxt = ray.maxt;
if (m_aabb.rayIntersect(ray, mint, maxt)) {
if (EXPECT_TAKEN(maxt > mint)) {
boost::tuple<bool, uint32_t, uint32_t, uint64_t> statistics =
rayIntersectHavranCollectStatistics(ray, mint, maxt, t, temp);
if (boost::get<0>(statistics))
nIntersections++;
if (i > warmup) {
A[idx].x = 1;
A[idx].y = boost::get<1>(statistics);
A[idx].z = boost::get<2>(statistics);
b[idx] = boost::get<3>(statistics);
idx++;
}
}
}
}
Log(EDebug, "Fitting to " SIZE_T_FMT " samples (" SIZE_T_FMT
" intersections)", idx, nIntersections);
/* Solve using normal equations */
ref<Matrix4x4> M = new Matrix4x4(0.0f);
Vector4 rhs(0.0f), x;
for (size_t i=0; i<3; ++i) {
for (size_t j=0; j<3; ++j)
for (size_t k=0; k<idx; ++k)
M->m[i][j] += A[k][i]*A[k][j];
for (size_t k=0; k<idx; ++k)
rhs[i] += A[k][i]*b[k];
}
M->m[3][3] = 1.0f;
Transform(M->inverse())(rhs, x);
Float avgRdtsc = 0, avgResidual = 0;
for (size_t i=0; i<idx; ++i) {
avgRdtsc += b[i];
Float model = x[0] * A[i][0]
+ x[1] * A[i][1]
+ x[2] * A[i][2];
//cout << b[i] << " vs " << (int) model << endl;
avgResidual += std::abs(b[i] - model);
}
avgRdtsc /= idx;
avgResidual /= idx;
for (size_t k=0; k<idx; ++k)
avgRdtsc += b[k];
avgRdtsc /= idx;
Log(EDebug, "Least squares fit:");
Log(EDebug, " Constant overhead = %.2f", x[0]);
Log(EDebug, " Traversal cost = %.2f", x[1]);
Log(EDebug, " Intersection cost = %.2f", x[2]);
Log(EDebug, " Average rdtsc value = %.2f", avgRdtsc);
Log(EDebug, " Avg. residual = %.2f", avgResidual);
x *= 10/x[1];
Log(EDebug, "Re-scaled:");
Log(EDebug, " Constant overhead = %.2f", x[0]);
Log(EDebug, " Traversal cost = %.2f", x[1]);
Log(EDebug, " Intersection cost = %.2f", x[2]);
delete[] A;
delete[] b;
traversalCost = x[1];
intersectionCost = x[2];
}
MTS_NAMESPACE_END

View File

@ -30,10 +30,10 @@
* whole following block:
*/
#ifdef MTS_SSE
//#define MTS_USE_TRIACCEL4 1
//#define MTS_USE_TRIACCEL 1
#define MTS_USE_TRIACCEL4 1
#define MTS_USE_TRIACCEL 1
#else
//#define MTS_USE_TRIACCEL 1
#define MTS_USE_TRIACCEL 1
#endif
#if defined(MTS_HAS_COHERENT_RT)

View File

@ -95,15 +95,46 @@ inline int TriAccel::load(const Point &A, const Point &B, const Point &C) {
FINLINE bool TriAccel::rayIntersect(const Ray &ray, Float mint, Float maxt,
Float &u, Float &v, Float &t) const {
static const int waldModulo[4] = { 1, 2, 0, 1 };
const int ku = waldModulo[k], kv = waldModulo[k+1];
#if 0
static const MM_ALIGN16 int waldModulo[4] = { 1, 2, 0, 1 };
const int ku = waldModulo[k], kv = waldModulo[k+1];
/* Get the u and v components */
const Float o_u = ray.o[ku], o_v = ray.o[kv], o_k = ray.o[k],
d_u = ray.d[ku], d_v = ray.d[kv], d_k = ray.d[k];
#else
Float o_u, o_v, o_k, d_u, d_v, d_k;
switch (k) {
case 0:
o_u = ray.o[1];
o_v = ray.o[2];
o_k = ray.o[0];
d_u = ray.d[1];
d_v = ray.d[2];
d_k = ray.d[0];
break;
case 1:
o_u = ray.o[2];
o_v = ray.o[0];
o_k = ray.o[1];
d_u = ray.d[2];
d_v = ray.d[0];
d_k = ray.d[1];
break;
case 2:
o_u = ray.o[0];
o_v = ray.o[1];
o_k = ray.o[2];
d_u = ray.d[0];
d_v = ray.d[1];
d_k = ray.d[2];
break;
}
#endif
/* Calculate the plane intersection (Typo in the thesis?) */
t = (n_d - o_u*n_u - o_v*n_v - o_k) / (d_u * n_u + d_v * n_v + d_k);
Float recip = 1.0f / (d_u * n_u + d_v * n_v + d_k);
t = (n_d - o_u*n_u - o_v*n_v - o_k) * recip;
if (t < mint || t > maxt)
return false;
@ -115,8 +146,7 @@ FINLINE bool TriAccel::rayIntersect(const Ray &ray, Float mint, Float maxt,
/* In barycentric coordinates */
u = hv * b_nu + hu * b_nv;
v = hu * c_nu + hv * c_nv;
return (u >= 0 && v >= 0 && u+v <= 1.0f);
return u >= 0 && v >= 0 && u+v <= 1.0f;
}
MTS_NAMESPACE_END

View File

@ -57,7 +57,7 @@ struct TriAccel4 {
FINLINE __m128 TriAccel::rayIntersectPacket(const RayPacket4 &packet,
__m128 mint, __m128 maxt, __m128 inactive, Intersection4 &its) const {
static const int waldModulo[4] = { 1, 2, 0, 1 };
static const MM_ALIGN16 int waldModulo[4] = { 1, 2, 0, 1 };
const int ku = waldModulo[k], kv = waldModulo[k+1];
/* Get the u and v components */

View File

@ -232,6 +232,12 @@ Matrix4x4::Matrix4x4() {
m[i][j] = (i == j) ? 1.0f : 0.0f;
}
Matrix4x4::Matrix4x4(Float value) {
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
m[i][j] = value;
}
Matrix4x4::Matrix4x4(Float _m[4][4]) {
memcpy(m, _m, sizeof(Float) * 16);
}

View File

@ -21,6 +21,103 @@
#include <mitsuba/render/gkdtree.h>
MTS_NAMESPACE_BEGIN
class TriKDTree : public GenericKDTree<TriKDTree> {
public:
TriKDTree(const Triangle *triangles,
const Vertex *vertexBuffer,
size_type triangleCount)
: m_triangles(triangles),
m_vertexBuffer(vertexBuffer),
m_triangleCount(triangleCount) {
}
FINLINE AABB getAABB(index_type idx) const {
return m_triangles[idx].getAABB(m_vertexBuffer);
}
FINLINE AABB getClippedAABB(index_type idx, const AABB &aabb) const {
return m_triangles[idx].getClippedAABB(m_vertexBuffer, aabb);
}
FINLINE size_type getPrimitiveCount() const {
return m_triangleCount;
}
FINLINE EIntersectionResult intersect(const Ray &ray, index_type idx,
Float mint, Float maxt, Float &t, void *tmp) const {
Float tempT, tempU, tempV;
#if 0
if (m_triangles[idx].rayIntersect(m_vertexBuffer, ray, tempU, tempV, tempT)) {
if (tempT < mint && tempT > maxt)
return ENo;
#else
if (m_triAccel[idx].rayIntersect(ray, mint, maxt, tempU, tempV, tempT)) {
#endif
index_type *indexPtr = reinterpret_cast<index_type *>(tmp);
Float *floatPtr = reinterpret_cast<Float *>(indexPtr + 1);
t = tempT;
*indexPtr = idx;
*floatPtr++ = tempU;
*floatPtr++ = tempV;
return EYes;
}
return ENo;
}
void build() {
buildInternal();
Log(EInfo, "Precomputing triangle intersection information (%s)",
memString(sizeof(TriAccel)*m_triangleCount).c_str());
m_triAccel = static_cast<TriAccel *>(allocAligned(m_triangleCount * sizeof(TriAccel)));
for (size_t i=0; i<m_triangleCount; ++i) {
const Triangle &tri = m_triangles[i];
const Vertex &v0 = m_vertexBuffer[tri.idx[0]];
const Vertex &v1 = m_vertexBuffer[tri.idx[1]];
const Vertex &v2 = m_vertexBuffer[tri.idx[2]];
m_triAccel[i].load(v0.p, v1.p, v2.p);
}
}
FINLINE void fillIntersectionDetails(const Ray &ray,
Float t, const void *tmp, Intersection &its) const {
its.p = ray(t);
//const index_type *indexPtr = reinterpret_cast<const index_type *>(tmp);
//const Float *floatPtr = reinterpret_cast<const Float *>(indexPtr + 1);
//const Triangle &tri = m_triangles[*indexPtr];
//const Vertex &v0 = m_vertexBuffer[tri.idx[0]];
//const Vertex &v1 = m_vertexBuffer[tri.idx[1]];
//const Vertex &v2 = m_vertexBuffer[tri.idx[2]];
//const Float u = *floatPtr++, v = *floatPtr++;
//const Vector b(1 - u - v, u, v);
/*
its.uv = v0.uv * b.x + v1.uv * b.y + v2.uv * b.z;
its.dpdu = v0.dpdu * b.x + v1.dpdu * b.y + v2.dpdu * b.z;
its.dpdv = v0.dpdv * b.x + v1.dpdv * b.y + v2.dpdv * b.z;
its.geoFrame = Frame(normalize(cross(v1.p-v0.p, v2.p-v0.p)));
its.shFrame.n = normalize(v0.n * b.x + v1.n * b.y + v2.n * b.z);
its.shFrame.s = normalize(its.dpdu - its.shFrame.n
* dot(its.shFrame.n, its.dpdu));
its.shFrame.t = cross(its.shFrame.n, its.shFrame.s);
its.wi = its.toLocal(-ray.d);
*/
its.hasUVPartials = false;
}
private:
const Triangle *m_triangles;
const Vertex *m_vertexBuffer;
TriAccel *m_triAccel;
size_type m_triangleCount;
};
class TestKDTree : public TestCase {
public:
@ -81,85 +178,6 @@ public:
assertEquals(Point(1, 1, 0), clippedAABB.max);
}
class TriKDTree : public GenericKDTree<TriKDTree> {
public:
TriKDTree(const Triangle *triangles,
const Vertex *vertexBuffer,
size_type triangleCount)
: m_triangles(triangles),
m_vertexBuffer(vertexBuffer),
m_triangleCount(triangleCount) {
}
FINLINE AABB getAABB(index_type idx) const {
return m_triangles[idx].getAABB(m_vertexBuffer);
}
FINLINE AABB getClippedAABB(index_type idx, const AABB &aabb) const {
return m_triangles[idx].getClippedAABB(m_vertexBuffer, aabb);
}
FINLINE size_type getPrimitiveCount() const {
return m_triangleCount;
}
FINLINE EIntersectionResult intersect(const Ray &ray, index_type idx,
Float mint, Float maxt, Float &t, void *tmp) const {
Float tempT, tempU, tempV;
if (m_triangles[idx].rayIntersect(m_vertexBuffer, ray, tempU, tempV, tempT)) {
if (tempT >= mint && tempT <= maxt) {
index_type *indexPtr = reinterpret_cast<index_type *>(tmp);
Float *floatPtr = reinterpret_cast<Float *>(indexPtr + 1);
t = tempT;
*indexPtr = idx;
*floatPtr++ = tempU;
*floatPtr++ = tempV;
return EYes;
}
return ENo;
} else {
return ENever;
}
}
FINLINE void fillIntersectionDetails(const Ray &ray,
Float t, const void *tmp, Intersection &its) const {
its.p = ray(t);
//const index_type *indexPtr = reinterpret_cast<const index_type *>(tmp);
//const Float *floatPtr = reinterpret_cast<const Float *>(indexPtr + 1);
//const Triangle &tri = m_triangles[*indexPtr];
//const Vertex &v0 = m_vertexBuffer[tri.idx[0]];
//const Vertex &v1 = m_vertexBuffer[tri.idx[1]];
//const Vertex &v2 = m_vertexBuffer[tri.idx[2]];
//const Float u = *floatPtr++, v = *floatPtr++;
//const Vector b(1 - u - v, u, v);
/*
its.uv = v0.uv * b.x + v1.uv * b.y + v2.uv * b.z;
its.dpdu = v0.dpdu * b.x + v1.dpdu * b.y + v2.dpdu * b.z;
its.dpdv = v0.dpdv * b.x + v1.dpdv * b.y + v2.dpdv * b.z;
its.geoFrame = Frame(normalize(cross(v1.p-v0.p, v2.p-v0.p)));
its.shFrame.n = normalize(v0.n * b.x + v1.n * b.y + v2.n * b.z);
its.shFrame.s = normalize(its.dpdu - its.shFrame.n
* dot(its.shFrame.n, its.dpdu));
its.shFrame.t = cross(its.shFrame.n, its.shFrame.s);
its.wi = its.toLocal(-ray.d);
*/
its.hasUVPartials = false;
}
private:
const Triangle *m_triangles;
const Vertex *m_vertexBuffer;
size_type m_triangleCount;
};
void test02_buildSimple() {
Properties bunnyProps("ply");
bunnyProps.setString("filename", "tools/tests/bunny.ply");
@ -169,13 +187,17 @@ public:
mesh->configure();
TriKDTree tree(mesh->getTriangles(),
mesh->getVertexBuffer(), mesh->getTriangleCount());
tree.setTraversalCost(10);
tree.setIntersectionCost(17);
tree.build();
BSphere bsphere(mesh->getBSphere());
/*
Float intersectionCost, traversalCost;
tree.findCosts(intersectionCost, traversalCost);
ref<KDTree> oldTree = new KDTree();
oldTree->addShape(mesh);
oldTree->build(); */
oldTree->build();
for (int j=0; j<3; ++j) {
ref<Random> random = new Random();
@ -203,7 +225,7 @@ public:
nIntersections, timer->getMilliseconds());
Log(EInfo, "New: %.3f MRays/s",
nRays / (timer->getMilliseconds() * (Float) 1000));
/*
random = new Random();
timer->reset();
nIntersections=0;
@ -224,7 +246,6 @@ public:
nIntersections, timer->getMilliseconds());
Log(EInfo, "Old: %.3f MRays/s",
nRays / (timer->getMilliseconds() * (Float) 1000));
*/
}
}
};