1142 lines
37 KiB
C++
1142 lines
37 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include <cmath>
|
|
#include <cfloat>
|
|
#include <cstring>
|
|
#include "core/geometry_kdtree.h"
|
|
#include "core/geometry.h"
|
|
#include "scene3d/mobject.h"
|
|
#include "scene3d/mlight.h"
|
|
#include "scene3d/mcamera.h"
|
|
#include "timing/benchmark.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS;
|
|
using namespace GS::Core;
|
|
|
|
|
|
GeometryKDTree::KDTreeNode::KDTreeNode(){m_KDTREE_NODE_ID_POLY = NULL; m_KDTREE_NODE_ID_VTX = NULL; memset(m_KDTREE_NODE_ID_ROPE, -1, sizeof(int)*6);};
|
|
|
|
#define KDTREE_MAX_DEPTH 20
|
|
#define KDTREE_MAX_POLY_PER_NODE 5
|
|
|
|
#define X 0
|
|
#define Y 1
|
|
#define Z 2
|
|
|
|
#define CROSS(dest,v1,v2) \
|
|
dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
|
|
dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
|
|
dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
|
|
|
|
#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
|
|
|
|
#define SUB(dest,v1,v2) \
|
|
dest[0]=v1[0]-v2[0]; \
|
|
dest[1]=v1[1]-v2[1]; \
|
|
dest[2]=v1[2]-v2[2];
|
|
|
|
#define FINDMINMAX(x0,x1,x2,Min,Max) \
|
|
Min = Max = x0; \
|
|
if(x1<Min) Min=x1;\
|
|
if(x1>Max) Max=x1;\
|
|
if(x2<Min) Min=x2;\
|
|
if(x2>Max) Max=x2;
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
int GeometryKDTree::planeBoxOverlap(float normal[3], float vert[3], float maxbox[3])
|
|
//-----------------------------------------------------------------------------------
|
|
{
|
|
int q;
|
|
float vmin[3],vmax[3],v;
|
|
|
|
for(q=X;q<=Z;q++)
|
|
{
|
|
v=vert[q];
|
|
|
|
if(normal[q]>0.0f)
|
|
{
|
|
vmin[q]=-maxbox[q] - v;
|
|
vmax[q]= maxbox[q] - v;
|
|
}
|
|
else
|
|
{
|
|
vmin[q]= maxbox[q] - v;
|
|
vmax[q]=-maxbox[q] - v;
|
|
}
|
|
}
|
|
|
|
if(DOT(normal,vmin)>0.0f)
|
|
return 0;
|
|
|
|
if(DOT(normal,vmax)>=0.0f)
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*======================== X-tests ========================*/
|
|
|
|
#define AXISTEST_X01(a, b, fa, fb) \
|
|
p0 = a*v0[Y] - b*v0[Z]; \
|
|
p2 = a*v2[Y] - b*v2[Z]; \
|
|
if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
|
rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
#define AXISTEST_X2(a, b, fa, fb) \
|
|
p0 = a*v0[Y] - b*v0[Z]; \
|
|
p1 = a*v1[Y] - b*v1[Z]; \
|
|
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
|
rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
/*======================== Y-tests ========================*/
|
|
|
|
#define AXISTEST_Y02(a, b, fa, fb) \
|
|
p0 = -a*v0[X] + b*v0[Z]; \
|
|
p2 = -a*v2[X] + b*v2[Z]; \
|
|
if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
|
|
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
#define AXISTEST_Y1(a, b, fa, fb) \
|
|
p0 = -a*v0[X] + b*v0[Z]; \
|
|
p1 = -a*v1[X] + b*v1[Z]; \
|
|
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
|
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
/*======================== Z-tests ========================*/
|
|
#define AXISTEST_Z12(a, b, fa, fb) \
|
|
p1 = a*v1[X] - b*v1[Y]; \
|
|
p2 = a*v2[X] - b*v2[Y]; \
|
|
if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
|
|
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
#define AXISTEST_Z0(a, b, fa, fb) \
|
|
p0 = a*v0[X] - b*v0[Y]; \
|
|
p1 = a*v1[X] - b*v1[Y]; \
|
|
if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
|
|
rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
|
|
if(min>rad || max<-rad) return 0;
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------
|
|
int GeometryKDTree::triBoxOverlap(float boxcenter[3],float boxhalfsize[3],float Verts1[3],float Verts2[3],float Verts3[3])
|
|
//-------------------------------------------------------------------------------------------------------------------------
|
|
|
|
{ /* use separating axis theorem to test overlap between triangle and box */
|
|
/* need to test for overlap in these directions: */
|
|
/* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
|
|
/* we do not even need to test these) */
|
|
/* 2) normal of the triangle */
|
|
/* 3) crossproduct(edge from tri, {x,y,z}-directin) */
|
|
/* this gives 3x3=9 more tests */
|
|
|
|
float v0[3],v1[3],v2[3];
|
|
|
|
// float axis[3];
|
|
float min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed
|
|
float normal[3],e0[3],e1[3],e2[3];
|
|
|
|
|
|
/* This is the fastest branch on Sun */
|
|
/* move everything so that the boxcenter is in (0,0,0) */
|
|
SUB(v0,Verts1,boxcenter);
|
|
SUB(v1,Verts2,boxcenter);
|
|
SUB(v2,Verts3,boxcenter);
|
|
|
|
/* compute triangle edges */
|
|
SUB(e0,v1,v0); /* tri edge 0 */
|
|
SUB(e1,v2,v1); /* tri edge 1 */
|
|
SUB(e2,v0,v2); /* tri edge 2 */
|
|
|
|
/* Bullet 3: */
|
|
|
|
/* test the 9 tests first (this was faster) */
|
|
fex = fabsf(e0[X]);
|
|
fey = fabsf(e0[Y]);
|
|
fez = fabsf(e0[Z]);
|
|
|
|
AXISTEST_X01(e0[Z], e0[Y], fez, fey);
|
|
AXISTEST_Y02(e0[Z], e0[X], fez, fex);
|
|
AXISTEST_Z12(e0[Y], e0[X], fey, fex);
|
|
|
|
fex = fabsf(e1[X]);
|
|
fey = fabsf(e1[Y]);
|
|
fez = fabsf(e1[Z]);
|
|
|
|
AXISTEST_X01(e1[Z], e1[Y], fez, fey);
|
|
AXISTEST_Y02(e1[Z], e1[X], fez, fex);
|
|
AXISTEST_Z0(e1[Y], e1[X], fey, fex);
|
|
|
|
fex = fabsf(e2[X]);
|
|
fey = fabsf(e2[Y]);
|
|
fez = fabsf(e2[Z]);
|
|
|
|
AXISTEST_X2(e2[Z], e2[Y], fez, fey);
|
|
AXISTEST_Y1(e2[Z], e2[X], fez, fex);
|
|
AXISTEST_Z12(e2[Y], e2[X], fey, fex);
|
|
|
|
/* Bullet 1: */
|
|
/* first test overlap in the {x,y,z}-directions */
|
|
/* find min, max of the triangle each direction, and test for overlap in */
|
|
/* that direction -- this is equivalent to testing a minimal AABB around */
|
|
/* the triangle against the AABB */
|
|
|
|
/* test in X-direction */
|
|
FINDMINMAX(v0[X],v1[X],v2[X],min,max);
|
|
|
|
if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0;
|
|
|
|
/* test in Y-direction */
|
|
FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max);
|
|
|
|
if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0;
|
|
|
|
/* test in Z-direction */
|
|
FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max);
|
|
|
|
if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0;
|
|
|
|
/* Bullet 2: */
|
|
/* test if the box intersects the plane of the triangle */
|
|
/* compute plane equation of triangle: normal*x+d=0 */
|
|
|
|
CROSS(normal,e0,e1);
|
|
|
|
if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0;
|
|
|
|
return 1; /* box and triangle overlaps */
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
int GeometryKDTree::GetKDtreeSideAABB(float* _AABB, Vector4 &_EntryPoint, int &_LastEntrySide)
|
|
//---------------------------------------------------------------------------------------------
|
|
{
|
|
int l_AvoidSide = _LastEntrySide;
|
|
if(_LastEntrySide != -1)
|
|
{
|
|
if(_LastEntrySide%2)
|
|
l_AvoidSide = _LastEntrySide-1;
|
|
else
|
|
l_AvoidSide = _LastEntrySide+1;
|
|
}
|
|
|
|
// check the nearest plane for the nearest rope
|
|
int l_SideChoose = -1;
|
|
float l_Dist = 3.402823466e+38F;
|
|
|
|
float l_CheckDist = fabs(_AABB[KDTREE_SIDE_LEFT] - _EntryPoint.x);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_LEFT)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_LEFT;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
l_CheckDist = fabs(_AABB[KDTREE_SIDE_RIGHT] - _EntryPoint.x);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_RIGHT)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_RIGHT;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
l_CheckDist = fabs(_AABB[KDTREE_SIDE_BOTTOM] - _EntryPoint.y);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_BOTTOM)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_BOTTOM;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
l_CheckDist = fabs(_AABB[KDTREE_SIDE_TOP] - _EntryPoint.y);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_TOP)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_TOP;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
l_CheckDist = fabs(_AABB[KDTREE_SIDE_BACK] - _EntryPoint.z);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_BACK)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_BACK;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
l_CheckDist = fabs(_AABB[KDTREE_SIDE_FRONT] - _EntryPoint.z);
|
|
if(l_CheckDist < l_Dist && l_AvoidSide != KDTREE_SIDE_FRONT)
|
|
{
|
|
l_SideChoose = KDTREE_SIDE_FRONT;
|
|
l_Dist = l_CheckDist;
|
|
}
|
|
|
|
_LastEntrySide = l_SideChoose;
|
|
|
|
return l_SideChoose;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
bool GeometryKDTree::IntersectTriangle(const Vector4 &s, const Vector4 &d, float* Vtx1, float* Vtx2, float* Vtx3, Vector4* _Edge1, Vector4* _Edge2, float &l_Dist, float &u, float &v, bool& _Backface)
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
{
|
|
const float EPSILON = 0.000001f;
|
|
l_Dist = 3.402823466e+38F;
|
|
|
|
//test if inside the plane
|
|
|
|
/* find vectors for two edges sharing vert0 */
|
|
//nVector l_edge1(Vtx2[0] - Vtx1[0], Vtx2[1] - Vtx1[1], Vtx2[2] - Vtx1[2]);
|
|
//nVector l_edge2(Vtx3[0] - Vtx1[0], Vtx3[1] - Vtx1[1], Vtx3[2] - Vtx1[2]);
|
|
|
|
/* begin calculating determinant - also used to calculate U parameter */
|
|
//nVector l_pvec = d.Cross( *_Edge2);
|
|
Vector4 l_pvec(d.y * _Edge2->z - d.z * _Edge2->y, d.z * _Edge2->x - d.x * _Edge2->z, d.x * _Edge2->y - d.y * _Edge2->x);
|
|
|
|
/* if determinant is near zero, ray lies in plane of triangle */
|
|
float l_det = _Edge1->Dot( l_pvec);
|
|
|
|
/* the non-culling branch */
|
|
if (l_det <= -EPSILON || l_det >= EPSILON)
|
|
{
|
|
float l_inv_det = 1.0f / l_det;
|
|
|
|
/* calculate distance from vert0 to ray origin */
|
|
Vector4 l_tvec(s.x - Vtx1[0], s.y - Vtx1[1], s.z - Vtx1[2]);
|
|
|
|
/* calculate U parameter and test bounds */
|
|
float _u = l_tvec.Dot( l_pvec) * l_inv_det;
|
|
if (_u >= 0.0f && _u <= 1.0f)
|
|
{
|
|
/* prepare to test V parameter */
|
|
Vector4 l_qvec = l_tvec.Cross( *_Edge1);
|
|
|
|
/* calculate V parameter and test bounds */
|
|
float _v = d.Dot( l_qvec) * l_inv_det;
|
|
if (_v >= 0.0f && _u + _v <= 1.0f)
|
|
{
|
|
/* calculate t, ray intersects triangle */
|
|
l_Dist = _Edge2->Dot( l_qvec) * l_inv_det;
|
|
u = _u;
|
|
v = _v;
|
|
|
|
if (l_det <= -EPSILON )
|
|
_Backface = true;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------
|
|
bool GeometryKDTree::AABBIntersectRay(float* _AABB, const Vector4 &o, const Vector4 &d, float &tmin, float &tmax)
|
|
//----------------------------------------------------------------------------------------------------------------
|
|
{
|
|
tmin = 0;
|
|
tmax = 3.402823466e+38F;
|
|
|
|
for (uint n = 0; n < 3; ++n)
|
|
if (Math::EqualZero(d[n]))
|
|
{
|
|
if ((o[n] < _AABB[n*2]) || (o[n] > _AABB[n*2+1]))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
float ood = 1.f / d[n];
|
|
float t0 = (_AABB[n*2] - o[n]) * ood;
|
|
float t1 = (_AABB[n*2+1] - o[n]) * ood;
|
|
|
|
if (t0 > t1)
|
|
{ float swp = t1; t1 = t0; t0 = swp; }
|
|
|
|
tmin = tmin < t0 ? t0 : tmin;
|
|
tmax = tmax < t1 ? tmax : t1;
|
|
|
|
if (tmin > tmax)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------
|
|
int GeometryKDTree::InsideKdTreeNode(const Vector4 &s, bool CheckInside)
|
|
//---------------------------------------------------
|
|
{
|
|
int l_CurrentNode = 0;
|
|
|
|
while(!m_NodeTree[l_CurrentNode].m_KDTREE_NODE_IS_LEAF)
|
|
{
|
|
switch (m_NodeTree[l_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT)
|
|
{
|
|
case KDTREE_X_AXIS:
|
|
if(s.x > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
break;
|
|
case KDTREE_Y_AXIS:
|
|
if(s.y > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
break;
|
|
case KDTREE_Z_AXIS:
|
|
if(s.z > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!CheckInside ||
|
|
(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[0] <= s.x && s.x <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[1] &&
|
|
m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[2] <= s.y && s.y <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[3] &&
|
|
m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[4] <= s.z && s.z <= m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB[5] ))
|
|
return l_CurrentNode;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
void GeometryKDTree::RaytraceGeometry(GeometryTrace &trace, const Vector4 &s, const Vector4 &d, float dist_max)
|
|
//---------------------------------------------------------------------------------------------------------------
|
|
{
|
|
trace.has_i = false;
|
|
|
|
// ray_count++;
|
|
trace.tri_test = 1;
|
|
|
|
if(m_count_bih <= 0)
|
|
return;
|
|
|
|
float l_DistEntry, l_DistExit;
|
|
|
|
int l_CurrentNode = 0;
|
|
|
|
// test the ray pass in this kdtree
|
|
if(!AABBIntersectRay(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, s, d, l_DistEntry, l_DistExit))
|
|
return;
|
|
|
|
// set the max distance
|
|
if(dist_max != -1.0f && dist_max < l_DistExit)
|
|
l_DistExit = dist_max;
|
|
|
|
l_DistEntry *= 0.9999f;
|
|
|
|
int l_LastEntrySide = -1;
|
|
Vector4 l_PointEntry;
|
|
float l_NearestDist = 3.402823466e+38F;
|
|
|
|
while(l_DistEntry < l_DistExit)
|
|
{
|
|
l_PointEntry = s + d*l_DistEntry;
|
|
|
|
while(!m_NodeTree[l_CurrentNode].m_KDTREE_NODE_IS_LEAF)
|
|
{
|
|
switch (m_NodeTree[l_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT)
|
|
{
|
|
case KDTREE_X_AXIS:
|
|
{
|
|
float l_X = l_PointEntry.x ;
|
|
if(l_X == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
// {
|
|
// float l_TempDistEntry, l_TempDistExit;
|
|
// if(AABBIntersectRay(m_NodeTree[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT].m_KDTREE_NODE_AABB, s, d, l_TempDistEntry, l_TempDistExit))
|
|
// {
|
|
// float l_TempDistEntry2, l_TempDistExit2;
|
|
// if(AABBIntersectRay(m_NodeTree[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT].m_KDTREE_NODE_AABB, s, d, l_TempDistEntry2, l_TempDistExit2))
|
|
// {
|
|
// if(l_DistEntry < l_TempDistEntry2 )
|
|
// l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
// else
|
|
// l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
// }
|
|
// else
|
|
// l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
// }
|
|
// else
|
|
// l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
// }
|
|
l_X += d.x*0.001f;
|
|
//else
|
|
if(l_X > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
}
|
|
break;
|
|
case KDTREE_Y_AXIS:
|
|
{
|
|
float l_Y = l_PointEntry.y ;
|
|
if(l_Y == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_Y += d.y*0.001f;
|
|
|
|
if(l_Y > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
}
|
|
break;
|
|
case KDTREE_Z_AXIS:
|
|
{
|
|
float l_Z = l_PointEntry.z;
|
|
if(l_Z == m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_Z += d.z*0.001f;
|
|
|
|
if(l_Z > m_NodeTree[l_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT)
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
float l_CurrentDistEntry, l_CurrentDistExit;
|
|
if(AABBIntersectRay(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, s, d, l_CurrentDistEntry, l_CurrentDistExit))
|
|
{
|
|
// it's a leaf continue by check the intersect triangle
|
|
int* l_TempPntVtx = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_VTX;
|
|
int l_CountPoly = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_COUNT_POLY;
|
|
for(int i=0; i< l_CountPoly; ++i)
|
|
{
|
|
float l_Dist = 0, u, v;
|
|
bool l_Backface = false;
|
|
if(IntersectTriangle(s, d, m_Vtx+(*(l_TempPntVtx))*4, m_Vtx+(*(l_TempPntVtx+1))*4, m_Vtx+(*(l_TempPntVtx+2))*4, &m_OptimizeEdgePoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]*2], &m_OptimizeEdgePoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]*2+1], l_Dist, u, v ,l_Backface) == 1)
|
|
{// intersection with this triangle , change the end entry
|
|
// the dist have to be between entry and exit
|
|
if(l_Dist >= 0 && l_Dist < l_NearestDist && l_CurrentDistEntry <= l_Dist*1.0001f && l_Dist* 0.9999f <= l_CurrentDistExit)
|
|
{
|
|
l_NearestDist = l_Dist;
|
|
|
|
int ip = m_RealIdPoly[m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_POLY[i]];
|
|
if(geometry->pol_normal.GetCount() > ip && geometry->pol.GetCount() > ip)
|
|
{
|
|
float dnv = trace.d.Dot(geometry->pol_normal[ip]);
|
|
Material *m = material_table[geometry->pol[ip].material];
|
|
|
|
if(!l_Backface || (dnv >= 0.f && m && m->renderword & Material::Render_DoubleSided))
|
|
{
|
|
l_DistExit = l_Dist;
|
|
|
|
trace.g = geometry;
|
|
trace.m = m;
|
|
trace.bi = pol_index[ip];
|
|
trace.ip = ip;
|
|
|
|
trace.backface = false;
|
|
|
|
trace.s = s;
|
|
trace.d = d;
|
|
|
|
trace.has_i = true;
|
|
trace.i_t = l_Dist;
|
|
|
|
trace.it = 0;
|
|
|
|
if(geometry->pol[ip].vtx_count == 4 && ((uint)*(l_TempPntVtx+1)) == geometry->pol[ip].binding[3])
|
|
{
|
|
trace.u = 1-u;
|
|
trace.v = 1-v;
|
|
}
|
|
else
|
|
{
|
|
trace.u = u;
|
|
trace.v = v;
|
|
}
|
|
trace.w = 1.0f - trace.u - trace.v;
|
|
|
|
trace.backface = l_Backface;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
l_TempPntVtx +=3;
|
|
}
|
|
}
|
|
|
|
// found a hit so your job is done here ! for now...
|
|
// wrong idea, if a big triangle is in a node before another little triangle at the good place but in a cell later.
|
|
if(trace.has_i)
|
|
return;
|
|
|
|
l_DistEntry = l_CurrentDistExit*1.0000001f;
|
|
|
|
// l_CurrentNode = 0;
|
|
|
|
// get the rope
|
|
l_PointEntry = s + d*l_CurrentDistExit;
|
|
int l_SideChoosen = GetKDtreeSideAABB(m_NodeTree[l_CurrentNode].m_KDTREE_NODE_AABB, l_PointEntry, l_LastEntrySide);
|
|
|
|
if(l_SideChoosen == -1) // if no node, no intersection
|
|
return;
|
|
else
|
|
l_CurrentNode = m_NodeTree[l_CurrentNode].m_KDTREE_NODE_ID_ROPE[l_SideChoosen];
|
|
|
|
// if no rope
|
|
if(l_CurrentNode < 0)
|
|
return;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
void GeometryKDTree::CreateRope(int &_CurrentNode, int *_RopeArray)
|
|
//------------------------------------------------------------------
|
|
{
|
|
if(m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF )
|
|
{
|
|
// finish the depth
|
|
|
|
int * l_TempRope = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_ROPE;
|
|
|
|
memcpy(l_TempRope, _RopeArray, sizeof(int)*6);
|
|
}
|
|
else
|
|
{
|
|
// copy the aabb to the child and change copy the right id into the left aabb and inverse
|
|
float* l_AABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
|
|
|
|
// do an optimization
|
|
for (int i=0; i<6; ++i)
|
|
{
|
|
if(_RopeArray[i] != -1)
|
|
{
|
|
while(!m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_IS_LEAF)
|
|
{
|
|
char l_TempTypeSplitAxisRope = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_TYPE_SPLIT;
|
|
|
|
// if the type axis is the same as the current node
|
|
if((int)(i*0.5f) == l_TempTypeSplitAxisRope)
|
|
{
|
|
// give the id node depend of the axis, if the rope is from the right, stay on the right
|
|
if(i%2)
|
|
_RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
else
|
|
_RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
// check the nearest rope to this plane, and stop if there is 2 nearest plane
|
|
float l_ValueSplitRope = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_VALUE_SPLIT;
|
|
if(l_AABB[l_TempTypeSplitAxisRope*2] > l_ValueSplitRope)
|
|
_RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
else
|
|
if(l_AABB[l_TempTypeSplitAxisRope*2+1] < l_ValueSplitRope)
|
|
_RopeArray[i] = m_NodeTree[_RopeArray[i]].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
else
|
|
break; //the split axis is just in the middle of the aabb so don't clip more
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
char l_TempTypeSplitAxis = m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT;
|
|
|
|
int l_IdChildLeft = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT;
|
|
int l_IdChildRight = m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT;
|
|
|
|
int * l_TempLeftChildRope = m_NodeTree[l_IdChildLeft].m_KDTREE_NODE_ID_ROPE;
|
|
int * l_TempRightChildRope = m_NodeTree[l_IdChildRight].m_KDTREE_NODE_ID_ROPE;
|
|
|
|
memcpy(l_TempLeftChildRope, _RopeArray, sizeof(int)*6);
|
|
memcpy(l_TempRightChildRope, _RopeArray, sizeof(int)*6);
|
|
|
|
l_TempLeftChildRope[l_TempTypeSplitAxis*2+1] = l_IdChildRight;
|
|
l_TempRightChildRope[l_TempTypeSplitAxis*2] = l_IdChildLeft;
|
|
|
|
CreateRope(l_IdChildLeft, l_TempLeftChildRope);
|
|
CreateRope(l_IdChildRight, l_TempRightChildRope);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
void GeometryKDTree::IncreaseSizeNodeKdtreeBuffer(int _IncreaseSize)
|
|
//-------------------------------------------------------------------
|
|
{
|
|
KDTreeNode* l_tempCopy = new KDTreeNode[m_SizeTree + _IncreaseSize];
|
|
memcpy(l_tempCopy, m_NodeTree, sizeof(KDTreeNode)*m_SizeTree);
|
|
|
|
for(int i=0; i<m_SizeTree; ++i)
|
|
{
|
|
if(m_NodeTree[i].m_KDTREE_NODE_ID_POLY)
|
|
{
|
|
l_tempCopy[i].m_KDTREE_NODE_ID_POLY = new int[m_NodeTree[i].m_KDTREE_NODE_COUNT_POLY];
|
|
memcpy( l_tempCopy[i].m_KDTREE_NODE_ID_POLY, m_NodeTree[i].m_KDTREE_NODE_ID_POLY, sizeof(int)*m_NodeTree[i].m_KDTREE_NODE_COUNT_POLY);
|
|
|
|
l_tempCopy[i].m_KDTREE_NODE_ID_VTX = new int[m_NodeTree[i].m_KDTREE_NODE_COUNT_POLY*3];
|
|
memcpy( l_tempCopy[i].m_KDTREE_NODE_ID_VTX, m_NodeTree[i].m_KDTREE_NODE_ID_VTX, sizeof(int)*m_NodeTree[i].m_KDTREE_NODE_COUNT_POLY*3);
|
|
}
|
|
}
|
|
|
|
m_SizeTree += _IncreaseSize;
|
|
|
|
delete []m_NodeTree;
|
|
m_NodeTree = l_tempCopy;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
void GeometryKDTree::CreateNodeKdtree(int &_CurrentNode, int *_IdPoly, int *_IdVtx, int _CountPoly, float *_Vtx, int _CountVtx, int _CurrentDepth)
|
|
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
{
|
|
// check if there is a minimum of place for 2 child
|
|
if(m_SizeTree < _CurrentNode + 3)
|
|
{
|
|
IncreaseSizeNodeKdtreeBuffer(1000);
|
|
}
|
|
|
|
// set the id of the node
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID = _CurrentNode;
|
|
|
|
//get the aabb
|
|
float * l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
|
|
|
|
// check if it's the moment to create the leaf
|
|
if(_CountPoly < KDTREE_MAX_POLY_PER_NODE || _CurrentDepth >= KDTREE_MAX_DEPTH
|
|
|| fabs(l_TempAABB[KDTREE_SIDE_LEFT] - l_TempAABB[KDTREE_SIDE_RIGHT]) < 0.1f
|
|
|| fabs(l_TempAABB[KDTREE_SIDE_BOTTOM] - l_TempAABB[KDTREE_SIDE_TOP]) < 0.1f
|
|
|| fabs(l_TempAABB[KDTREE_SIDE_BACK] - l_TempAABB[KDTREE_SIDE_FRONT]) < 0.1f)
|
|
{
|
|
// check if there is a minimum of place for all the poly
|
|
if(m_SizeTree < (_CurrentNode + _CountPoly*3 + _CountPoly))
|
|
{
|
|
IncreaseSizeNodeKdtreeBuffer(10000 + _CountPoly*3 + _CountPoly);
|
|
}
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = true;
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = -1;
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = -1;
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_COUNT_POLY = _CountPoly;
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_POLY = new int[_CountPoly];
|
|
memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_POLY, _IdPoly, sizeof(int)*_CountPoly);
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_VTX = new int[_CountPoly*3];
|
|
memcpy( m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_VTX, _IdVtx, sizeof(int)*_CountPoly*3);
|
|
|
|
// set the new id to set back
|
|
++_CurrentNode;
|
|
}
|
|
else
|
|
{
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_IS_LEAF = false;
|
|
|
|
float l_TempValueSplit = 0.0f;
|
|
char l_TempTypeSplitAxis = m_NodeTree[_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT;
|
|
|
|
int l_CountAveragePoly = 0;
|
|
int *l_TempIdPnt = _IdVtx;
|
|
|
|
float l_ExtremeRight = -3.402823466e+38F;
|
|
float l_ExtremeLeft = 3.402823466e+38F;
|
|
for(int i=0; i<_CountPoly; ++i)
|
|
{
|
|
if(l_ExtremeRight < _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis])
|
|
l_ExtremeRight = _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis];
|
|
if(l_ExtremeRight < _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis])
|
|
l_ExtremeRight = _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis];
|
|
if(l_ExtremeRight < _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis])
|
|
l_ExtremeRight = _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis];
|
|
|
|
if(l_ExtremeLeft > _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis])
|
|
l_ExtremeLeft = _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis];
|
|
if(l_ExtremeLeft > _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis])
|
|
l_ExtremeLeft = _Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis];
|
|
if(l_ExtremeLeft > _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis])
|
|
l_ExtremeLeft = _Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis];
|
|
|
|
l_TempValueSplit += ( _Vtx[(*l_TempIdPnt)*4+l_TempTypeSplitAxis] +
|
|
_Vtx[(*(l_TempIdPnt+1))*4+l_TempTypeSplitAxis] +
|
|
_Vtx[(*(l_TempIdPnt+2))*4+l_TempTypeSplitAxis])
|
|
;
|
|
++l_CountAveragePoly;
|
|
|
|
l_TempIdPnt += 3;
|
|
}
|
|
|
|
if(l_CountAveragePoly)
|
|
l_TempValueSplit /= (l_CountAveragePoly*3.0f);
|
|
|
|
// check if the extreme is better split
|
|
float l_MiddleAABB = (l_TempAABB[l_TempTypeSplitAxis*2] + l_TempAABB[l_TempTypeSplitAxis*2+1])*0.5f;
|
|
|
|
if(l_ExtremeRight < l_MiddleAABB && l_ExtremeRight > l_TempAABB[l_TempTypeSplitAxis*2])
|
|
l_TempValueSplit = l_ExtremeRight;
|
|
else
|
|
if(l_ExtremeLeft > l_MiddleAABB && l_ExtremeLeft < l_TempAABB[l_TempTypeSplitAxis*2+1])
|
|
l_TempValueSplit = l_ExtremeLeft;
|
|
|
|
if(l_TempValueSplit <= l_TempAABB[l_TempTypeSplitAxis*2] ||
|
|
l_TempValueSplit >= l_TempAABB[l_TempTypeSplitAxis*2+1])
|
|
l_TempValueSplit = l_MiddleAABB;
|
|
|
|
// if(l_TempValueSplit < _CurrentNode->m_AABB[_CurrentNode->m_TypeSplitAxis*2] || l_TempValueSplit > _CurrentNode->m_AABB[_CurrentNode->m_TypeSplitAxis*2+1] )
|
|
// int yo = 0;
|
|
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_VALUE_SPLIT = l_TempValueSplit;
|
|
|
|
// create the 2 childs
|
|
//set new axis
|
|
int l_NewAxis = l_TempTypeSplitAxis+1;
|
|
if(l_NewAxis >= 3)
|
|
l_NewAxis = 0;
|
|
|
|
// create the 2 child list
|
|
int l_IdInBigArray;
|
|
|
|
// left node
|
|
{
|
|
int l_NewIdChildLeft = _CurrentNode + 1;
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_LEFT = l_NewIdChildLeft;
|
|
|
|
m_NodeTree[l_NewIdChildLeft].m_KDTREE_NODE_TYPE_SPLIT = (char)(l_NewAxis);
|
|
|
|
// set the new aabb
|
|
float * l_TempAABBLeftChild = m_NodeTree[l_NewIdChildLeft].m_KDTREE_NODE_AABB;
|
|
|
|
l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
|
|
memcpy(l_TempAABBLeftChild, l_TempAABB, sizeof(float)*6);
|
|
l_TempAABBLeftChild[l_TempTypeSplitAxis*2+1] = l_TempValueSplit;
|
|
|
|
int *l_IdLeftList = new int [_CountPoly*3];
|
|
int *l_IdLeftPolyList = new int [_CountPoly];
|
|
int l_IdLeftCount = 0;
|
|
|
|
float l_LeftBoxCenter[3];
|
|
l_LeftBoxCenter[0] = (l_TempAABBLeftChild[KDTREE_SIDE_RIGHT] + l_TempAABBLeftChild[KDTREE_SIDE_LEFT])*0.5f;
|
|
l_LeftBoxCenter[1] = (l_TempAABBLeftChild[KDTREE_SIDE_TOP] + l_TempAABBLeftChild[KDTREE_SIDE_BOTTOM])*0.5f;
|
|
l_LeftBoxCenter[2] = (l_TempAABBLeftChild[KDTREE_SIDE_FRONT] + l_TempAABBLeftChild[KDTREE_SIDE_BACK])*0.5f;
|
|
|
|
float l_LeftHalfSize[3];
|
|
l_LeftHalfSize[0] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_RIGHT] - l_LeftBoxCenter[0])*1.001f;
|
|
l_LeftHalfSize[1] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_TOP] - l_LeftBoxCenter[1])*1.001f;
|
|
l_LeftHalfSize[2] = fabs(l_TempAABBLeftChild[KDTREE_SIDE_FRONT] - l_LeftBoxCenter[2])*1.001f;
|
|
|
|
l_TempIdPnt = _IdVtx;
|
|
for(int i=0; i<_CountPoly; ++i)
|
|
{
|
|
if(triBoxOverlap(l_LeftBoxCenter, l_LeftHalfSize, _Vtx+(*l_TempIdPnt)*4,
|
|
_Vtx+(*(l_TempIdPnt+1))*4,
|
|
_Vtx+(*(l_TempIdPnt+2))*4))
|
|
{
|
|
l_IdLeftList[l_IdLeftCount*3] = (*l_TempIdPnt);
|
|
l_IdLeftList[l_IdLeftCount*3+1] = *(l_TempIdPnt+1);
|
|
l_IdLeftList[l_IdLeftCount*3+2] = *(l_TempIdPnt+2);
|
|
|
|
l_IdLeftPolyList[l_IdLeftCount] = _IdPoly[i];
|
|
|
|
++l_IdLeftCount;
|
|
}
|
|
|
|
l_TempIdPnt += 3;
|
|
}
|
|
|
|
// copy the strict minimum, not good, because it's fragment memory, but it's just for the creation
|
|
{
|
|
int* l_tempCopy = new int[l_IdLeftCount*3];
|
|
memcpy(l_tempCopy, l_IdLeftList, sizeof(int)*l_IdLeftCount*3);
|
|
|
|
delete []l_IdLeftList;
|
|
l_IdLeftList = l_tempCopy;
|
|
}
|
|
{
|
|
int* l_tempCopy = new int[l_IdLeftCount];
|
|
memcpy(l_tempCopy, l_IdLeftPolyList, sizeof(int)*l_IdLeftCount);
|
|
|
|
delete []l_IdLeftPolyList;
|
|
l_IdLeftPolyList = l_tempCopy;
|
|
}
|
|
|
|
CreateNodeKdtree(l_NewIdChildLeft, l_IdLeftPolyList, l_IdLeftList, l_IdLeftCount, _Vtx, _CountVtx, _CurrentDepth+1);
|
|
|
|
l_IdInBigArray = l_NewIdChildLeft;
|
|
|
|
delete []l_IdLeftList;
|
|
delete []l_IdLeftPolyList;
|
|
}
|
|
|
|
// right node
|
|
{
|
|
if(m_SizeTree < l_IdInBigArray + 3)
|
|
IncreaseSizeNodeKdtreeBuffer(10000);
|
|
|
|
int l_NewIdChildRight = l_IdInBigArray;
|
|
m_NodeTree[_CurrentNode].m_KDTREE_NODE_ID_CHILD_RIGHT = l_NewIdChildRight;
|
|
|
|
m_NodeTree[l_NewIdChildRight].m_KDTREE_NODE_TYPE_SPLIT = (char)(l_NewAxis);
|
|
|
|
// set the new aabb
|
|
float * l_TempAABBRightChild = m_NodeTree[l_NewIdChildRight].m_KDTREE_NODE_AABB;
|
|
|
|
l_TempAABB = m_NodeTree[_CurrentNode].m_KDTREE_NODE_AABB;
|
|
memcpy(l_TempAABBRightChild, l_TempAABB, sizeof(float)*6);
|
|
l_TempAABBRightChild[l_TempTypeSplitAxis*2] = l_TempValueSplit;
|
|
|
|
int *l_IdRightList = new int [_CountPoly*3];
|
|
int *l_IdRightPolyList = new int [_CountPoly];
|
|
int l_IdRightCount = 0;
|
|
|
|
float l_RightBoxCenter[3];
|
|
l_RightBoxCenter[0] = (l_TempAABBRightChild[KDTREE_SIDE_RIGHT] + l_TempAABBRightChild[KDTREE_SIDE_LEFT])*0.5f;
|
|
l_RightBoxCenter[1] = (l_TempAABBRightChild[KDTREE_SIDE_TOP] + l_TempAABBRightChild[KDTREE_SIDE_BOTTOM])*0.5f;
|
|
l_RightBoxCenter[2] = (l_TempAABBRightChild[KDTREE_SIDE_FRONT] + l_TempAABBRightChild[KDTREE_SIDE_BACK])*0.5f;
|
|
|
|
float l_RightHalfSize[3];
|
|
l_RightHalfSize[0] = fabs(l_TempAABBRightChild[KDTREE_SIDE_RIGHT] - l_RightBoxCenter[0])*1.001f;
|
|
l_RightHalfSize[1] = fabs(l_TempAABBRightChild[KDTREE_SIDE_TOP] - l_RightBoxCenter[1])*1.001f;
|
|
l_RightHalfSize[2] = fabs(l_TempAABBRightChild[KDTREE_SIDE_FRONT] - l_RightBoxCenter[2])*1.001f;
|
|
|
|
l_TempIdPnt = _IdVtx;
|
|
for(int i=0; i<_CountPoly; ++i)
|
|
{
|
|
if(triBoxOverlap(l_RightBoxCenter, l_RightHalfSize,_Vtx +(*l_TempIdPnt)*4,
|
|
_Vtx+(*(l_TempIdPnt+1))*4,
|
|
_Vtx+(*(l_TempIdPnt+2))*4))
|
|
{
|
|
l_IdRightList[l_IdRightCount*3] = (*l_TempIdPnt);
|
|
l_IdRightList[l_IdRightCount*3+1] = *(l_TempIdPnt+1);
|
|
l_IdRightList[l_IdRightCount*3+2] = *(l_TempIdPnt+2);
|
|
|
|
l_IdRightPolyList[l_IdRightCount] = _IdPoly[i];
|
|
|
|
++l_IdRightCount;
|
|
}
|
|
|
|
l_TempIdPnt += 3;
|
|
}
|
|
|
|
// copy the strict minimum, not good, because it's fragment memory, but it's just for the creation
|
|
{
|
|
int* l_tempCopy = new int[l_IdRightCount*3];
|
|
memcpy(l_tempCopy, l_IdRightList, sizeof(int)*l_IdRightCount*3);
|
|
|
|
delete []l_IdRightList;
|
|
l_IdRightList = l_tempCopy;
|
|
}
|
|
{
|
|
int* l_tempCopy = new int[l_IdRightCount];
|
|
memcpy(l_tempCopy, l_IdRightPolyList, sizeof(int)*l_IdRightCount);
|
|
|
|
delete []l_IdRightPolyList;
|
|
l_IdRightPolyList = l_tempCopy;
|
|
}
|
|
|
|
CreateNodeKdtree(l_NewIdChildRight, l_IdRightPolyList, l_IdRightList, l_IdRightCount, _Vtx, _CountVtx, _CurrentDepth+1);
|
|
|
|
//set the new id for the next node in the stack
|
|
_CurrentNode = l_NewIdChildRight;
|
|
|
|
delete []l_IdRightList;
|
|
delete []l_IdRightPolyList;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
bool GeometryKDTree::BuildFromGeometry(ResourceFactory &gf, Geometry *g)
|
|
//--------------------------------------------------------------------------------
|
|
{
|
|
Free();
|
|
|
|
__LOG__ << "Building KD-Tree...\n";
|
|
Benchmark build_bench(true);
|
|
|
|
geometry = g;
|
|
geometry->ComputePolygonIndex(pol_index);
|
|
|
|
int l_CountVtx = 0;
|
|
int *l_IdVtx = NULL;
|
|
m_Vtx = NULL;
|
|
|
|
if (!g->material_table.GetCount() || !g->pol.GetCount())
|
|
return false;
|
|
|
|
material_table.Allocate(g->material_table.GetCount());
|
|
for (uint n = 0; n < material_table.GetCount(); ++n)
|
|
material_table[n] = gf.LoadMaterial(g->material_table[n].name);
|
|
|
|
// create the optimize edge for the intersect ray
|
|
m_OptimizeEdgePoly = new Vector4[g->pol.GetCount() * 2*2];
|
|
|
|
// to keep the real id of the poly, in case of no triangle poly
|
|
m_RealIdPoly = new int[g->pol.GetCount()*2];
|
|
|
|
// Transfer topology.
|
|
m_count_bih = 0;
|
|
l_IdVtx = new int[g->pol.GetCount() * 3*2];
|
|
int *l_TPointer = l_IdVtx;
|
|
for (uint n = 0; n < g->pol.GetCount(); ++n)
|
|
{
|
|
//nVector l_edge1(Vtx2[0] - Vtx1[0], Vtx2[1] - Vtx1[1], Vtx2[2] - Vtx1[2]);
|
|
//nVector l_edge2(Vtx3[0] - Vtx1[0], Vtx3[1] - Vtx1[1], Vtx3[2] - Vtx1[2]);
|
|
|
|
Polygon &pol = g->pol[n];
|
|
if(pol.vtx_count == 3)
|
|
{
|
|
m_RealIdPoly[m_count_bih] = n;
|
|
|
|
l_TPointer[m_count_bih*3] = pol.binding[0];
|
|
l_TPointer[m_count_bih*3+1] = pol.binding[1];
|
|
l_TPointer[m_count_bih*3+2] = pol.binding[2];
|
|
|
|
m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[1]] - g->vtx[pol.binding[0]];
|
|
m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[2]] - g->vtx[pol.binding[0]];
|
|
|
|
++m_count_bih;
|
|
}
|
|
else
|
|
if(pol.vtx_count == 4)
|
|
{
|
|
m_RealIdPoly[m_count_bih] = n;
|
|
l_TPointer[m_count_bih*3] = pol.binding[0];
|
|
l_TPointer[m_count_bih*3+1] = pol.binding[1];
|
|
l_TPointer[m_count_bih*3+2] = pol.binding[2];
|
|
|
|
m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[1]] - g->vtx[pol.binding[0]];
|
|
m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[2]] - g->vtx[pol.binding[0]];
|
|
|
|
++m_count_bih;
|
|
|
|
m_RealIdPoly[m_count_bih] = n;
|
|
l_TPointer[m_count_bih*3] = pol.binding[2];
|
|
l_TPointer[m_count_bih*3+1] = pol.binding[3];
|
|
l_TPointer[m_count_bih*3+2] = pol.binding[0];
|
|
|
|
m_OptimizeEdgePoly[m_count_bih*2] = g->vtx[pol.binding[3]] - g->vtx[pol.binding[2]];
|
|
m_OptimizeEdgePoly[m_count_bih*2+1] = g->vtx[pol.binding[0]] - g->vtx[pol.binding[2]];
|
|
|
|
++m_count_bih;
|
|
}
|
|
}
|
|
|
|
// keep the good amount of memory
|
|
{
|
|
int* l_TempIdVtx = new int[m_count_bih * 3];
|
|
memcpy(l_TempIdVtx, l_IdVtx, sizeof(int)*m_count_bih * 3);
|
|
delete []l_IdVtx;
|
|
l_IdVtx = l_TempIdVtx;
|
|
}
|
|
|
|
{
|
|
Vector4* l_TempOptimizeEdgePoly = new Vector4[m_count_bih*2];
|
|
memcpy(l_TempOptimizeEdgePoly, m_OptimizeEdgePoly, sizeof(Vector4)*m_count_bih * 2);
|
|
delete []m_OptimizeEdgePoly;
|
|
m_OptimizeEdgePoly = l_TempOptimizeEdgePoly;
|
|
}
|
|
{
|
|
int* l_TempRealIdPoly = new int[m_count_bih];
|
|
memcpy(l_TempRealIdPoly, m_RealIdPoly, sizeof(int)*m_count_bih);
|
|
delete []m_RealIdPoly;
|
|
m_RealIdPoly = l_TempRealIdPoly;
|
|
}
|
|
|
|
// Transfer vertice.
|
|
m_Vtx = new float[g->vtx.GetCount()*4];
|
|
for (uint n = 0; n < g->vtx.GetCount(); ++n)
|
|
{
|
|
Vector4 l_Temp2Vtx = g->vtx[n];
|
|
m_Vtx[n*4] = l_Temp2Vtx.x;
|
|
m_Vtx[n*4+1] = l_Temp2Vtx.y;
|
|
m_Vtx[n*4+2] = l_Temp2Vtx.z;
|
|
m_Vtx[n*4+3] = l_Temp2Vtx.w;
|
|
}
|
|
|
|
l_CountVtx = g->vtx.GetCount();
|
|
|
|
//very not powerful kdtree construction
|
|
|
|
m_SizeTree = m_count_bih*4;
|
|
m_NodeTree = new KDTreeNode[m_SizeTree];
|
|
|
|
int m_CurrentNode = 0;
|
|
|
|
m_NodeTree[m_CurrentNode].m_KDTREE_NODE_TYPE_SPLIT = KDTREE_X_AXIS;
|
|
|
|
float * l_TempAABB = m_NodeTree[m_CurrentNode].m_KDTREE_NODE_AABB;
|
|
|
|
l_TempAABB[KDTREE_SIDE_LEFT] = 3.402823466e+38F;
|
|
l_TempAABB[KDTREE_SIDE_BOTTOM] = 3.402823466e+38F;
|
|
l_TempAABB[KDTREE_SIDE_BACK] = 3.402823466e+38F;
|
|
l_TempAABB[KDTREE_SIDE_RIGHT] = -3.402823466e+38F;
|
|
l_TempAABB[KDTREE_SIDE_TOP] = -3.402823466e+38F;
|
|
l_TempAABB[KDTREE_SIDE_FRONT] = -3.402823466e+38F;
|
|
|
|
float* l_TempVtx = m_Vtx;
|
|
for(int i=0; i<l_CountVtx; ++i)
|
|
{
|
|
if((*l_TempVtx) < l_TempAABB[KDTREE_SIDE_LEFT])
|
|
l_TempAABB[KDTREE_SIDE_LEFT] = (*l_TempVtx);
|
|
if((*l_TempVtx) > l_TempAABB[KDTREE_SIDE_RIGHT])
|
|
l_TempAABB[KDTREE_SIDE_RIGHT] = (*l_TempVtx);
|
|
|
|
++l_TempVtx;
|
|
if((*l_TempVtx) < l_TempAABB[KDTREE_SIDE_BOTTOM])
|
|
l_TempAABB[KDTREE_SIDE_BOTTOM] = (*l_TempVtx);
|
|
if((*l_TempVtx) > l_TempAABB[KDTREE_SIDE_TOP])
|
|
l_TempAABB[KDTREE_SIDE_TOP] = (*l_TempVtx);
|
|
|
|
++l_TempVtx;
|
|
if((*l_TempVtx) < l_TempAABB[KDTREE_SIDE_BACK])
|
|
l_TempAABB[KDTREE_SIDE_BACK] = (*l_TempVtx);
|
|
if((*l_TempVtx) >l_TempAABB[KDTREE_SIDE_FRONT])
|
|
l_TempAABB[KDTREE_SIDE_FRONT] = (*l_TempVtx);
|
|
|
|
++l_TempVtx;
|
|
++l_TempVtx;
|
|
}
|
|
|
|
|
|
// to build the kdtree: id of the poly
|
|
int* l_IdPoly = new int[m_count_bih];
|
|
for(int i=0; i<m_count_bih; ++i)
|
|
l_IdPoly[i] = i;
|
|
|
|
CreateNodeKdtree(m_CurrentNode, l_IdPoly, l_IdVtx, m_count_bih, m_Vtx, l_CountVtx, 0);
|
|
|
|
int l_RopeArray[6];
|
|
memset(l_RopeArray, -1, sizeof(int)*6);
|
|
|
|
// Create the rope to have quick access
|
|
m_CurrentNode = 0;
|
|
CreateRope(m_CurrentNode, l_RopeArray);
|
|
|
|
_safe_delete_array(l_IdVtx);
|
|
_safe_delete_array(l_IdPoly);
|
|
|
|
build_bench.Stop();
|
|
__LOG__ << "Done in " << build_bench.GetMs() << "ms.\n";
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------
|
|
void GeometryKDTree::Free()
|
|
//-----------------------------------------
|
|
{
|
|
geometry = NULL;
|
|
_safe_delete_array(m_NodeTree);
|
|
_safe_delete_array(m_Vtx);
|
|
_safe_delete_array(m_OptimizeEdgePoly);
|
|
_safe_delete_array(m_RealIdPoly);
|
|
m_count_bih = 0;
|
|
}
|
|
|
|
GeometryKDTree::GeometryKDTree()
|
|
{
|
|
geometry = NULL;
|
|
m_NodeTree = NULL;
|
|
m_Vtx = NULL;
|
|
m_OptimizeEdgePoly = NULL;
|
|
m_count_bih = 0;
|
|
m_RealIdPoly = NULL;
|
|
}
|