real ViewEdge::getLength2D() const { float length = 0.0f; ViewEdge::const_fedge_iterator itlast = fedge_iterator_last(); ViewEdge::const_fedge_iterator it = fedge_iterator_begin(), itend = fedge_iterator_end(); Vec2r seg; do { seg = Vec2r((*it)->orientation2d()[0], (*it)->orientation2d()[1]); length += seg.norm(); ++it; } while ((it != itend) && (it != itlast)); return length; }
Vec2r SVertex::ImageSpaceNormal() const { if (_Normals.size() == 0) return Vec2r(0,0); Vec3r normal = *(_Normals.begin()); Vec3r pos = _Point3D; Vec2r imgNormal = SilhouetteGeomEngine::WorldToImage2(pos + normal) - SilhouetteGeomEngine::WorldToImage2(pos); imgNormal.normalize(); return imgNormal; }
/*! Calculates the trapezoidal transformation matrix \a matNT that transforms post projection light space so that shadow map resolution in the "foreground" is maximized. The major steps are: - compute the intersection of eyeFrust and lightFrust - construct a trapezoid that contains the intersection - determine the transformation that maps this trapezoid to the (-1, 1) square Returns \c true if the transform was computed, \c false otherwise (e.g. if the intersection of eyeFrust and lightFrust is empty). For details see "T. Martin, T.-S. Tan: Anti-aliasing and Continuity with Trapezoidal Shadow Maps" */ bool TrapezoidalShadowMapEngine::calcTrapezoidalTransform( Matrixr &matNT, const Matrixr &matEyeToWorld, const Matrixr &matLightFull, const FrustumVolume &eyeFrust, const FrustumVolume &lightFrust ) { // obtain post proj. light space eye position Pnt3r eyePos; matEyeToWorld.mult (eyePos, eyePos); matLightFull .multFull(eyePos, eyePos); // intersect eye and light frusta, get vertices and center of intersection std::vector<Pnt3r> intVerts; Pnt3r intCenter; intersectFrusta(eyeFrust, lightFrust, intVerts, intCenter); if(intVerts.empty() == true) return false; // xform intCenter and intVerts to post proj. light space matLightFull.multFull(intCenter, intCenter); std::vector<Pnt3r>::iterator ivIt = intVerts.begin(); std::vector<Pnt3r>::iterator ivEnd = intVerts.end (); for(; ivIt != ivEnd; ++ivIt) matLightFull.multFull(*ivIt, *ivIt); Pnt2r eyePos2D (eyePos [0], eyePos [1]); Pnt2r intCenter2D(intCenter[0], intCenter[1]); // center line, normal, direction and distance from origin Vec2r clDir (intCenter2D - eyePos2D); clDir.normalize(); Vec2r clNorm(-clDir[1], clDir[0]); // distance of the center line from the origin Real clDist = clNorm.dot(eyePos2D.subZero()); // compute top and base lines: // - project intVerts onto the center line. // - top line is perpendicular to center line and goes through the // projected point closest to eyePos // - base line is perpendicular to center line and goes through the // projected point farthest from eyePos Pnt2r tlBase; Pnt2r blBase; Real topDist = TypeTraits<Real>::getMax(); Real baseDist = TypeTraits<Real>::getMin(); std::vector<Pnt3r>::const_iterator ivCIt = intVerts.begin(); std::vector<Pnt3r>::const_iterator ivCEnd = intVerts.end (); for(; ivCIt != ivCEnd; ++ivCIt) { Pnt2r ivPnt((*ivCIt)[0], (*ivCIt)[1]); ivPnt = ivPnt - (clNorm.dot(ivPnt) - clDist) * clNorm; Real dist = (ivPnt - eyePos2D).squareLength(); dist *= osgSgn(clDir.dot(ivPnt - eyePos2D)); if(dist < topDist) { topDist = dist; tlBase = ivPnt; } if(dist > baseDist) { baseDist = dist; blBase = ivPnt; } } topDist = osgSgn(topDist ) * osgSqrt(osgAbs(topDist )); baseDist = osgSgn(baseDist) * osgSqrt(osgAbs(baseDist)); // compute side lines: // - choose focusPnt (everything closer to the near plane is mapped to // 80% of the shadow map) - here we just take the point at 0.7 between // tlBase and blBase // - find a point (trapTip, q in the paper) on center line such that // focusPnt is mapped the 80% line in the shadow map // - choose lines through q that touch the convex hull of intVerts ivCIt = intVerts.begin(); ivCEnd = intVerts.end (); // Real centerDist = (intCenter2D - eyePos2D).length(); Real lambda = baseDist - topDist; Real delta = 0.5f * lambda; Real xi = -0.6f; Real eta = ((lambda * delta) + (lambda * delta * xi)) / (lambda - 2.f * delta - lambda * xi ); Pnt2r trapTip = tlBase - (eta * clDir); Pnt2r focusPnt = tlBase + (delta * clDir); // on both sides of the center line, find the point in intVerts that has // the smallest |cosine| (largest angle) between clDir and the vector // from trapTip to intVerts[i] Pnt2r posPnt; Real posCos = 1.f; Pnt2r negPnt; Real negCos = 1.f; for(UInt32 i = 0; ivCIt != ivCEnd; ++ivCIt, ++i) { Pnt2r ivPnt((*ivCIt)[0], (*ivCIt)[1]); Vec2r v = ivPnt - trapTip; v.normalize(); Real currCos = osgAbs(clDir.dot(v)); if(clNorm.dot(v) >= 0.f) { if(currCos <= posCos) { posPnt = ivPnt; posCos = currCos; } } else { if(currCos <= negCos) { negPnt = ivPnt; negCos = currCos; } } } // compute corners of trapezoid: Pnt2r trapVerts [4]; Pnt2r extraVerts[2]; Real posTan = osgTan(osgACos(posCos)); Real negTan = osgTan(osgACos(negCos)); trapVerts[0] = blBase - ((eta + lambda) * negTan * clNorm); trapVerts[1] = blBase + ((eta + lambda) * posTan * clNorm); trapVerts[2] = tlBase + ( eta * posTan * clNorm); trapVerts[3] = tlBase - ( eta * negTan * clNorm); extraVerts[0] = focusPnt + ((eta + delta) * posTan * clNorm); extraVerts[1] = focusPnt - ((eta + delta) * negTan * clNorm); // == xform trapezoid to unit square == // M1 = R * T1 -- translate center of top line to origin and rotate Vec2r u = 0.5f * (trapVerts[2].subZero() + trapVerts[3].subZero()); Vec2r v = trapVerts[3] - trapVerts[2]; v.normalize(); matNT.setValue( v[0], v[1], 0.f, -(u[0] * v[0] + u[1] * v[1]), -v[1], v[0], 0.f, (u[0] * v[1] - u[1] * v[0]), 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 1.f); // M2 = T2 * M1 -- translate tip to origin matNT[3][0] = - (matNT[0][0] * trapTip[0] + matNT[1][0] * trapTip[1]); matNT[3][1] = - (matNT[0][1] * trapTip[0] + matNT[1][1] * trapTip[1]); // M3 = H * M2 -- shear to make it symmetric wrt to the y axis // v = M2 * u v[0] = matNT[0][0] * u[0] + matNT[1][0] * u[1] + matNT[3][0]; v[1] = matNT[0][1] * u[0] + matNT[1][1] * u[1] + matNT[3][1]; Real a = - v[0] / v[1]; // matNT[*][0] : = mat[*][0] + a * mat[*][1] matNT[0][0] += a * matNT[0][1]; matNT[1][0] += a * matNT[1][1]; matNT[2][0] += a * matNT[2][1]; matNT[3][0] += a * matNT[3][1]; // M4 = S1 * M3 -- scale to make sidelines orthogonal and // top line is at y == 1 // v = 1 / (M3 * t2) v[0] = 1.f / (matNT[0][0] * trapVerts[2][0] + matNT[1][0] * trapVerts[2][1] + matNT[3][0]); v[1] = 1.f / (matNT[0][1] * trapVerts[2][0] + matNT[1][1] * trapVerts[2][1] + matNT[3][1]); matNT[0][0] *= v[0]; matNT[0][1] *= v[1]; matNT[1][0] *= v[0]; matNT[1][1] *= v[1]; matNT[2][0] *= v[0]; matNT[2][1] *= v[1]; matNT[3][0] *= v[0]; matNT[3][1] *= v[1]; // M5 = N * M4 -- turn trapezoid into rectangle matNT[0][3] = matNT[0][1]; matNT[1][3] = matNT[1][1]; matNT[2][3] = matNT[2][1]; matNT[3][3] = matNT[3][1]; matNT[3][1] += 1.f; // M6 = T3 * M5 -- translate center to origin // u = "M5 * t0" - only y and w coordinates // v = "M5 * t2" - only y and w coordinates u[0] = matNT[0][1] * trapVerts[0][0] + matNT[1][1] * trapVerts[0][1] + matNT[3][1]; u[1] = matNT[0][3] * trapVerts[0][0] + matNT[1][3] * trapVerts[0][1] + matNT[3][3]; v[0] = matNT[0][1] * trapVerts[2][0] + matNT[1][1] * trapVerts[2][1] + matNT[3][1]; v[1] = matNT[0][3] * trapVerts[2][0] + matNT[1][3] * trapVerts[2][1] + matNT[3][3]; a = - 0.5f * (u[0] / u[1] + v[0] / v[1]); matNT[0][1] += matNT[0][3] * a; matNT[1][1] += matNT[1][3] * a; matNT[2][1] += matNT[2][3] * a; matNT[3][1] += matNT[3][3] * a; // M7 = S2 * M6 -- scale to fill -1/+1 square // u = "M6 * t0" - only y and w coordinates u[0] = matNT[0][1] * trapVerts[0][0] + matNT[1][1] * trapVerts[0][1] + matNT[3][1]; u[1] = matNT[0][3] * trapVerts[0][0] + matNT[1][3] * trapVerts[0][1] + matNT[3][3]; a = -u[1] / u[0]; matNT[0][1] *= a; matNT[1][1] *= a; matNT[2][1] *= a; matNT[3][1] *= a; return true; }