Hi Cyril,
Good shoot ;-). You got me. Its the bug, vertex and fragment shaders are
inconsistent ;-) StandardShadowMap Vertex shader produces specular term on
SecondaryColor but fragment shader expects specular added to primary color
and assumes gl_Color contains both diffuse and specular.
See attached modified StandardShadowMap.cpp. I hope it will do better
speculars ;-) But I have no time nor model at hand to test it now, so if you
are anxious you are going to be the first user. Let me know how the tests
passsed.
It also contains alternative set of shaders that does not use vertex
shaders. This alternative shaders can be activated with setting
FRAGMENT_SHADERS_ONLY to 1. They will work correctly only if 1 light is
active.
I will send this to submissions lists soon but not today as I need to test
it first....
Cheers,
Wojtek
-----Original Message-----
From: Cyril Bondue
Sent: Wednesday, January 26, 2011 7:25 PM
To: [email protected]
Subject: [osg-users] MinimalShadowMap and specular
Hello,
I'm using MinimalShadowMap in an application and I would like to display
objects with their specular value. But whenever I use a sub class of
StandardShadowMap my objects appear totally "matte finish".
If I use ShadowMap my objects are well rendered with specular so the problem
comes from MinimapShadowMap I guess. I looked in the code but wasn't able to
find anything that could solve my problem. Is there something I'm missing?
Here is my code for light parameters and shadow :
Code:
//light
_light->setAmbient(osg::Vec4(0.35, 0.35, 0.35, 1.0f));
_light->setDiffuse(osg::Vec4(0.65, 0.65, 0.65, 1.0f));
_light->setSpecular(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
_light->setPosition(osg::Vec4(30, 30, 170, 1));
//shadows
osg::ref_ptr<osgShadow::MinimalShadowMap> sm = new
osgShadow::MinimalShadowMap();
sm->setTextureSize(osg::Vec2s(2048, 2048));
sm->setLight(_light);
_sceneRoot->setShadowTechnique(sm.get());
I'm using Windows 7 pro 32 bits, with an ATI X1950XT card and the lastest
drivers. I got the same result using osg 2.8.3 or 2.9.7.
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=35998#35998
Attachments:
http://forum.openscenegraph.org//files/specular_nospecular_480.jpg
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified
under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* ViewDependentShadow codes Copyright (C) 2008 Wojciech Lewandowski
* Thanks to to my company http://www.ai.com.pl for allowing me free this
work.
*/
#include <osgShadow/StandardShadowMap>
#include <osg/PolygonOffset>
#include <osg/ComputeBoundsVisitor>
#include <osgShadow/ShadowedScene>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/CullFace>
#include <osg/AlphaFunc>
#include <osg/Point>
#include <stdio.h>
using namespace osgShadow;
#define DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR 0
#define FRAGMENT_SHADERS_ONLY 0
StandardShadowMap::StandardShadowMap():
BaseClass(),
_polygonOffsetFactor( 1.1f ),
_polygonOffsetUnits( 4.0f ),
_textureSize( 1024, 1024 ),
_baseTextureUnit( 0 ),
_shadowTextureUnit( 1 ),
_baseTextureCoordIndex( 0 ),
_shadowTextureCoordIndex( 1 )
{
#if FRAGMENT_SHADERS_ONLY
_mainFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[0] 0 - can be subsituted with other index
\n"
"
\n"
"float DynamicShadow( );
\n"
"
\n"
"uniform sampler2D baseTexture;
\n"
"
\n"
"void main(void)
\n"
"{
\n"
" vec4 colorAmbientEmissive =
gl_FrontLightModelProduct.sceneColor;
\n"
" // Add ambient from Light of index = 0
\n"
" colorAmbientEmissive += gl_FrontLightProduct[0].ambient;
\n"
" float shadow = DynamicShadow();
\n"
" color *= mix( colorAmbientEmissive, gl_Color, shadow );
\n"
" color.rgb += gl_SecondaryColor.rgb * shadow;
\n"
#if DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR
" color.xy = abs( dFdy( gl_TexCoord[1].xy / gl_TexCoord[1].w ) )*
1024.0; \n"
" color.z = color.y; \n"
" color.x = color.z; \n"
" color.y = color.z; \n"
" color.a = 1.0; \n"
#endif
// " float fog = clamp((gl_Fog.end - gl_FogFragCoord)*gl_Fog.scale,
0.,1.);\n"
// " color.rgb = mix( gl_Fog.color.rgb, color.rgb, fog );
\n"
" gl_FragColor = color;
\n"
"} \n" );
_shadowFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[1] 1 - can be subsituted with other index
\n"
"
\n"
"uniform sampler2DShadow shadowTexture;
\n"
"
\n"
"float DynamicShadow( )
\n"
"{
\n"
" return shadow2DProj( shadowTexture, gl_TexCoord[1] ).r;
\n"
"} \n" );
_shadowVertexShader = NULL;
_mainVertexShader = NULL;
#else
_mainFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[0] 0 - can be subsituted with other index
\n"
"
\n"
"float DynamicShadow( );
\n"
"
\n"
"varying vec4 colorAmbientEmissive;
\n"
"
\n"
"uniform sampler2D baseTexture;
\n"
"
\n"
"void main(void)
\n"
"{
\n"
" vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy );
\n"
" float shadow = DynamicShadow();
\n"
" color *= mix( colorAmbientEmissive, gl_Color, shadow );
\n"
" color.rgb += gl_SecondaryColor.rgb * shadow;
\n"
#if DISPLAY_SHADOW_TEXEL_TO_PIXEL_ERROR
" color.xy = abs( dFdy( gl_TexCoord[1].xy / gl_TexCoord[1].w ) )*
1024.0; \n"
" color.z = color.y; \n"
" color.x = color.z; \n"
" color.y = color.z; \n"
" color.a = 1.0; \n"
#endif
// " float fog = clamp((gl_Fog.end - gl_FogFragCoord)*gl_Fog.scale,
0.,1.);\n"
// " color.rgb = mix( gl_Fog.color.rgb, color.rgb, fog );
\n"
" gl_FragColor = color;
\n"
"} \n" );
_shadowFragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[1] 1 - can be subsituted with other index
\n"
"
\n"
"uniform sampler2DShadow shadowTexture;
\n"
"
\n"
"float DynamicShadow( )
\n"
"{
\n"
" return shadow2DProj( shadowTexture, gl_TexCoord[1] ).r;
\n"
"} \n" );
_shadowVertexShader = new osg::Shader( osg::Shader::VERTEX,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[1] 1 - can be subsituted with other index
\n"
" // gl_EyePlaneS[1] 1 - can be subsituted with other index
\n"
" // gl_EyePlaneT[1] 1 - can be subsituted with other index
\n"
" // gl_EyePlaneR[1] 1 - can be subsituted with other index
\n"
" // gl_EyePlaneQ[1] 1 - can be subsituted with other index
\n"
"
\n"
"void DynamicShadow( in vec4 ecPosition )
\n"
"{
\n"
" // generate coords for shadow mapping
\n"
" gl_TexCoord[1].s = dot( ecPosition, gl_EyePlaneS[1] );
\n"
" gl_TexCoord[1].t = dot( ecPosition, gl_EyePlaneT[1] );
\n"
" gl_TexCoord[1].p = dot( ecPosition, gl_EyePlaneR[1] );
\n"
" gl_TexCoord[1].q = dot( ecPosition, gl_EyePlaneQ[1] );
\n"
"} \n" );
_mainVertexShader = new osg::Shader( osg::Shader::VERTEX,
" // following expressions are auto modified - do not change them:
\n"
" // gl_TexCoord[0] 0 - can be subsituted with other index
\n"
" // gl_TextureMatrix[0] 0 - can be subsituted with other index
\n"
" // gl_MultiTexCoord0 0 - can be subsituted with other index
\n"
"
\n"
"const int NumEnabledLights = 1;
\n"
"
\n"
"void DynamicShadow( in vec4 ecPosition );
\n"
"
\n"
"varying vec4 colorAmbientEmissive;
\n"
"
\n"
"void SpotLight(in int i,
\n"
" in vec3 eye,
\n"
" in vec3 ecPosition3,
\n"
" in vec3 normal,
\n"
" inout vec4 ambient,
\n"
" inout vec4 diffuse,
\n"
" inout vec4 specular)
\n"
"{
\n"
" float nDotVP; // normal . light direction
\n"
" float nDotHV; // normal . light half vector
\n"
" float pf; // power factor
\n"
" float spotDot; // cosine of angle between spotlight
\n"
" float spotAttenuation; // spotlight attenuation factor
\n"
" float attenuation; // computed attenuation factor
\n"
" float d; // distance from surface to light source
\n"
" vec3 VP; // direction from surface to light
position \n"
" vec3 halfVector; // direction of maximum highlights
\n"
"
\n"
" // Compute vector from surface to light position
\n"
" VP = vec3(gl_LightSource[i].position) - ecPosition3;
\n"
"
\n"
" // Compute distance between surface and light position
\n"
" d = length(VP);
\n"
"
\n"
" // Normalize the vector from surface to light position
\n"
" VP = normalize(VP);
\n"
"
\n"
" // Compute attenuation
\n"
" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
\n"
" gl_LightSource[i].linearAttenuation * d +
\n"
" gl_LightSource[i].quadraticAttenuation
*d*d); \n"
"
\n"
" // See if point on surface is inside cone of illumination
\n"
" spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));
\n"
"
\n"
" if (spotDot < gl_LightSource[i].spotCosCutoff)
\n"
" spotAttenuation = 0.0; // light adds no contribution
\n"
" else
\n"
" spotAttenuation = pow(spotDot,
gl_LightSource[i].spotExponent);\n"
"
\n"
" // Combine the spotlight and distance attenuation.
\n"
" attenuation *= spotAttenuation;
\n"
"
\n"
" halfVector = normalize(VP + eye);
\n"
"
\n"
" nDotVP = max(0.0, dot(normal, VP));
\n"
" nDotHV = max(0.0, dot(normal, halfVector));
\n"
"
\n"
" if (nDotVP == 0.0)
\n"
" pf = 0.0;
\n"
" else
\n"
" pf = pow(nDotHV, gl_FrontMaterial.shininess);
\n"
"
\n"
" ambient += gl_LightSource[i].ambient * attenuation;
\n"
" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;
\n"
" specular += gl_LightSource[i].specular * pf * attenuation;
\n"
"}
\n"
"
\n"
"void PointLight(in int i,
\n"
" in vec3 eye,
\n"
" in vec3 ecPosition3,
\n"
" in vec3 normal,
\n"
" inout vec4 ambient,
\n"
" inout vec4 diffuse,
\n"
" inout vec4 specular)
\n"
"{
\n"
" float nDotVP; // normal . light direction
\n"
" float nDotHV; // normal . light half vector
\n"
" float pf; // power factor
\n"
" float attenuation; // computed attenuation factor
\n"
" float d; // distance from surface to light source
\n"
" vec3 VP; // direction from surface to light position
\n"
" vec3 halfVector; // direction of maximum highlights
\n"
"
\n"
" // Compute vector from surface to light position
\n"
" VP = vec3(gl_LightSource[i].position) - ecPosition3;
\n"
"
\n"
" // Compute distance between surface and light position
\n"
" d = length(VP);
\n"
"
\n"
" // Normalize the vector from surface to light position
\n"
" VP = normalize(VP);
\n"
"
\n"
" // Compute attenuation
\n"
" attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
\n"
" gl_LightSource[i].linearAttenuation * d +
\n"
" gl_LightSource[i].quadraticAttenuation *
d*d);\n"
"
\n"
" halfVector = normalize(VP + eye);
\n"
"
\n"
" nDotVP = max(0.0, dot(normal, VP));
\n"
" nDotHV = max(0.0, dot(normal, halfVector));
\n"
"
\n"
" if (nDotVP == 0.0)
\n"
" pf = 0.0;
\n"
" else
\n"
" pf = pow(nDotHV, gl_FrontMaterial.shininess);
\n"
"
\n"
" ambient += gl_LightSource[i].ambient * attenuation;
\n"
" diffuse += gl_LightSource[i].diffuse * nDotVP * attenuation;
\n"
" specular += gl_LightSource[i].specular * pf * attenuation;
\n"
"}
\n"
"
\n"
"void DirectionalLight(in int i,
\n"
" in vec3 normal,
\n"
" inout vec4 ambient,
\n"
" inout vec4 diffuse,
\n"
" inout vec4 specular)
\n"
"{
\n"
" float nDotVP; // normal . light direction
\n"
" float nDotHV; // normal . light half vector
\n"
" float pf; // power factor
\n"
"
\n"
" nDotVP = max(0.0, dot(normal,
\n"
" normalize(vec3(gl_LightSource[i].position))));
\n"
" nDotHV = max(0.0, dot(normal,
\n"
" vec3(gl_LightSource[i].halfVector)));
\n"
"
\n"
" if (nDotVP == 0.0)
\n"
" pf = 0.0;
\n"
" else
\n"
" pf = pow(nDotHV, gl_FrontMaterial.shininess);
\n"
"
\n"
" ambient += gl_LightSource[i].ambient;
\n"
" diffuse += gl_LightSource[i].diffuse * nDotVP;
\n"
" specular += gl_LightSource[i].specular * pf;
\n"
"}
\n"
"
\n"
"void main( )
\n"
"{
\n"
" // Transform vertex to clip space
\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
\n"
" vec3 normal = normalize( gl_NormalMatrix * gl_Normal );
\n"
"
\n"
" vec4 ecPos = gl_ModelViewMatrix * gl_Vertex;
\n"
" float ecLen = length( ecPos );
\n"
" vec3 ecPosition3 = ecPos.xyz / ecPos.w;
\n"
"
\n"
" vec3 eye = vec3( 0.0, 0.0, 1.0 );
\n"
" //vec3 eye = -normalize(ecPosition3);
\n"
"
\n"
" DynamicShadow( ecPos );
\n"
"
\n"
" gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
\n"
"
\n"
" // Front Face lighting
\n"
"
\n"
" // Clear the light intensity accumulators
\n"
" vec4 amb = vec4(0.0);
\n"
" vec4 diff = vec4(0.0);
\n"
" vec4 spec = vec4(0.0);
\n"
"
\n"
" // Loop through enabled lights, compute contribution from each
\n"
" for (int i = 0; i < NumEnabledLights; i++)
\n"
"
{ \n"
" if (gl_LightSource[i].position.w == 0.0)
\n"
" DirectionalLight(i, normal, amb, diff, spec);
\n"
" else if (gl_LightSource[i].spotCutoff == 180.0)
\n"
" PointLight(i, eye, ecPosition3, normal, amb, diff,
spec); \n"
" else
\n"
" SpotLight(i, eye, ecPosition3, normal, amb, diff, spec);
\n"
" }
\n"
"
\n"
" colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor +
\n"
" amb * gl_FrontMaterial.ambient;
\n"
"
\n"
" gl_FrontColor = colorAmbientEmissive +
\n"
" diff * gl_FrontMaterial.diffuse;
\n"
"
\n"
" gl_FrontSecondaryColor = vec4(spec*gl_FrontMaterial.specular);
\n"
"
\n"
" gl_BackColor = gl_FrontColor;
\n"
" gl_BackSecondaryColor = gl_FrontSecondaryColor;
\n"
"
\n"
" gl_FogFragCoord = ecLen;
\n"
"} \n" );
#endif
}
StandardShadowMap::StandardShadowMap(const StandardShadowMap& copy, const
osg::CopyOp& copyop) :
BaseClass(copy,copyop),
_polygonOffsetFactor( copy._polygonOffsetFactor ),
_polygonOffsetUnits( copy._polygonOffsetUnits ),
_textureSize( copy._textureSize ),
_baseTextureUnit( copy._baseTextureUnit ),
_shadowTextureUnit( copy._shadowTextureUnit )
{
if( copy._mainVertexShader.valid() )
_mainVertexShader = dynamic_cast<osg::Shader*>
( copy._mainVertexShader->clone(copyop) );
if( copy._mainFragmentShader.valid() )
_mainFragmentShader = dynamic_cast<osg::Shader*>
( copy._mainFragmentShader->clone(copyop) );
if( copy._shadowVertexShader.valid() )
_shadowVertexShader = dynamic_cast<osg::Shader*>
( copy._shadowVertexShader->clone(copyop) );
if( copy._shadowFragmentShader.valid() )
_shadowFragmentShader = dynamic_cast<osg::Shader*>
( copy._shadowFragmentShader->clone(copyop) );
}
StandardShadowMap::~StandardShadowMap(void)
{
}
void StandardShadowMap::updateTextureCoordIndices( unsigned int
fromTextureCoordIndex, unsigned int toTextureCoordIndex )
{
if( fromTextureCoordIndex == toTextureCoordIndex ) return;
const char *expressions[] = {
"gl_TexCoord[","]",
"gl_TextureMatrix[","]",
"gl_MultiTexCoord","",
"gl_EyePlaneS[","]",
"gl_EyePlaneT[","]",
"gl_EyePlaneR[","]",
"gl_EyePlaneQ[","]"
};
for( unsigned int i = 0;
i < sizeof( expressions ) / sizeof( expressions[0] );
i+=2 )
{
char acFrom[ 32 ], acTo[32];
// its not elegant to mix stdio & stl strings
// but in this context I do an exception for cleaner code
sprintf( acFrom, "%s%d%s", expressions[i], fromTextureCoordIndex,
expressions[i+1]);
sprintf( acTo, "%s%d%s", expressions[i], toTextureCoordIndex,
expressions[i+1]);
std::string from( acFrom ), to( acTo );
searchAndReplaceShaderSource( getShadowVertexShader(), from, to );
searchAndReplaceShaderSource( getShadowFragmentShader(), from, to );
searchAndReplaceShaderSource( getMainVertexShader(), from, to );
searchAndReplaceShaderSource( getMainFragmentShader(), from, to );
}
dirty();
}
void StandardShadowMap::searchAndReplaceShaderSource
( osg::Shader* shader, std::string fromString, std::string
toString )
{
if( !shader || fromString == toString ) return;
const std::string & srceString = shader->getShaderSource();
std::string destString;
std::string::size_type fromLength = fromString.length();
std::string::size_type srceLength = srceString.length();
for( std::string::size_type pos = 0; pos < srceLength; )
{
std::string::size_type end = srceString.find( fromString, pos );
if( end == std::string::npos )
end = srceLength;
destString.append( srceString, pos, end - pos );
if( end == srceLength )
break;
destString.append( toString );
pos = end + fromLength;
}
shader->setShaderSource( destString );
}
void StandardShadowMap::ViewData::cull()
{
// step 1:
// cull shadowed scene ie put into render bins and states into stage
graphs
cullShadowReceivingScene( );
// step 2:
// find the light casting our shadows
osg::Vec4 lightPos;
osg::Vec3 lightDir;
osg::Vec3 lightUp( 0,0,0 ); // force computing most approprate dir
const osg::Light *light = selectLight( lightPos, lightDir );
if ( !light )
return;// bail out - no shadowing needed in darkest night
// step 3:
// compute shadow casting matrices and apply them to shadow map camera
aimShadowCastingCamera( light, lightPos, lightDir, lightUp );
// step 4:
// cull scene casting shadow and generate render
cullShadowCastingScene( );
// step 5:
// setup texgen generating shadow map coords for the shadow receiving
scene
addShadowReceivingTexGen( );
BaseClass::ViewData::cull();
}
void StandardShadowMap::ViewData::init( ThisClass *st, osgUtil::CullVisitor
*cv )
{
BaseClass::ViewData::init( st, cv );
_lightPtr = &st->_light;
_shadowTextureUnitPtr = &st->_shadowTextureUnit;
_baseTextureUnitPtr = &st->_baseTextureUnit;
{ // Setup shadow texture
osg::Texture2D * texture = new osg::Texture2D;
texture->setTextureSize( st->_textureSize.x(),
st->_textureSize.y());
texture->setInternalFormat(GL_DEPTH_COMPONENT);
texture->setShadowComparison(true);
texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR
);
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR
);
// the shadow comparison should fail if object is outside the
texture
texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BOR
DER);
texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BOR
DER);
texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
_texture = texture;
}
_camera = new osg::Camera;
{ // Setup shadow map camera
_camera->setName( "ShadowCamera" );
#if 0 // Absolute reference frame INHERIT_VIEWPOINT works better than this
_camera->setCullingMode
( _camera->getCullingMode() &
~osg::CullSettings::SMALL_FEATURE_CULLING );
#endif
_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOIN
T);
_camera->setCullCallback(new CameraCullCallback( st ));
_camera->setClearMask(GL_DEPTH_BUFFER_BIT);
#if 0 // Left in case of some debug testing
_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
_camera->setClearColor( osg::Vec4(1.0f,1.0f,1.0f,1.0f) );
#endif
_camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR)
;
_camera->setViewport(0,0, st->_textureSize.x(),
st->_textureSize.y() );
_camera->setRenderOrder(osg::Camera::PRE_RENDER);
_camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJ
ECT);
_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
}
_texgen = new osg::TexGen;
_stateset = new osg::StateSet;
{ // Create and add fake texture for use with nodes without any texture
osg::Image * image = new osg::Image;
image->allocateImage( 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE );
*(osg::Vec4ub*)image->data() = osg::Vec4ub( 0xFF, 0xFF, 0xFF,
0xFF );
osg::Texture2D* fakeTex = new osg::Texture2D( image );
fakeTex->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
fakeTex->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT);
fakeTex->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEARES
T);
fakeTex->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEARES
T);
_stateset->setTextureAttribute(st->_baseTextureUnit,fakeTex,osg::Sta
teAttribute::ON);
_stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_2D,osg::St
ateAttribute::ON);
_stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_3D,osg::St
ateAttribute::OFF);
#if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
_stateset->setTextureMode(st->_baseTextureUnit,GL_TEXTURE_1D,osg
::StateAttribute::OFF);
#endif
}
{ // Add shadow texture
_stateset->setTextureAttributeAndModes(st->_shadowTextureUnit,_textu
re.get(),osg::StateAttribute::ON);
_stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_S,os
g::StateAttribute::ON);
_stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_T,os
g::StateAttribute::ON);
_stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_R,os
g::StateAttribute::ON);
_stateset->setTextureMode(st->_shadowTextureUnit,GL_TEXTURE_GEN_Q,os
g::StateAttribute::ON);
}
{ // Setup shaders used in shadow casting
osg::Program * program = new osg::Program();
_stateset->setAttribute( program );
if( st->_shadowFragmentShader.valid() )
program->addShader( st->_shadowFragmentShader.get() );
if( st->_mainFragmentShader.valid() )
program->addShader( st->_mainFragmentShader.get() );
if( st->_shadowVertexShader.valid() )
program->addShader( st->_shadowVertexShader.get() );
if( st->_mainVertexShader.valid() )
program->addShader( st->_mainVertexShader.get() );
_stateset->addUniform
( new osg::Uniform( "baseTexture", int(
st->_baseTextureUnit ) ) );
_stateset->addUniform
( new osg::Uniform( "shadowTexture", int(
st->_shadowTextureUnit ) ) );
}
{ // Setup states used for shadow map generation
osg::StateSet * stateset = _camera->getOrCreateStateSet();
stateset->setAttribute(
new osg::PolygonOffset( st->_polygonOffsetFactor,
st->_polygonOffsetUnits ),
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
stateset->setMode( GL_POLYGON_OFFSET_FILL,
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
// agressive optimization
stateset->setRenderBinDetails( 0, "RenderBin",
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
// Assure that AlphaTest/AlphaRef works when redirecting all
drawables to single bin.
// If AlphaFunc/AlphaTest is off - transparent objects will cast
solid blocky shadows.
// No override to allow users change this policy in the model if
really want solid shadows.
stateset->setAttributeAndModes
( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0 ),
osg::StateAttribute::ON );
// agressive optimization
stateset->setAttributeAndModes
( new osg::ColorMask( false, false, false, false ),
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
// note soft (attribute only no mode override) setting. When this
works ?
// 1. for objects prepared for backface culling
// because they usually also set CullFace and CullMode on in
their state
// For them we override CullFace but CullMode remains set by them
// 2. For one faced, trees, and similar objects which cannot use
// backface nor front face so they usually use CullMode off set
here.
// In this case we will draw them in their entirety.
stateset->setAttribute( new osg::CullFace( osg::CullFace::FRONT ),
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
// make sure GL_CULL_FACE is off by default
// we assume that if object has cull face attribute set to back
// it will also set cull face mode ON so no need for override
stateset->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
// optimization attributes
osg::Program* program = new osg::Program;
stateset->setAttribute( program, osg::StateAttribute::OVERRIDE |
osg::StateAttribute::ON );
stateset->setMode
( GL_LIGHTING, osg::StateAttribute::OVERRIDE |
osg::StateAttribute::OFF );
stateset->setMode
( GL_BLEND, osg::StateAttribute::OVERRIDE |
osg::StateAttribute::OFF );
#if 0 // fixed pipeline seems faster (at least on my 7800)
program->addShader( new osg::Shader( osg::Shader::FRAGMENT,
"uniform sampler2D texture;
\n"
"void main(void)
\n"
"{
\n"
" gl_FragColor = texture2D( texture, gl_TexCoord[0].xy );
\n"
"}
\n"
) ); // program->addShader Fragment
program->addShader( new osg::Shader( osg::Shader::VERTEX,
"void main(void)
\n"
"{
\n"
" gl_Position = ftransform();
\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;
\n"
"}
\n"
) ); // program->addShader Vertex
#endif
for( unsigned stage = 1; stage < 4; stage ++ )
{
#if !defined(OSG_GLES1_AVAILABLE) &&
!defined(OSG_GLES2_AVAILABLE)
stateset->setTextureMode( stage, GL_TEXTURE_1D,
osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
#endif
stateset->setTextureMode( stage, GL_TEXTURE_2D,
osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
stateset->setTextureMode( stage, GL_TEXTURE_3D,
osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
}
}
}
const osg::Light* StandardShadowMap::ViewData::selectLight
( osg::Vec4 & lightPos, osg::Vec3 &
lightDir )
{
const osg::Light* light = 0;
//MR testing giving a specific light
osgUtil::RenderStage * rs = _cv->getRenderStage();
osgUtil::PositionalStateContainer::AttrMatrixList& aml =
rs->getPositionalStateContainer()->getAttrMatrixList();
osg::RefMatrix* matrix = 0;
for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr =
aml.begin();
itr != aml.end();
++itr)
{
const osg::Light* found = dynamic_cast<const
osg::Light*>(itr->first.get());
if( found )
{
if( _lightPtr->valid() && _lightPtr->get() != found )
continue; // continue search for the right one
light = found;
matrix = itr->second.get();
}
}
if( light ) { // transform light to world space
osg::Matrix localToWorld = osg::Matrix::inverse(
*_cv->getModelViewMatrix() );
if( matrix ) localToWorld.preMult( *matrix );
lightPos = light->getPosition();
if( lightPos[3] == 0 )
lightDir.set( -lightPos[0], -lightPos[1], -lightPos[2] );
else
lightDir = light->getDirection();
lightPos = lightPos * localToWorld;
lightDir = osg::Matrix::transform3x3( lightDir, localToWorld );
lightDir.normalize();
}
return light;
}
void StandardShadowMap::ViewData::aimShadowCastingCamera( const osg::Light
*light,
const osg::Vec4 &lightPos,
const osg::Vec3 &lightDir,
const osg::Vec3 &lightUp
/* by default = osg::Vec3( 0, 1
0 )*/ )
{
#if 0 // less precise but faster
osg::BoundingSphere bs =_st->getShadowedScene()->getBound();
#else
// get the bounds of the model.
osg::ComputeBoundsVisitor
cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN);
cbbv.setTraversalMask(_st->getShadowedScene()->getCastsShadowTraversalMa
sk());
_st->getShadowedScene()->osg::Group::traverse(cbbv);
osg::BoundingSphere bs( cbbv.getBoundingBox() );
#endif
aimShadowCastingCamera
( bs, light, lightPos, lightDir, lightUp );
}
void StandardShadowMap::ViewData::aimShadowCastingCamera(
const osg::BoundingSphere &bs,
const osg::Light *light,
const osg::Vec4 &lightPos,
const osg::Vec3 &lightDir,
const osg::Vec3 &lightUpVector
/* by default = osg::Vec3( 0, 1
0 )*/ )
{
osg::Matrixd & view = _camera->getViewMatrix();
osg::Matrixd & projection = _camera->getProjectionMatrix();
osg::Vec3 up = lightUpVector;
if( up.length2() <= 0 ) up.set( 0,1,0 );
osg::Vec3d position(lightPos.x(), lightPos.y(), lightPos.z());
if (lightPos[3]==0.0) // infinite directional light
{
// make an orthographic projection
// set the position far away along the light direction
position = bs.center() - lightDir * bs.radius() * 2;
}
float centerDistance = (position-bs.center()).length();
float znear = centerDistance-bs.radius();
float zfar = centerDistance+bs.radius();
float zNearRatio = 0.001f;
if (znear<zfar*zNearRatio)
znear = zfar*zNearRatio;
if ( lightPos[3]!=0.0 ) { // positional light
if( light->getSpotCutoff() < 180.0f) // also needs znear zfar
estimates
{
float spotAngle = light->getSpotCutoff();
projection.makePerspective( spotAngle * 2, 1.0, znear, zfar);
view.makeLookAt(position,position+lightDir,up);
} else { // standard omnidirectional positional light
float top = (bs.radius()/centerDistance)*znear;
float right = top;
projection.makeFrustum(-right,right,-top,top,znear,zfar);
view.makeLookAt(position,bs.center(),up );
}
}
else // directional light
{
float top = bs.radius();
float right = top;
projection.makeOrtho(-right, right, -top, top, znear, zfar);
view.makeLookAt(position,bs.center(),up);
}
}
void StandardShadowMap::ViewData::cullShadowReceivingScene( )
{
_cv->pushStateSet( _stateset.get() );
_st->getShadowedScene()->osg::Group::traverse( *_cv );
_cv->popStateSet();
}
void StandardShadowMap::ViewData::cullShadowCastingScene( )
{
// record the traversal mask on entry so we can reapply it later.
unsigned int traversalMask = _cv->getTraversalMask();
_cv->setTraversalMask( traversalMask &
_st->getShadowedScene()->getCastsShadowTraversalMask() );
// do RTT camera traversal
_camera->accept(*_cv);
// reapply the original traversal mask
_cv->setTraversalMask( traversalMask );
}
void StandardShadowMap::ViewData::addShadowReceivingTexGen( )
{
_texgen->setMode(osg::TexGen::EYE_LINEAR);
// compute the matrix which takes a vertex from view coords into tex
coords
_texgen->setPlanesFromMatrix(
_camera->getProjectionMatrix() *
osg::Matrix::translate(1.0,1.0,1.0) *
osg::Matrix::scale(0.5f,0.5f,0.5f) );
osg::RefMatrix * refMatrix = new osg::RefMatrix
( _camera->getInverseViewMatrix() *
*_cv->getModelViewMatrix() );
_cv->getRenderStage()->getPositionalStateContainer()->
addPositionedTextureAttribute
( *_shadowTextureUnitPtr, refMatrix, _texgen.get() );
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org