#include "SamplingStrategy.h" #include "Ray.h" #include "Intersectable.h" #include "Preprocessor.h" #include "ViewCellsManager.h" #include "AxisAlignedBox3.h" #include "RssTree.h" #include "Vector2.h" #include "RndGauss.h" #include "Mutation.h" #include "Exporter.h" #ifdef GTP_INTERNAL #include "ArchModeler2MLRT.hxx" #endif namespace GtpVisibilityPreprocessor { #define MUTATION_USE_CDF 0 #define USE_SILHOUETTE_MUTATIONS 0 #define SIL_TERMINATION_MUTATION_PROB 0.9f #define EVALUATE_MUTATION_STATS 1 #define Q_SEARCH_STEPS 3 #define SORT_RAY_ENTRIES 1 // use avg ray contribution as importance // if 0 the importance is evaluated from the succ of mutations #define USE_AVG_CONTRIBUTION 1 MutationBasedDistribution::RayEntry & MutationBasedDistribution::GetEntry(const int index) { #if SORT_RAY_ENTRIES return mRays[index]; #else return mRays[(mBufferStart+index)%mRays.size()]; #endif } void MutationBasedDistribution::Update(VssRayContainer &vssRays) { // for (int i=0; i < mRays.size(); i++) // cout<mPvsContribution) { // reset the counter of unsuccsseful mutation for a generating ray (if it exists) if (vssRays[i]->mDistribution == MUTATION_BASED_DISTRIBUTION && vssRays[i]->mGeneratorId != -1 ) { mRays[vssRays[i]->mGeneratorId].mUnsuccessfulMutations = 0; #if EVALUATE_MUTATION_STATS mutationRays++; Intersectable *newObject = vssRays[i]->mTerminationObject; Intersectable *oldObject =mRays[vssRays[i]->mGeneratorId].mRay->mTerminationObject; if (oldObject == newObject) dummyCMutations++; #endif } contributingRays++; if (mRays.size() < mMaxRays) { VssRay *newRay = new VssRay(*vssRays[i]); // add this ray newRay->Ref(); mRays.push_back(RayEntry(newRay)); } else { // unref the old ray *mRays[mBufferStart].mRay = *vssRays[i]; mRays[mBufferStart].mMutations = 0; mRays[mBufferStart].mUnsuccessfulMutations = 0; mRays[mBufferStart].ResetReverseMutation(); // mRays[mBufferStart] = RayEntry(newRay); mBufferStart++; if (mBufferStart >= mMaxRays) mBufferStart = 0; } } else { if (vssRays[i]->mDistribution == MUTATION_BASED_DISTRIBUTION && vssRays[i]->mGeneratorId != -1 ) { // check whether not to store a new backward mutation candidate VssRay *oldRay = mRays[vssRays[i]->mGeneratorId].mRay; VssRay *newRay = vssRays[i]; #define DIST_THRESHOLD 3.0f Intersectable *oldObject = oldRay->mTerminationObject; if (!mRays[newRay->mGeneratorId].HasReverseMutation()) { if (DotProd(oldRay->GetDir(), newRay->GetDir()) > 0.0f) { float oldDist = Magnitude(oldRay->mTermination - newRay->mOrigin); float newDist = Magnitude(newRay->mTermination - newRay->mOrigin); if (newDist < oldDist - oldObject->GetBox().Radius()*DIST_THRESHOLD) { Vector3 origin, termination; if (ComputeReverseMutation(*oldRay, *newRay, origin, termination)) { mRays[newRay->mGeneratorId].SetReverseMutation(origin, termination); } reverseCandidates++; //mReverseCandidates } } } #if EVALUATE_MUTATION_STATS mutationRays++; Intersectable *newObject = vssRays[i]->mTerminationObject; if (oldObject == newObject) dummyNcMutations++; #endif } } } if (mutationRays) { cout<<"Mutated rays:"< Limits::Small) // nv = Normalize(v); // else // nv = v; // v = nv*size + v*size; return v*(4.0f*radius); #endif #if 0 return (U*(vr2.xx - 0.5f) + V*(vr2.yy - 0.5f))*(4.0f*radius); #endif Vector2 gaussvec2; #if 1 float sigma = radius; GaussianOn2D(vr2, sigma, // input gaussvec2); // output Vector3 shift = gaussvec2.xx * U + gaussvec2.yy * V; // cout<GetBox(); box.Scale(2.0f); const int packetSize = 4; static int hit_triangles[packetSize]; static float dist[packetSize]; static Vector3 dirs[packetSize]; static Vector3 shifts[packetSize]; // now find the silhouette along the line int i; float left = 0.0f; float right = 1.0f; // cast rays to find silhouette ray for (int j=0; j < Q_SEARCH_STEPS; j++) { for (i=0; i < packetSize; i++) { float r = left + (i+1)*(right-left)/(packetSize+1); shifts[i] = r*line; dirs[i] = Normalize(newPivot + shifts[i] - termination ); mlrtaStoreRayASEye4(&termination.x, &dirs[i].x, i); } mlrtaTraverseGroupASEye4(&box.Min().x, &box.Max().x, hit_triangles, dist); for (i=0; i < packetSize; i++) { if (hit_triangles[i] == -1) { // break on first passing ray break; } } float rr = left + (i+1)*(right-left)/(packetSize+1); float rl = left + i*(right-left)/(packetSize+1); left = rl; right = rr; } float t = right; if (right==1.0f) return false; if (i == packetSize) origin = newPivot + right*line; else origin = newPivot + shifts[i]; if (0) { static VssRayContainer rRays; static int counter = 0; char filename[256]; if (counter < 50) { sprintf(filename, "reverse_rays_%03d.x3d", counter++); VssRay tRay(origin, termination, NULL, NULL); rRays.push_back((VssRay *)&oldRay); rRays.push_back((VssRay *)&newRay); rRays.push_back(&tRay); Exporter *exporter = NULL; exporter = Exporter::GetExporter(filename); exporter->SetFilled(); Intersectable *occludee = oldRay.mTerminationObject; exporter->SetForcedMaterial(RgbColor(0,0,1)); exporter->ExportIntersectable(occluder); exporter->SetForcedMaterial(RgbColor(0,1,0)); exporter->ExportIntersectable(occludee); exporter->ResetForcedMaterial(); exporter->SetWireframe(); exporter->ExportRays(rRays, RgbColor(1, 0, 0)); delete exporter; rRays.clear(); } } return true; // now the origin and termination is swapped compred to the generator ray // swap(origin, termination);??? // -> perhaps not neccessary as the reverse mutation wil only be used once! } Vector3 MutationBasedDistribution::ComputeSilhouetteTerminationMutation(const VssRay &ray, const Vector3 &origin, const AxisAlignedBox3 &box, const Vector3 &U, const Vector3 &V, const float radius ) { const int packetSize = 4; static int hit_triangles[packetSize]; static float dist[packetSize]; static Vector3 dirs[packetSize]; static Vector3 shifts[packetSize]; // mutate the float alpha = RandomValue(0.0f, 2.0f*M_PI); //float alpha = vr2.x*2.0f*M_PI; // direction along which we will mutate the ray Vector3 line = sin(alpha)*U + cos(alpha)*V; // cout<GetViewPoint(origin, Vector3(rr[0], rr[1], rr[2])); direction = UniformRandomVector(rr[3], rr[4]); const float pdf = 1.0f; sray = SimpleRay(origin, direction, MUTATION_BASED_DISTRIBUTION, pdf); sray.mGeneratorId = -1; return true; } int index; #if !MUTATION_USE_CDF #if SORT_RAY_ENTRIES index = mLastIndex - 1; if (index < 0 || index >= mRays.size()-1) { index = mRays.size() - 1; } else if ( mRays[index].GetSamplingFactor() >= mRays[mLastIndex].GetSamplingFactor()) { // make another round // cout<<"R2"< mRays[mLastIndex].GetSamplingFactor()) { // search back for index where this is valid index = (mLastIndex - 1 + mRays.size())%mRays.size(); for (int i=0; i < mRays.size(); i++) { // if (mRays[index].mMutations > mRays[mLastIndex].mMutations) // break; if (mRays[index].GetSamplingFactor() > mRays[mLastIndex].GetSamplingFactor() ) break; index = (index - 1 + mRays.size())%mRays.size(); } // go one step back index = (index+1)%mRays.size(); } #endif #else static HaltonSequence iHalton; iHalton.GetNext(1, rr); //rr[0] = RandomValue(0,1); // use binary search to find index with this cdf int l=0, r=mRays.size()-1; while(l= mRays[r].mCdf) // index = r; // else // index = l; #endif // cout<GetDir(); float objectRadius = box.Radius(); // cout<mOrigin; Vector3 termination = ray->mTermination; //box.Center(); //ray->mTermination; //box.Center(); // optimal for Pompeii 0.1f // optimal for Vienna 0.5f float radiusExtension = 0.5f; // + mRays[index].mMutations/50.0f; float mutationRadius = objectRadius*radiusExtension; // tmp for pompeii // mutationRadius = 0.22f; // use probabilitistic approach to decide for the type of mutation float a = RandomValue(0.0f,1.0f); if (a < SIL_TERMINATION_MUTATION_PROB) { termination += ComputeSilhouetteTerminationMutation(*ray, origin, box, U, V, 2.0f*objectRadius); } else { mRays[index].mHalton.GetNext(4, rr); // fuzzy random mutation origin += ComputeOriginMutation(*ray, U, V, Vector2(rr[0], rr[1]), mutationRadius); termination += ComputeTerminationMutation(*ray, U, V, Vector2(rr[2], rr[3]), mutationRadius); } Vector3 direction = termination - origin; if (Magnitude(direction) < Limits::Small) return false; // shift the origin a little bit origin += direction*0.5f; direction.Normalize(); // $$ jb the pdf is yet not correct for all sampling methods! const float pdf = 1.0f; sray = SimpleRay(origin, direction, MUTATION_BASED_DISTRIBUTION, pdf); sray.mGeneratorId = index; return true; } bool MutationBasedDistribution::GenerateMutation(const int index, SimpleRay &sray) { VssRay *ray = mRays[index].mRay; Intersectable *object = ray->mTerminationObject; AxisAlignedBox3 box = object->GetBox(); if (GenerateMutationCandidate(index, sray, object, box)) { mRays[index].mMutations++; mRays[index].mUnsuccessfulMutations++; return true; } return false; } bool MutationBasedDistribution::GenerateSilhouetteMutation(const int index, SimpleRay &sray) { #ifndef GTP_INTERNAL return GenerateMutation(index, sray); #else const int packetSize = 4; const int maxTries = 8; static int hit_triangles[16]; static float dist[16]; SimpleRay mutationCandidates[packetSize]; int candidates = 0; VssRay *ray = mRays[index].mRay; Intersectable *object = mPreprocessor.mViewCellsManager->GetIntersectable( *ray, true); AxisAlignedBox3 box = object->GetBox(); int id = 0; int silhouetteRays = 0; int tries = 0; while (silhouetteRays == 0 && tries < maxTries) { for (candidates = 0; candidates < packetSize && tries < maxTries; tries++) if (GenerateMutationCandidate(index, mutationCandidates[candidates], object, box)) candidates++; if (candidates < packetSize) break; // cout< // GetViewSpaceBox().Diagonal())*1e-3; } }