void ShaderShadowMapEngine::calcPointLightMatrices(
    Matrixr    &matWorldToLight,
    Matrixr    &matEyeToLight,
    const PointLight *pointL,
    const Matrixr    &matEyeToWorld)
{
    if(pointL->getBeacon() != NULL)
        pointL->getBeacon()->getToWorld(matWorldToLight);

    Matrixr matLightPos;
    matLightPos    .setTranslate(pointL->getPosition());
    matWorldToLight.mult        (matLightPos          );
    matWorldToLight.invert      (                     );

    matEyeToLight = matWorldToLight;
    matEyeToLight.mult(matEyeToWorld);
}
/*! Calculates \a matWorldToLight and \a matEyeToLight for a directional light
    \a dirL and inverse viewing matrix \a matEyeToWorld.
*/
void ShaderShadowMapEngine::calcDirectionalLightMatrices(
    Matrixr          &matWorldToLight,
    Matrixr          &matEyeToLight,
    const DirectionalLight *dirL,
    const Matrixr          &matEyeToWorld)
{
    if(dirL->getBeacon() != NULL)
        dirL->getBeacon()->getToWorld(matWorldToLight);

    Quaternion rotLightDir  (Vec3r(0.f, 0.f, 1.f), dirL->getDirection());
    Matrixr    matLightDir;
    matLightDir.setRotate(rotLightDir);

    matWorldToLight.mult  (matLightDir);
    matWorldToLight.invert(           );

    matEyeToLight = matWorldToLight;
    matEyeToLight.mult(matEyeToWorld);
}
/*! Calculates \a matWorldToLight and \a matEyeToLight for a spot light
    \a spotL and inverse viewing matrix \a matEyeToWorld.
*/
void ShaderShadowMapEngine::calcSpotLightMatrices(
    Matrixr   &matWorldToLight,
    Matrixr   &matEyeToLight,
    const SpotLight *spotL,
    const Matrixr   &matEyeToWorld)
{
    if(spotL->getBeacon() != NULL)
        spotL->getBeacon()->getToWorld(matWorldToLight);

    Matrixr matLightPos;
    matLightPos.setTranslate(spotL->getPosition());

    Matrixr    matLightDir;
    Quaternion rotLightDir(Vec3r(0.f, 0.f, 1.f), -spotL->getDirection());
    matLightDir.setRotate(rotLightDir);

    matWorldToLight.mult  (matLightPos);
    matWorldToLight.mult  (matLightDir);
    matWorldToLight.invert(           );

    matEyeToLight = matWorldToLight;
    matEyeToLight.mult(matEyeToWorld);
}
Example #4
0
void Joint::accumulateMatrix(Matrixr &result)
{
    Inherited::accumulateMatrix(result);

    result.mult(getJointTransformation());
}
/*! 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;
}
Example #6
0
void ReplicateTransform::accumulateMatrix(Matrixr &result)
{
    result.mult(_invWorld);
}
void ShaderShadowMapEngine::handleDirectionalLightEnter(
    DirectionalLight *dirL, RenderAction *ract, SSMEngineData *data)
{
    RenderPartition *parentPart = ract      ->getActivePartition();
    FrustumVolume    camFrust   = parentPart->getFrustum        ();

    Matrixr matEyeToWorld  (parentPart->getCameraToWorld());
    Matrixr matWorldToLight;
    Matrixr matEyeToLight;

    calcDirectionalLightMatrices(matWorldToLight, matEyeToLight,
                                 dirL,            matEyeToWorld );

    // place light camera outside the scene bounding box:
    //  - project camera frustum and scene bounding box into a
    //    coordinate system where the directional light shines
    //    along the -z axis.
    //  - compute 2 AABBs that contain the projected frustum and
    //    scene BB
    //  - width and height of the ortho projection are determined from
    //    the frustum AABB, while near and far are determined by the
    //    scene AABB (offscreen objects cast shadows into the view volume)
    Pnt3r      camVerts  [10];
    Pnt3r      sceneVerts[10];
    const Matrix    &matSceneToWorld = ract->topMatrix ();
    BoxVolume  sceneBB         = ract->getActNode()->getVolume();

    camFrust.getCorners(camVerts  [0], camVerts  [1],
                        camVerts  [2], camVerts  [3],
                        camVerts  [4], camVerts  [5],
                        camVerts  [6], camVerts  [7] );
    sceneBB .getCorners(sceneVerts[0], sceneVerts[1],
                        sceneVerts[2], sceneVerts[3],
                        sceneVerts[4], sceneVerts[5],
                        sceneVerts[6], sceneVerts[7] );

    camVerts  [8].setValues(TypeTraits<Real>::getMax(),
                            TypeTraits<Real>::getMax(),
                            TypeTraits<Real>::getMax() );
    camVerts  [9].setValues(TypeTraits<Real>::getMin(),
                            TypeTraits<Real>::getMin(),
                            TypeTraits<Real>::getMin() );
    sceneVerts[8].setValues(TypeTraits<Real>::getMax(),
                            TypeTraits<Real>::getMax(),
                            TypeTraits<Real>::getMax() );
    sceneVerts[9].setValues(TypeTraits<Real>::getMin(),
                            TypeTraits<Real>::getMin(),
                            TypeTraits<Real>::getMin() );

    for(UInt32 i = 0; i < 8; ++i)
    {
        matWorldToLight.mult(camVerts  [i], camVerts  [i]);

        matSceneToWorld.mult(sceneVerts[i], sceneVerts[i]);
        matWorldToLight.mult(sceneVerts[i], sceneVerts[i]);

        camVerts  [8][0] = osgMin(camVerts  [8][0], camVerts  [i][0]);
        camVerts  [9][0] = osgMax(camVerts  [9][0], camVerts  [i][0]);
        camVerts  [8][1] = osgMin(camVerts  [8][1], camVerts  [i][1]);
        camVerts  [9][1] = osgMax(camVerts  [9][1], camVerts  [i][1]);

        sceneVerts[8][0] = osgMin(sceneVerts[8][0], sceneVerts[i][0]);
        sceneVerts[9][0] = osgMax(sceneVerts[9][0], sceneVerts[i][0]);
        sceneVerts[8][1] = osgMin(sceneVerts[8][1], sceneVerts[i][1]);
        sceneVerts[9][1] = osgMax(sceneVerts[9][1], sceneVerts[i][1]);
        sceneVerts[8][2] = osgMin(sceneVerts[8][2], sceneVerts[i][2]);
        sceneVerts[9][2] = osgMax(sceneVerts[9][2], sceneVerts[i][2]);
    }

    // these points are the corners of the ortho shadow view volume
    Pnt3r lightMin(osgMax(camVerts[8][0], sceneVerts[8][0]),
                   osgMax(camVerts[8][1], sceneVerts[8][1]),
                   -sceneVerts[9][2]);

    Pnt3r lightMax(osgMin(camVerts[9][0], sceneVerts[9][0]),
                   osgMin(camVerts[9][1], sceneVerts[9][1]),
                   -sceneVerts[8][2]);

    // enlarge by 2% in x, y, z direction
    lightMin[0] -= (lightMax[0] - lightMin[0]) * 0.01f;
    lightMin[1] -= (lightMax[1] - lightMin[1]) * 0.01f;
    lightMin[2] -= (lightMax[2] - lightMin[2]) * 0.01f;

    lightMax[0] += (lightMax[0] - lightMin[0]) * 0.01f;
    lightMax[1] += (lightMax[1] - lightMin[1]) * 0.01f;
    lightMax[2] += (lightMax[2] - lightMin[2]) * 0.01f;

    Matrixr matLightProj;
    Matrixr matLightProjTrans;

    MatrixOrthogonal(matLightProj,
                     lightMin[0], lightMax[0],
                     lightMin[1], lightMax[1],
                     lightMin[2], lightMax[2] );

    updateShadowTexImage  (data);
    updateShadowTexBuffers(data);
    updateRenderTargets   (data);

    Int32 shadowTexUnit = (this->getForceTextureUnit() > 0) ?
                          this->getForceTextureUnit()      : 7;

    ShaderProgram *shadowFP = this->getShadowFragmentProgram();

    if(shadowFP == NULL)
    {
        ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal();
        newShadowFP->setShaderType(GL_FRAGMENT_SHADER);
        newShadowFP->setProgram   (_dirFPCode        );

        newShadowFP->addUniformVariable("SSME_matEyeToLight", matEyeToLight);
        newShadowFP->addUniformVariable("SSME_matLightProj",  matLightProj );
        newShadowFP->addUniformVariable("SSME_texShadow",     shadowTexUnit);

        this->setShadowFragmentProgram(newShadowFP);
        shadowFP = newShadowFP;
    }
    else
    {
        shadowFP->updateUniformVariable("SSME_matEyeToLight", matEyeToLight);
        shadowFP->updateUniformVariable("SSME_matLightProj",  matLightProj );
    }

    commitChanges();

    this->pushPartition(ract);
    {
        RenderPartition   *part   = ract->getActivePartition( );
        Window            *win    = ract->getWindow         ( );
        FrameBufferObject *target = data->getRenderTargets  (0);
        Background        *back   = data->getBackground     ( );

        part->setRenderTarget(target);
        part->setWindow      (win   );

        part->calcViewportDimension(0.f, 0.f, 1.f, 1.f,
                                    target->getWidth (),
                                    target->getHeight() );

        part->setupProjection(matLightProj, matLightProjTrans);
        part->setupViewing   (matWorldToLight                );

        part->setNear        (parentPart->getNear());
        part->setFar         (parentPart->getFar ());

        part->calcFrustum    (                     );

        part->setBackground  (back                 );

        // force material for shadow map generation
        part->overrideMaterial(data->getLightPassMaterials(0),
                               ract->getActNode           ( ) );

        this->recurseFrom(ract, dirL);
        ract->useNodeList(false     );

        // undo override
        part->overrideMaterial(NULL,
                               ract->getActNode           ( ) );
    }
    this->popPartition(ract);
}