/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #include #include #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(x1Max) Max=x1;\ if(x2Max) 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(p0rad || 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(p0rad || 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(p0rad || 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(p0rad || 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(p2rad || 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(p0rad || 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= 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_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