OSGShaderShadowMapEngine.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *                  Copyright (C) 2009 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038
00039 //---------------------------------------------------------------------------
00040 //  Includes
00041 //---------------------------------------------------------------------------
00042
00043 #include <cstdlib>
00044 #include <cstdio>
00045
00046 #include "OSGConfig.h"
00047
00048 #include "OSGShaderShadowMapEngine.h"
00049
00050 #include "OSGMatrixUtility.h"
00051 #include "OSGSolidBackground.h"
00052 #include "OSGColorMaskChunk.h"
00053 #include "OSGMaterialChunk.h"
00054 #include "OSGPolygonChunk.h"
00055 #include "OSGShaderProgram.h"
00056
00057 #include "OSGBlendChunk.h"
00058 #include "OSGDepthChunk.h"
00059
00060 #include "OSGGL.h"
00061
00062 #include <boost/cast.hpp>
00063
00064 #include <strstream>
00065
00066 OSG_BEGIN_NAMESPACE
00067
00068 // Documentation for this class is emitted in the
00069 // OSGShaderShadowMapEngineBase.cpp file.
00070 // To modify it, please change the .fcd file (OSGShaderShadowMapEngine.fcd) and
00071 // regenerate the base file.
00072
00073 /***************************************************************************\
00074  *                           Class variables                               *
00075 \***************************************************************************/
00076
00077 const Matrixr ShaderShadowMapEngine::_matCubeFaceInv[6] =
00078     {
00079         Matrixr( 1,  0,  0,  0,   // + Z
00080                  0, -1,  0,  0,
00081                  0,  0, -1,  0,
00082                  0,  0,  0,  1),
00083
00084         Matrixr(-1,  0,  0,  0,   // - Z
00085                  0, -1,  0,  0,
00086                  0,  0,  1,  0,
00087                  0,  0,  0,  1),
00088
00089         Matrixr( 1,  0,  0,  0,   // + Y
00090                  0,  0,  1,  0,
00091                  0, -1,  0,  0,
00092                  0,  0,  0,  1),
00093
00094         Matrixr( 1,  0,  0,  0,   // - Y
00095                  0,  0, -1,  0,
00096                  0,  1,  0,  0,
00097                  0,  0,  0,  1),
00098
00099         Matrixr( 0,  0, -1,  0,   // + X
00100                  0, -1,  0,  0,
00101                 -1,  0,  0,  0,
00102                  0,  0,  0,  1),
00103
00104         Matrixr( 0,  0,  1,  0,   // - X
00105                  0, -1,  0,  0,
00106                  1,  0,  0,  0,
00107                  0,  0,  0,  1),
00108     };
00109
00110 const GLenum ShaderShadowMapEngine::_cubeFaceTargets[6] =
00111     {
00112         GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
00113         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
00114         GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
00115         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
00116         GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
00117         GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
00118     };
00119
00120 const std::string ShaderShadowMapEngine::_pointFPCode(
00121     "#version 120\n"
00122     "\n"
00123     "#extension GL_EXT_gpu_shader4 : require\n"
00124     "#extension GL_EXT_gpu_shader4 : enable\n"
00125     "\n"
00126     "uniform samplerCubeShadow SSME_texShadow;\n"
00127     "\n"
00128     "uniform mat4              SSME_matEyeToLight;\n"
00129     "uniform mat4              SSME_matLightProj;\n"
00130     "\n"
00131     "vec4 OSG_SSME_FP_calcShadow(in vec4 ecFragPos)\n"
00132     "{\n"
00133     "    vec4 shadow   = vec4(0., 0., 0., 0.);\n"
00134     "    vec4 lcPos    = SSME_matEyeToLight * ecFragPos;\n"
00135     "    vec4 lcAbsPos = abs(lcPos);\n"
00136     "    vec4 plcPos;\n"
00137     "\n"
00138     "    if(lcAbsPos.x > lcAbsPos.y && lcAbsPos.x > lcAbsPos.z)\n"
00139     "    {\n"
00140     "        if(lcPos.x >= 0.)\n"
00141     "            plcPos = vec4(-1, -1, -1, 1) * lcPos.zyxw;\n"
00142     "        else\n"
00143     "            plcPos = vec4( 1, -1,  1, 1) * lcPos.zyxw;\n"
00144     "    }\n"
00145     "    else if(lcAbsPos.y > lcAbsPos.x && lcAbsPos.y > lcAbsPos.z)\n"
00146     "    {\n"
00147     "        if(lcPos.y >= 0.)\n"
00148     "            plcPos = vec4( 1,  1, -1, 1) * lcPos.xzyw;\n"
00149     "        else\n"
00150     "            plcPos = vec4( 1, -1,  1, 1) * lcPos.xzyw;\n"
00151     "    }\n"
00152     "    else\n"
00153     "    {\n"
00154     "        if(lcPos.z >= 0.)\n"
00155     "            plcPos = vec4( 1, -1, -1, 1) * lcPos;\n"
00156     "        else\n"
00157     "            plcPos = vec4(-1, -1,  1, 1) * lcPos;\n"
00158     "    }\n"
00159     "\n"
00160     "    plcPos = SSME_matLightProj * plcPos;\n"
00161     "    plcPos = plcPos / plcPos.w;\n"
00162     "    plcPos = 0.5 + 0.5 * plcPos;\n"
00163     "\n"
00164     "    shadow = shadowCube(SSME_texShadow, vec4(lcPos.xyz, plcPos.z));\n"
00165     "\n"
00166     "    return shadow;\n"
00167     "}\n");
00168
00169 const std::string ShaderShadowMapEngine::_dirFPCode(
00170     "#version 120\n"
00171     "\n"
00172     "uniform sampler2DShadow   SSME_texShadow;\n"
00173     "\n"
00174     "uniform mat4              SSME_matEyeToLight;\n"
00175     "uniform mat4              SSME_matLightProj;\n"
00176     "\n"
00177     "vec4 OSG_SSME_FP_calcShadow(in vec4 ecFragPos)\n"
00178     "{\n"
00179     "    vec4 lcPos    = SSME_matEyeToLight * ecFragPos;\n"
00180     "    vec4 plcPos   = SSME_matLightProj  * lcPos;\n"
00181     "\n"
00182     "    plcPos = plcPos / plcPos.w;\n"
00183     "    plcPos = 0.5 + 0.5 * plcPos;\n"
00184     "\n"
00185     "    return shadow2D(SSME_texShadow, plcPos.xyz);\n"
00186     "}\n");
00187
00188 const std::string ShaderShadowMapEngine::_spotFPCode(
00189     "#version 120\n"
00190     "\n"
00191     "uniform sampler2DShadow   SSME_texShadow;\n"
00192     "\n"
00193     "uniform mat4              SSME_matEyeToLight;\n"
00194     "uniform mat4              SSME_matLightProj;\n"
00195     "\n"
00196     "vec4 OSG_SSME_FP_calcShadow(in vec4 ecFragPos)\n"
00197     "{\n"
00198     "    vec4 lcPos  = SSME_matEyeToLight * ecFragPos;\n"
00199     "    vec4 plcPos = SSME_matLightProj  * lcPos;\n"
00200     "\n"
00201     "    plcPos      = plcPos / plcPos.w;\n"
00202     "    plcPos      = 0.5 + 0.5 * plcPos;\n"
00203     "\n"
00204     "    return shadow2D(SSME_texShadow, plcPos.xyz);\n"
00205     "}\n");
00206
00207 /***************************************************************************\
00208  *                           Class methods                                 *
00209 \***************************************************************************/
00210
00211 void ShaderShadowMapEngine::initMethod(InitPhase ePhase)
00212 {
00213     Inherited::initMethod(ePhase);
00214 }
00215
00216
00217 /***************************************************************************\
00218  *                           Instance methods                              *
00219 \***************************************************************************/
00220
00221 /*-------------------------------------------------------------------------*\
00222  -  private                                                                 -
00223 \*-------------------------------------------------------------------------*/
00224
00225 /*----------------------- constructors & destructors ----------------------*/
00226
00227 ShaderShadowMapEngine::ShaderShadowMapEngine(void) :
00228     Inherited()
00229 {
00230 }
00231
00232 ShaderShadowMapEngine::ShaderShadowMapEngine(const ShaderShadowMapEngine &source) :
00233     Inherited(source)
00234 {
00235 }
00236
00237 ShaderShadowMapEngine::~ShaderShadowMapEngine(void)
00238 {
00239 }
00240
00241 /*----------------------------- class specific ----------------------------*/
00242
00243 ActionBase::ResultE ShaderShadowMapEngine::runOnEnter(
00244     Light *light, LightTypeE eType, RenderAction *ract)
00245 {
00246     BitVector      bvMask = ract->getPassMask             (            );
00247     SSMEngineData *data   = ract->getData<SSMEngineData *>(_iDataSlotId);
00248
00249     if(data == NULL)
00250     {
00251         SSMEngineDataUnrecPtr newData = SSMEngineData::createLocal();
00252         this->setData(newData, _iDataSlotId, ract);
00253
00254         data = newData;
00255     }
00256
00257     if(0x0000 != bvMask)
00258     {
00259         // already generating a shadow map for another light source
00260         if(0x0000 != (bvMask & bvLightPassMask))
00261         {
00262             this->recurseFrom(ract, light);
00263
00264             handleEnter(light, eType, ract, data);
00265         }
00266     }
00267     else
00268     {
00269         // first light source to generate a shadow map
00270         ract->addPassMask(bvLightPassMask);
00271             handleEnter(light, eType, ract, data);
00272         ract->subPassMask(bvLightPassMask);
00273     }
00274
00275     // continue rendering normally
00276     return Action::Continue;
00277 }
00278
00279 ActionBase::ResultE ShaderShadowMapEngine::runOnLeave(
00280     Light *light, LightTypeE eType, RenderAction *ract)
00281 {
00282     return Action::Continue;
00283 }
00284
00285 void ShaderShadowMapEngine::changed(ConstFieldMaskArg whichField,
00286                                     UInt32            origin,
00287                                     BitVector         details)
00288 {
00289     Inherited::changed(whichField, origin, details);
00290 }
00291
00292 void ShaderShadowMapEngine::dump(      UInt32    ,
00293                          const BitVector ) const
00294 {
00295     SLOG << "Dump ShaderShadowMapEngine NI" << std::endl;
00296 }
00297
00298 void ShaderShadowMapEngine::handleEnter(
00299     Light *light, LightTypeE eType, RenderAction *ract, SSMEngineData *data)
00300 {
00301     updateShadowTexChunk   (data);
00302     updateLightPassMaterial(data);
00303     updateBackground       (data);
00304
00305     UInt32 parentTravMask = ract->getTravMask();
00306     ract->setTravMask(_sfShadowTravMask.getValue());
00307
00308     // call specific handler for light type
00309     switch(eType)
00310     {
00311     case Point:
00312     {
00313         PointLight *pointL =
00314             boost::polymorphic_downcast<PointLight *>(light);
00315
00316         handlePointLightEnter(pointL, ract, data);
00317     }
00318     break;
00319
00320     case Directional:
00321     {
00322         DirectionalLight *dirL =
00323             boost::polymorphic_downcast<DirectionalLight *>(light);
00324
00325         handleDirectionalLightEnter(dirL, ract, data);
00326     }
00327     break;
00328
00329     case Spot:
00330     {
00331         SpotLight *spotL =
00332             boost::polymorphic_downcast<SpotLight *>(light);
00333
00334         handleSpotLightEnter(spotL, ract, data);
00335     }
00336     break;
00337
00338     default:
00339     {
00340         FWARNING(("ShaderShadowMapEngine::handleEnter: Unknown "
00341                   "light type [%u]\n", eType));
00342     }
00343     break;
00344     }
00345
00346     ract->setTravMask(parentTravMask);
00347 }
00348
00349 void ShaderShadowMapEngine::handlePointLightEnter(
00350     PointLight *pointL, RenderAction *ract, SSMEngineData *data)
00351 {
00352     RenderPartition *parentPart = ract->getActivePartition();
00353
00354     Matrixr matEyeToWorld(parentPart->getCameraToWorld());
00355     Matrixr matLightProj;
00356
00357     Real    lightNear;
00358     Real    lightFar;
00359
00360     calcPointLightRange(pointL, 0.001f,
00361                         parentPart->getNear(), parentPart->getFar(),
00362                         lightNear,             lightFar             );
00363
00364     MatrixPerspective(matLightProj, Pi / 4.f, 1.f,
00365                       lightNear, lightFar         );
00366
00367     Matrixr matWorldToLight;
00368     Matrixr matEyeToLight;
00369
00370     calcPointLightMatrices(matWorldToLight, matEyeToLight,
00371                            pointL,          matEyeToWorld );
00372
00373     updatePointLightShadowTexImage  (data);
00374     updatePointLightShadowTexBuffers(data);
00375     updatePointLightRenderTargets   (data);
00376
00377     Int32 shadowTexUnit = (this->getForceTextureUnit() > 0) ?
00378                            this->getForceTextureUnit()      : 7;
00379
00380     ShaderProgram *shadowFP = this->getShadowFragmentProgram();
00381
00382     if(shadowFP == NULL)
00383     {
00384         ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal();
00385         newShadowFP->setShaderType(GL_FRAGMENT_SHADER);
00386         newShadowFP->setProgram   (_pointFPCode      );
00387
00388         newShadowFP->addUniformVariable("SSME_matEyeToLight", matEyeToLight);
00389         newShadowFP->addUniformVariable("SSME_matLightProj",  matLightProj );
00390         newShadowFP->addUniformVariable("SSME_texShadow",     shadowTexUnit);
00391
00392         this->setShadowFragmentProgram(newShadowFP);
00393         shadowFP = newShadowFP;
00394     }
00395     else
00396     {
00397         shadowFP->updateUniformVariable("SSME_matEyeToLight", matEyeToLight);
00398         shadowFP->updateUniformVariable("SSME_matLightProj",  matLightProj );
00399     }
00400
00401     commitChanges();
00402
00403     // schedule rendering of cube faces
00404     for(UInt16 i = 0; i < 6; ++i)
00405     {
00406         Matrixr matWorldToLightFace(matWorldToLight);
00407         matWorldToLightFace.multLeft(_matCubeFaceInv[i]);
00408
00409         ract->pushPartition();
00410         {
00411             RenderPartition   *part   = ract->getActivePartition( );
00412             Window            *win    = ract->getWindow         ( );
00413             FrameBufferObject *target = data->getRenderTargets  (i);
00414             Background        *back   = data->getBackground     ( );
00415
00416             part->setRenderTarget(target);
00417             part->setWindow      (win   );
00418
00419             part->calcViewportDimension(0.f, 0.f, 1.f, 1.f,
00420                                         target->getWidth (),
00421                                         target->getHeight() );
00422
00423             part->setupProjection(matLightProj, Matrixr::identity());
00424             part->setupViewing   (matWorldToLightFace              );
00425
00426             part->setNear        (parentPart->getNear());
00427             part->setFar         (parentPart->getFar ());
00428
00429             part->calcFrustum    (                     );
00430
00431             part->setBackground  (back                 );
00432
00433             // force material for shadow map generation
00434             part->overrideMaterial(data->getLightPassMaterials(0),
00435                                    ract->getActNode           ( ) );
00436
00437             this->recurseFrom(ract, pointL);
00438             ract->useNodeList(false       );
00439
00440             // undo override
00441             part->overrideMaterial(NULL,
00442                                    ract->getActNode           ( ) );
00443         }
00444         ract->popPartition();
00445     }
00446 }
00447
00448 void ShaderShadowMapEngine::handleDirectionalLightEnter(
00449     DirectionalLight *dirL, RenderAction *ract, SSMEngineData *data)
00450 {
00451     RenderPartition *parentPart = ract      ->getActivePartition();
00452     FrustumVolume    camFrust   = parentPart->getFrustum        ();
00453
00454     Matrixr matEyeToWorld  (parentPart->getCameraToWorld());
00455     Matrixr matWorldToLight;
00456     Matrixr matEyeToLight;
00457
00458     calcDirectionalLightMatrices(matWorldToLight, matEyeToLight,
00459                                  dirL,            matEyeToWorld );
00460
00461     // place light camera outside the scene bounding box:
00462     //  - project camera frustum and scene bounding box into a
00463     //    coordinate system where the directional light shines
00464     //    along the -z axis.
00465     //  - compute 2 AABBs that contain the projected frustum and
00466     //    scene BB
00467     //  - width and height of the ortho projection are determined from
00468     //    the frustum AABB, while near and far are determined by the
00469     //    scene AABB (offscreen objects cast shadows into the view volume)
00470           Pnt3r      camVerts  [10];
00471           Pnt3r      sceneVerts[10];
00472     const Matrix    &matSceneToWorld = ract->topMatrix ();
00473           BoxVolume  sceneBB         = ract->getActNode()->getVolume();
00474
00475     camFrust.getCorners(camVerts  [0], camVerts  [1],
00476                         camVerts  [2], camVerts  [3],
00477                         camVerts  [4], camVerts  [5],
00478                         camVerts  [6], camVerts  [7] );
00479     sceneBB .getCorners(sceneVerts[0], sceneVerts[1],
00480                         sceneVerts[2], sceneVerts[3],
00481                         sceneVerts[4], sceneVerts[5],
00482                         sceneVerts[6], sceneVerts[7] );
00483
00484     camVerts  [8].setValues(TypeTraits<Real>::getMax(),
00485                             TypeTraits<Real>::getMax(),
00486                             TypeTraits<Real>::getMax() );
00487     camVerts  [9].setValues(TypeTraits<Real>::getMin(),
00488                             TypeTraits<Real>::getMin(),
00489                             TypeTraits<Real>::getMin() );
00490     sceneVerts[8].setValues(TypeTraits<Real>::getMax(),
00491                             TypeTraits<Real>::getMax(),
00492                             TypeTraits<Real>::getMax() );
00493     sceneVerts[9].setValues(TypeTraits<Real>::getMin(),
00494                             TypeTraits<Real>::getMin(),
00495                             TypeTraits<Real>::getMin() );
00496
00497     for(UInt32 i = 0; i < 8; ++i)
00498     {
00499         matWorldToLight.mult(camVerts  [i], camVerts  [i]);
00500
00501         matSceneToWorld.mult(sceneVerts[i], sceneVerts[i]);
00502         matWorldToLight.mult(sceneVerts[i], sceneVerts[i]);
00503
00504         camVerts  [8][0] = osgMin(camVerts  [8][0], camVerts  [i][0]);
00505         camVerts  [9][0] = osgMax(camVerts  [9][0], camVerts  [i][0]);
00506         camVerts  [8][1] = osgMin(camVerts  [8][1], camVerts  [i][1]);
00507         camVerts  [9][1] = osgMax(camVerts  [9][1], camVerts  [i][1]);
00508
00509         sceneVerts[8][0] = osgMin(sceneVerts[8][0], sceneVerts[i][0]);
00510         sceneVerts[9][0] = osgMax(sceneVerts[9][0], sceneVerts[i][0]);
00511         sceneVerts[8][1] = osgMin(sceneVerts[8][1], sceneVerts[i][1]);
00512         sceneVerts[9][1] = osgMax(sceneVerts[9][1], sceneVerts[i][1]);
00513         sceneVerts[8][2] = osgMin(sceneVerts[8][2], sceneVerts[i][2]);
00514         sceneVerts[9][2] = osgMax(sceneVerts[9][2], sceneVerts[i][2]);
00515     }
00516
00517     // these points are the corners of the ortho shadow view volume
00518     Pnt3r lightMin(osgMax(camVerts[8][0], sceneVerts[8][0]),
00519                    osgMax(camVerts[8][1], sceneVerts[8][1]),
00520                    -sceneVerts[9][2]);
00521
00522     Pnt3r lightMax(osgMin(camVerts[9][0], sceneVerts[9][0]),
00523                    osgMin(camVerts[9][1], sceneVerts[9][1]),
00524                    -sceneVerts[8][2]);
00525
00526     // enlarge by 2% in x, y, z direction
00527     lightMin[0] -= (lightMax[0] - lightMin[0]) * 0.01f;
00528     lightMin[1] -= (lightMax[1] - lightMin[1]) * 0.01f;
00529     lightMin[2] -= (lightMax[2] - lightMin[2]) * 0.01f;
00530
00531     lightMax[0] += (lightMax[0] - lightMin[0]) * 0.01f;
00532     lightMax[1] += (lightMax[1] - lightMin[1]) * 0.01f;
00533     lightMax[2] += (lightMax[2] - lightMin[2]) * 0.01f;
00534
00535     Matrixr matLightProj;
00536     Matrixr matLightProjTrans;
00537
00538     MatrixOrthogonal(matLightProj,
00539                      lightMin[0], lightMax[0],
00540                      lightMin[1], lightMax[1],
00541                      lightMin[2], lightMax[2] );
00542
00543     updateShadowTexImage  (data);
00544     updateShadowTexBuffers(data);
00545     updateRenderTargets   (data);
00546
00547     Int32 shadowTexUnit = (this->getForceTextureUnit() > 0) ?
00548                            this->getForceTextureUnit()      : 7;
00549
00550     ShaderProgram *shadowFP = this->getShadowFragmentProgram();
00551
00552     if(shadowFP == NULL)
00553     {
00554         ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal();
00555         newShadowFP->setShaderType(GL_FRAGMENT_SHADER);
00556         newShadowFP->setProgram   (_dirFPCode        );
00557
00558         newShadowFP->addUniformVariable("SSME_matEyeToLight", matEyeToLight);
00559         newShadowFP->addUniformVariable("SSME_matLightProj",  matLightProj );
00560         newShadowFP->addUniformVariable("SSME_texShadow",     shadowTexUnit);
00561
00562         this->setShadowFragmentProgram(newShadowFP);
00563         shadowFP = newShadowFP;
00564     }
00565     else
00566     {
00567         shadowFP->updateUniformVariable("SSME_matEyeToLight", matEyeToLight);
00568         shadowFP->updateUniformVariable("SSME_matLightProj",  matLightProj );
00569     }
00570
00571     commitChanges();
00572
00573     ract->pushPartition();
00574     {
00575         RenderPartition   *part   = ract->getActivePartition( );
00576         Window            *win    = ract->getWindow         ( );
00577         FrameBufferObject *target = data->getRenderTargets  (0);
00578         Background        *back   = data->getBackground     ( );
00579
00580         part->setRenderTarget(target);
00581         part->setWindow      (win   );
00582
00583         part->calcViewportDimension(0.f, 0.f, 1.f, 1.f,
00584                                     target->getWidth (),
00585                                     target->getHeight() );
00586
00587         part->setupProjection(matLightProj, matLightProjTrans);
00588         part->setupViewing   (matWorldToLight                );
00589
00590         part->setNear        (parentPart->getNear());
00591         part->setFar         (parentPart->getFar ());
00592
00593         part->calcFrustum    (                     );
00594
00595         part->setBackground  (back                 );
00596
00597         // force material for shadow map generation
00598         part->overrideMaterial(data->getLightPassMaterials(0),
00599                                ract->getActNode           ( ) );
00600
00601         this->recurseFrom(ract, dirL);
00602         ract->useNodeList(false     );
00603
00604         // undo override
00605         part->overrideMaterial(NULL,
00606                                ract->getActNode           ( ) );
00607     }
00608     ract->popPartition();
00609 }
00610
00611 void ShaderShadowMapEngine::handleSpotLightEnter(
00612     SpotLight *spotL, RenderAction *ract, SSMEngineData *data)
00613 {
00614     RenderPartition *parentPart    = ract->getActivePartition();
00615 //    Real             cosSpotCutOff = osgCos(spotL->getSpotCutOff());
00616
00617     Matrixr matEyeToWorld  (parentPart->getCameraToWorld());
00618     Matrixr matWorldToLight;
00619     Matrixr matEyeToLight;
00620
00621     calcSpotLightMatrices(matWorldToLight, matEyeToLight,
00622                           spotL,           matEyeToWorld );
00623
00624     Real    lightNear;
00625     Real    lightFar;
00626
00627     calcPointLightRange(spotL, 0.001f,
00628                         parentPart->getNear(), parentPart->getFar(),
00629                         lightNear,             lightFar             );
00630
00631     if(getShadowNear() != 0.f)
00632     {
00633         lightNear = getShadowNear();
00634     }
00635
00636     if(getShadowFar() != 0.f)
00637     {
00638         lightFar  = getShadowFar();
00639     }
00640
00641     Matrixr matLightProj;
00642     Matrixr matLightProjTrans;
00643
00644     MatrixPerspective(matLightProj,
00645                       spotL->getSpotCutOff(), 1.f,
00646                       lightNear, lightFar         );
00647
00648     updateShadowTexImage  (data);
00649     updateShadowTexBuffers(data);
00650     updateRenderTargets   (data);
00651
00652     Int32          shadowTexUnit = (this->getForceTextureUnit() > 0) ?
00653                                     this->getForceTextureUnit()      : 7;
00654     ShaderProgram *shadowFP      = this->getShadowFragmentProgram();
00655
00656     if(shadowFP == NULL)
00657     {
00658         ShaderProgramUnrecPtr newShadowFP = ShaderProgram::createLocal();
00659         newShadowFP->setShaderType(GL_FRAGMENT_SHADER);
00660         newShadowFP->setProgram   (_spotFPCode       );
00661
00662         newShadowFP->addUniformVariable("SSME_matEyeToLight", matEyeToLight);
00663         newShadowFP->addUniformVariable("SSME_matLightProj",  matLightProj );
00664         newShadowFP->addUniformVariable("SSME_texShadow",     shadowTexUnit);
00665
00666         this->setShadowFragmentProgram(newShadowFP);
00667         shadowFP = newShadowFP;
00668     }
00669     else
00670     {
00671         shadowFP->updateUniformVariable("SSME_matEyeToLight", matEyeToLight);
00672         shadowFP->updateUniformVariable("SSME_matLightProj",  matLightProj );
00673     }
00674
00675     commitChanges();
00676
00677     ract->pushPartition();
00678     {
00679         RenderPartition   *part   = ract->getActivePartition( );
00680         Window            *win    = ract->getWindow         ( );
00681         FrameBufferObject *target = data->getRenderTargets  (0);
00682         Background        *back   = data->getBackground     ( );
00683
00684         part->setRenderTarget(target);
00685         part->setWindow      (win   );
00686
00687         part->calcViewportDimension(0.f, 0.f, 1.f, 1.f,
00688                                     target->getWidth (),
00689                                     target->getHeight() );
00690
00691         part->setupProjection(matLightProj, matLightProjTrans);
00692         part->setupViewing   (matWorldToLight                );
00693
00694         part->setNear        (parentPart->getNear());
00695         part->setFar         (parentPart->getFar ());
00696
00697         part->calcFrustum    (                     );
00698
00699         part->setBackground  (back                 );
00700
00701         // force material for shadow map generation
00702         part->overrideMaterial(data->getLightPassMaterials(0),
00703                                ract->getActNode           ( ) );
00704
00705         this->recurseFrom(ract, spotL);
00706         ract->useNodeList(false      );
00707
00708         // undo override
00709         part->overrideMaterial(NULL,
00710                                ract->getActNode           ( ) );
00711     }
00712     ract->popPartition();
00713 }
00714
00718 void ShaderShadowMapEngine::calcDirectionalLightMatrices(
00719           Matrixr          &matWorldToLight,
00720           Matrixr          &matEyeToLight,
00721     const DirectionalLight *dirL,
00722     const Matrixr          &matEyeToWorld)
00723 {
00724     if(dirL->getBeacon() != NULL)
00725         dirL->getBeacon()->getToWorld(matWorldToLight);
00726
00727     Quaternion rotLightDir  (Vec3r(0.f, 0.f, 1.f), dirL->getDirection());
00728     Matrixr    matLightDir;
00729     matLightDir.setRotate(rotLightDir);
00730
00731     matWorldToLight.mult  (matLightDir);
00732     matWorldToLight.invert(           );
00733
00734     matEyeToLight = matWorldToLight;
00735     matEyeToLight.mult(matEyeToWorld);
00736 }
00737
00738 void ShaderShadowMapEngine::calcPointLightMatrices(
00739           Matrixr    &matWorldToLight,
00740           Matrixr    &matEyeToLight,
00741     const PointLight *pointL,
00742     const Matrixr    &matEyeToWorld)
00743 {
00744     if(pointL->getBeacon() != NULL)
00745         pointL->getBeacon()->getToWorld(matWorldToLight);
00746
00747     Matrixr matLightPos;
00748     matLightPos    .setTranslate(pointL->getPosition());
00749     matWorldToLight.mult        (matLightPos          );
00750     matWorldToLight.invert      (                     );
00751
00752     matEyeToLight = matWorldToLight;
00753     matEyeToLight.mult(matEyeToWorld);
00754 }
00755
00759 void ShaderShadowMapEngine::calcSpotLightMatrices(
00760           Matrixr   &matWorldToLight,
00761           Matrixr   &matEyeToLight,
00762     const SpotLight *spotL,
00763     const Matrixr   &matEyeToWorld)
00764 {
00765     if(spotL->getBeacon() != NULL)
00766         spotL->getBeacon()->getToWorld(matWorldToLight);
00767
00768     Matrixr matLightPos;
00769     matLightPos.setTranslate(spotL->getPosition());
00770
00771     Matrixr    matLightDir;
00772     Quaternion rotLightDir(Vec3r(0.f, 0.f, 1.f), -spotL->getDirection());
00773     matLightDir.setRotate(rotLightDir);
00774
00775     matWorldToLight.mult  (matLightPos);
00776     matWorldToLight.mult  (matLightDir);
00777     matWorldToLight.invert(           );
00778
00779     matEyeToLight = matWorldToLight;
00780     matEyeToLight.mult(matEyeToWorld);
00781 }
00782
00783 void ShaderShadowMapEngine::calcPointLightRange(
00784     const PointLight *pointL,      Real  lightThreshold,
00785           Real        defaultNear, Real  defaultFar,
00786           Real       &outNear,     Real &outFar         )
00787 {
00788     outNear = defaultNear;
00789     outFar  = defaultFar;
00790
00791     Real kQ = pointL->getQuadraticAttenuation();
00792     Real kL = pointL->getLinearAttenuation   ();
00793     Real kC = pointL->getConstantAttenuation ();
00794
00795     if(osgAbs(kQ) > Eps)
00796     {
00797         Real det = kL * kL  - 4.f * kQ * (kC - 1.f / lightThreshold);
00798
00799         if(det >= 0)
00800         {
00801             det     = osgSqrt(det);
00802             Real r1 = - kL + det / (2.f * kQ);
00803             Real r2 = - kL - det / (2.f * kQ);
00804
00805             if(r1 > 0.f && r2 > 0.f)
00806             {
00807                 outFar = osgMin(r1, r2);
00808             }
00809             else if(r1 > 0.f)
00810             {
00811                 outFar = r1;
00812             }
00813             else if(r2 > 0.f)
00814             {
00815                 outFar = r2;
00816             }
00817         }
00818     }
00819     else if(osgAbs(kL) > Eps)
00820     {
00821         Real r = (1.f / lightThreshold - kC) / kL;
00822
00823         if(r > 0.f)
00824         {
00825             outFar = r;
00826         }
00827     }
00828 }
00829
00830 void ShaderShadowMapEngine::updateShadowTexChunk(SSMEngineData *data)
00831 {
00832     TextureObjChunk *bufTex = data->getShadowTexChunk();
00833
00834     if(bufTex == NULL)
00835     {
00836         TextureObjChunkUnrecPtr newBufTex = TextureObjChunk::createLocal();
00837         newBufTex->setMinFilter     (GL_LINEAR              );
00838         newBufTex->setMagFilter     (GL_LINEAR              );
00839         newBufTex->setWrapS         (GL_CLAMP_TO_EDGE       );
00840         newBufTex->setWrapT         (GL_CLAMP_TO_EDGE       );
00841         newBufTex->setWrapR         (GL_CLAMP_TO_EDGE       );
00842         newBufTex->setScale         (false                  );
00843         newBufTex->setInternalFormat(GL_DEPTH_COMPONENT24   );
00844         newBufTex->setExternalFormat(GL_DEPTH_COMPONENT     );
00845         newBufTex->setCompareMode   (GL_COMPARE_R_TO_TEXTURE);
00846         newBufTex->setCompareFunc   (GL_LESS                );
00847         newBufTex->setDepthMode     (GL_LUMINANCE           );
00848
00849         data->setShadowTexChunk(newBufTex);
00850         this->setShadowTexChunk(newBufTex);
00851     }
00852 }
00853
00854 void ShaderShadowMapEngine::updateLightPassMaterial(SSMEngineData *data)
00855 {
00856     if(data->getMFLightPassMaterials()->empty() == true)
00857     {
00858         MaterialChunkUnrecPtr newMatChunk = MaterialChunk::createLocal();
00859         newMatChunk->setLit          (false  );
00860         newMatChunk->setColorMaterial(GL_NONE);
00861
00862         ColorMaskChunkUnrecPtr newCMaskChunk = ColorMaskChunk::create();
00863         newCMaskChunk->setMaskR(false);
00864         newCMaskChunk->setMaskG(false);
00865         newCMaskChunk->setMaskB(false);
00866         newCMaskChunk->setMaskA(false);
00867
00868         PolygonChunkUnrecPtr newPolyChunk = PolygonChunk::createLocal();
00869         newPolyChunk->setOffsetFill  (true                   );
00870         newPolyChunk->setOffsetFactor(this->getOffsetFactor());
00871         newPolyChunk->setOffsetBias  (this->getOffsetBias  ());
00872
00873         ChunkMaterialUnrecPtr newLightPassMat = ChunkMaterial::createLocal();
00874         newLightPassMat->addChunk(newMatChunk  );
00875         newLightPassMat->addChunk(newCMaskChunk);
00876         newLightPassMat->addChunk(newPolyChunk );
00877
00878         data->editMFLightPassMaterials()->push_back(newLightPassMat);
00879     }
00880 }
00881
00882 void ShaderShadowMapEngine::updateBackground(SSMEngineData *data)
00883 {
00884     Background *back = data->getBackground();
00885
00886     if(back == NULL)
00887     {
00888         SolidBackgroundUnrecPtr newBack = SolidBackground::createLocal();
00889         newBack->setClearColor(false);
00890
00891         data->setBackground(newBack);
00892     }
00893 }
00894
00895 void ShaderShadowMapEngine::updatePointLightShadowTexImage(SSMEngineData *data)
00896 {
00897     Image           *bufImg = data->getShadowTexImage();
00898     TextureObjChunk *bufTex = data->getShadowTexChunk();
00899
00900     FASSERT((bufTex != NULL), false)
00901
00902     if(bufImg == NULL)
00903     {
00904         ImageUnrecPtr newBufImg = Image::createLocal();
00905         newBufImg->set(Image::OSG_L_PF,
00906                        this->getWidth (),
00907                        this->getHeight(),
00908                        1,
00909                        1,
00910                        1,
00911                        0.,
00912                        NULL,
00913                        Image::OSG_UINT8_IMAGEDATA,
00914                        false,
00915                        6);
00916
00917         bufTex->setImage         (newBufImg);
00918         data  ->setShadowTexImage(newBufImg);
00919
00920         bufImg = newBufImg;
00921     }
00922
00923     if((bufImg->getWidth () != this->getWidth ()) ||
00924        (bufImg->getHeight() != this->getHeight())   )
00925     {
00926         bufImg->setWidth (this->getWidth ());
00927         bufImg->setHeight(this->getHeight());
00928     }
00929 }
00930
00931 void ShaderShadowMapEngine::updateShadowTexImage(SSMEngineData *data)
00932 {
00933     Image           *bufImg = data->getShadowTexImage();
00934     TextureObjChunk *bufTex = data->getShadowTexChunk();
00935
00936     FASSERT((bufTex != NULL), false)
00937
00938     if(bufImg == NULL)
00939     {
00940         ImageUnrecPtr newBufImg = Image::createLocal();
00941         newBufImg->set(Image::OSG_L_PF,
00942                        this->getWidth (),
00943                        this->getHeight(),
00944                        1,
00945                        1,
00946                        1,
00947                        0.,
00948                        NULL,
00949                        Image::OSG_UINT8_IMAGEDATA,
00950                        false,
00951                        1);
00952
00953         bufTex->setImage         (newBufImg);
00954         data  ->setShadowTexImage(newBufImg);
00955
00956         bufImg = newBufImg;
00957     }
00958
00959     if((bufImg->getWidth () != this->getWidth ()) ||
00960        (bufImg->getHeight() != this->getHeight())   )
00961     {
00962         bufImg->setWidth (this->getWidth ());
00963         bufImg->setHeight(this->getHeight());
00964     }
00965 }
00966
00967 void ShaderShadowMapEngine::updatePointLightShadowTexBuffers(
00968     SSMEngineData *data)
00969 {
00970     TextureObjChunk *bufTex = data->getShadowTexChunk();
00971
00972     if(data->getMFShadowTexBuffers()->empty() == true)
00973     {
00974         for(UInt16 i = 0; i < 6; ++i)
00975         {
00976             TextureBufferUnrecPtr newBuf = TextureBuffer::createLocal();
00977             newBuf->setTexture  (bufTex             );
00978             newBuf->setTexTarget(_cubeFaceTargets[i]);
00979
00980             data->editMFShadowTexBuffers()->push_back(newBuf);
00981         }
00982     }
00983 }
00984
00985 void ShaderShadowMapEngine::updateShadowTexBuffers(SSMEngineData *data)
00986 {
00987     TextureObjChunk *bufTex = data->getShadowTexChunk();
00988
00989     if(data->getMFShadowTexBuffers()->empty() == true)
00990     {
00991         TextureBufferUnrecPtr newBuf = TextureBuffer::createLocal();
00992         newBuf->setTexture  (bufTex       );
00993         newBuf->setTexTarget(GL_TEXTURE_2D);
00994
00995         data->editMFShadowTexBuffers()->push_back(newBuf);
00996     }
00997 }
00998
00999 void ShaderShadowMapEngine::updatePointLightRenderTargets(SSMEngineData *data)
01000 {
01001     if(data->getMFRenderTargets()->empty() == true)
01002     {
01003         for(UInt16 i = 0; i < 6; ++i)
01004         {
01005             FrameBufferObjectUnrecPtr newTarget =
01006                 FrameBufferObject::createLocal();
01007             newTarget->setWidth          (this->getWidth           ( ));
01008             newTarget->setHeight         (this->getHeight          ( ));
01009             newTarget->setDepthAttachment(data->getShadowTexBuffers(i));
01010
01011             data->editMFRenderTargets()->push_back(newTarget);
01012         }
01013     }
01014     else
01015     {
01016         for(UInt16 i = 0; i < 6; ++i)
01017         {
01018             FrameBufferObject *target = data->getRenderTargets(i);
01019
01020             if((target->getWidth () != this->getWidth ()) ||
01021                (target->getHeight() != this->getHeight())   )
01022             {
01023                 target->setWidth (this->getWidth ());
01024                 target->setHeight(this->getHeight());
01025             }
01026         }
01027     }
01028 }
01029
01030 void ShaderShadowMapEngine::updateRenderTargets(SSMEngineData *data)
01031 {
01032     if(data->getMFRenderTargets()->empty() == true)
01033     {
01034         FrameBufferObjectUnrecPtr newTarget =
01035             FrameBufferObject::createLocal();
01036         newTarget->setWidth          (this->getWidth           ( ));
01037         newTarget->setHeight         (this->getHeight          ( ));
01038         newTarget->setDepthAttachment(data->getShadowTexBuffers(0));
01039
01040         data->editMFRenderTargets()->push_back(newTarget);
01041     }
01042     else
01043     {
01044         FrameBufferObject *target = data->getRenderTargets(0);
01045
01046         if((target->getWidth () != this->getWidth ()) ||
01047            (target->getHeight() != this->getHeight())   )
01048         {
01049             target->setWidth (this->getWidth ());
01050             target->setHeight(this->getHeight());
01051         }
01052     }
01053 }
01054
01055 OSG_END_NAMESPACE