root/OpenSceneGraph/trunk/src/osgShadow/SoftShadowMap.cpp @ 10852

Revision 10852, 12.9 kB (checked in by robert, 5 years ago)

From Mathieu Marache, "I replaced the Vec4 by a float and used only the x component of the shadow2DProj . This works on my apple box."

  • Property svn:executable set to *
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
14#include <stdlib.h>
15
16#include <osgShadow/ShadowMap>
17#include <osgShadow/SoftShadowMap>
18#include <osgShadow/ShadowedScene>
19#include <osg/Notify>
20#include <osg/ComputeBoundsVisitor>
21#include <osg/PolygonOffset>
22#include <osg/CullFace>
23#include <osg/io_utils>
24
25using namespace osgShadow;
26
27#include <iostream>
28//for debug
29#include <osg/LightSource>
30#include <osg/PolygonMode>
31#include <osg/Geometry>
32#include <osgDB/ReadFile>
33#include <osgText/Text>
34#include <osg/Texture3D>
35#include <osg/TexGen>
36
37#define IMPROVE_TEXGEN_PRECISION 1
38
39//////////////////////////////////////////////////////////////////
40// fragment shader
41//
42// Implementation from Chapter 17, Efficient Soft-Edged Shadows Using Pixel Shader Branching, Yury Uralsky.
43// GPU Gems 2, Matt Pharr ed. Addison-Wesley.
44//
45static const char fragmentSoftShaderSource_noBaseTexture[] =
46   "#define SAMPLECOUNT 64 \n"
47    "#define SAMPLECOUNT_FLOAT 64.0 \n"
48    "#define SAMPLECOUNT_D2 32 \n"
49    "#define SAMPLECOUNT_D2_FLOAT 32.0 \n"
50    "#define INV_SAMPLECOUNT (1.0 / SAMPLECOUNT_FLOAT) \n"
51
52    "uniform sampler2DShadow osgShadow_shadowTexture; \n"
53    "uniform sampler3D osgShadow_jitterTexture; \n"
54
55    "uniform vec2 osgShadow_ambientBias; \n"
56    "uniform float osgShadow_softnessWidth; \n"
57    "uniform float osgShadow_jitteringScale; \n"
58
59    "void main(void) \n"
60    "{ \n"
61    "  vec4 sceneShadowProj  = gl_TexCoord[1]; \n"
62    "  float softFactor = osgShadow_softnessWidth * sceneShadowProj.w; \n"
63    "  vec4 smCoord  = sceneShadowProj; \n"
64    "  vec3 jitterCoord = vec3( gl_FragCoord.xy / osgShadow_jitteringScale, 0.0 ); \n"
65    "  float shadow = 0.0; \n"
66// First "cheap" sample test
67    "  const float pass_div = 1.0 / (2.0 * 4.0); \n"
68    "  for ( int i = 0; i < 4; ++i ) \n"
69    "  { \n"
70// Get jitter values in [0,1]; adjust to have values in [-1,1]
71    "    vec4 offset = 2.0 * texture3D( osgShadow_jitterTexture, jitterCoord ) -1.0; \n"
72    "    jitterCoord.z += 1.0 / SAMPLECOUNT_D2_FLOAT; \n"
73
74    "    smCoord.xy = sceneShadowProj.xy  + (offset.xy) * softFactor; \n"
75    "    shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * pass_div; \n"
76
77    "    smCoord.xy = sceneShadowProj.xy  + (offset.zw) * softFactor; \n"
78    "    shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x *pass_div; \n"
79    "  } \n"
80// skip all the expensive shadow sampling if not needed
81    "  if ( shadow * (shadow -1.0) != 0.0 ) \n"
82    "  { \n"
83    "    shadow *= pass_div; \n"
84    "    for (int i=0; i<SAMPLECOUNT_D2 - 4; ++i){ \n"
85    "      vec4 offset = 2.0 * texture3D( osgShadow_jitterTexture, jitterCoord ) - 1.0; \n"
86    "      jitterCoord.z += 1.0 / SAMPLECOUNT_D2_FLOAT; \n"
87
88    "      smCoord.xy = sceneShadowProj.xy  + offset.xy * softFactor; \n"
89    "      shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * INV_SAMPLECOUNT; \n"
90
91    "      smCoord.xy = sceneShadowProj.xy  + offset.zw * softFactor; \n"
92    "      shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * INV_SAMPLECOUNT; \n"
93    "    } \n"
94    "  } \n"
95// apply shadow, modulo the ambient bias
96    "  gl_FragColor = gl_Color * (osgShadow_ambientBias.x + shadow * osgShadow_ambientBias.y); \n"
97    "} \n";
98
99
100
101//////////////////////////////////////////////////////////////////
102// fragment shader
103//
104static const char fragmentSoftShaderSource_withBaseTexture[] =
105    "#define SAMPLECOUNT 64 \n"
106    "#define SAMPLECOUNT_FLOAT 64.0 \n"
107    "#define SAMPLECOUNT_D2 32 \n"
108    "#define SAMPLECOUNT_D2_FLOAT 32.0 \n"
109    "#define INV_SAMPLECOUNT (1.0 / SAMPLECOUNT_FLOAT) \n"
110
111    "uniform sampler2D osgShadow_baseTexture; \n"
112    "uniform sampler2DShadow osgShadow_shadowTexture; \n"
113    "uniform sampler3D osgShadow_jitterTexture; \n"
114
115    "uniform vec2 osgShadow_ambientBias; \n"
116    "uniform float osgShadow_softnessWidth; \n"
117    "uniform float osgShadow_jitteringScale; \n"
118
119    "void main(void) \n"
120    "{ \n"
121    "  vec4 sceneShadowProj  = gl_TexCoord[1]; \n"
122    "  float softFactor = osgShadow_softnessWidth * sceneShadowProj.w; \n"
123    "  vec4 smCoord  = sceneShadowProj; \n"
124    "  vec3 jitterCoord = vec3( gl_FragCoord.xy / osgShadow_jitteringScale, 0.0 ); \n"
125    "  float shadow = 0.0; \n"
126// First "cheap" sample test
127    "  const float pass_div = 1.0 / (2.0 * 4.0); \n"
128    "  for ( int i = 0; i < 4; ++i ) \n"
129    "  { \n"
130// Get jitter values in [0,1]; adjust to have values in [-1,1]
131    "    vec4 offset = 2.0 * texture3D( osgShadow_jitterTexture, jitterCoord ) -1.0; \n"
132    "    jitterCoord.z += 1.0 / SAMPLECOUNT_D2_FLOAT; \n"
133
134    "    smCoord.xy = sceneShadowProj.xy  + (offset.xy) * softFactor; \n"
135    "    shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * pass_div; \n"
136
137    "    smCoord.xy = sceneShadowProj.xy  + (offset.zw) * softFactor; \n"
138    "    shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x *pass_div; \n"
139    "  } \n"
140// skip all the expensive shadow sampling if not needed
141    "  if ( shadow * (shadow -1.0) != 0.0 ) \n"
142    "  { \n"
143    "    shadow *= pass_div; \n"
144    "    for (int i=0; i<SAMPLECOUNT_D2 -4; ++i){ \n"
145    "      vec4 offset = 2.0 * texture3D( osgShadow_jitterTexture, jitterCoord ) - 1.0; \n"
146    "      jitterCoord.z += 1.0 / SAMPLECOUNT_D2_FLOAT; \n"
147
148    "      smCoord.xy = sceneShadowProj.xy  + offset.xy * softFactor; \n"
149    "      shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * INV_SAMPLECOUNT; \n"
150
151    "      smCoord.xy = sceneShadowProj.xy  + offset.zw * softFactor; \n"
152    "      shadow +=  shadow2DProj( osgShadow_shadowTexture, smCoord ).x * INV_SAMPLECOUNT; \n"
153    "    } \n"
154    "  } \n"
155// apply color and object base texture
156    "  vec4 color = gl_Color * texture2D( osgShadow_baseTexture, gl_TexCoord[0].xy ); \n"
157// apply shadow, modulo the ambient bias
158    "  gl_FragColor = color * (osgShadow_ambientBias.x + shadow * osgShadow_ambientBias.y); \n"
159    "} \n";
160
161
162
163
164
165SoftShadowMap::SoftShadowMap():
166    _softnessWidth(0.005f),
167    _jitteringScale(32.f),
168    _jitterTextureUnit(_shadowTextureUnit+1)
169{
170}
171
172SoftShadowMap::SoftShadowMap(const SoftShadowMap& copy, const osg::CopyOp& copyop):
173ShadowMap(copy,copyop),
174    _softnessWidth(copy._softnessWidth),
175    _jitteringScale(copy._jitteringScale),
176    _jitterTextureUnit(copy._shadowTextureUnit)
177{
178}
179
180void SoftShadowMap::setJitteringScale(const float jitteringScale)
181{
182    _jitteringScale = jitteringScale;
183    if (_jitteringScaleUniform.valid()) _jitteringScaleUniform->set(_jitteringScale);
184}
185
186void SoftShadowMap::setSoftnessWidth(const float softnessWidth)
187{
188    _softnessWidth = softnessWidth;
189    if (_softnessWidthUniform.valid()) _softnessWidthUniform->set(_softnessWidth);
190}
191
192void SoftShadowMap::setJitterTextureUnit(unsigned int jitterTextureUnit)
193{
194    _jitterTextureUnit=jitterTextureUnit;
195}
196
197void SoftShadowMap::createUniforms()
198{
199    _uniformList.clear();
200
201    osg::Uniform* baseTextureSampler = new osg::Uniform("osgShadow_baseTexture",(int)_baseTextureUnit);
202    _uniformList.push_back(baseTextureSampler);
203
204    osg::Uniform* shadowTextureSampler = new osg::Uniform("osgShadow_shadowTexture",(int)_shadowTextureUnit);
205    _uniformList.push_back(shadowTextureSampler);
206
207    _ambientBiasUniform = new osg::Uniform("osgShadow_ambientBias",_ambientBias);
208    _uniformList.push_back(_ambientBiasUniform.get());
209
210    _softnessWidthUniform = new osg::Uniform("osgShadow_softnessWidth",_softnessWidth);
211    _uniformList.push_back(_softnessWidthUniform.get());
212
213    _jitteringScaleUniform = new osg::Uniform("osgShadow_jitteringScale",_jitteringScale);
214    _uniformList.push_back(_jitteringScaleUniform.get());
215
216    _jitterTextureUnit=_shadowTextureUnit+1;
217    initJittering(_stateset.get());
218
219    osg::Uniform* jitterTextureSampler = new osg::Uniform("osgShadow_jitterTexture",(int)_jitterTextureUnit);
220    _uniformList.push_back(jitterTextureSampler);
221
222
223}
224
225void SoftShadowMap::createShaders()
226{
227    // if we are not given shaders, use the default
228    if( _shaderList.empty() )
229    {
230        if (_shadowTextureUnit==0)
231        {
232            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentSoftShaderSource_noBaseTexture);
233            _shaderList.push_back(fragment_shader);
234        }
235        else
236        {
237            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentSoftShaderSource_withBaseTexture);
238            _shaderList.push_back(fragment_shader);
239
240        }
241    }
242}
243
244
245// Implementation from Chapter 17, Efficient Soft-Edged Shadows Using Pixel Shader Branching, Yury Uralsky.
246// GPU Gems 2, Matt Pharr ed. Addison-Wesley.
247//
248// Creates a 3D texture containing jittering data used in the shader to take samples of the shadow map.
249void SoftShadowMap::initJittering(osg::StateSet *ss)
250{
251    // create a 3D texture with hw mipmapping
252    osg::Texture3D* texture3D = new osg::Texture3D;
253    texture3D->setFilter(osg::Texture3D::MIN_FILTER,osg::Texture3D::NEAREST);
254    texture3D->setFilter(osg::Texture3D::MAG_FILTER,osg::Texture3D::NEAREST);
255    texture3D->setWrap(osg::Texture3D::WRAP_S,osg::Texture3D::REPEAT);
256    texture3D->setWrap(osg::Texture3D::WRAP_T,osg::Texture3D::REPEAT);
257    texture3D->setWrap(osg::Texture3D::WRAP_R,osg::Texture3D::REPEAT);
258    texture3D->setUseHardwareMipMapGeneration(true);
259
260    const unsigned int size = 16;
261    const unsigned int gridW =  8;
262    const unsigned int gridH =  8;
263    unsigned int R = (gridW * gridH / 2);
264    texture3D->setTextureSize(size, size, R);
265
266    // then create the 3d image to fill with jittering data
267    osg::Image* image3D = new osg::Image;
268    unsigned char *data3D = new unsigned char[size * size * R * 4];
269
270    for ( unsigned int s = 0; s < size; ++s )
271    {
272        for ( unsigned int t = 0; t < size; ++t )
273        {
274            float v[4], d[4];
275
276            for ( unsigned int r = 0; r < R; ++r )
277            {
278                const int x = r % ( gridW / 2 );
279                const int y = ( gridH - 1 ) - ( r / (gridW / 2) );
280
281                // Generate points on a  regular gridW x gridH rectangular
282                // grid.   We  multiply  x   by  2  because,  we  treat  2
283                // consecutive x  each loop iteration.  Add 0.5f  to be in
284                // the center of the pixel. x, y belongs to [ 0.0, 1.0 ].
285                v[0] = float( x * 2     + 0.5f ) / gridW;
286                v[1] = float( y         + 0.5f ) / gridH;
287                v[2] = float( x * 2 + 1 + 0.5f ) / gridW;
288                v[3] = v[1];
289
290                // Jitter positions. ( 0.5f / w ) == ( 1.0f / 2*w )
291                v[0] += ((float)rand() * 2.f / RAND_MAX - 1.f) * ( 0.5f / gridW );
292                v[1] += ((float)rand() * 2.f / RAND_MAX - 1.f) * ( 0.5f / gridH );
293                v[2] += ((float)rand() * 2.f / RAND_MAX - 1.f) * ( 0.5f / gridW );
294                v[3] += ((float)rand() * 2.f / RAND_MAX - 1.f) * ( 0.5f / gridH );
295
296                // Warp to disk; values in [-1,1]
297                d[0] = sqrtf( v[1] ) * cosf( 2.f * 3.1415926f * v[0] );
298                d[1] = sqrtf( v[1] ) * sinf( 2.f * 3.1415926f * v[0] );
299                d[2] = sqrtf( v[3] ) * cosf( 2.f * 3.1415926f * v[2] );
300                d[3] = sqrtf( v[3] ) * sinf( 2.f * 3.1415926f * v[2] );
301
302                // store d into unsigned values [0,255]
303                const unsigned int tmp = ( (r * size * size) + (t * size) + s ) * 4;
304                data3D[ tmp + 0 ] = (unsigned char)( ( 1.f + d[0] ) * 127  );
305                data3D[ tmp + 1 ] = (unsigned char)( ( 1.f + d[1] ) * 127  );
306                data3D[ tmp + 2 ] = (unsigned char)( ( 1.f + d[2] ) * 127  );
307                data3D[ tmp + 3 ] = (unsigned char)( ( 1.f + d[3] ) * 127  );
308
309            }
310        }
311    }
312
313    // the GPU Gem implementation uses a NV specific internal texture format (GL_SIGNED_RGBA_NV)
314    // In order to make it more generic, we use GL_RGBA4 which should be cross platform.
315    #ifdef GL_RGBA4
316    GLenum internalTextureFormat = GL_RGBA4;
317    #else
318    // OpenGLES 1.1 doesn't define GL_RGBA4, so we'll just assume RGBA
319    GLenum internalTextureFormat = GL_RGBA;
320    #endif
321    image3D->setImage(size, size, R, internalTextureFormat, GL_RGBA, GL_UNSIGNED_BYTE, data3D, osg::Image::USE_NEW_DELETE);
322
323    texture3D->setImage(image3D);
324
325    ss->setTextureAttributeAndModes(_jitterTextureUnit, texture3D, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
326    ss->setTextureMode(_jitterTextureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
327    ss->setTextureMode(_jitterTextureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
328    ss->setTextureMode(_jitterTextureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
329
330}
Note: See TracBrowser for help on using the browser.