#include using namespace std; #include "KdTree.h" #include "AxisAlignedBox3.h" #include "Ray.h" #include "MutualVisibility.h" void TriangleSample::Init( const Triangle3 &source, const Triangle3 &target) { mDepth = 0; mSource = source; mTarget = target; } Vector3 TriangleSample::GetIntersectionPoint(const int rayIndex, const int depth) const { Vector3 origin, direction; GetRay(rayIndex, origin, direction); return origin + direction*mIntersections[rayIndex][depth].mT; } void TriangleSample::GetRay(const int rayIndex, Vector3 &origin, Vector3 &direction) const { const int indices[][2] = { {0,0}, {0,1}, {0,2}, {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2} }; origin = mSource.mVertices[indices[rayIndex][0]]; direction = mTarget.mVertices[indices[rayIndex][1]] - origin; } void MutualVisibilitySampler::PerformSplit( const TriangleSample &sample, const bool splitSource, const int edge, const Vector3 &splitPoint, const Ray &ray, TriangleSample &sample1, TriangleSample &sample2 ) { const Triangle3 *triangle; Triangle3 *triangle1, *triangle2; // split the triangles if (splitSource) { sample1.mTarget = sample.mTarget; sample2.mTarget = sample.mTarget; triangle1 = &sample1.mSource; triangle2 = &sample2.mSource; triangle = &sample.mSource; } else { sample1.mSource = sample.mSource; sample2.mSource = sample.mSource; triangle1 = &sample1.mTarget; triangle2 = &sample2.mTarget; triangle = &sample.mTarget; } // split the intersections switch (edge) { case 0: sample1.mIntersections[0] = sample.mIntersections[0]; sample1.mIntersections[1] = sample.mIntersections[1]; triangle1->mVertices[0] = triangle->mVertices[0]; triangle1->mVertices[1] = triangle->mVertices[1]; sample2.mIntersections[0] = sample.mIntersections[2]; sample2.mIntersections[1] = sample.mIntersections[0]; triangle2->mVertices[0] = triangle->mVertices[2]; triangle2->mVertices[1] = triangle->mVertices[0]; break; case 1: sample1.mIntersections[0] = sample.mIntersections[0]; sample1.mIntersections[1] = sample.mIntersections[1]; triangle1->mVertices[0] = triangle->mVertices[0]; triangle1->mVertices[1] = triangle->mVertices[1]; sample2.mIntersections[0] = sample.mIntersections[1]; sample2.mIntersections[1] = sample.mIntersections[2]; triangle2->mVertices[0] = triangle->mVertices[1]; triangle2->mVertices[1] = triangle->mVertices[2]; break; case 2: sample1.mIntersections[0] = sample.mIntersections[2]; sample1.mIntersections[1] = sample.mIntersections[0]; triangle1->mVertices[0] = triangle->mVertices[2]; triangle1->mVertices[1] = triangle->mVertices[0]; sample2.mIntersections[0] = sample.mIntersections[1]; sample2.mIntersections[1] = sample.mIntersections[2]; triangle2->mVertices[0] = triangle->mVertices[1]; triangle2->mVertices[1] = triangle->mVertices[2]; break; } // the new sample sample1.mIntersections[2] = ray.intersections; sample2.mIntersections[2] = ray.intersections; triangle1->mVertices[2] = splitPoint; triangle2->mVertices[2] = splitPoint; // establish the new samples sample1.mDepth = sample2.mDepth = sample.mDepth+1; } float MutualVisibilitySampler::GetSpatialAngle(const TriangleSample &sample, const Vector3 &point ) { const int sampleIndices[][3]={ (0,0,0), (0,1,0), (-1,-1,-1) }; float sum = 0.0f; int i; for (i=0; i < 10; i++) { Triangle3 triangle(sample.GetIntersectionPoint(sampleIndices[i][0], 0), sample.GetIntersectionPoint(sampleIndices[i][1], 0), sample.GetIntersectionPoint(sampleIndices[i][2], 0)); sum += triangle.GetSpatialAngle(point); } return sum; } void MutualVisibilitySampler::ComputeError(TriangleSample &sample) { // evaluate minimal error which can be achieved by more precise evaluation // if this is above the threshold do not proceed further float maxAngle = GetSpatialAngle(sample, sample.mSource.GetCenter()); for (int i=0; i < 3; i++) { float angle = GetSpatialAngle(sample, sample.mSource.mVertices[i]); if (angle > maxAngle) maxAngle = angle; } sample.mError = maxAngle; } void MutualVisibilitySampler::ConstructInitialSamples( const AxisAlignedBox3 &source, const AxisAlignedBox3 &target, vector &samples ) { // get all rectangles potentially visible from the source box int i; int sourceMask = 0; for (i=0; i < 8; i++) sourceMask |= source.GetFaceVisibilityMask(target.GetVertex(i)); // now for each visble source face find all visible target faces for (i=0; i < 6; i++) { Rectangle3 sourceFace = source.GetFace(i); if ( sourceMask &(1< &samples ) { Triangle3 sourceTriangles[2]; Triangle3 targetTriangles[2]; sourceTriangles[0].Init(sourceRect.mVertices[0], sourceRect.mVertices[1], sourceRect.mVertices[2]); sourceTriangles[1].Init(sourceRect.mVertices[0], sourceRect.mVertices[2], sourceRect.mVertices[3]); targetTriangles[0].Init(targetRect.mVertices[0], targetRect.mVertices[1], targetRect.mVertices[2]); targetTriangles[1].Init(targetRect.mVertices[0], targetRect.mVertices[2], targetRect.mVertices[3]); int i, j; for (i=0; i < 2; i++) for (j=0; j < 2; j++) { TriangleSample *sample = new TriangleSample(sourceTriangles[i], targetTriangles[j]); samples.push_back(sample); } } int MutualVisibilitySampler::ComputeVisibility() { stack sampleStack; Ray ray; // now process the samples as long as we have something to do while (!sampleStack.empty()) { TriangleSample *sample = sampleStack.top(); sampleStack.pop(); // // cast a new ray // int triangleSplitEdge = SetupExtremalRay(sample, source, ray); // if (!kdTree->CastRay(ray)) // return VISIBLE; // // generate 2 new samples // TriangleSample newSamples[2]; // sample.Split(triangleSplitEdge, ray, newSamples[0], newSamples[1]); // for (i=0; i < 2; i++) { // newSamples[i].ComputeError(); // if (newSamples[i].mError > solidAngleThreshold) { // sampleStack.push(newSamples[i]); // } // } // } } return INVISIBLE; } MutualVisibilitySampler::MutualVisibilitySampler(KdTree *kdTree, AxisAlignedBox3 &source, AxisAlignedBox3 &target, const float solidAngleThreshold) { mKdTree = kdTree; mSource = source; mTarget = target; mSolidAngleThreshold = solidAngleThreshold; } int ComputeBoxVisibility(KdTree *kdTree, AxisAlignedBox3 &source, AxisAlignedBox3 &target, const float solidAngleThreshold) { MutualVisibilitySampler sampler(kdTree, source, target, solidAngleThreshold); int visibility = sampler.ComputeVisibility(); return visibility; }