fixed: compile issue
[opensg.git] / Source / Contrib / TrapezoidalShadowMaps / OSGTrapezoidalShadowMapEngine.cpp
blob21dcba5da58ecd52bf5cfb6b908b1baedb8685fa
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2006 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
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. *
18 * *
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. *
23 * *
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. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 //---------------------------------------------------------------------------
40 // Includes
41 //---------------------------------------------------------------------------
43 #include "OSGConfig.h"
45 #include "OSGTrapezoidalShadowMapEngine.h"
47 #include "OSGLine.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
69 OSG_BEGIN_NAMESPACE
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 /***************************************************************************\
77 * Class variables *
78 \***************************************************************************/
80 #ifdef OSG_TSME_LIGHTPASS_EXACT
82 const std::string TrapezoidalShadowMapEngine::_lightPassVPCode(
83 "#version 120\n"
84 "\n"
85 "uniform mat4 TSME_matNT;\n"
86 "\n"
87 "varying vec4 TSME_plcPos;\n"
88 "\n"
89 "void main(void)\n"
90 "{\n"
91 " TSME_plcPos = ftransform();\n"
92 " gl_Position = TSME_matNT * TSME_plcPos;\n"
93 "}\n"
96 const std::string TrapezoidalShadowMapEngine::_lightPassFPCode(
97 "#version 120\n"
98 "\n"
99 "const float TSME_depthEps = 1e-7;\n"
100 "\n"
101 "uniform float TSME_offsetFactor;\n"
102 "uniform float TSME_offsetBias;\n"
103 "\n"
104 "varying vec4 TSME_plcPos;\n"
105 "\n"
106 "void main(void)\n"
107 "{\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"
113 "}\n"
116 #else
118 const std::string TrapezoidalShadowMapEngine::_lightPassVPCode(
119 "#version 120\n"
120 "\n"
121 "uniform mat4 TSME_matNT;\n"
122 "\n"
123 "void main(void)\n"
124 "{\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"
128 "}\n"
131 const std::string TrapezoidalShadowMapEngine::_lightPassFPCode("");
133 #endif // OSG_TSME_LIGHTPASS_EXACT
135 const std::string TrapezoidalShadowMapEngine::_pointFPCode(
136 "#version 120\n"
137 "\n"
138 "#define TSME_PCF 1\n"
139 "\n"
140 "#extension GL_EXT_gpu_shader4 : require\n"
141 "#extension GL_EXT_gpu_shader4 : enable\n"
142 "\n"
143 "uniform samplerCubeShadow TSME_texShadow;\n"
144 "uniform vec2 TSME_texShadowSizeInv;\n"
145 "\n"
146 "uniform mat4 TSME_matEyeToLight;\n"
147 "uniform mat4 TSME_matLightProj;\n"
148 "uniform mat4 TSME_matNT[6];\n"
149 "\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"
155 "\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"
162 "\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"
169 " );\n"
170 "\n"
171 "vec4 OSG_SSME_FP_calcShadow(in vec4 fragPos)\n"
172 "{\n"
173 " vec4 shadow = vec4(0., 0., 0., 0.);\n"
174 " vec4 lcPos = TSME_matEyeToLight * fragPos;\n"
175 " vec4 lcAbsPos = abs(lcPos);\n"
176 " vec4 plcPos;\n"
177 " vec4 tcPos;\n"
178 " vec4 pcfOffset0;\n"
179 " vec4 pcfOffset1;\n"
180 "\n"
181 " if(lcAbsPos.x > lcAbsPos.y && lcAbsPos.x > lcAbsPos.z)\n"
182 " {\n"
183 " pcfOffset0 = vec4(0., 0., TSME_texShadowSizeInv.x, 0.);\n"
184 " pcfOffset1 = vec4(0., TSME_texShadowSizeInv.y, 0. , 0.);\n"
185 "\n"
186 " if(lcPos.x >= 0.)\n"
187 " {\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"
193 " tcPos.x = 1.;\n"
194 " }\n"
195 " else\n"
196 " {\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"
202 " tcPos.x = -1.;\n"
203 " }\n"
204 " }\n"
205 " else if(lcAbsPos.y > lcAbsPos.x && lcAbsPos.y > lcAbsPos.z)\n"
206 " {\n"
207 " pcfOffset0 = vec4(TSME_texShadowSizeInv.x, 0., 0., 0.);\n"
208 " pcfOffset1 = vec4(0., 0., TSME_texShadowSizeInv.y, 0.);\n"
209 "\n"
210 " if(lcPos.y >= 0.)\n"
211 " {\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"
217 " tcPos.y = 1.;\n"
218 " }\n"
219 " else\n"
220 " {\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"
226 " tcPos.y = -1.;\n"
227 " }\n"
228 " }\n"
229 " else\n"
230 " {\n"
231 " pcfOffset0 = vec4(TSME_texShadowSizeInv.x, 0., 0., 0.);\n"
232 " pcfOffset1 = vec4(0., TSME_texShadowSizeInv.y, 0., 0.);\n"
233 "\n"
234 " if(lcPos.z >= 0.)\n"
235 " {\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"
241 " tcPos.z = 1.;\n"
242 " }\n"
243 " else\n"
244 " {\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"
250 " tcPos.z = -1.;\n"
251 " }\n"
252 " }\n"
253 "\n"
254 " plcPos = plcPos / plcPos.w;\n"
255 " plcPos = 0.5 + 0.5 * plcPos;\n"
256 "\n"
257 "#ifndef TSME_PCF\n"
258 " shadow = shadowCube(TSME_texShadow, vec4(tcPos.xyz, plcPos.z));\n"
259 "#else\n"
260 " vec4 lookupBase = vec4(tcPos.xyz, plcPos.z);\n"
261 " vec4 lookup;\n"
262 "\n"
263 " for(int i = 0; i < 4; ++i)\n"
264 " {\n"
265 " lookup = TSME_offsetFactors[i].x * pcfOffset0 +\n"
266 " TSME_offsetFactors[i].y * pcfOffset1 + lookupBase;\n"
267 " shadow += shadowCube(TSME_texShadow, lookup);\n"
268 " }\n"
269 "\n"
270 " if((shadow.x - 4.0) * shadow.x == 0.0)\n"
271 " {\n"
272 " shadow *= 0.25;\n"
273 " }\n"
274 " else\n"
275 " {\n"
276 " for(int i = 4; i < 16; ++i)\n"
277 " {\n"
278 " lookup = TSME_offsetFactors[i].x * pcfOffset0 +\n"
279 " TSME_offsetFactors[i].y * pcfOffset1 + lookupBase;\n"
280 " shadow += shadowCube(TSME_texShadow, lookup);\n"
281 " }\n"
282 "\n"
283 " shadow *= 1.0 / 16.0;\n"
284 " }\n"
285 "#endif // TSME_PCF\n"
286 "\n"
287 " return shadow;\n"
288 "}\n"
291 const std::string TrapezoidalShadowMapEngine::_spotFPCode(
292 "#version 120\n"
293 "\n"
294 "#define TSME_PCF 1\n"
295 "\n"
296 "uniform sampler2DShadow TSME_texShadow;\n"
297 "uniform vec2 TSME_texShadowSizeInv;\n"
298 "\n"
299 "uniform mat4 TSME_matEyeToLight;\n"
300 "uniform mat4 TSME_matLightProj;\n"
301 "uniform mat4 TSME_matNT;\n"
302 "\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"
308 "\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"
315 "\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"
322 " );\n"
323 "\n"
324 "vec4 OSG_SSME_FP_calcShadow(in vec4 ecFragPos)\n"
325 "{\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"
329 "\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"
334 "\n"
335 " vec3 lookupBase = vec3(tcPos.xy, plcPos.z);\n"
336 " vec3 lookup;\n"
337 "\n"
338 "#ifndef TSME_PCF\n"
339 " shadow = shadow2D(TSME_texShadow, lookupBase);\n"
340 "#else\n"
341 " for(int i = 0; i < 4; ++i)\n"
342 " {\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"
347 " }\n"
348 "\n"
349 " if((shadow.x - 4.) * shadow.x == 0)\n"
350 " {\n"
351 " shadow *= 0.25;\n"
352 " }\n"
353 " else\n"
354 " {\n"
355 " for(int i = 4; i < 16; ++i)\n"
356 " {\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"
361 " }\n"
362 "\n"
363 " shadow *= 1.0 / 16.0;\n"
364 " }\n"
365 "#endif\n"
366 "\n"
367 " return shadow;\n"
368 "}\n"
371 /***************************************************************************\
372 * Class methods *
373 \***************************************************************************/
375 void TrapezoidalShadowMapEngine::initMethod(InitPhase ePhase)
377 Inherited::initMethod(ePhase);
381 /***************************************************************************\
382 * Instance methods *
383 \***************************************************************************/
385 /*-------------------------------------------------------------------------*\
386 - private -
387 \*-------------------------------------------------------------------------*/
389 /*----------------------- constructors & destructors ----------------------*/
391 TrapezoidalShadowMapEngine::TrapezoidalShadowMapEngine(void) :
392 Inherited()
396 TrapezoidalShadowMapEngine::TrapezoidalShadowMapEngine(const TrapezoidalShadowMapEngine &source) :
397 Inherited(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);
415 if(data == NULL)
417 TSMEngineDataUnrecPtr newData = TSMEngineData::createLocal();
418 this->setData(newData, _iDataSlotId, ract);
420 data = newData;
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);
433 else
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,
450 UInt32 origin,
451 BitVector details)
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());
471 switch(eType)
473 case Point:
475 PointLight *pointL =
476 boost::polymorphic_downcast<PointLight *>(light);
478 handlePointLightEnter(pointL, ract, data);
480 break;
482 case Directional:
484 DirectionalLight *dirL =
485 boost::polymorphic_downcast<DirectionalLight *>(light);
487 handleDirectionalLightEnter(dirL, ract, data);
489 break;
491 case Spot:
493 SpotLight *spotL =
494 boost::polymorphic_downcast<SpotLight *>(light);
496 handleSpotLightEnter(spotL, ract, data);
498 break;
500 default:
502 FWARNING(("TrapezoidalShadowMapEngine::handleEnter: Unknown "
503 "light type [%u]\n", eType));
505 break;
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());
517 Matrix matLightProj;
519 Real32 shadowNear = (getShadowNear() != 0.f ?
520 getShadowNear() :
521 parentPart->getNear() );
522 Real32 shadowFar = (getShadowFar () != 0.f ?
523 getShadowFar () :
524 parentPart->getFar() );
526 Inherited::calcPointLightRange(
527 pointL, 0.01f,
528 shadowNear, shadowFar, shadowNear, shadowFar);
530 MatrixPerspective(matLightProj, Pi / 4.f, 1.f,
531 shadowNear, shadowFar );
533 Matrix matWorldToLight;
534 Matrix matEyeToLight;
535 MFMatrix mfMatNT;
537 mfMatNT.resize(6);
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();
550 if(shadowFP == NULL)
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;
567 else
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;
584 Matrix matNT;
586 lightFrust.setPlanes(matLightFull);
588 bool matNTValid =
589 calcTrapezoidalTransform(mfMatNT[faceIdx],
590 matEyeToWorld, matLightFull,
591 eyeFrust, lightFrust );
593 if(matNTValid == false)
595 // setup a minimal partition to clear the cube face
597 commitChanges();
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,
615 target->getWidth (),
616 target->getHeight() );
618 part->setBackground(back);
620 RenderPartition::SimpleDrawCallback emptyCubeFaceDraw =
621 boost::bind(
622 &TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc,
623 this, _1);
625 part->dropFunctor(emptyCubeFaceDraw);
627 this->popPartition(ract);
629 else
631 updateLightPassMaterial(data, faceIdx, mfMatNT[faceIdx]);
633 commitChanges();
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,
646 target->getWidth (),
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 );
693 Matrix matLightProj;
694 Matrix matLightFull(matWorldToLight);
696 Real32 shadowNear = (getShadowNear() != 0.f ?
697 getShadowNear() :
698 parentPart->getNear() );
699 Real32 shadowFar = (getShadowFar () != 0.f ?
700 getShadowFar () :
701 parentPart->getFar() );
703 Inherited::calcPointLightRange(
704 spotL, 0.01f,
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;
719 Matrix matNT;
721 lightFrust.setPlanes(matLightFull);
723 bool matNTValid = calcTrapezoidalTransform(matNT,
724 matEyeToWorld, matLightFull,
725 eyeFrust, lightFrust );
727 if(matNTValid == false)
728 return;
730 // Real32 cosSpotCutOff = osgCos(spotL->getSpotCutOff());
732 Int32 shadowTexUnit = (this->getForceTextureUnit() >= 0) ?
733 this->getForceTextureUnit() : 7;
734 ShaderProgram *shadowFP = this->getShadowFragmentProgram();
736 if(shadowFP == NULL)
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;
753 else
755 shadowFP->updateUniformVariable("TSME_matEyeToLight", matEyeToLight);
756 shadowFP->updateUniformVariable("TSME_matLightProj", matLightProj );
757 shadowFP->updateUniformVariable("TSME_matNT", matNT );
760 updateLightPassMaterial(data, 0, matNT);
762 commitChanges();
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,
775 target->getWidth (),
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];
809 intVerts.clear ( );
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,
821 // left/right).
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) )
834 continue;
836 Line intLine;
837 if(planes[i]->intersect(*planes[j], intLine) == false)
838 continue;
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) )
848 continue;
850 Pnt3f intPoint;
851 if(planes[k]->intersectInfinite(intLine, intPoint) == false)
852 continue;
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)
863 continue;
865 if(planes[m]->isInHalfSpace(intPoint) == false)
867 intPointValid = false;
868 break;
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);
925 #else
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;
949 #endif
953 else
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.
970 The major steps are:
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
974 (-1, 1) square
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(
983 Matrix &matNT,
984 const Matrix &matEyeToWorld,
985 const Matrix &matLightFull,
986 const FrustumVolume &eyeFrust,
987 const FrustumVolume &lightFrust )
989 // obtain post proj. light space eye position
990 Pnt3f eyePos;
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;
996 Pnt3f intCenter;
997 intersectFrusta(eyeFrust, lightFrust, intVerts, intCenter);
999 if(intVerts.empty() == true)
1000 return false;
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);
1016 clDir.normalize();
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
1029 Pnt2f tlBase;
1030 Pnt2f blBase;
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));
1046 if(dist < topDist)
1048 topDist = dist;
1049 tlBase = ivPnt;
1052 if(dist > baseDist)
1054 baseDist = dist;
1055 blBase = ivPnt;
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;
1077 Real32 xi = -0.6f;
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]
1086 Pnt2f posPnt;
1087 Real32 posCos = 1.f;
1088 Pnt2f negPnt;
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;
1096 v.normalize();
1097 Real32 currCos = osgAbs(clDir.dot(v));
1099 if(clNorm.dot(v) >= 0.f)
1101 if(currCos <= posCos)
1103 posPnt = ivPnt;
1104 posCos = currCos;
1107 else
1109 if(currCos <= negCos)
1111 negPnt = ivPnt;
1112 negCos = currCos;
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];
1136 v.normalize();
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]),
1140 0.f, 0.f, 1.f, 0.f,
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
1148 // v = M2 * u
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];
1176 matNT[3][1] += 1.f;
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];
1196 a = -u[1] / u[0];
1198 matNT[0][1] *= a;
1199 matNT[1][1] *= a;
1200 matNT[2][1] *= a;
1201 matNT[3][1] *= a;
1203 return true;
1206 // Dummy draw function.
1207 void TrapezoidalShadowMapEngine::emptyCubeFaceDrawFunc(DrawEnv *drawEnv)
1211 #if 0
1212 void TrapezoidalShadowMapEngine::calcJitterTexture(
1213 Image *img,
1214 UInt32 blockSizeX, UInt32 blockSizeY,
1215 UInt32 angleSectors, UInt32 distSectors)
1217 UInt32 zSize = angleSector * distSectors / 2;
1219 img->set(OSG_RGBA_PF,
1220 blockSizeX,
1221 blockSizeY,
1222 zSize,
1225 0.0,
1226 NULL,
1227 OSG_UINT8_IMAGEDATA,
1228 true,
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)
1257 #endif
1259 OSG_END_NAMESPACE