void TrapezoidalShadowMapEngine::handleSpotLightEnter( SpotLight *spotL, RenderAction *ract, TSMEngineData *data) { RenderPartition *parentPart = ract->getActivePartition(); Matrixr matEyeToWorld(parentPart->getCameraToWorld()); Matrixr matWorldToLight; Matrixr matEyeToLight; Inherited::calcSpotLightMatrices(matWorldToLight, matEyeToLight, spotL, matEyeToWorld ); Matrixr matLightProj; Matrixr matLightFull(matWorldToLight); Real shadowNear = (getShadowNear() != 0.f ? getShadowNear() : parentPart->getNear() ); Real shadowFar = (getShadowFar () != 0.f ? getShadowFar () : parentPart->getFar() ); Inherited::calcPointLightRange( spotL, 0.01f, shadowNear, shadowFar, shadowNear, shadowFar); MatrixPerspective(matLightProj, spotL->getSpotCutOff(), 1.f, shadowNear, shadowFar ); matLightFull.multLeft(matLightProj); Inherited::updateShadowTexImage (data); Inherited::updateShadowTexBuffers(data); Inherited::updateRenderTargets (data); const FrustumVolume &eyeFrust = parentPart->getFrustum(); FrustumVolume lightFrust; Matrixr matNT; lightFrust.setPlanes(matLightFull); bool matNTValid = calcTrapezoidalTransform(matNT, matEyeToWorld, matLightFull, eyeFrust, lightFrust ); if(matNTValid == false) return; // Real cosSpotCutOff = osgCos(spotL->getSpotCutOff()); 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 (_spotFPCode ); newShadowFP->addUniformVariable("TSME_matEyeToLight", matEyeToLight); newShadowFP->addUniformVariable("TSME_matLightProj", matLightProj ); newShadowFP->addUniformVariable("TSME_matNT", matNT ); newShadowFP->addUniformVariable("TSME_texShadow", shadowTexUnit); newShadowFP->addUniformVariable("TSME_texShadowSizeInv", Vec2f(1.f / getWidth (), 1.f / getHeight() ) ); this->setShadowFragmentProgram(newShadowFP); shadowFP = newShadowFP; } else { shadowFP->updateUniformVariable("TSME_matEyeToLight", matEyeToLight); shadowFP->updateUniformVariable("TSME_matLightProj", matLightProj ); shadowFP->updateUniformVariable("TSME_matNT", matNT ); } updateLightPassMaterial(data, 0, matNT); 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, Matrixr::identity()); part->setupViewing (matWorldToLight ); part->setNear (parentPart->getNear()); part->setFar (parentPart->getFar ()); part->setFrustum (lightFrust ); part->setBackground (back ); part->overrideMaterial(data->getLightPassMaterials(0), ract->getActNode ( ) ); this->recurseFrom(ract, spotL); ract->useNodeList(false ); part->overrideMaterial(NULL, ract->getActNode ( ) ); } this->popPartition(ract); }
void ShaderShadowMapEngine::handleDirectionalLightEnter( DirectionalLight *dirL, RenderAction *ract, SSMEngineData *data) { RenderPartition *parentPart = ract ->getActivePartition(); FrustumVolume camFrust = parentPart->getFrustum (); Matrix matEyeToWorld (parentPart->getCameraToWorld()); Matrix matWorldToLight; Matrix 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) Pnt3f camVerts [10]; Pnt3f 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<Real32>::getMax(), TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax() ); camVerts [9].setValues(TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin() ); sceneVerts[8].setValues(TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax(), TypeTraits<Real32>::getMax() ); sceneVerts[9].setValues(TypeTraits<Real32>::getMin(), TypeTraits<Real32>::getMin(), TypeTraits<Real32>::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 Pnt3f lightMin(osgMax(camVerts[8][0], sceneVerts[8][0]), osgMax(camVerts[8][1], sceneVerts[8][1]), -sceneVerts[9][2]); Pnt3f 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; Matrix matLightProj; Matrix 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); }
void TrapezoidalShadowMapEngine::handlePointLightEnter( PointLight *pointL, RenderAction *ract, TSMEngineData *data) { RenderPartition *parentPart = ract->getActivePartition(); Matrixr matEyeToWorld(parentPart->getCameraToWorld()); Matrixr matLightProj; Real shadowNear = (getShadowNear() != 0.f ? getShadowNear() : parentPart->getNear() ); Real shadowFar = (getShadowFar () != 0.f ? getShadowFar () : parentPart->getFar() ); Inherited::calcPointLightRange( pointL, 0.01f, shadowNear, shadowFar, shadowNear, shadowFar); MatrixPerspective(matLightProj, Pi / 4.f, 1.f, shadowNear, shadowFar ); Matrixr matWorldToLight; Matrixr matEyeToLight; MFMatrixr mfMatNT; mfMatNT.resize(6); Inherited::calcPointLightMatrices(matWorldToLight, matEyeToLight, pointL, matEyeToWorld ); Inherited::updatePointLightShadowTexImage (data); Inherited::updatePointLightShadowTexBuffers(data); Inherited::updatePointLightRenderTargets (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 (_pointFPCode ); newShadowFP->addUniformVariable("TSME_matEyeToLight", matEyeToLight); newShadowFP->addUniformVariable("TSME_matLightProj", matLightProj ); newShadowFP->addUniformVariable("TSME_matNT", mfMatNT ); newShadowFP->addUniformVariable("TSME_texShadow", shadowTexUnit); newShadowFP->addUniformVariable("TSME_texShadowSizeInv", Vec2f(1.f / getWidth (), 1.f / getHeight() ) ); this->setShadowFragmentProgram(newShadowFP); shadowFP = newShadowFP; } else { shadowFP->updateUniformVariable("TSME_matEyeToLight", matEyeToLight); shadowFP->updateUniformVariable("TSME_matLightProj", matLightProj ); } const FrustumVolume &eyeFrust = parentPart->getFrustum(); for(UInt16 faceIdx = 0; faceIdx < 6; ++faceIdx) { Matrixr matWorldToLightFace (matWorldToLight ); matWorldToLightFace.multLeft(_matCubeFaceInv[faceIdx]); Matrixr matLightFull(matWorldToLightFace); matLightFull.multLeft(matLightProj); FrustumVolume lightFrust; Matrixr matNT; lightFrust.setPlanes(matLightFull); bool matNTValid = calcTrapezoidalTransform(mfMatNT[faceIdx], matEyeToWorld, matLightFull, eyeFrust, lightFrust ); if(matNTValid == false) { // setup a minimal partition to clear the cube face commitChanges(); this->pushPartition(ract, RenderPartition::CopyNothing, RenderPartition::SimpleCallback); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (faceIdx); Background *back = data->getBackground ( ); part->setSetupMode(RenderPartition::ViewportSetup | RenderPartition::BackgroundSetup ); part->setRenderTarget(target); part->setWindow (win ); part->calcViewportDimension(0.f, 0.f, 1.f, 1.f, target->getWidth (), target->getHeight() ); part->setBackground(back); RenderPartition::SimpleDrawCallback emptyCubeFaceDraw = boost::bind( &TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc, this, _1); part->dropFunctor(emptyCubeFaceDraw); } this->popPartition(ract); } else { updateLightPassMaterial(data, faceIdx, mfMatNT[faceIdx]); commitChanges(); this->pushPartition(ract); { RenderPartition *part = ract->getActivePartition( ); Window *win = ract->getWindow ( ); FrameBufferObject *target = data->getRenderTargets (faceIdx); 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, Matrixr::identity()); part->setupViewing (matWorldToLightFace ); part->setNear (parentPart->getNear()); part->setFar (parentPart->getFar ()); part->setFrustum (lightFrust ); part->setBackground (back ); part->overrideMaterial(data->getLightPassMaterials(faceIdx), ract->getActNode ( ) ); this->recurseFrom(ract, pointL); ract->useNodeList(false ); part->overrideMaterial(NULL, ract->getActNode ( ) ); } this->popPartition(ract); } } shadowFP->updateUniformVariable("TSME_matNT", mfMatNT); }