#include "SceneGraph.h" #include "KdTree.h" #include "SamplingPreprocessor.h" #include "X3dExporter.h" #include "Environment.h" #include "MutualVisibility.h" #include "Polygon3.h" #include "ViewCell.h" #include "ViewCellsManager.h" #include "RenderSimulator.h" namespace GtpVisibilityPreprocessor { SamplingPreprocessor::SamplingPreprocessor(): mPass(0) { // this should increase coherence of the samples Environment::GetSingleton()->GetIntValue("Sampling.samplesPerPass", mSamplesPerPass); Environment::GetSingleton()->GetIntValue("Sampling.totalSamples", mTotalSamples); mStats.open("stats.log"); } SamplingPreprocessor::~SamplingPreprocessor() { CLEAR_CONTAINER(mSampleRays); CLEAR_CONTAINER(mVssSampleRays); } void SamplingPreprocessor::SetupRay(Ray &ray, const Vector3 &point, const Vector3 &direction, const int type, const Ray::Intersection &origin) { ray.Clear(); ray.mFlags |= Ray::STORE_KDLEAVES | Ray::STORE_BSP_INTERSECTIONS; // cout< leaves; mKdTree->CollectLeaves(leaves); // go through all the leaves and evaluate their passing contribution for (int i=0 ; i < leaves.size(); i++) { KdLeaf *leaf = leaves[i]; cout<mPassingRays<CastRay(*(*it)); vssRays.push_back(new VssRay(*(*it))); } mViewCellsManager->ComputeSampleContributions(vssRays, true, false); CLEAR_CONTAINER(vssRays); } int SamplingPreprocessor::CastRay(Ray &ray) { // cast ray to KD tree to find intersection with other objects mKdTree->CastRay(ray); VssRay vssRay(ray); mViewCellsManager->ComputeSampleContributions(vssRay, true, false); return vssRay.mPvsContribution; } int SamplingPreprocessor::CastEdgeSamples( Intersectable *object, const Vector3 &point, MeshInstance *mi, const int samples ) { Ray ray; int maxTries = samples*10; int i; int rays = 0; int edgeSamplesContributions = 0; for (i=0; i < maxTries && rays < samples; i++) { // pickup a random face of each mesh Mesh *mesh = mi->GetMesh(); int face = (int)RandomValue(0, (Real)((int)mesh->mFaces.size() - 1)); Polygon3 poly(mesh->mFaces[face], mesh); poly.Scale(1.001f); // now extend a random edge of the face int edge = (int)RandomValue(0, (Real)((int)poly.mVertices.size() - 1)); float t = RandomValue(0.0f, 1.0f); Vector3 target = t*poly.mVertices[edge] + (1.0f-t)*poly.mVertices[(edge + 1)% poly.mVertices.size()]; SetupRay(ray, point, target - point, Ray::LOCAL_RAY, Ray::Intersection(0, object, 0)); if (!mesh->CastRay(ray, mi)) { // the rays which intersect the mesh have been discarded since they are not tangent // to the mesh rays++; edgeSamplesContributions += CastRay(ray); } } return edgeSamplesContributions; } KdNode * SamplingPreprocessor::GetNodeToSample(Intersectable *object) { int pvsSize = object->mKdPvs.GetSize(); KdNode *nodeToSample = NULL; bool samplePvsBoundary = false; if (pvsSize && samplePvsBoundary) { // this samples the nodes from the boundary of the current PVS // mail all nodes from the pvs Intersectable::NewMail(); KdPvsMap::iterator i = object->mKdPvs.mEntries.begin(); for (; i != object->mKdPvs.mEntries.end(); i++) { KdNode *node = (*i).first; node->Mail(); } int maxTries = 2*pvsSize; Debug << "Finding random neighbour" << endl; for (int tries = 0; tries < 10; tries++) { int index = (int)RandomValue(0, (Real)(pvsSize - 1)); KdPvsData data; KdNode *node; object->mKdPvs.GetData(index, node, data); nodeToSample = mKdTree->FindRandomNeighbor(node, true); if (nodeToSample) break; } } else { // just pickup a random node // nodeToSample = mKdTree->GetRandomLeaf(Plane3(normal, point)); nodeToSample = mKdTree->GetRandomLeaf(); } return nodeToSample; } void SamplingPreprocessor::VerifyVisibility(Intersectable *object) { // mail all nodes from the pvs Intersectable::NewMail(); KdPvsMap::iterator i = object->mKdPvs.mEntries.begin(); for (; i != object->mKdPvs.mEntries.end(); i++) { KdNode *node = (*i).first; node->Mail(); } Debug << "Get all neighbours from PVS" << endl; vector invisibleNeighbors; // get all neighbors of all PVS nodes i = object->mKdPvs.mEntries.begin(); for (; i != object->mKdPvs.mEntries.end(); i++) { KdNode *node = (*i).first; mKdTree->FindNeighbors(node, invisibleNeighbors, true); AxisAlignedBox3 box = object->GetBox(); for (int j=0; j < invisibleNeighbors.size(); j++) { int visibility = ComputeBoxVisibility(mSceneGraph, mKdTree, box, mKdTree->GetBox(invisibleNeighbors[j]), 1e-6f); // exit(0); } // now rank all the neighbors according to probability that a new // sample creates some contribution } } bool SamplingPreprocessor::ComputeVisibility() { /// rays per pass RayContainer passRays; mViewCellsManager->SetViewSpaceBox(mKdTree->GetBox()); Vector3 point, normal, direction; //Ray ray; long startTime = GetTime(); int i; int totalSamples = 0; int pvsSize = 0; while (totalSamples < mTotalSamples) { int passContributingSamples = 0; int passSampleContributions = 0; int passSamples = 0; int index = 0; int reverseSamples = 0; for (i = 0; i < mObjects.size(); i++) { KdNode *nodeToSample = NULL; Intersectable *object = mObjects[i]; int pvsSize = 0; if (0 && pvsSize && mPass == 1000 ) { VerifyVisibility(object); } int faceIndex = object->GetRandomSurfacePoint(point, normal); bool viewcellSample = true; //int sampleContributions; bool debug = false; //(object->GetId() >= 2199); if (viewcellSample) { //mKdTree->GetRandomLeaf(Plane3(normal, point)); nodeToSample = GetNodeToSample(object); for (int k=0; k < mSamplesPerPass; k++) { bool reverseSample = false; if (nodeToSample) { AxisAlignedBox3 box = mKdTree->GetBox(nodeToSample); Vector3 pointToSample = box.GetRandomPoint(); // pointToSample.y = 0.9*box.Min().y + 0.1*box.Max().y; if (object->GetRandomVisibleSurfacePoint( point, normal, pointToSample, 3 )) { direction = pointToSample - point; } else { reverseSamples++; reverseSample = true; direction = point - pointToSample; point = pointToSample; //Debug << "point: " << pointToSample << endl; } } else { direction = UniformRandomVector(normal); } Ray *ray = new Ray(); // construct a ray SetupRay(*ray, point, direction, Ray::LOCAL_RAY, Ray::Intersection(0, reverseSample ? NULL : object, faceIndex)); passRays.push_back(ray); //-- CORR matt: put block inside loop /*if (sampleContributions) { passContributingSamples ++; passSampleContributions += sampleContributions; }*/ } } else { // edge samples // get random visible mesh // object->GetRandomVisibleMesh(Plane3(normal, point)); } // CORR matt: must add all samples passSamples += mSamplesPerPass; } //------------------- // cast rays for view cells construction ProcessViewCells(passRays, mObjects, passSampleContributions, passContributingSamples); CLEAR_CONTAINER(passRays); totalSamples += passSamples; // if (pass>10) // HoleSamplingPass(); mPass ++; pvsSize += passSampleContributions; float avgRayContrib = (passContributingSamples > 0) ? passSampleContributions / (float)passContributingSamples : 0; cout << "#Pass " << mPass << " : t = " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl; cout << "#TotalSamples=" << totalSamples/1000 << "k #SampleContributions=" << passSampleContributions << " (" << 100*passContributingSamples/(float)passSamples<<"%)" << " avgPVS=" << (float)pvsSize /(float)mObjects.size() << endl << "avg ray contrib=" << avgRayContrib << endl << "reverse samples [%]" << reverseSamples/(float)passSamples*100.0f << endl; mStats << "#Pass\n" <SetExportRayDensity(true); exporter->ExportKdTree(*mKdTree); delete exporter; } // construct view cells if not already constructed if (!mViewCellsManager->ViewCellsConstructed()) mViewCellsManager->ConstructSubdivision(mObjects, mVssSampleRays); // $$JB temporary removed // mViewCellsManager->PostProcess(objects, mSampleRays); //-- several visualizations and statistics Debug << "view cells after post processing: " << endl; mViewCellsManager->PrintStatistics(Debug); //-- render simulation after merge cout << "\nevaluating bsp view cells render time after merge ... "; mRenderSimulator->RenderScene(); SimulationStatistics ss; mRenderSimulator->GetStatistics(ss); cout << " finished" << endl; cout << ss << endl; Debug << ss << endl; // $$JB temporary removed //mViewCellsManager->Visualize(objects, mSampleRays); return true; } void SamplingPreprocessor::ProcessViewCells(const RayContainer &newRays, const ObjectContainer &objects, int &sampleContributions, int &contributingSamples) { // cast rays to view cells CastRays(newRays); // save rays for view cells construction if (!mViewCellsManager->ViewCellsConstructed()) { if ((int)mVssSampleRays.size() < mViewCellsManager->GetConstructionSamples()) { RayContainer::const_iterator it, it_end = newRays.end(); for (it = newRays.begin(); it != it_end; ++ it) mVssSampleRays.push_back(new VssRay(*(*it))); } else { // construct view cells mViewCellsManager->ConstructSubdivision(objects, mVssSampleRays); // throw away samples //CLEAR_CONTAINER(mVssSampleRays); } } // Need rays (with ordered intersections) for post processing => collect new rays if (((int)mSampleRays.size() < mViewCellsManager->GetPostProcessSamples()) || ((int)mSampleRays.size() < mViewCellsManager->GetVisualizationSamples())) { RayContainer::const_iterator it, it_end = newRays.end(); for (it = newRays.begin(); it != it_end; ++ it) mSampleRays.push_back(new Ray(*(*it))); } } }