// Written by Vlastimil Havran, December 2007 // This macro allows to use the ray shooting written by // Vlastimil Havran, 2007-2008 #include "HavranRayCaster.h" #include "VssRay.h" #include "KdTree.h" #include "Preprocessor.h" #include "IntersectableWrapper.h" #ifdef USE_HAVRAN_RAYCASTER #include "timer.h" #include "ktball.h" #include "ktb.h" #include "raypack.h" #endif // USE_HAVRAN_RAYCASTER #define DEBUG_RAYCAST 0 namespace GtpVisibilityPreprocessor { #ifdef USE_HAVRAN_RAYCASTER // static rays RayPacket2x2 HavranRayCaster::raypack; #endif // USE_HAVRAN_RAYCASTER HavranRayCaster::HavranRayCaster(const Preprocessor &preprocessor): RayCaster(preprocessor), mKtbtree(0) { #ifdef USE_HAVRAN_RAYCASTER mKtbtree = new CKTB(); #endif } HavranRayCaster::~HavranRayCaster() { #ifdef USE_HAVRAN_RAYCASTER delete mKtbtree; mKtbtree = 0; #endif // USE_HAVRAN_RAYCASTER } void HavranRayCaster::Build(ObjectContainer &objlist) { #ifdef USE_HAVRAN_RAYCASTER CTimer timer; cout << "\nBuilding up kd-tree for Havran ray caster ..."<BuildUp(objlist); timer.Stop(); cout << "\nBuilding up kd-tree is finished, user time = " << timer.UserTime() << " real time = " << timer.RealTime() << endl <FindNearestI(raypack, boxmin, boxmax); for (int i = 0; i < 4; i++) { // if ray intersects an object, we set the pointer to // this object Intersectable* intersectable; if ( (intersectable = raypack.GetObject(i)) ) // $$JB this is very hacky - > should be replaced with fetching the index of the triangle result4[i] = (int)intersectable; } return; #endif } int HavranRayCaster::CastRay(const SimpleRay &simpleRay, VssRayContainer &vssRays, const AxisAlignedBox3 &box, const bool castDoubleRay, const bool pruneInvalidRays) { #ifdef USE_HAVRAN_RAYCASTER int hits = 0; Intersection hitA(simpleRay.mOrigin), hitB(simpleRay.mOrigin); // inside test for bounding box // enlarge box slightly so the view point fits for sure // AxisAlignedBox3 sbox = box; // sbox.Enlarge(Vector3(-Limits::Small)); // $$ JB moved here from Validate routine // if (!box.IsInside(simpleRay.mOrigin)) { // cout<<"out of box "<FindNearestI(simpleRay)) { hitA.mObject = SimpleRay::IntersectionRes[0].intersectable; float tdist = SimpleRay::IntersectionRes[0].tdist; hitA.mPoint = simpleRay.Extrap(tdist); hitA.mNormal = SimpleRay::IntersectionRes[0].intersectable->GetNormal(0); //hitA.mNormal = (dynamic_cast< TriangleIntersectable *> // (hitA.mObject))->GetNormal(0); } if (castDoubleRay) { Vector3 *v = (Vector3*)(&simpleRay.mDirection); *v = -(*v); // ray.mFlags &= ~Ray::CULL_BACKFACES; if (mKtbtree->FindNearestI(simpleRay)) { hitB.mObject = SimpleRay::IntersectionRes[0].intersectable; float tdist = SimpleRay::IntersectionRes[0].tdist; hitB.mPoint = simpleRay.Extrap(tdist); hitB.mNormal = SimpleRay::IntersectionRes[0].intersectable->GetNormal(0); //hitB.mNormal = (dynamic_cast< TriangleIntersectable *> // (hitB.mObject))->GetNormal(0); } // restore the direction to the original *v = -simpleRay.mDirection; } // This code is also in IntelRayCaster.cpp return ProcessRay( simpleRay, hitA, hitB, vssRays, box, castDoubleRay, pruneInvalidRays ); #else // USE_HAVRAN_RAYCASTER return 0; #endif } void HavranRayCaster::CastRays16(SimpleRayContainer &rays, VssRayContainer &vssRays, const AxisAlignedBox3 &sbox, const bool castDoubleRay, const bool pruneInvalidRays) { CastRays16(rays, 0, vssRays, sbox, castDoubleRay, pruneInvalidRays); } void HavranRayCaster::CastRays16(SimpleRayContainer &rays, int offset, VssRayContainer &vssRays, const AxisAlignedBox3 &sbox, const bool castDoubleRays, const bool pruneInvalidRays) { #ifdef USE_HAVRAN_RAYCASTER #if DEBUG_RAYCAST Debug << "C16 " << flush; #endif #if 0 SimpleRayContainer::const_iterator sit, sit_end = rays.end(); // no acceleration for ray bundles implemented right now for (sit = rays.begin(); sit != sit_end; ++ sit) { CastRay(*sit, vssRays, sbox, castDoubleRays, pruneInvalidRays); } #else if (castDoubleRays) { #if 0 // Special routine to cast double sided rays mKtbtree->SetOffset(0); mKtbtree->FindNearestI_16twoDir(rays); #else // Here we decompose shooting into two phases #if 1 // Here we shoot first forward rays and then backward ones mKtbtree->SetOffset(0); mKtbtree->FindNearestI_16oneDir(rays, offset); SimpleRayContainer::iterator sit = rays.begin() + offset; SimpleRayContainer::const_iterator sit_end = rays.begin() + offset + 16; for (; sit != sit_end; ++ sit) { (*sit).mDirection = - (*sit).mDirection; } // We store the results at different place mKtbtree->SetOffset(16); mKtbtree->FindNearestI_16oneDir(rays, offset); sit = rays.begin() + offset; for ( ; sit != sit_end; ++ sit) { (*sit).mDirection = - (*sit).mDirection; } #else // Here we shoot first backward rays and forward ones SimpleRayContainer::iterator sit = rays.begin() + offset; SimpleRayContainer::const_iterator sit_end = rays.begin() + offset + 16; for ( ; sit != sit_end; ++ sit) { (*sit).mDirection = - (*sit).mDirection; } // backward rays to be shot mKtbtree->SetOffset(16); mKtbtree->FindNearestI_16oneDir(rays, offset); sit = rays.begin() + offset; for ( ; sit != sit_end; ++ sit) { (*sit).mDirection = - (*sit).mDirection; } // forward rays to be shot mKtbtree->SetOffset(0); mKtbtree->FindNearestI_16oneDir(rays, offset); #endif #endif } else { // Shoot all 16 rays at the same time using a special algorithm mKtbtree->SetOffset(0); mKtbtree->FindNearestI_16oneDir(rays, offset); } #endif for (int i=0, k=offset; i < 16; i++, k++) { Intersection hitA(rays[k].mOrigin), hitB(rays[k].mOrigin); #if DEBUG_RAYCAST Debug<<"FH\n"<GetNormal(0); //-rays[index+i].mDirection; // $$ temporary float tdist = SimpleRay::IntersectionRes[i].tdist; hitA.mPoint = rays[k].Extrap(tdist); } #if DEBUG_RAYCAST Debug<<"BH\n"<GetNormal(0);; float tdist = SimpleRay::IntersectionRes[i].tdist; hitB.mPoint = rays[k].Extrap(-tdist); } } #if DEBUG_RAYCAST Debug<<"PR\n"<FindNearestI_16oneDir(rays, offset); // ??? What to do with the results ? These are // not used at the moment also in IntelRayCaster.cpp } // for for (; k < rays.size(); k++) { double normal[3]; mKtbtree->FindNearestI(rays[k]); // ??? What to do with the results ? These are // not used at the moment also in IntelRayCaster.cpp } return; } void HavranRayCaster::CastRays( SimpleRayContainer &rays, VssRayContainer &vssRays, const AxisAlignedBox3 &sbox, const bool castDoubleRay, const bool pruneInvalidRays ) { int buckets = rays.size()/16; int offset = 0; #if 0 int time = GetTime(); CastSimpleForwardRays(rays, sbox); cout<<1e-3*2*rays.size()/TimeDiff(time, GetTime())<<" Mrays/sec"< 100000 && i % (100000/16) == 0) cout<<"\r"<FindNearestI(raysPack); for (int i = 0; i < 4; i++) raysPack.SetDir(i, -raysPack.GetDir(i)); // cast backward rays mKtbtree->FindNearestI(raysPack); // reverse the rays back for (int i = 0; i < 4; i++) raysPack.SetDir(i, -raysPack.GetDir(i)); } else { // only rays forwards mKtbtree->FindNearestI(raysPack); #if 0 // Only verification of correctness by casting single rays static int cntBugs = 0; SimpleRay ray; int cntErrors = 0, cntDistErrors = 0; bool newBug = false; for (int i = 0; i < 4; i++) { ray.mOrigin = raysPack.GetLoc(i); ray.mDirection = raysPack.GetDir(i); mKtbtree->FindNearestI(ray); if (raysPack.GetObject(i) != SimpleRay::IntersectionRes[0].intersectable) { float dist = (raysPack.GetT(i) - SimpleRay::IntersectionRes[0].tdist); if (fabs(dist) > 0.001f) { cntErrors++; newBug = true; cntBugs++; cout << " BUG1 d= " << dist; } } else { float dist = 0.f; if (raysPack.GetObject(i) && SimpleRay::IntersectionRes[0].intersectable) if (fabs((dist=(fabs (raysPack.GetT(i) - SimpleRay::IntersectionRes[0].tdist)))) > 1.f) { cntDistErrors++; newBug = true; cntBugs++; cout << " BUG2 distdf= " << dist ; } } } // for if (newBug) cout << " CB= " << cntBugs << "\n"; #endif } return; #endif // USE_HAVRAN_RAYCASTER } #endif } // the namespace