root/OpenSceneGraph/trunk/src/osgShadow/StandardShadowMap.cpp @ 13041

Revision 13041, 41.4 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12 *
13 * ViewDependentShadow codes Copyright (C) 2008 Wojciech Lewandowski
14 * Thanks to to my company http://www.ai.com.pl for allowing me free this work.
15*/
16
17#include <osgShadow/StandardShadowMap>
18#include <osg/PolygonOffset>
19#include <osg/ComputeBoundsVisitor>
20#include <osgShadow/ShadowedScene>
21#include <osg/Geode>
22#include <osg/Geometry>
23#include <osg/CullFace>
24#include <osg/AlphaFunc>
25#include <osg/Point>
26
27#include <stdio.h>
28
29using namespace osgShadow;
30
31#define DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR 0
32#define FRAGMENT_SHADERS_ONLY 1
33
34
35StandardShadowMap::StandardShadowMap():
36    BaseClass(),
37    _polygonOffsetFactor( 1.1f ),
38    _polygonOffsetUnits( 4.0f ),
39    _textureSize( 1024, 1024 ),
40    _baseTextureUnit( 0 ),
41    _shadowTextureUnit( 1 ),
42    _baseTextureCoordIndex( 0 ),
43    _shadowTextureCoordIndex( 1 )
44
45{
46#if FRAGMENT_SHADERS_ONLY
47    _mainFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
48        " // following expressions are auto modified - do not change them:       \n"
49        " // gl_TexCoord[0]  0 - can be subsituted with other index              \n"
50        "                                                                        \n"
51        "float DynamicShadow( );                                                 \n"
52        "                                                                        \n"
53        "uniform sampler2D baseTexture;                                          \n"
54        "                                                                        \n"
55        "void main(void)                                                         \n"
56        "{                                                                       \n"
57        "  vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor;     \n"
58//        "  // Add ambient from Light of index = 0                                \n"
59//        "  colorAmbientEmissive += gl_FrontLightProduct[0].ambient;              \n"
60        "  vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy );             \n"
61        "  color *= mix( colorAmbientEmissive, gl_Color, DynamicShadow() );      \n"
62#if DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR
63        "  color.xy = abs( dFdy( gl_TexCoord[1].xy / gl_TexCoord[1].w ) )* 1024.0; \n"
64        "  color.z = color.y; \n"
65        "  color.x = color.z; \n"
66        "  color.y = color.z; \n"
67        "  color.a = 1.0; \n"
68#endif
69//      "  float fog = clamp((gl_Fog.end - gl_FogFragCoord)*gl_Fog.scale, 0.,1.);\n"
70//      "  color.rgb = mix( gl_Fog.color.rgb, color.rgb, fog );                  \n"
71        "  gl_FragColor = color;                                                 \n"
72        "} \n" );
73
74    _shadowFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
75        " // following expressions are auto modified - do not change them:      \n"
76        " // gl_TexCoord[1]  1 - can be subsituted with other index             \n"
77        "                                                                       \n"
78        "uniform sampler2DShadow shadowTexture;                                 \n"
79        "                                                                       \n"
80        "float DynamicShadow( )                                                 \n"
81        "{                                                                      \n"
82        "    return shadow2DProj( shadowTexture, gl_TexCoord[1] ).r;            \n"
83        "} \n" );
84
85
86    _shadowVertexShader = NULL;
87    _mainVertexShader = NULL;
88
89#else
90    _mainFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
91        " // following expressions are auto modified - do not change them:       \n"
92        " // gl_TexCoord[0]  0 - can be subsituted with other index              \n"
93        "                                                                        \n"
94        "float DynamicShadow( );                                                 \n"
95        "                                                                        \n"
96        "varying vec4 colorAmbientEmissive;                                      \n"
97        "                                                                        \n"
98        "uniform sampler2D baseTexture;                                          \n"
99        "                                                                        \n"
100        "void main(void)                                                         \n"
101        "{                                                                       \n"
102        "  vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy );             \n"
103        "  color *= mix( colorAmbientEmissive, gl_Color, DynamicShadow() );      \n"
104#if DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR
105        "  color.xy = abs( dFdy( gl_TexCoord[1].xy / gl_TexCoord[1].w ) )* 1024.0; \n"
106        "  color.z = color.y; \n"
107        "  color.x = color.z; \n"
108        "  color.y = color.z; \n"
109        "  color.a = 1.0; \n"
110#endif
111//      "  float fog = clamp((gl_Fog.end - gl_FogFragCoord)*gl_Fog.scale, 0.,1.);\n"
112//      "  color.rgb = mix( gl_Fog.color.rgb, color.rgb, fog );                  \n"
113        "  gl_FragColor = color;                                                 \n"
114        "} \n" );
115
116
117    _shadowFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
118        " // following expressions are auto modified - do not change them:      \n"
119        " // gl_TexCoord[1]  1 - can be subsituted with other index             \n"
120        "                                                                       \n"
121        "uniform sampler2DShadow shadowTexture;                                 \n"
122        "                                                                       \n"
123        "float DynamicShadow( )                                                 \n"
124        "{                                                                      \n"
125        "    return shadow2DProj( shadowTexture, gl_TexCoord[1] ).r;            \n"
126        "} \n" );
127
128
129
130    _shadowVertexShader = new osg::Shader( osg::Shader::VERTEX,
131        " // following expressions are auto modified - do not change them:      \n"
132        " // gl_TexCoord[1]  1 - can be subsituted with other index             \n"
133        " // gl_EyePlaneS[1] 1 - can be subsituted with other index             \n"
134        " // gl_EyePlaneT[1] 1 - can be subsituted with other index             \n"
135        " // gl_EyePlaneR[1] 1 - can be subsituted with other index             \n"
136        " // gl_EyePlaneQ[1] 1 - can be subsituted with other index             \n"
137        "                                                                       \n"
138        "void DynamicShadow( in vec4 ecPosition )                               \n"
139        "{                                                                      \n"
140        "    // generate coords for shadow mapping                              \n"
141        "    gl_TexCoord[1].s = dot( ecPosition, gl_EyePlaneS[1] );             \n"
142        "    gl_TexCoord[1].t = dot( ecPosition, gl_EyePlaneT[1] );             \n"
143        "    gl_TexCoord[1].p = dot( ecPosition, gl_EyePlaneR[1] );             \n"
144        "    gl_TexCoord[1].q = dot( ecPosition, gl_EyePlaneQ[1] );             \n"
145        "} \n" );
146
147    _mainVertexShader = new osg::Shader( osg::Shader::VERTEX,
148        " // following expressions are auto modified - do not change them:      \n"
149        " // gl_TexCoord[0]      0 - can be subsituted with other index         \n"
150        " // gl_TextureMatrix[0] 0 - can be subsituted with other index         \n"
151        " // gl_MultiTexCoord0   0 - can be subsituted with other index         \n"
152        "                                                                       \n"
153        "const int NumEnabledLights = 1;                                        \n"
154        "                                                                       \n"
155        "void DynamicShadow( in vec4 ecPosition );                              \n"
156        "                                                                       \n"
157        "varying vec4 colorAmbientEmissive;                                     \n"
158        "                                                                       \n"
159        "void SpotLight(in int i,                                               \n"
160        "               in vec3 eye,                                            \n"
161        "               in vec3 ecPosition3,                                    \n"
162        "               in vec3 normal,                                         \n"
163        "               inout vec4 ambient,                                     \n"
164        "               inout vec4 diffuse,                                     \n"
165        "               inout vec4 specular)                                    \n"
166        "{                                                                      \n"
167        "    float nDotVP;          // normal . light direction                 \n"
168        "    float nDotHV;          // normal . light half vector               \n"
169        "    float pf;              // power factor                             \n"
170        "    float spotDot;         // cosine of angle between spotlight        \n"
171        "    float spotAttenuation; // spotlight attenuation factor             \n"
172        "    float attenuation;     // computed attenuation factor              \n"
173        "    float d;               // distance from surface to light source    \n"
174        "    vec3 VP;               // direction from surface to light position \n"
175        "    vec3 halfVector;       // direction of maximum highlights          \n"
176        "                                                                       \n"
177        "    // Compute vector from surface to light position                   \n"
178        "    VP = vec3(gl_LightSource[i].position) - ecPosition3;               \n"
179        "                                                                       \n"
180        "    // Compute distance between surface and light position             \n"
181        "    d = length(VP);                                                    \n"
182        "                                                                       \n"
183        "    // Normalize the vector from surface to light position             \n"
184        "    VP = normalize(VP);                                                \n"
185        "                                                                       \n"
186        "    // Compute attenuation                                             \n"
187        "    attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +       \n"
188        "                         gl_LightSource[i].linearAttenuation * d +     \n"
189        "                         gl_LightSource[i].quadraticAttenuation *d*d); \n"
190        "                                                                       \n"
191        "    // See if point on surface is inside cone of illumination          \n"
192        "    spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));    \n"
193        "                                                                       \n"
194        "    if (spotDot < gl_LightSource[i].spotCosCutoff)                     \n"
195        "        spotAttenuation = 0.0; // light adds no contribution           \n"
196        "    else                                                               \n"
197        "        spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);\n"
198        "                                                                       \n"
199        "    // Combine the spotlight and distance attenuation.                 \n"
200        "    attenuation *= spotAttenuation;                                    \n"
201        "                                                                       \n"
202        "    halfVector = normalize(VP + eye);                                  \n"
203        "                                                                       \n"
204        "    nDotVP = max(0.0, dot(normal, VP));                                \n"
205        "    nDotHV = max(0.0, dot(normal, halfVector));                        \n"
206        "                                                                       \n"
207        "    if (nDotVP == 0.0)                                                 \n"
208        "        pf = 0.0;                                                      \n"
209        "    else                                                               \n"
210        "        pf = pow(nDotHV, gl_FrontMaterial.shininess);                  \n"
211        "                                                                       \n"
212        "    ambient  += gl_LightSource[i].ambient * attenuation;               \n"
213        "    diffuse  += gl_LightSource[i].diffuse * nDotVP * attenuation;      \n"
214        "    specular += gl_LightSource[i].specular * pf * attenuation;         \n"
215        "}                                                                      \n"
216        "                                                                       \n"
217        "void PointLight(in int i,                                              \n"
218        "                in vec3 eye,                                           \n"
219        "                in vec3 ecPosition3,                                   \n"
220        "                in vec3 normal,                                        \n"
221        "                inout vec4 ambient,                                    \n"
222        "                inout vec4 diffuse,                                    \n"
223        "                inout vec4 specular)                                   \n"
224        "{                                                                      \n"
225        "    float nDotVP;      // normal . light direction                     \n"
226        "    float nDotHV;      // normal . light half vector                   \n"
227        "    float pf;          // power factor                                 \n"
228        "    float attenuation; // computed attenuation factor                  \n"
229        "    float d;           // distance from surface to light source        \n"
230        "    vec3  VP;          // direction from surface to light position     \n"
231        "    vec3  halfVector;  // direction of maximum highlights              \n"
232        "                                                                       \n"
233        "    // Compute vector from surface to light position                   \n"
234        "    VP = vec3(gl_LightSource[i].position) - ecPosition3;               \n"
235        "                                                                       \n"
236        "    // Compute distance between surface and light position             \n"
237        "    d = length(VP);                                                    \n"
238        "                                                                       \n"
239        "    // Normalize the vector from surface to light position             \n"
240        "    VP = normalize(VP);                                                \n"
241        "                                                                       \n"
242        "    // Compute attenuation                                             \n"
243        "    attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +       \n"
244        "                         gl_LightSource[i].linearAttenuation * d +     \n"
245        "                         gl_LightSource[i].quadraticAttenuation * d*d);\n"
246        "                                                                       \n"
247        "    halfVector = normalize(VP + eye);                                  \n"
248        "                                                                       \n"
249        "    nDotVP = max(0.0, dot(normal, VP));                                \n"
250        "    nDotHV = max(0.0, dot(normal, halfVector));                        \n"
251        "                                                                       \n"
252        "    if (nDotVP == 0.0)                                                 \n"
253        "        pf = 0.0;                                                      \n"
254        "    else                                                               \n"
255        "        pf = pow(nDotHV, gl_FrontMaterial.shininess);                  \n"
256        "                                                                       \n"
257        "    ambient += gl_LightSource[i].ambient * attenuation;                \n"
258        "    diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;       \n"
259        "    specular += gl_LightSource[i].specular * pf * attenuation;         \n"
260        "}                                                                      \n"
261        "                                                                       \n"
262        "void DirectionalLight(in int i,                                        \n"
263        "                      in vec3 normal,                                  \n"
264        "                      inout vec4 ambient,                              \n"
265        "                      inout vec4 diffuse,                              \n"
266        "                      inout vec4 specular)                             \n"
267        "{                                                                      \n"
268        "     float nDotVP;         // normal . light direction                 \n"
269        "     float nDotHV;         // normal . light half vector               \n"
270        "     float pf;             // power factor                             \n"
271        "                                                                       \n"
272        "     nDotVP = max(0.0, dot(normal,                                     \n"
273        "                normalize(vec3(gl_LightSource[i].position))));         \n"
274        "     nDotHV = max(0.0, dot(normal,                                     \n"
275        "                      vec3(gl_LightSource[i].halfVector)));            \n"
276        "                                                                       \n"
277        "     if (nDotVP == 0.0)                                                \n"
278        "         pf = 0.0;                                                     \n"
279        "     else                                                              \n"
280        "         pf = pow(nDotHV, gl_FrontMaterial.shininess);                 \n"
281        "                                                                       \n"
282        "     ambient  += gl_LightSource[i].ambient;                            \n"
283        "     diffuse  += gl_LightSource[i].diffuse * nDotVP;                   \n"
284        "     specular += gl_LightSource[i].specular * pf;                      \n"
285        "}                                                                      \n"
286        "                                                                       \n"
287        "void main( )                                                           \n"
288        "{                                                                      \n"
289        "    // Transform vertex to clip space                                  \n"
290        "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;            \n"
291        "    vec3 normal = normalize( gl_NormalMatrix * gl_Normal );            \n"
292        "                                                                       \n"
293        "    vec4  ecPos  = gl_ModelViewMatrix * gl_Vertex;                     \n"
294        "    float ecLen  = length( ecPos );                                    \n"
295        "    vec3  ecPosition3 = ecPos.xyz / ecPos.w;                           \n"
296        "                                                                       \n"
297        "    vec3  eye = vec3( 0.0, 0.0, 1.0 );                                 \n"
298        "    //vec3  eye = -normalize(ecPosition3);                             \n"
299        "                                                                       \n"
300        "    DynamicShadow( ecPos );                                            \n"
301        "                                                                       \n"
302        "     gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;         \n"
303        "                                                                       \n"
304        "    // Front Face lighting                                             \n"
305        "                                                                       \n"
306        "    // Clear the light intensity accumulators                          \n"
307        "    vec4 amb  = vec4(0.0);                                             \n"
308        "    vec4 diff = vec4(0.0);                                             \n"
309        "    vec4 spec = vec4(0.0);                                             \n"
310        "                                                                       \n"
311        "    // Loop through enabled lights, compute contribution from each     \n"
312        "    for (int i = 0; i < NumEnabledLights; i++)                         \n"
313        "   {                                                                   \n"
314        "       if (gl_LightSource[i].position.w == 0.0)                        \n"
315        "           DirectionalLight(i, normal, amb, diff, spec);               \n"
316        "       else if (gl_LightSource[i].spotCutoff == 180.0)                 \n"
317        "           PointLight(i, eye, ecPosition3, normal, amb, diff, spec);   \n"
318        "       else                                                            \n"
319        "           SpotLight(i, eye, ecPosition3, normal, amb, diff, spec);    \n"
320        "    }                                                                  \n"
321        "                                                                       \n"
322        "    colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor +      \n"
323        "                           amb * gl_FrontMaterial.ambient;             \n"
324        "                                                                       \n"
325        "    gl_FrontColor = colorAmbientEmissive +                             \n"
326        "                    diff * gl_FrontMaterial.diffuse;                   \n"
327        "                                                                       \n"
328        "    gl_FrontSecondaryColor = vec4(spec*gl_FrontMaterial.specular);    \n"
329        "                                                                       \n"
330        "    gl_BackColor = gl_FrontColor;                                      \n"
331        "    gl_BackSecondaryColor = gl_FrontSecondaryColor;                    \n"
332        "                                                                       \n"
333        "    gl_FogFragCoord = ecLen;                                           \n"
334        "} \n" );
335#endif
336}
337
338StandardShadowMap::StandardShadowMap(const StandardShadowMap& copy, const osg::CopyOp& copyop) :
339    BaseClass(copy,copyop),
340    _polygonOffsetFactor( copy._polygonOffsetFactor ),
341    _polygonOffsetUnits( copy._polygonOffsetUnits ),
342    _textureSize( copy._textureSize ),
343    _baseTextureUnit( copy._baseTextureUnit ),
344    _shadowTextureUnit( copy._shadowTextureUnit )
345{
346    if( copy._mainVertexShader.valid() )
347        _mainVertexShader = dynamic_cast<osg::Shader*>
348            ( copy._mainVertexShader->clone(copyop) );
349
350    if( copy._mainFragmentShader.valid() )
351        _mainFragmentShader = dynamic_cast<osg::Shader*>
352            ( copy._mainFragmentShader->clone(copyop) );
353
354    if( copy._shadowVertexShader.valid() )
355        _shadowVertexShader = dynamic_cast<osg::Shader*>
356            ( copy._shadowVertexShader->clone(copyop) );
357
358    if( copy._shadowFragmentShader.valid() )
359        _shadowFragmentShader = dynamic_cast<osg::Shader*>
360            ( copy._shadowFragmentShader->clone(copyop) );
361}
362
363StandardShadowMap::~StandardShadowMap(void)
364{
365
366}
367
368void StandardShadowMap::updateTextureCoordIndices( unsigned int fromTextureCoordIndex, unsigned int toTextureCoordIndex )
369{
370
371    if( fromTextureCoordIndex == toTextureCoordIndex ) return;
372
373    const char *expressions[] = {
374        "gl_TexCoord[","]",
375        "gl_TextureMatrix[","]",
376        "gl_MultiTexCoord","",
377        "gl_EyePlaneS[","]",
378        "gl_EyePlaneT[","]",
379        "gl_EyePlaneR[","]",
380        "gl_EyePlaneQ[","]"
381    };
382
383    for( unsigned int i = 0;
384         i < sizeof( expressions ) / sizeof( expressions[0] );
385         i+=2 )
386    {
387        char acFrom[ 32 ], acTo[32];
388
389        // its not elegant to mix stdio & stl strings
390        // but in this context I do an exception for cleaner code
391
392        sprintf( acFrom, "%s%d%s", expressions[i], fromTextureCoordIndex, expressions[i+1]);
393        sprintf( acTo, "%s%d%s", expressions[i], toTextureCoordIndex, expressions[i+1]);
394
395        std::string from( acFrom ), to( acTo );
396
397        searchAndReplaceShaderSource( getShadowVertexShader(), from, to );
398        searchAndReplaceShaderSource( getShadowFragmentShader(), from, to );
399        searchAndReplaceShaderSource( getMainVertexShader(), from, to );
400        searchAndReplaceShaderSource( getMainFragmentShader(), from, to );
401    }
402
403    dirty();
404}
405
406void StandardShadowMap::searchAndReplaceShaderSource
407           ( osg::Shader* shader, std::string fromString, std::string toString )
408{
409    if( !shader || fromString == toString ) return;
410
411    const std::string & srceString = shader->getShaderSource();
412    std::string destString;
413
414    std::string::size_type fromLength = fromString.length();
415    std::string::size_type srceLength = srceString.length();
416
417    for( std::string::size_type pos = 0; pos < srceLength; )
418    {
419        std::string::size_type end = srceString.find( fromString, pos );
420
421        if( end == std::string::npos )
422            end = srceLength;
423
424        destString.append( srceString, pos, end - pos );
425
426        if( end == srceLength )
427            break;
428
429        destString.append( toString );
430        pos = end + fromLength;
431    }
432
433    shader->setShaderSource( destString );
434}
435
436void StandardShadowMap::ViewData::cull()
437{
438    // step 1:
439    // cull shadowed scene ie put into render bins and states into stage graphs
440    cullShadowReceivingScene( );
441
442    // step 2:
443    // find the light casting our shadows
444    osg::Vec4 lightPos;
445    osg::Vec3 lightDir;
446    osg::Vec3 lightUp( 0,0,0 ); // force computing most approprate dir
447    const osg::Light *light = selectLight( lightPos, lightDir );
448
449    if ( !light )
450        return;// bail out - no shadowing needed in darkest night
451
452    // step 3:
453    // compute shadow casting matrices and apply them to shadow map camera
454    aimShadowCastingCamera( light, lightPos, lightDir, lightUp );
455
456    // step 4:
457    // cull scene casting shadow and generate render
458    cullShadowCastingScene( );
459
460    // step 5:
461    // setup texgen generating shadow map coords for the shadow receiving scene
462    addShadowReceivingTexGen( );
463
464    BaseClass::ViewData::cull();
465}
466
467void StandardShadowMap::ViewData::init( ThisClass *st, osgUtil::CullVisitor *cv )
468{
469    BaseClass::ViewData::init( st, cv );
470
471    _lightPtr             = &st->_light;
472    _shadowTextureUnitPtr = &st->_shadowTextureUnit;
473    _baseTextureUnitPtr   = &st->_baseTextureUnit;
474
475    { // Setup shadow texture
476        osg::Texture2D * texture = new osg::Texture2D;
477        texture->setTextureSize( st->_textureSize.x(), st->_textureSize.y());
478        texture->setInternalFormat(GL_DEPTH_COMPONENT);
479        texture->setShadowComparison(true);
480        texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
481        texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
482        texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
483
484        // the shadow comparison should fail if object is outside the texture
485        texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
486        texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
487        texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
488        _texture = texture;
489    }
490
491    _camera = new osg::Camera;
492    { // Setup shadow map camera
493        _camera->setName( "ShadowCamera" );
494#if 0  // Absolute reference frame INHERIT_VIEWPOINT works better than this
495        _camera->setCullingMode
496                ( _camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING );
497#endif
498        _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
499        _camera->setCullCallback(new CameraCullCallback( st ));
500        _camera->setClearMask(GL_DEPTH_BUFFER_BIT);
501
502#if 0   // Left in case of some debug testing
503        _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
504        _camera->setClearColor( osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
505#endif
506        _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
507        _camera->setViewport(0,0, st->_textureSize.x(), st->_textureSize.y() );
508        _camera->setRenderOrder(osg::Camera::PRE_RENDER);
509        _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
510        _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
511    }
512
513    _texgen = new osg::TexGen;
514
515    _stateset = new osg::StateSet;
516    { // Create and add fake texture for use with nodes without any texture
517        osg::Image * image = new osg::Image;
518        image->allocateImage( 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE );
519        *(osg::Vec4ub*)image->data() = osg::Vec4ub( 0xFF, 0xFF, 0xFF, 0xFF );
520
521        osg::Texture2D* fakeTex = new osg::Texture2D( image );
522        fakeTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
523        fakeTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT);
524        fakeTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
525        fakeTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
526
527        _stateset->setTextureAttribute(st->_baseTextureUnit,fakeTex,osg::StateAttribute::ON);
528        _stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_2D,osg::StateAttribute::ON);
529        _stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_3D,osg::StateAttribute::OFF);
530        #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
531            _stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_1D,osg::StateAttribute::OFF);
532        #endif
533    }
534
535    { // Add shadow texture
536        _stateset->setTextureAttributeAndModes(st->_shadowTextureUnit,_texture.get(),osg::StateAttribute::ON);
537        _stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
538        _stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
539        _stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
540        _stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
541    }
542
543    {  // Setup shaders used in shadow casting
544        osg::Program * program = new osg::Program();
545        _stateset->setAttribute( program );
546
547        if( st->_shadowFragmentShader.valid() )
548            program->addShader( st->_shadowFragmentShader.get() );
549
550        if( st->_mainFragmentShader.valid() )
551            program->addShader( st->_mainFragmentShader.get() );
552
553        if( st->_shadowVertexShader.valid() )
554            program->addShader( st->_shadowVertexShader.get() );
555
556        if( st->_mainVertexShader.valid() )
557            program->addShader( st->_mainVertexShader.get() );
558
559        _stateset->addUniform
560            ( new osg::Uniform( "baseTexture", int( st->_baseTextureUnit ) ) );
561        _stateset->addUniform
562            ( new osg::Uniform( "shadowTexture", int( st->_shadowTextureUnit ) ) );
563    }
564
565    { // Setup states used for shadow map generation
566        osg::StateSet * stateset = _camera->getOrCreateStateSet();
567
568        stateset->setAttribute(
569            new osg::PolygonOffset( st->_polygonOffsetFactor, st->_polygonOffsetUnits ),
570                osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
571
572        stateset->setMode( GL_POLYGON_OFFSET_FILL,
573              osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
574
575        // agressive optimization
576        stateset->setRenderBinDetails( 0, "RenderBin",
577                            osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
578
579        // Assure that AlphaTest/AlphaRef works when redirecting all drawables to single bin.
580        // If AlphaFunc/AlphaTest is off - transparent objects will cast solid blocky shadows.
581        // No override to allow users change this policy in the model if really want solid shadows.
582        stateset->setAttributeAndModes
583            ( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0 ), osg::StateAttribute::ON );
584
585        // agressive optimization
586        stateset->setAttributeAndModes
587            ( new osg::ColorMask( false, false, false, false ),
588            osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
589
590        // note soft (attribute only no mode override) setting. When this works ?
591        // 1. for objects prepared for backface culling
592        //    because they usually also set CullFace and CullMode on in their state
593        //    For them we override CullFace but CullMode remains set by them
594        // 2. For one faced, trees, and similar objects which cannot use
595        //    backface nor front face so they usually use CullMode off set here.
596        //    In this case we will draw them in their entirety.
597
598        stateset->setAttribute( new osg::CullFace( osg::CullFace::FRONT ),
599              osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
600
601        // make sure GL_CULL_FACE is off by default
602        // we assume that if object has cull face attribute set to back
603        // it will also set cull face mode ON so no need for override
604        stateset->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
605
606        // optimization attributes
607        osg::Program* program = new osg::Program;
608        stateset->setAttribute( program, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
609        stateset->setMode
610            ( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
611        stateset->setMode
612            ( GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
613
614#if 0 // fixed pipeline seems faster (at least on my 7800)
615        program->addShader( new osg::Shader( osg::Shader::FRAGMENT,
616            "uniform sampler2D texture;                                       \n"
617            "void main(void)                                                  \n"
618            "{                                                                \n"
619            " gl_FragColor = texture2D( texture, gl_TexCoord[0].xy );         \n"
620            "}                                                                \n"
621        ) ); // program->addShader Fragment
622
623        program->addShader( new osg::Shader( osg::Shader::VERTEX,
624            "void main(void)                                                  \n"
625            "{                                                                \n"
626            "   gl_Position = ftransform();                                   \n"
627            "   gl_TexCoord[0] = gl_MultiTexCoord0;                           \n"
628            "}                                                                \n"
629        ) ); // program->addShader Vertex
630#endif
631
632        for( unsigned stage = 1; stage < 4; stage ++ )
633        {
634            #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
635                stateset->setTextureMode( stage, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
636            #endif
637            stateset->setTextureMode( stage, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
638            stateset->setTextureMode( stage, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
639        }
640    }
641}
642
643const osg::Light* StandardShadowMap::ViewData::selectLight
644                                ( osg::Vec4 & lightPos, osg::Vec3 & lightDir )
645{
646    const osg::Light* light = 0;
647
648    //MR testing giving a specific light
649    osgUtil::RenderStage * rs = _cv->getRenderStage();
650
651    osgUtil::PositionalStateContainer::AttrMatrixList& aml =
652        rs->getPositionalStateContainer()->getAttrMatrixList();
653
654    osg::RefMatrix* matrix = 0;
655
656    for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin();
657        itr != aml.end();
658        ++itr)
659    {
660        const osg::Light* found = dynamic_cast<const osg::Light*>(itr->first.get());
661        if( found )
662        {
663            if( _lightPtr->valid() && _lightPtr->get() != found )
664                continue; // continue search for the right one
665
666            light = found;
667            matrix = itr->second.get();
668        }
669    }
670
671    if( light ) { // transform light to world space
672
673        osg::Matrix localToWorld = osg::Matrix::inverse( *_cv->getModelViewMatrix() );
674        if( matrix ) localToWorld.preMult( *matrix );
675
676        lightPos = light->getPosition();
677
678        if( lightPos[3] == 0 )
679            lightDir.set( -lightPos[0], -lightPos[1], -lightPos[2] );
680        else
681            lightDir = light->getDirection();
682
683        lightPos = lightPos * localToWorld;
684        lightDir = osg::Matrix::transform3x3( lightDir, localToWorld );
685        lightDir.normalize();
686    }
687
688    return light;
689}
690
691void StandardShadowMap::ViewData::aimShadowCastingCamera( const osg::Light *light,
692                                                  const osg::Vec4 &lightPos,
693                                                  const osg::Vec3 &lightDir,
694                                                  const osg::Vec3 &lightUp
695                                        /* by default = osg::Vec3( 0, 1 0 )*/ )
696{
697#if 0 // less precise but faster
698    osg::BoundingSphere bs =_st->getShadowedScene()->getBound();
699#else
700    // get the bounds of the model.
701    osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
702    cbbv.setTraversalMask(_st->getShadowedScene()->getCastsShadowTraversalMask());
703    _st->getShadowedScene()->osg::Group::traverse(cbbv);
704    osg::BoundingSphere bs( cbbv.getBoundingBox() );
705#endif
706
707    aimShadowCastingCamera
708        ( bs, light, lightPos, lightDir, lightUp );
709}
710
711void StandardShadowMap::ViewData::aimShadowCastingCamera(
712                                        const osg::BoundingSphere &bs,
713                                        const osg::Light *light,
714                                        const osg::Vec4 &lightPos,
715                                        const osg::Vec3 &lightDir,
716                                        const osg::Vec3 &lightUpVector
717                                        /* by default = osg::Vec3( 0, 1 0 )*/ )
718{
719    osg::Matrixd & view = _camera->getViewMatrix();
720    osg::Matrixd & projection = _camera->getProjectionMatrix();
721
722    osg::Vec3 up = lightUpVector;
723    if( up.length2() <= 0 )  up.set( 0,1,0 );
724
725    osg::Vec3d position(lightPos.x(), lightPos.y(), lightPos.z());
726    if (lightPos[3]==0.0)   // infinite directional light
727    {
728        // make an orthographic projection
729        // set the position far away along the light direction
730        position = bs.center() - lightDir * bs.radius() * 2;
731    }
732
733    float centerDistance = (position-bs.center()).length();
734    float znear = centerDistance-bs.radius();
735    float zfar  = centerDistance+bs.radius();
736    float zNearRatio = 0.001f;
737    if (znear<zfar*zNearRatio)
738        znear = zfar*zNearRatio;
739
740    if ( lightPos[3]!=0.0 ) {  // positional light
741        if( light->getSpotCutoff() < 180.0f) // also needs znear zfar estimates
742        {
743            float spotAngle = light->getSpotCutoff();
744            projection.makePerspective( spotAngle * 2, 1.0, znear, zfar);
745            view.makeLookAt(position,position+lightDir,up);
746        } else { // standard omnidirectional positional light
747            float top   = (bs.radius()/centerDistance)*znear;
748            float right = top;
749
750            projection.makeFrustum(-right,right,-top,top,znear,zfar);
751            view.makeLookAt(position,bs.center(),up );
752        }
753    }
754    else    // directional light
755    {
756            float top   = bs.radius();
757            float right = top;
758            projection.makeOrtho(-right, right, -top, top, znear, zfar);
759            view.makeLookAt(position,bs.center(),up);
760    }
761}
762
763void StandardShadowMap::ViewData::cullShadowReceivingScene( )
764{
765    _cv->pushStateSet( _stateset.get() );
766
767    _st->getShadowedScene()->osg::Group::traverse( *_cv );
768
769    _cv->popStateSet();
770}
771
772void StandardShadowMap::ViewData::cullShadowCastingScene( )
773{
774    // record the traversal mask on entry so we can reapply it later.
775    unsigned int traversalMask = _cv->getTraversalMask();
776
777    _cv->setTraversalMask( traversalMask &
778         _st->getShadowedScene()->getCastsShadowTraversalMask() );
779
780    // do RTT camera traversal
781    _camera->accept(*_cv);
782
783    // reapply the original traversal mask
784    _cv->setTraversalMask( traversalMask );
785}
786
787void StandardShadowMap::ViewData::addShadowReceivingTexGen( )
788{
789     _texgen->setMode(osg::TexGen::EYE_LINEAR);
790
791     // compute the matrix which takes a vertex from view coords into tex coords
792     _texgen->setPlanesFromMatrix(
793            _camera->getProjectionMatrix() *
794            osg::Matrix::translate(1.0,1.0,1.0) *
795            osg::Matrix::scale(0.5f,0.5f,0.5f) );
796
797     osg::RefMatrix * refMatrix = new osg::RefMatrix
798            ( _camera->getInverseViewMatrix() * *_cv->getModelViewMatrix() );
799
800     _cv->getRenderStage()->getPositionalStateContainer()->
801         addPositionedTextureAttribute
802            ( *_shadowTextureUnitPtr, refMatrix, _texgen.get() );
803}
Note: See TracBrowser for help on using the browser.