#include "SceneGraph.h" #include "KdTree.h" #include "SamplingPreprocessor.h" #include "X3dExporter.h" #include "Environment.h" #include "MutualVisibility.h" #include "Polygon3.h" SamplingPreprocessor::SamplingPreprocessor() { // this should increase coherence of the samples environment->GetIntValue("Sampling.samplesPerPass", mSamplesPerPass); environment->GetIntValue("Sampling.totalSamples", mTotalSamples); mKdPvsDepth = 100; mStats.open("stats.log"); } void SamplingPreprocessor::SetupRay(Ray &ray, const Vector3 &point, const Vector3 &direction) { ray.intersections.clear(); ray.leaves.clear(); ray.meshes.clear(); // cout<mParent && node->mDepth > mKdPvsDepth) node = node->mParent; return node; } int SamplingPreprocessor::AddNodeSamples(Intersectable *object, const Ray &ray ) { int contributingSamples = 0; int j; for (j=0; j < ray.leaves.size(); j++) { KdNode *node = GetNodeForPvs( ray.leaves[j] ); contributingSamples += object->mKdPvs.AddNodeSample(node); } if (mPass > 10) for (j=1; j < ray.leaves.size() - 1; j++) { ray.leaves[j]->AddPassingRay(ray, contributingSamples ? 1 : 0); } return contributingSamples; } void SamplingPreprocessor::HoleSamplingPass() { vector 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(ray); int sampleContributions = 0; if (ray.leaves.size()) { sampleContributions += AddNodeSamples(object, ray); if (ray.intersections.size()) { sampleContributions += AddNodeSamples(ray.intersections[0].mObject, ray); } } return sampleContributions; } // 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); // } // } // } void SamplingPreprocessor::CastEdgeSamples( Intersectable *object, const Vector3 &point, Mesh &mesh, const int samples ) { Ray ray; int i; for (i=0; i < samples; i++) { // pickup a random face of each mesh 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); CastRay(object, ray); } } bool SamplingPreprocessor::ComputeVisibility() { // pickup an object ObjectContainer objects; mSceneGraph->CollectObjects(&objects); Vector3 point, normal, direction; Ray ray; long startTime = GetTime(); int i; int totalSamples = 0; int pvsOut = Min((int)objects.size(), 10); vector rays[10]; while (totalSamples < mTotalSamples) { int passContributingSamples = 0; int passSampleContributions = 0; int passSamples = 0; int index = 0; for (i =0; i < objects.size(); i++) { KdNode *nodeToSample = NULL; Intersectable *object = objects[i]; int pvsSize = object->mKdPvs.GetSize(); if (0 && pvsSize) { // 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; for (int tries = 0; tries < 10; tries++) { index = RandomValue(0, pvsSize - 1); KdPvsData data; KdNode *node; object->mKdPvs.GetData(index, node, data); nodeToSample = mKdTree->FindRandomNeighbor(node, true); if (nodeToSample) break; } } if (0 && pvsSize && mPass == 1000 ) { // 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(); } 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 } } object->GetRandomSurfacePoint(point, normal); bool viewcellSample = true; int sampleContributions; if (viewcellSample) { nodeToSample = mKdTree->GetRandomLeaf(Plane3(normal, point)); for (int k=0; k < mSamplesPerPass; k++) { if (nodeToSample) { int maxTries = 5; for (int tries = 0; tries < maxTries; tries++) { direction = mKdTree->GetBox(nodeToSample).GetRandomPoint() - point; if (DotProd(direction, normal) > Limits::Small) break; } if (tries == maxTries) direction = UniformRandomVector(normal); } else { direction = UniformRandomVector(normal); } // construct a ray SetupRay(ray, point, direction); sampleContributions = CastRay(object, ray); } } else { // edge samples // get random visible mesh // object->GetRandomVisibleMesh(Plane3(normal, point)); } if ( i < pvsOut ) rays[i].push_back(ray); if (ray.intersections.size()) { // check whether we can add this to the rays for (int j = 0; j < pvsOut; j++) { if (objects[j] == ray.intersections[0].mObject) { rays[j].push_back(ray); } } } passSamples++; if (sampleContributions) { passContributingSamples++; passSampleContributions += sampleContributions; } } totalSamples += passSamples; // if (pass>10) // HoleSamplingPass(); mPass++; int pvsSize = 0; for (i=0; i < objects.size(); i++) { Intersectable *object = objects[i]; pvsSize += object->mKdPvs.GetSize(); } cout << "#Pass " << mPass<<" : t = " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl; cout << "#TotalSamples=" << totalSamples/1000 << "k #SampleContributions=" << passSampleContributions << " (" << 100*passContributingSamples/(float)passSamples<<"%)" << " avgPVS=" << pvsSize/(float)objects.size() << endl << "avg ray contrib=" << passSampleContributions/(float)passContributingSamples << endl; mStats << "#Pass\n" <CollectLeafPvs(); cout << "#totalPvsSize=" << totalPvsSize << endl; // HoleSamplingPass(); if (1) { Exporter *exporter = Exporter::GetExporter("ray-density.x3d"); exporter->SetExportRayDensity(true); exporter->ExportKdTree(*mKdTree); exporter->ExportBspTree(*mBspTree); delete exporter; } bool exportRays = false; if (exportRays) { Exporter *exporter = NULL; exporter = Exporter::GetExporter("sample-rays.x3d"); exporter->SetWireframe(); exporter->ExportKdTree(*mKdTree); exporter->ExportBspTree(*mBspTree); for (i=0; i < pvsOut; i++) exporter->ExportRays(rays[i], 1000, RgbColor(1, 0, 0)); exporter->SetFilled(); delete exporter; } if (1) { for (int k=0; k < pvsOut; k++) { Intersectable *object = objects[k]; char s[64]; sprintf(s, "sample-pvs%04d.x3d", k); Exporter *exporter = Exporter::GetExporter(s); exporter->SetWireframe(); KdPvsMap::iterator i = object->mKdPvs.mEntries.begin(); Intersectable::NewMail(); // avoid adding the object to the list object->Mail(); ObjectContainer visibleObjects; for (; i != object->mKdPvs.mEntries.end(); i++) { KdNode *node = (*i).first; exporter->ExportBox(mKdTree->GetBox(node)); mKdTree->CollectObjects(node, visibleObjects); } exporter->ExportRays(rays[k], 1000, RgbColor(0, 1, 0)); exporter->SetFilled(); for (int j = 0; j < visibleObjects.size(); j++) exporter->ExportIntersectable(visibleObjects[j]); Material m; m.mDiffuseColor = RgbColor(1, 0, 0); exporter->SetForcedMaterial(m); exporter->ExportIntersectable(object); delete exporter; } } return true; }