#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" SamplingPreprocessor::SamplingPreprocessor(): mPass(0) { // this should increase coherence of the samples environment->GetIntValue("Sampling.samplesPerPass", mSamplesPerPass); environment->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.intersections.clear(); ray.kdLeaves.clear(); ray.testedObjects.clear(); ray.bspIntersections.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)); // for KD tree, intersecting view cells are already known, so no // additional ray must be cast to them const bool castRaysToViewCells = (mViewCellsManager->GetType() != ViewCellsManager::KD); mViewCellsManager->ComputeSampleContributions(rays, sampleContributions, contributingSamples, castRaysToViewCells); } int SamplingPreprocessor::CastRay(Ray &ray) { // cast ray to KD tree to find intersection with other objects mKdTree->CastRay(ray); bool castRayToViewCells = mViewCellsManager->GetType() != ViewCellsManager::KD; return mViewCellsManager->ComputeSampleContributions(ray, castRayToViewCells); } // void // SamplingPreprocessor::AvsGenerateRandomRay(Ray &ray) // { // int objId = RandomValue(0, mObjects.size()); // Intersectable *object = objects[objId]; // object->GetRandomSurfacePoint(point, normal); // direction = UniformRandomVector(normal); // SetupRay(ray, point, direction); // } // void // SamplingPreprocessor::AvsHandleRay(Ray &ray) // { // int sampleContributions = 0; // mKdTree->CastRay(ray); // if (ray.leaves.size()) { // sampleContributions += AddNodeSamples(object, ray, pass); // if (ray.intersections.size()) { // sampleContributions += AddNodeSamples(ray.intersections[0].mObject, ray, pass); // } // } // } // void // SamplingPreprocessor::AvsBorderSampling(Ray &ray) // { // } // void // SamplingPreprocessor::AvsPass() // { // Ray ray; // while (1) { // AvsGenerateRay(ray); // HandleRay(ray); // while ( !mRayQueue.empty() ) { // Ray ray = mRayQueue.pop(); // mRayQueue.pop(); // AdaptiveBorderSampling(ray); // } // } // } 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 = RandomValue(0, mesh->mFaces.size()-1); Polygon3 poly(mesh->mFaces[face], mesh); poly.Scale(1.001); // now extend a random edge of the face int edge = RandomValue(0, 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 = RandomValue(0, 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() { // pickup an object ObjectContainer objects; /// rays per pass RayContainer passRays; mSceneGraph->CollectObjects(&objects); 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 < objects.size(); i++) { KdNode *nodeToSample = NULL; Intersectable *object = objects[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, objects, 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)objects.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->Construct(objects, mVssSampleRays); mViewCellsManager->PostProcess(objects, mSampleRays); //-- several visualizations and statistics Debug << "===== Final view cells statistics ==========" << endl; mViewCellsManager->PrintStatistics(Debug); //-- render simulation after merge cout << "\nevaluating bsp view cells render time after merge ... "; const SimulationStatistics ss = mViewCellsManager->SimulateRendering(); cout << " finished" << endl; cout << ss << endl; Debug << ss << endl; 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, sampleContributions, contributingSamples); // 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->Construct(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))); } }