#include "SceneGraph.h" #include "KdTree.h" #include "RssPreprocessor.h" #include "X3dExporter.h" #include "Environment.h" #include "MutualVisibility.h" #include "Polygon3.h" #include "ViewCell.h" #include "VssRay.h" #include "RssTree.h" #include "ViewCellsManager.h" #include "RenderSimulator.h" #include "GlRenderer.h" static bool useViewSpaceBox = true; static bool use2dSampling = false; static bool fromBoxVisibility = false; RssPreprocessor::RssPreprocessor(): mPass(0), mVssRays() { // this should increase coherence of the samples environment->GetIntValue("RssPreprocessor.samplesPerPass", mSamplesPerPass); environment->GetIntValue("RssPreprocessor.initialSamples", mInitialSamples); environment->GetIntValue("RssPreprocessor.vssSamples", mRssSamples); environment->GetIntValue("RssPreprocessor.vssSamplesPerPass", mRssSamplesPerPass); environment->GetBoolValue("RssPreprocessor.useImportanceSampling", mUseImportanceSampling); environment->GetBoolValue("RssPreprocessor.Export.pvs", mExportPvs); environment->GetBoolValue("RssPreprocessor.Export.rssTree", mExportRssTree); environment->GetBoolValue("RssPreprocessor.Export.rays", mExportRays); environment->GetIntValue("RssPreprocessor.Export.numRays", mExportNumRays); environment->GetBoolValue("RssPreprocessor.useViewcells", mUseViewcells); environment->GetBoolValue("RssPreprocessor.objectBasedSampling", mObjectBasedSampling); environment->GetBoolValue("RssPreprocessor.directionalSampling", mDirectionalSampling); environment->GetBoolValue("RssPreprocessor.loadInitialSamples", mLoadInitialSamples); environment->GetBoolValue("RssPreprocessor.storeInitialSamples", mStoreInitialSamples); mStats.open("stats.log"); } RssPreprocessor::~RssPreprocessor() { // mVssRays get deleted in the tree // CLEAR_CONTAINER(mVssRays); } void RssPreprocessor::SetupRay(Ray &ray, const Vector3 &point, const Vector3 &direction ) { ray.intersections.clear(); // do not store anything else then intersections at the ray ray.Init(point, direction, Ray::LOCAL_RAY); } int RssPreprocessor::CastRay( Vector3 &viewPoint, Vector3 &direction, VssRayContainer &vssRays ) { int hits = 0; static Ray ray; AxisAlignedBox3 box = mKdTree->GetBox(); AxisAlignedBox3 sbox = box; sbox.Enlarge(Vector3(-Limits::Small)); if (!sbox.IsInside(viewPoint)) return 0; SetupRay(ray, viewPoint, direction); // cast ray to KD tree to find intersection with other objects Intersectable *objectA, *objectB; Vector3 pointA, pointB; float bsize = Magnitude(box.Size()); if (mKdTree->CastRay(ray)) { objectA = ray.intersections[0].mObject; pointA = ray.Extrap(ray.intersections[0].mT); } else { objectA = NULL; // compute intersection with the scene bounding box float tmin, tmax; if (box.ComputeMinMaxT(ray, &tmin, &tmax) && tmin < tmax) pointA = ray.Extrap(tmax); else return 0; } bool detectEmptyViewSpace = true; if (detectEmptyViewSpace) { SetupRay(ray, pointA, -direction); } else SetupRay(ray, viewPoint, -direction); if (mKdTree->CastRay(ray)) { objectB = ray.intersections[0].mObject; pointB = ray.Extrap(ray.intersections[0].mT); } else { objectB = NULL; float tmin, tmax; if (box.ComputeMinMaxT(ray, &tmin, &tmax) && tmin < tmax) pointB = ray.Extrap(tmax); else return 0; } // if (objectA == NULL && objectB != NULL) { if (1) { // cast again to ensure that there is no objectA SetupRay(ray, pointB, direction); if (mKdTree->CastRay(ray)) { objectA = ray.intersections[0].mObject; pointA = ray.Extrap(ray.intersections[0].mT); } } VssRay *vssRay = NULL; bool validSample = (objectA != objectB); if (0 && detectEmptyViewSpace) { // consider all samples valid // check if the viewpoint lies on the line segment AB if (Distance(pointA, pointB) < Distance(viewPoint, pointA) + Distance(viewPoint, pointB) - Limits::Small) { validSample = false; } } if (validSample) { if (objectA) { vssRay = new VssRay(pointB, pointA, objectB, objectA, mPass ); vssRays.push_back(vssRay); hits ++; } if (objectB) { vssRay = new VssRay(pointA, pointB, objectA, objectB, mPass ); vssRays.push_back(vssRay); hits ++; } } return hits; } Vector3 RssPreprocessor::GetViewpoint(AxisAlignedBox3 *viewSpaceBox) { AxisAlignedBox3 box; if (viewSpaceBox) box =*viewSpaceBox; else box = mKdTree->GetBox(); // shrink the box in the y direction return box.GetRandomPoint(); } Vector3 RssPreprocessor::GetDirection(const Vector3 &viewpoint, AxisAlignedBox3 *viewSpaceBox ) { Vector3 point; if (!use2dSampling) { if (mObjectBasedSampling) { Vector3 normal; int i = RandomValue(0, mObjects.size()-1); Intersectable *object = mObjects[i]; object->GetRandomSurfacePoint(point, normal); } else { // select if (mDirectionalSampling) { point = viewpoint + UniformRandomVector(); } else { // select the other point uniformly distruted in the whole viewspace AxisAlignedBox3 box; if (viewSpaceBox) box =*viewSpaceBox; else box = mKdTree->GetBox(); point = box.GetRandomPoint(); } } } else { AxisAlignedBox3 box; if (viewSpaceBox) box =*viewSpaceBox; else box = mKdTree->GetBox(); point = box.GetRandomPoint(); point.y = viewpoint.y; } return point - viewpoint; } Vector3 RssPreprocessor::InitialGetDirection(const Vector3 &viewpoint, AxisAlignedBox3 *viewSpaceBox ) { Vector3 point; if (!use2dSampling) { if (1 || mObjectBasedSampling) { Vector3 normal; int i = RandomValue(0, mObjects.size()-1); Intersectable *object = mObjects[i]; object->GetRandomSurfacePoint(point, normal); } else { // select if (1 || mDirectionalSampling) { point = viewpoint + UniformRandomVector(); } else { // select the other point uniformly distruted in the whole viewspace AxisAlignedBox3 box; if (viewSpaceBox) box =*viewSpaceBox; else box = mKdTree->GetBox(); point = box.GetRandomPoint(); } } } else { AxisAlignedBox3 box; if (viewSpaceBox) box =*viewSpaceBox; else box = mKdTree->GetBox(); point = box.GetRandomPoint(); point.y = viewpoint.y; } return point - viewpoint; } int RssPreprocessor::GenerateImportanceRays(RssTree *rssTree, const int desiredSamples, SimpleRayContainer &rays ) { int num; rssTree->UpdateTreeStatistics(); cout<< "#RSS_AVG_PVS_SIZE\n"<stat.avgPvsSize<stat.avgRays<stat.avgRayContribution<stat.avgPvsEntropy<stat.avgRayLengthEntropy<stat.avgImportance<stat.avgRayContribution*rssTree->stat.Leaves()); num = rssTree->GenerateRays(p, rays); } else { int leaves = rssTree->stat.Leaves()/1; num = rssTree->GenerateRays(desiredSamples, leaves, rays); } cout<<"Generated "<SetWireframe(); // exporter->ExportKdTree(*mKdTree); exporter->SetFilled(); exporter->ExportScene(mSceneGraph->mRoot); exporter->SetWireframe(); if (mViewSpaceBox) { exporter->SetForcedMaterial(RgbColor(1,0,1)); exporter->ExportBox(*mViewSpaceBox); exporter->ResetForcedMaterial(); } VssRayContainer rays; vssRays.SelectRays( number, rays); exporter->ExportRays(rays, RgbColor(1, 0, 0)); delete exporter; cout<<"done."<SetFilled(); exporter->ExportScene(mSceneGraph->mRoot); // exporter->SetWireframe(); bool result = exporter->ExportRssTree2( *tree, dir ); delete exporter; return result; } bool RssPreprocessor::ExportRssTreeLeaf(char *filename, RssTree *tree, RssTreeLeaf *leaf) { Exporter *exporter = NULL; exporter = Exporter::GetExporter(filename); exporter->SetWireframe(); exporter->ExportKdTree(*mKdTree); if (mViewSpaceBox) { exporter->SetForcedMaterial(RgbColor(1,0,0)); exporter->ExportBox(*mViewSpaceBox); exporter->ResetForcedMaterial(); } exporter->SetForcedMaterial(RgbColor(0,0,1)); exporter->ExportBox(tree->GetBBox(leaf)); exporter->ResetForcedMaterial(); VssRayContainer rays[4]; for (int i=0; i < leaf->rays.size(); i++) { int k = leaf->rays[i].GetRayClass(); rays[k].push_back(leaf->rays[i].mRay); } // SOURCE RAY exporter->ExportRays(rays[0], RgbColor(1, 0, 0)); // TERMINATION RAY exporter->ExportRays(rays[1], RgbColor(1, 1, 1)); // PASSING_RAY exporter->ExportRays(rays[2], RgbColor(1, 1, 0)); // CONTAINED_RAY exporter->ExportRays(rays[3], RgbColor(0, 0, 1)); delete exporter; return true; } void RssPreprocessor::ExportRssTreeLeaves(RssTree *tree, const int number) { vector leaves; tree->CollectLeaves(leaves); int num = 0; int i; float p = number / (float)leaves.size(); for (i=0; i < leaves.size(); i++) { if (RandomValue(0,1) < p) { char filename[64]; sprintf(filename, "rss-leaf-%04d.x3d", num); ExportRssTreeLeaf(filename, tree, leaves[i]); num++; } if (num >= number) break; } } float RssPreprocessor::GetAvgPvsSize(RssTree *tree, const vector &viewcells ) { vector::const_iterator it, it_end = viewcells.end(); int sum = 0; for (it = viewcells.begin(); it != it_end; ++ it) sum += tree->GetPvsSize(*it); return sum/(float)viewcells.size(); } void RssPreprocessor::ExportPvs(char *filename, RssTree *rssTree ) { ObjectContainer pvs; if (rssTree->CollectRootPvs(pvs)) { Exporter *exporter = Exporter::GetExporter(filename); exporter->SetFilled(); exporter->ExportGeometry(pvs); exporter->SetWireframe(); exporter->ExportBox(rssTree->bbox); exporter->ExportViewpoint(rssTree->bbox.Center(), Vector3(1,0,0)); delete exporter; } } void RssPreprocessor::ComputeRenderError() { // compute rendering error if (renderer) { // emit EvalPvsStat(); // QMutex mutex; // mutex.lock(); // renderer->mRenderingFinished.wait(&mutex); // mutex.unlock(); renderer->EvalPvsStat(); mStats << "#AvgPvsRenderError\n" <mPvsStat.GetAvgError()<mPvsStat.GetMaxError()<mPvsStat.GetErrorFreeFrames()<GetBox()); if (fromBoxVisibility) { float m = box->Min(1); float bsize = box->Size(1); float size = 0.02f; float s = 0.5f - size; float olds = Magnitude(box->Size()); box->Enlarge(box->Size()*Vector3(-s)); // Vector3 translation = Vector3(-olds*0.2f, 0, 0); Vector3 translation = Vector3(-0.05f*olds, 0, 0); box->SetMin(box->Min() + translation); box->SetMax(box->Max() + translation); box->SetMin(1, m + bsize*0.1f); box->SetMax(1, m + bsize*0.6f); } else { // sample city like heights float m = box->Min(1); float bsize = box->Size(1); box->SetMin(1, m + bsize*0.2f); box->SetMax(1, m + bsize*0.3f); } if (use2dSampling) box->SetMax(1, box->Min(1)); if (useViewSpaceBox) { mViewSpaceBox = box; mViewCellsManager->SetViewSpaceBox(*box); } else { mViewSpaceBox = NULL; mViewCellsManager->SetViewSpaceBox(mKdTree->GetBox()); } RssTree *rssTree = NULL; int rssPass = 0; int rssSamples = 0; #if 0 if (mLoadInitialSamples) { cout << "Loading samples from file ... "; LoadSamples(mVssRays, mObjects); cout << "finished\n" << endl; } else { #endif while (totalSamples < mInitialSamples) { int passContributingSamples = 0; int passSampleContributions = 0; int passSamples = 0; int index = 0; int sampleContributions; //int s = Min(mSamplesPerPass, mInitialSamples); int s = mInitialSamples; for (int k=0; k < s; k++) { //Vector3 viewpoint = GetViewpoint(mViewSpaceBox); Vector3 viewpoint; // mViewCellsManager->GetViewPoint(viewpoint); viewpoint = GetViewpoint(mViewSpaceBox); Vector3 direction = InitialGetDirection(viewpoint, mViewSpaceBox); sampleContributions = CastRay(viewpoint, direction, mVssRays); //-- CORR matt: put block inside loop if (sampleContributions) { passContributingSamples ++; passSampleContributions += sampleContributions; } passSamples++; totalSamples++; } 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<<"%)" << "avgcontrib=" << avgRayContrib << endl; mPass++; } cout << "#totalPvsSize=" << mKdTree->CollectLeafPvs() << endl; cout << "#totalRayStackSize=" << (int)mVssRays.size() << endl <Construct(mObjects, mVssRays); // evaluate contributions of the intitial rays mViewCellsManager->ComputeSampleContributions(mVssRays); mStats << "#Pass\n" <PrintPvsStatistics(mStats); VssRayContainer selectedRays; int desired = Max( mViewCellsManager->GetPostProcessSamples(), mViewCellsManager->GetVisualizationSamples()); mVssRays.SelectRays(desired, selectedRays); //-- post process view cells mViewCellsManager->PostProcess(mObjects, selectedRays); //-- several visualizations and statistics Debug << "view cells after post processing: " << endl; mViewCellsManager->PrintStatistics(Debug); if (1) mViewCellsManager->Visualize(mObjects, selectedRays); } rssPass++; rssTree = new RssTree; rssTree->SetPass(mPass); if (mUseImportanceSampling) { if (fromBoxVisibility) rssTree->Construct(mVssRays, mViewSpaceBox); else rssTree->Construct(mVssRays, NULL); rssTree->stat.Print(mStats); cout<<"RssTree root PVS size = "<GetRootPvsSize()<UpdatePVS(newVssRays); while (1) { int num = mRssSamplesPerPass; SimpleRayContainer rays; VssRayContainer vssRays; if (!mUseImportanceSampling) { for (int j=0; j < num; j++) { //changed by matt //Vector3 viewpoint = GetViewpoint(mViewSpaceBox); Vector3 viewpoint; mViewCellsManager->GetViewPoint(viewpoint); Vector3 direction = GetDirection(viewpoint, mViewSpaceBox); rays.push_back(SimpleRay(viewpoint, direction)); } } else { num = GenerateImportanceRays(rssTree, num, rays); } for (int i=0; i < rays.size(); i++) CastRay(rays[i].mOrigin, rays[i].mDirection, vssRays); totalSamples += rays.size(); rssSamples += vssRays.size(); mStats << "#Pass\n" <ComputeSampleContributions(vssRays); vssRays.PrintStatistics(mStats); mViewCellsManager->PrintPvsStatistics(mStats); } ComputeRenderError(); // epxort rays before adding them to the tree -> some of them can be deleted if (mExportRays) { char filename[64]; if (mUseImportanceSampling) sprintf(filename, "rss-rays-i%04d.x3d", rssPass); else sprintf(filename, "rss-rays-%04d.x3d", rssPass); ExportRays(filename, vssRays, mExportNumRays); // now export all contributing rays VssRayContainer contributingRays; vssRays.GetContributingRays(contributingRays, mPass); mStats<<"#NUM_CONTRIBUTING_RAYS\n"<AddRays(vssRays); if (0) { cout<<"############# Rss PVS STAT ##################\n"; cout<<"#AVG_RSS_PVS\n"<GetAvgPvsSize()<GetRootPvsSize()<UpdateSubdivision(); cout<<"subdivided leafs = "<= mRssSamples + mInitialSamples) break; rssPass++; mPass++; rssTree->SetPass(mPass); } if (mUseViewcells) { //-- 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; } delete rssTree; return true; }