1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
43 #include "OSGConfig.h"
45 #include "OSGTrapezoidalShadowMapEngine.h"
48 #include "OSGMaterialChunk.h"
49 #include "OSGMathMFields.h"
50 #include "OSGMatrixUtility.h"
51 #include "OSGColorMaskChunk.h"
52 #include "OSGPolygonChunk.h"
53 #include "OSGRenderAction.h"
54 #include "OSGShaderProgram.h"
55 #include "OSGShaderProgramChunk.h"
57 #include "OSGSpotLight.h"
58 #include "OSGDirectionalLight.h"
60 #include "OSGFrameBufferObject.h"
62 #include "OSGChunkMaterial.h"
63 #include "OSGShaderShadowMapEngineData.h"
65 #include <boost/cast.hpp>
67 #define OSG_TSME_LIGHTPASS_EXACT 1
71 // Documentation for this class is emitted in the
72 // OSGTrapezoidalShadowMapEngineBase.cpp file.
73 // To modify it, please change the .fcd file (OSGTrapezoidalShadowMapEngine.fcd) and
74 // regenerate the base file.
76 /***************************************************************************\
78 \***************************************************************************/
80 #ifdef OSG_TSME_LIGHTPASS_EXACT
82 const std::string
TrapezoidalShadowMapEngine::_lightPassVPCode(
85 "uniform mat4 TSME_matNT;\n"
87 "varying vec4 TSME_plcPos;\n"
91 " TSME_plcPos = ftransform();\n"
92 " gl_Position = TSME_matNT * TSME_plcPos;\n"
96 const std::string
TrapezoidalShadowMapEngine::_lightPassFPCode(
99 "const float TSME_depthEps = 1e-7;\n"
101 "uniform float TSME_offsetFactor;\n"
102 "uniform float TSME_offsetBias;\n"
104 "varying vec4 TSME_plcPos;\n"
108 " float depth = 0.5 + 0.5 * (TSME_plcPos.z / TSME_plcPos.w);\n"
109 " float depthSlope = max(abs(dFdx(depth)),\n"
110 " abs(dFdy(depth)) );\n"
111 " gl_FragDepth = depth + TSME_offsetFactor * depthSlope\n"
112 " + TSME_offsetBias * TSME_depthEps;\n"
118 const std::string
TrapezoidalShadowMapEngine::_lightPassVPCode(
121 "uniform mat4 TSME_matNT;\n"
125 " vec4 plcPos = ftransform();\n"
126 " vec4 tcPos = TSME_matNT * plcPos;\n"
127 " gl_Position = vec4(tcPos.xy, (plcPos.z / plcPos.w) * tcPos.w, tcPos.w);\n"
131 const std::string
TrapezoidalShadowMapEngine::_lightPassFPCode("");
133 #endif // OSG_TSME_LIGHTPASS_EXACT
135 const std::string
TrapezoidalShadowMapEngine::_pointFPCode(
138 "#define TSME_PCF 1\n"
140 "#extension GL_EXT_gpu_shader4 : require\n"
141 "#extension GL_EXT_gpu_shader4 : enable\n"
143 "uniform samplerCubeShadow TSME_texShadow;\n"
144 "uniform vec2 TSME_texShadowSizeInv;\n"
146 "uniform mat4 TSME_matEyeToLight;\n"
147 "uniform mat4 TSME_matLightProj;\n"
148 "uniform mat4 TSME_matNT[6];\n"
150 "vec2 TSME_offsetFactors[16] = vec2[](\n"
151 " vec2(-1.5, -1.5),\n"
152 " vec2( 1.5, -1.5),\n"
153 " vec2(-1.5, 1.5),\n"
154 " vec2( 1.5, 1.5),\n"
156 " vec2(-0.5, 1.5),\n"
157 " vec2( 0.5, 1.5),\n"
158 " vec2(-1.0, 1.0),\n"
159 " vec2( 1.0, 1.0),\n"
160 " vec2(-1.5, 0.5),\n"
161 " vec2( 1.5, 0.5),\n"
163 " vec2(-1.5, -0.5),\n"
164 " vec2( 1.5, -0.5),\n"
165 " vec2(-1.0, -1.0),\n"
166 " vec2( 1.0, -1.0),\n"
167 " vec2(-0.5, -1.5),\n"
168 " vec2( 0.5, -1.5) \n"
171 "vec4 OSG_SSME_FP_calcShadow(in vec4 fragPos)\n"
173 " vec4 shadow = vec4(0., 0., 0., 0.);\n"
174 " vec4 lcPos = TSME_matEyeToLight * fragPos;\n"
175 " vec4 lcAbsPos = abs(lcPos);\n"
178 " vec4 pcfOffset0;\n"
179 " vec4 pcfOffset1;\n"
181 " if(lcAbsPos.x > lcAbsPos.y && lcAbsPos.x > lcAbsPos.z)\n"
183 " pcfOffset0 = vec4(0., 0., TSME_texShadowSizeInv.x, 0.);\n"
184 " pcfOffset1 = vec4(0., TSME_texShadowSizeInv.y, 0. , 0.);\n"
186 " if(lcPos.x >= 0.)\n"
188 " plcPos = vec4(-1, -1, -1, 1) * lcPos.zyxw;\n"
189 " plcPos = TSME_matLightProj * plcPos;\n"
190 " tcPos = TSME_matNT[4] * plcPos;\n"
191 " tcPos = tcPos / tcPos.w;\n"
192 " tcPos = vec4(-1, -1, -1, 1) * tcPos.zyxw;\n"
197 " plcPos = vec4( 1, -1, 1, 1) * lcPos.zyxw;\n"
198 " plcPos = TSME_matLightProj * plcPos;\n"
199 " tcPos = TSME_matNT[5] * plcPos;\n"
200 " tcPos = tcPos / tcPos.w;\n"
201 " tcPos = vec4( 1, -1, 1, 1) * tcPos.zyxw;\n"
205 " else if(lcAbsPos.y > lcAbsPos.x && lcAbsPos.y > lcAbsPos.z)\n"
207 " pcfOffset0 = vec4(TSME_texShadowSizeInv.x, 0., 0., 0.);\n"
208 " pcfOffset1 = vec4(0., 0., TSME_texShadowSizeInv.y, 0.);\n"
210 " if(lcPos.y >= 0.)\n"
212 " plcPos = vec4( 1, 1, -1, 1) * lcPos.xzyw;\n"
213 " plcPos = TSME_matLightProj * plcPos;\n"
214 " tcPos = TSME_matNT[2] * plcPos;\n"
215 " tcPos = tcPos / tcPos.w;\n"
216 " tcPos = vec4( 1, -1, 1, 1) * tcPos.xzyw;\n"
221 " plcPos = vec4( 1, -1, 1, 1) * lcPos.xzyw;\n"
222 " plcPos = TSME_matLightProj * plcPos;\n"
223 " tcPos = TSME_matNT[3] * plcPos;\n"
224 " tcPos = tcPos / tcPos.w;\n"
225 " tcPos = vec4( 1, 1, -1, 1) * tcPos.xzyw;\n"
231 " pcfOffset0 = vec4(TSME_texShadowSizeInv.x, 0., 0., 0.);\n"
232 " pcfOffset1 = vec4(0., TSME_texShadowSizeInv.y, 0., 0.);\n"
234 " if(lcPos.z >= 0.)\n"
236 " plcPos = vec4( 1, -1, -1, 1) * lcPos;\n"
237 " plcPos = TSME_matLightProj * plcPos;\n"
238 " tcPos = TSME_matNT[0] * plcPos;\n"
239 " tcPos = tcPos / tcPos.w;\n"
240 " tcPos = vec4( 1, -1, -1, 1) * tcPos;\n"
245 " plcPos = vec4(-1, -1, 1, 1) * lcPos;\n"
246 " plcPos = TSME_matLightProj * plcPos;\n"
247 " tcPos = TSME_matNT[1] * plcPos;\n"
248 " tcPos = tcPos / tcPos.w;\n"
249 " tcPos = vec4(-1, -1, 1, 1) * tcPos;\n"
254 " plcPos = plcPos / plcPos.w;\n"
255 " plcPos = 0.5 + 0.5 * plcPos;\n"
258 " shadow = shadowCube(TSME_texShadow, vec4(tcPos.xyz, plcPos.z));\n"
260 " vec4 lookupBase = vec4(tcPos.xyz, plcPos.z);\n"
263 " for(int i = 0; i < 4; ++i)\n"
265 " lookup = TSME_offsetFactors[i].x * pcfOffset0 +\n"
266 " TSME_offsetFactors[i].y * pcfOffset1 + lookupBase;\n"
267 " shadow += shadowCube(TSME_texShadow, lookup);\n"
270 " if((shadow.x - 4.0) * shadow.x == 0.0)\n"
276 " for(int i = 4; i < 16; ++i)\n"
278 " lookup = TSME_offsetFactors[i].x * pcfOffset0 +\n"
279 " TSME_offsetFactors[i].y * pcfOffset1 + lookupBase;\n"
280 " shadow += shadowCube(TSME_texShadow, lookup);\n"
283 " shadow *= 1.0 / 16.0;\n"
285 "#endif // TSME_PCF\n"
291 const std::string
TrapezoidalShadowMapEngine::_spotFPCode(
294 "#define TSME_PCF 1\n"
296 "uniform sampler2DShadow TSME_texShadow;\n"
297 "uniform vec2 TSME_texShadowSizeInv;\n"
299 "uniform mat4 TSME_matEyeToLight;\n"
300 "uniform mat4 TSME_matLightProj;\n"
301 "uniform mat4 TSME_matNT;\n"
303 "vec2 TSME_offsetFactors[16] = vec2[](\n"
304 " vec2(-1.5, -1.5),\n"
305 " vec2( 1.5, -1.5),\n"
306 " vec2(-1.5, 1.5),\n"
307 " vec2( 1.5, 1.5),\n"
309 " vec2(-0.5, 1.5),\n"
310 " vec2( 0.5, 1.5),\n"
311 " vec2(-1.0, 1.0),\n"
312 " vec2( 1.0, 1.0),\n"
313 " vec2(-1.5, 0.5),\n"
314 " vec2( 1.5, 0.5),\n"
316 " vec2(-1.5, -0.5),\n"
317 " vec2( 1.5, -0.5),\n"
318 " vec2(-1.0, -1.0),\n"
319 " vec2( 1.0, -1.0),\n"
320 " vec2(-0.5, -1.5),\n"
321 " vec2( 0.5, -1.5) \n"
324 "vec4 OSG_SSME_FP_calcShadow(in vec4 ecFragPos)\n"
326 " vec4 shadow = vec4(0., 0., 0., 0.);\n"
327 " vec4 plcPos = TSME_matLightProj * TSME_matEyeToLight * ecFragPos;\n"
328 " vec4 tcPos = TSME_matNT * plcPos;\n"
330 " plcPos = plcPos / plcPos.w;\n"
331 " plcPos = 0.5 + 0.5 * plcPos;\n"
332 " tcPos = tcPos / tcPos.w;\n"
333 " tcPos = 0.5 + 0.5 * tcPos;\n"
335 " vec3 lookupBase = vec3(tcPos.xy, plcPos.z);\n"
339 " shadow = shadow2D(TSME_texShadow, lookupBase);\n"
341 " for(int i = 0; i < 4; ++i)\n"
343 " lookup = vec3(TSME_offsetFactors[i].x * TSME_texShadowSizeInv.x,\n"
344 " TSME_offsetFactors[i].y * TSME_texShadowSizeInv.y,\n"
345 " 0.0) + lookupBase;\n"
346 " shadow += shadow2D(TSME_texShadow, lookup);\n"
349 " if((shadow.x - 4.) * shadow.x == 0)\n"
355 " for(int i = 4; i < 16; ++i)\n"
357 " lookup = vec3(TSME_offsetFactors[i].x * TSME_texShadowSizeInv.x,\n"
358 " TSME_offsetFactors[i].y * TSME_texShadowSizeInv.y,\n"
359 " 0.0) + lookupBase;\n"
360 " shadow += shadow2D(TSME_texShadow, lookup);\n"
363 " shadow *= 1.0 / 16.0;\n"
371 /***************************************************************************\
373 \***************************************************************************/
375 void TrapezoidalShadowMapEngine::initMethod(InitPhase ePhase
)
377 Inherited::initMethod(ePhase
);
381 /***************************************************************************\
383 \***************************************************************************/
385 /*-------------------------------------------------------------------------*\
387 \*-------------------------------------------------------------------------*/
389 /*----------------------- constructors & destructors ----------------------*/
391 TrapezoidalShadowMapEngine::TrapezoidalShadowMapEngine(void) :
396 TrapezoidalShadowMapEngine::TrapezoidalShadowMapEngine(const TrapezoidalShadowMapEngine
&source
) :
401 TrapezoidalShadowMapEngine::~TrapezoidalShadowMapEngine(void)
405 /*----------------------------- class specific ----------------------------*/
407 Action::ResultE
TrapezoidalShadowMapEngine::runOnEnter(
408 Light
*light
, LightTypeE eType
, RenderAction
*ract
)
410 typedef ShaderShadowMapEngineDataUnrecPtr TSMEngineDataUnrecPtr
;
412 BitVector passMask
= ract
->getPassMask ( );
413 TSMEngineData
*data
= ract
->getData
<TSMEngineData
*>(_iDataSlotId
);
417 TSMEngineDataUnrecPtr newData
= TSMEngineData::createLocal();
418 this->setData(newData
, _iDataSlotId
, ract
);
423 if(passMask
!= 0x0000)
425 // already generating a shadow map for another light source?
426 if((passMask
& bvLightPassMask
) != 0x0000)
428 this->recurseFrom(ract
, light
);
430 handleEnter(light
, eType
, ract
, data
);
435 ract
->addPassMask(bvLightPassMask
);
436 handleEnter(light
, eType
, ract
, data
);
437 ract
->subPassMask(bvLightPassMask
);
440 return Action::Continue
;
443 Action::ResultE
TrapezoidalShadowMapEngine::runOnLeave(
444 Light
*light
, LightTypeE eType
, RenderAction
*ract
)
446 return Action::Continue
;
449 void TrapezoidalShadowMapEngine::changed(ConstFieldMaskArg whichField
,
453 Inherited::changed(whichField
, origin
, details
);
456 void TrapezoidalShadowMapEngine::dump( UInt32
,
457 const BitVector
) const
459 SLOG
<< "Dump TrapezoidalShadowMapEngine NI" << std::endl
;
462 void TrapezoidalShadowMapEngine::handleEnter(
463 Light
*light
, LightTypeE eType
, RenderAction
*ract
, TSMEngineData
*data
)
465 Inherited::updateShadowTexChunk (data
);
466 Inherited::updateBackground (data
);
468 UInt32 parentTravMask
= ract
->getTravMask();
469 ract
->setTravMask(_sfShadowTravMask
.getValue());
476 boost::polymorphic_downcast
<PointLight
*>(light
);
478 handlePointLightEnter(pointL
, ract
, data
);
484 DirectionalLight
*dirL
=
485 boost::polymorphic_downcast
<DirectionalLight
*>(light
);
487 handleDirectionalLightEnter(dirL
, ract
, data
);
494 boost::polymorphic_downcast
<SpotLight
*>(light
);
496 handleSpotLightEnter(spotL
, ract
, data
);
502 FWARNING(("TrapezoidalShadowMapEngine::handleEnter: Unknown "
503 "light type [%u]\n", eType
));
508 ract
->setTravMask(parentTravMask
);
511 void TrapezoidalShadowMapEngine::handlePointLightEnter(
512 PointLight
*pointL
, RenderAction
*ract
, TSMEngineData
*data
)
514 RenderPartition
*parentPart
= ract
->getActivePartition();
516 Matrix
matEyeToWorld(parentPart
->getCameraToWorld());
519 Real32 shadowNear
= (getShadowNear() != 0.f
?
521 parentPart
->getNear() );
522 Real32 shadowFar
= (getShadowFar () != 0.f
?
524 parentPart
->getFar() );
526 Inherited::calcPointLightRange(
528 shadowNear
, shadowFar
, shadowNear
, shadowFar
);
530 MatrixPerspective(matLightProj
, Pi
/ 4.f
, 1.f
,
531 shadowNear
, shadowFar
);
533 Matrix matWorldToLight
;
534 Matrix matEyeToLight
;
539 Inherited::calcPointLightMatrices(matWorldToLight
, matEyeToLight
,
540 pointL
, matEyeToWorld
);
542 Inherited::updatePointLightShadowTexImage (data
);
543 Inherited::updatePointLightShadowTexBuffers(data
);
544 Inherited::updatePointLightRenderTargets (data
);
546 Int32 shadowTexUnit
= (this->getForceTextureUnit() >= 0) ?
547 this->getForceTextureUnit() : 7;
548 ShaderProgram
*shadowFP
= this->getShadowFragmentProgram();
552 ShaderProgramUnrecPtr newShadowFP
= ShaderProgram::createLocal();
553 newShadowFP
->setShaderType(GL_FRAGMENT_SHADER
);
554 newShadowFP
->setProgram (_pointFPCode
);
556 newShadowFP
->addUniformVariable("TSME_matEyeToLight", matEyeToLight
);
557 newShadowFP
->addUniformVariable("TSME_matLightProj", matLightProj
);
558 newShadowFP
->addUniformVariable("TSME_matNT", mfMatNT
);
559 newShadowFP
->addUniformVariable("TSME_texShadow", shadowTexUnit
);
560 newShadowFP
->addUniformVariable("TSME_texShadowSizeInv",
561 Vec2f(1.f
/ getWidth (),
562 1.f
/ getHeight() ) );
564 this->setShadowFragmentProgram(newShadowFP
);
565 shadowFP
= newShadowFP
;
569 shadowFP
->updateUniformVariable("TSME_matEyeToLight", matEyeToLight
);
570 shadowFP
->updateUniformVariable("TSME_matLightProj", matLightProj
);
573 const FrustumVolume
&eyeFrust
= parentPart
->getFrustum();
575 for(UInt16 faceIdx
= 0; faceIdx
< 6; ++faceIdx
)
577 Matrix
matWorldToLightFace (matWorldToLight
);
578 matWorldToLightFace
.multLeft(_matCubeFaceInv
[faceIdx
]);
580 Matrix
matLightFull(matWorldToLightFace
);
581 matLightFull
.multLeft(matLightProj
);
583 FrustumVolume lightFrust
;
586 lightFrust
.setPlanes(matLightFull
);
589 calcTrapezoidalTransform(mfMatNT
[faceIdx
],
590 matEyeToWorld
, matLightFull
,
591 eyeFrust
, lightFrust
);
593 if(matNTValid
== false)
595 // setup a minimal partition to clear the cube face
599 this->pushPartition(ract
,
600 RenderPartition::CopyNothing
,
601 RenderPartition::SimpleCallback
);
603 RenderPartition
*part
= ract
->getActivePartition( );
604 Window
*win
= ract
->getWindow ( );
605 FrameBufferObject
*target
= data
->getRenderTargets (faceIdx
);
606 Background
*back
= data
->getBackground ( );
608 part
->setSetupMode(RenderPartition::ViewportSetup
|
609 RenderPartition::BackgroundSetup
);
611 part
->setRenderTarget(target
);
612 part
->setWindow (win
);
614 part
->calcViewportDimension(0.f
, 0.f
, 1.f
, 1.f
,
616 target
->getHeight() );
618 part
->setBackground(back
);
620 RenderPartition::SimpleDrawCallback emptyCubeFaceDraw
=
622 &TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc
,
625 part
->dropFunctor(emptyCubeFaceDraw
);
627 this->popPartition(ract
);
631 updateLightPassMaterial(data
, faceIdx
, mfMatNT
[faceIdx
]);
635 this->pushPartition(ract
);
637 RenderPartition
*part
= ract
->getActivePartition( );
638 Window
*win
= ract
->getWindow ( );
639 FrameBufferObject
*target
= data
->getRenderTargets (faceIdx
);
640 Background
*back
= data
->getBackground ( );
642 part
->setRenderTarget(target
);
643 part
->setWindow (win
);
645 part
->calcViewportDimension(0.f
, 0.f
, 1.f
, 1.f
,
647 target
->getHeight() );
649 part
->setupProjection(matLightProj
, Matrix::identity());
650 part
->setupViewing (matWorldToLightFace
);
652 part
->setNear (parentPart
->getNear());
653 part
->setFar (parentPart
->getFar ());
655 part
->setFrustum (lightFrust
);
657 part
->setBackground (back
);
659 part
->overrideMaterial(data
->getLightPassMaterials(faceIdx
),
660 ract
->getActNode ( ) );
662 this->recurseFrom(ract
, pointL
);
663 ract
->useNodeList(false );
665 part
->overrideMaterial(NULL
,
666 ract
->getActNode ( ) );
668 this->popPartition(ract
);
672 shadowFP
->updateUniformVariable("TSME_matNT", mfMatNT
);
675 void TrapezoidalShadowMapEngine::handleDirectionalLightEnter(
676 DirectionalLight
*dirL
, RenderAction
*ract
, TSMEngineData
*data
)
678 FWARNING(("TrapezoidalShadowMapEngine::handleDirectionalLightEnter: NIY\n"));
681 void TrapezoidalShadowMapEngine::handleSpotLightEnter(
682 SpotLight
*spotL
, RenderAction
*ract
, TSMEngineData
*data
)
684 RenderPartition
*parentPart
= ract
->getActivePartition();
686 Matrix
matEyeToWorld(parentPart
->getCameraToWorld());
687 Matrix matWorldToLight
;
688 Matrix matEyeToLight
;
690 Inherited::calcSpotLightMatrices(matWorldToLight
, matEyeToLight
,
691 spotL
, matEyeToWorld
);
694 Matrix
matLightFull(matWorldToLight
);
696 Real32 shadowNear
= (getShadowNear() != 0.f
?
698 parentPart
->getNear() );
699 Real32 shadowFar
= (getShadowFar () != 0.f
?
701 parentPart
->getFar() );
703 Inherited::calcPointLightRange(
705 shadowNear
, shadowFar
, shadowNear
, shadowFar
);
707 MatrixPerspective(matLightProj
,
708 spotL
->getSpotCutOff(), 1.f
,
709 shadowNear
, shadowFar
);
711 matLightFull
.multLeft(matLightProj
);
713 Inherited::updateShadowTexImage (data
);
714 Inherited::updateShadowTexBuffers(data
);
715 Inherited::updateRenderTargets (data
);
717 const FrustumVolume
&eyeFrust
= parentPart
->getFrustum();
718 FrustumVolume lightFrust
;
721 lightFrust
.setPlanes(matLightFull
);
723 bool matNTValid
= calcTrapezoidalTransform(matNT
,
724 matEyeToWorld
, matLightFull
,
725 eyeFrust
, lightFrust
);
727 if(matNTValid
== false)
730 // Real32 cosSpotCutOff = osgCos(spotL->getSpotCutOff());
732 Int32 shadowTexUnit
= (this->getForceTextureUnit() >= 0) ?
733 this->getForceTextureUnit() : 7;
734 ShaderProgram
*shadowFP
= this->getShadowFragmentProgram();
738 ShaderProgramUnrecPtr newShadowFP
= ShaderProgram::createLocal();
739 newShadowFP
->setShaderType(GL_FRAGMENT_SHADER
);
740 newShadowFP
->setProgram (_spotFPCode
);
742 newShadowFP
->addUniformVariable("TSME_matEyeToLight", matEyeToLight
);
743 newShadowFP
->addUniformVariable("TSME_matLightProj", matLightProj
);
744 newShadowFP
->addUniformVariable("TSME_matNT", matNT
);
745 newShadowFP
->addUniformVariable("TSME_texShadow", shadowTexUnit
);
746 newShadowFP
->addUniformVariable("TSME_texShadowSizeInv",
747 Vec2f(1.f
/ getWidth (),
748 1.f
/ getHeight() ) );
750 this->setShadowFragmentProgram(newShadowFP
);
751 shadowFP
= newShadowFP
;
755 shadowFP
->updateUniformVariable("TSME_matEyeToLight", matEyeToLight
);
756 shadowFP
->updateUniformVariable("TSME_matLightProj", matLightProj
);
757 shadowFP
->updateUniformVariable("TSME_matNT", matNT
);
760 updateLightPassMaterial(data
, 0, matNT
);
764 this->pushPartition(ract
);
766 RenderPartition
*part
= ract
->getActivePartition( );
767 Window
*win
= ract
->getWindow ( );
768 FrameBufferObject
*target
= data
->getRenderTargets (0);
769 Background
*back
= data
->getBackground ( );
771 part
->setRenderTarget(target
);
772 part
->setWindow (win
);
774 part
->calcViewportDimension(0.f
, 0.f
, 1.f
, 1.f
,
776 target
->getHeight() );
778 part
->setupProjection(matLightProj
, Matrix::identity());
779 part
->setupViewing (matWorldToLight
);
781 part
->setNear (parentPart
->getNear());
782 part
->setFar (parentPart
->getFar ());
784 part
->setFrustum (lightFrust
);
786 part
->setBackground (back
);
788 part
->overrideMaterial(data
->getLightPassMaterials(0),
789 ract
->getActNode ( ) );
791 this->recurseFrom(ract
, spotL
);
792 ract
->useNodeList(false );
794 part
->overrideMaterial(NULL
,
795 ract
->getActNode ( ) );
797 this->popPartition(ract
);
800 /*! Calculate the vertices (\a intVerts) and center (\a intCenter) of
801 the intersection of \a fA and \a fB.
803 void TrapezoidalShadowMapEngine::intersectFrusta(
804 const FrustumVolume
&fA
, const FrustumVolume
&fB
,
805 std::vector
<Pnt3f
> &intVerts
, Pnt3f
&intCenter
)
807 const Plane
*planes
[12];
810 intVerts
.reserve(16);
812 for(UInt32 i
= 0; i
< 6; ++i
)
814 planes
[i
] = &(fA
.getPlanes()[i
]);
815 planes
[6 + i
] = &(fB
.getPlanes()[i
]);
818 // take all combinations of 3 planes -- but avoid choosing planes
819 // we know to be parallel (i.e. near and far of the same frustum), or
820 // that are known to intersect outside the frustum (i.e top/bottom,
823 for(UInt32 i
= 0; i
< 12; ++i
)
825 // choose initial value of j such that it avoids near and far of fA
826 for(UInt32 j
= osgMax
<UInt32
>(2, i
+ 1); j
< 12; ++j
)
828 // near/far are parallel,
829 // left/right always intersect outside the frustum,
830 // top/bottom always intersect outside the frustum
831 if((i
== 6 && j
== 7) ||
832 (i
== 2 && j
== 3) || (i
== 8 && j
== 9) ||
833 (i
== 4 && j
== 5) || (i
== 10 && j
== 11) )
837 if(planes
[i
]->intersect(*planes
[j
], intLine
) == false)
840 for(UInt32 k
= j
+ 1; k
< 12; ++k
)
842 // near/far are parallel,
843 // left/right always intersect outside the frustum,
844 // top/bottom always intersect outside the frustum
845 if((j
== 6 && k
== 7) ||
846 (j
== 2 && k
== 3) || (j
== 8 && k
== 9) ||
847 (j
== 4 && k
== 5) || (j
== 10 && k
== 11) )
851 if(planes
[k
]->intersectInfinite(intLine
, intPoint
) == false)
854 bool intPointValid
= true;
856 // check the intersection point against all planes to ensure
857 // it is in both frusta
858 for(UInt32 m
= 0; m
< 12; ++m
)
860 // intPoint is the intersection of planes i, j, k, so
861 // we don't have to test against those
862 if(m
== i
|| m
== j
|| m
== k
)
865 if(planes
[m
]->isInHalfSpace(intPoint
) == false)
867 intPointValid
= false;
872 if(intPointValid
== true)
874 intCenter
+= intPoint
.subZero();
875 intVerts
.push_back(intPoint
);
881 intCenter
/= intVerts
.size();
884 void TrapezoidalShadowMapEngine::updateLightPassMaterial(
885 TSMEngineData
*data
, UInt16 faceIdx
, const Matrix
&matNT
)
887 if(data
->getMFLightPassMaterials()->size() < 6)
888 data
->editMFLightPassMaterials()->resize(6, NULL
);
890 ChunkMaterial
*lightPassMat
= data
->getLightPassMaterials(faceIdx
);
892 if(lightPassMat
== NULL
)
894 ColorMaskChunkUnrecPtr newCMaskChunk
= ColorMaskChunk::create();
895 newCMaskChunk
->setMaskR(false);
896 newCMaskChunk
->setMaskG(false);
897 newCMaskChunk
->setMaskB(false);
898 newCMaskChunk
->setMaskA(false);
900 #ifdef OSG_TSME_LIGHTPASS_EXACT
902 ShaderProgramUnrecPtr newLightPassVP
= ShaderProgram::createLocal();
903 newLightPassVP
->setShaderType(GL_VERTEX_SHADER
);
904 newLightPassVP
->setProgram (_lightPassVPCode
);
905 newLightPassVP
->addUniformVariable("TSME_matNT", matNT
);
907 ShaderProgramUnrecPtr newLightPassFP
= ShaderProgram::createLocal();
908 newLightPassFP
->setShaderType(GL_FRAGMENT_SHADER
);
909 newLightPassFP
->setProgram (_lightPassFPCode
);
910 newLightPassFP
->addUniformVariable("TSME_offsetFactor", getOffsetFactor());
911 newLightPassFP
->addUniformVariable("TSME_offsetBias", getOffsetBias ());
913 ShaderProgramChunkUnrecPtr newLightPassSHChunk
=
914 ShaderProgramChunk::createLocal();
915 newLightPassSHChunk
->addVertexShader (newLightPassVP
);
916 newLightPassSHChunk
->addFragmentShader(newLightPassFP
);
918 ChunkMaterialUnrecPtr newLightPassMat
= ChunkMaterial::createLocal();
919 newLightPassMat
->addChunk(newCMaskChunk
);
920 newLightPassMat
->addChunk(newLightPassSHChunk
);
922 lightPassMat
= newLightPassMat
;
923 data
->editMFLightPassMaterials()->replace(faceIdx
, newLightPassMat
);
927 PolygonChunkUnrecPtr newPolyChunk
= PolygonChunk::createLocal();
928 newPolyChunk
->setOffsetFill (true );
929 newPolyChunk
->setOffsetFactor(getOffsetFactor());
930 newPolyChunk
->setOffsetBias (getOffsetBias ());
932 ShaderProgramUnrecPtr newLightPassVP
= ShaderProgram::createLocal();
933 newLightPassVP
->setShaderType (GL_VERTEX_SHADER
);
934 newLightPassVP
->setProgram (_lightPassVPCode
);
935 newLightPassVP
->addUniformVariable("TSME_matNT", matNT
);
937 ShaderProgramChunkUnrecPtr newLightPassSHChunk
=
938 ShaderProgramChunk::createLocal();
939 newLightPassSHChunk
->addVertexShader(newLightPassVP
);
941 ChunkMaterialUnrecPtr newLightPassMat
= ChunkMaterial::createLocal();
942 newLightPassMat
->addChunk(newCMaskChunk
);
943 newLightPassMat
->addChunk(newPolyChunk
);
944 newLightPassMat
->addChunk(newLightPassSHChunk
);
946 lightPassMat
= newLightPassMat
;
947 (*data
->editMFLightPassMaterials())[faceIdx
] = newLightPassMat
;
955 ShaderProgramChunk
*lightPassSHChunk
=
956 dynamic_cast<ShaderProgramChunk
*>(
957 lightPassMat
->find(ShaderProgramChunk::getClassType()));
959 if(lightPassSHChunk
!= NULL
)
961 ShaderProgram
*lightPassVP
= lightPassSHChunk
->getVertexShader(0);
962 lightPassVP
->updateUniformVariable("TSME_matNT", matNT
);
967 /*! Calculates the trapezoidal transformation matrix \a matNT that transforms
968 post projection light space so that shadow map resolution in the
969 "foreground" is maximized.
971 - compute the intersection of eyeFrust and lightFrust
972 - construct a trapezoid that contains the intersection
973 - determine the transformation that maps this trapezoid to the
976 Returns \c true if the transform was computed, \c false otherwise (e.g. if
977 the intersection of eyeFrust and lightFrust is empty).
979 For details see "T. Martin, T.-S. Tan: Anti-aliasing and Continuity
980 with Trapezoidal Shadow Maps"
982 bool TrapezoidalShadowMapEngine::calcTrapezoidalTransform(
984 const Matrix
&matEyeToWorld
,
985 const Matrix
&matLightFull
,
986 const FrustumVolume
&eyeFrust
,
987 const FrustumVolume
&lightFrust
)
989 // obtain post proj. light space eye position
991 matEyeToWorld
.mult (eyePos
, eyePos
);
992 matLightFull
.multFull(eyePos
, eyePos
);
994 // intersect eye and light frusta, get vertices and center of intersection
995 std::vector
<Pnt3f
> intVerts
;
997 intersectFrusta(eyeFrust
, lightFrust
, intVerts
, intCenter
);
999 if(intVerts
.empty() == true)
1002 // xform intCenter and intVerts to post proj. light space
1003 matLightFull
.multFull(intCenter
, intCenter
);
1005 std::vector
<Pnt3f
>::iterator ivIt
= intVerts
.begin();
1006 std::vector
<Pnt3f
>::iterator ivEnd
= intVerts
.end ();
1008 for(; ivIt
!= ivEnd
; ++ivIt
)
1009 matLightFull
.multFull(*ivIt
, *ivIt
);
1011 Pnt2f
eyePos2D (eyePos
[0], eyePos
[1]);
1012 Pnt2f
intCenter2D(intCenter
[0], intCenter
[1]);
1014 // center line, normal, direction and distance from origin
1015 Vec2f
clDir (intCenter2D
- eyePos2D
);
1017 Vec2f
clNorm(-clDir
[1], clDir
[0]);
1019 // distance of the center line from the origin
1020 Real32 clDist
= clNorm
.dot(eyePos2D
.subZero());
1022 // compute top and base lines:
1023 // - project intVerts onto the center line.
1024 // - top line is perpendicular to center line and goes through the
1025 // projected point closest to eyePos
1026 // - base line is perpendicular to center line and goes through the
1027 // projected point farthest from eyePos
1031 Real32 topDist
= TypeTraits
<Real32
>::getMax();
1032 Real32 baseDist
= TypeTraits
<Real32
>::getMin();
1034 std::vector
<Pnt3f
>::const_iterator ivCIt
= intVerts
.begin();
1035 std::vector
<Pnt3f
>::const_iterator ivCEnd
= intVerts
.end ();
1037 for(; ivCIt
!= ivCEnd
; ++ivCIt
)
1039 Pnt2f
ivPnt((*ivCIt
)[0], (*ivCIt
)[1]);
1041 ivPnt
= ivPnt
- (clNorm
.dot(ivPnt
) - clDist
) * clNorm
;
1043 Real32 dist
= (ivPnt
- eyePos2D
).squareLength();
1044 dist
*= osgSgn(clDir
.dot(ivPnt
- eyePos2D
));
1059 topDist
= osgSgn(topDist
) * osgSqrt(osgAbs(topDist
));
1060 baseDist
= osgSgn(baseDist
) * osgSqrt(osgAbs(baseDist
));
1062 // compute side lines:
1063 // - choose focusPnt (everything closer to the near plane is mapped to
1064 // 80% of the shadow map) - here we just take the point at 0.7 between
1065 // tlBase and blBase
1066 // - find a point (trapTip, q in the paper) on center line such that
1067 // focusPnt is mapped the 80% line in the shadow map
1068 // - choose lines through q that touch the convex hull of intVerts
1070 ivCIt
= intVerts
.begin();
1071 ivCEnd
= intVerts
.end ();
1073 // Real32 centerDist = (intCenter2D - eyePos2D).length();
1075 Real32 lambda
= baseDist
- topDist
;
1076 Real32 delta
= 0.5f
* lambda
;
1078 Real32 eta
= ((lambda
* delta
) + (lambda
* delta
* xi
)) /
1079 (lambda
- 2.f
* delta
- lambda
* xi
);
1080 Pnt2f trapTip
= tlBase
- (eta
* clDir
);
1081 Pnt2f focusPnt
= tlBase
+ (delta
* clDir
);
1083 // on both sides of the center line, find the point in intVerts that has
1084 // the smallest |cosine| (largest angle) between clDir and the vector
1085 // from trapTip to intVerts[i]
1087 Real32 posCos
= 1.f
;
1089 Real32 negCos
= 1.f
;
1091 for(UInt32 i
= 0; ivCIt
!= ivCEnd
; ++ivCIt
, ++i
)
1093 Pnt2f
ivPnt((*ivCIt
)[0], (*ivCIt
)[1]);
1095 Vec2f v
= ivPnt
- trapTip
;
1097 Real32 currCos
= osgAbs(clDir
.dot(v
));
1099 if(clNorm
.dot(v
) >= 0.f
)
1101 if(currCos
<= posCos
)
1109 if(currCos
<= negCos
)
1117 // compute corners of trapezoid:
1118 Pnt2f trapVerts
[4];
1119 Pnt2f extraVerts
[2];
1120 Real32 posTan
= osgTan(osgACos(posCos
));
1121 Real32 negTan
= osgTan(osgACos(negCos
));
1123 trapVerts
[0] = blBase
- ((eta
+ lambda
) * negTan
* clNorm
);
1124 trapVerts
[1] = blBase
+ ((eta
+ lambda
) * posTan
* clNorm
);
1125 trapVerts
[2] = tlBase
+ ( eta
* posTan
* clNorm
);
1126 trapVerts
[3] = tlBase
- ( eta
* negTan
* clNorm
);
1128 extraVerts
[0] = focusPnt
+ ((eta
+ delta
) * posTan
* clNorm
);
1129 extraVerts
[1] = focusPnt
- ((eta
+ delta
) * negTan
* clNorm
);
1131 // == xform trapezoid to unit square ==
1133 // M1 = R * T1 -- translate center of top line to origin and rotate
1134 Vec2f u
= 0.5f
* (trapVerts
[2].subZero() + trapVerts
[3].subZero());
1135 Vec2f v
= trapVerts
[3] - trapVerts
[2];
1138 matNT
.setValue( v
[0], v
[1], 0.f
, -(u
[0] * v
[0] + u
[1] * v
[1]),
1139 -v
[1], v
[0], 0.f
, (u
[0] * v
[1] - u
[1] * v
[0]),
1141 0.f
, 0.f
, 0.f
, 1.f
);
1143 // M2 = T2 * M1 -- translate tip to origin
1144 matNT
[3][0] = - (matNT
[0][0] * trapTip
[0] + matNT
[1][0] * trapTip
[1]);
1145 matNT
[3][1] = - (matNT
[0][1] * trapTip
[0] + matNT
[1][1] * trapTip
[1]);
1147 // M3 = H * M2 -- shear to make it symmetric wrt to the y axis
1149 v
[0] = matNT
[0][0] * u
[0] + matNT
[1][0] * u
[1] + matNT
[3][0];
1150 v
[1] = matNT
[0][1] * u
[0] + matNT
[1][1] * u
[1] + matNT
[3][1];
1152 Real32 a
= - v
[0] / v
[1];
1154 // matNT[*][0] : = mat[*][0] + a * mat[*][1]
1155 matNT
[0][0] += a
* matNT
[0][1];
1156 matNT
[1][0] += a
* matNT
[1][1];
1157 matNT
[2][0] += a
* matNT
[2][1];
1158 matNT
[3][0] += a
* matNT
[3][1];
1160 // M4 = S1 * M3 -- scale to make sidelines orthogonal and
1161 // top line is at y == 1
1162 // v = 1 / (M3 * t2)
1163 v
[0] = 1.f
/ (matNT
[0][0] * trapVerts
[2][0] + matNT
[1][0] * trapVerts
[2][1] + matNT
[3][0]);
1164 v
[1] = 1.f
/ (matNT
[0][1] * trapVerts
[2][0] + matNT
[1][1] * trapVerts
[2][1] + matNT
[3][1]);
1166 matNT
[0][0] *= v
[0]; matNT
[0][1] *= v
[1];
1167 matNT
[1][0] *= v
[0]; matNT
[1][1] *= v
[1];
1168 matNT
[2][0] *= v
[0]; matNT
[2][1] *= v
[1];
1169 matNT
[3][0] *= v
[0]; matNT
[3][1] *= v
[1];
1171 // M5 = N * M4 -- turn trapezoid into rectangle
1172 matNT
[0][3] = matNT
[0][1];
1173 matNT
[1][3] = matNT
[1][1];
1174 matNT
[2][3] = matNT
[2][1];
1175 matNT
[3][3] = matNT
[3][1];
1178 // M6 = T3 * M5 -- translate center to origin
1179 // u = "M5 * t0" - only y and w coordinates
1180 // v = "M5 * t2" - only y and w coordinates
1181 u
[0] = matNT
[0][1] * trapVerts
[0][0] + matNT
[1][1] * trapVerts
[0][1] + matNT
[3][1];
1182 u
[1] = matNT
[0][3] * trapVerts
[0][0] + matNT
[1][3] * trapVerts
[0][1] + matNT
[3][3];
1183 v
[0] = matNT
[0][1] * trapVerts
[2][0] + matNT
[1][1] * trapVerts
[2][1] + matNT
[3][1];
1184 v
[1] = matNT
[0][3] * trapVerts
[2][0] + matNT
[1][3] * trapVerts
[2][1] + matNT
[3][3];
1185 a
= - 0.5f
* (u
[0] / u
[1] + v
[0] / v
[1]);
1187 matNT
[0][1] += matNT
[0][3] * a
;
1188 matNT
[1][1] += matNT
[1][3] * a
;
1189 matNT
[2][1] += matNT
[2][3] * a
;
1190 matNT
[3][1] += matNT
[3][3] * a
;
1192 // M7 = S2 * M6 -- scale to fill -1/+1 square
1193 // u = "M6 * t0" - only y and w coordinates
1194 u
[0] = matNT
[0][1] * trapVerts
[0][0] + matNT
[1][1] * trapVerts
[0][1] + matNT
[3][1];
1195 u
[1] = matNT
[0][3] * trapVerts
[0][0] + matNT
[1][3] * trapVerts
[0][1] + matNT
[3][3];
1206 // Dummy draw function.
1207 void TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc(DrawEnv
*drawEnv
)
1212 void TrapezoidalShadowMapEngine::calcJitterTexture(
1214 UInt32 blockSizeX
, UInt32 blockSizeY
,
1215 UInt32 angleSectors
, UInt32 distSectors
)
1217 UInt32 zSize
= angleSector
* distSectors
/ 2;
1219 img
->set(OSG_RGBA_PF
,
1227 OSG_UINT8_IMAGEDATA
,
1231 Real32 sizeCellU
= 1.f
/ angleSectors
;
1232 Real32 sizeCellV
= 1.f
/ distSectors
;
1234 UInt8
*pPixel
= img
->editData(0, 0, 0);
1236 for(UInt32 zPos
= 0; zPos
< zSize
; ++zPos
)
1238 Real32 cell0U
= sizeCellU
* (2 * zPos
% angleSectors
);
1239 Real32 cell0V
= sizeCellV
* (distSectors
- 1 - (2 * zPos
/ angleSectors
));
1240 Real32 cell1U
= sizeCellU
* (1 + (2 * zPos
% angleSectors
));
1241 Real32 cell1V
= sizeCellV
* (distSectors
- 1 - (2 * zPos
/ angleSectors
));
1243 Real32 grid0U
= sizeCellU
* (2 * zPos
% blockSizeX
);
1244 Real32 grid0V
= 1.f
- sizeCellV
* (2 * zPos
/ blockSizeY
);
1245 Real32 grid1U
= sizeCellU
* ((2 * zPos
% blockSizeX
) + 1);
1246 Real32 grid1V
= 1.f
- sizeCellV
* (2 * zPos
/ blockSizeY
);
1248 for(UInt32 xPos
= 0; xPos
< blockSizeX
; ++xPos
)
1250 for(UInt32 yPos
= 0; yPos
< blockSizeY
; ++yPos
)