From Adrian Egli, "Improvements to the PSSM implementation"

This commit is contained in:
Robert Osfield 2008-06-19 14:45:54 +00:00
parent cc9d12f34f
commit 0faaf93dc2
2 changed files with 211 additions and 174 deletions

View File

@ -29,6 +29,7 @@
#include <osg/Camera>
#include <osg/Material>
#include <osg/Depth>
#include <osg/ClipPlane>
#include <osgShadow/ShadowTechnique>
@ -77,24 +78,45 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique
/** Set min near distance for splits */
inline void setMinNearDistanceForSplits(double nd){ _split_min_near_dist=nd; }
/** use linear split (default: linear) */
inline void useLinearSplit(bool flag) { _linearSplit = flag;}
/** set a user defined light for shadow simulation (sun light, ... )
* when this light get passed to pssm, the scene's light are no longer collected
* and simulated. just this user passed light, it needs to be a directional light.
*/
inline void setUserLight(osg::Light* light) { _userLight = light; }
/** Set the values for the ambient bias the shader will use.*/
void setAmbientBias(const osg::Vec2& ambientBias );
/**
* you can overwrite the fragment shader if you like to modify it yourself, own fragment shader can be used
*/
class FragmentShaderGenerator : public osg::Referenced {
public:
/**
* generate the GLSL fragement shader
*/
virtual std::string generateGLSL_FragmentShader_BaseTex(bool debug, unsigned int splitCount,double textureRes, bool filtered, unsigned int nbrSplits,unsigned int textureOffset);
};
/** set fragment shader generator */
inline void setFragmentShaderGenerator(FragmentShaderGenerator* fsw) { _FragmentShaderGenerator = fsw;}
/** enable / disable shadow filtering */
inline void enableShadowGLSLFiltering(bool filtering = true) { _GLSL_shadow_filtered = filtering; }
enum SplitCalcMode {
SPLIT_LINEAR,
SPLIT_EXP
};
/** set split calculation mode */
inline void setSplitCalculationMode(SplitCalcMode scm=SPLIT_EXP) { _SplitCalcMode = scm; }
protected :
virtual ~ParallelSplitShadowMap() {}
std::string generateGLSL_FragmentShader_BaseTex(bool debug, unsigned int splitCount);
struct PSSMShadowSplitTexture {
// RTT
@ -105,7 +127,7 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique
unsigned int _textureUnit;
osg::ref_ptr<osg::Depth> _depth;
double _split_far;
osg::ref_ptr<osg::Camera> _debug_camera;
osg::ref_ptr<osg::Texture2D> _debug_texture;
@ -127,8 +149,8 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique
unsigned int _resolution;
osg::Uniform* _farDistanceSplit;
};
typedef std::map<unsigned int,PSSMShadowSplitTexture> PSSMShadowSplitTextureMap;
PSSMShadowSplitTextureMap _PSSMShadowSplitTextureMap;
@ -158,11 +180,12 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique
double _split_min_near_dist;
double _move_vcam_behind_rcam_factor;
osg::ref_ptr<osg::Light> _userLight;
osg::ref_ptr<FragmentShaderGenerator> _FragmentShaderGenerator;
bool _linearSplit;
osg::Light* _userLight;
bool _GLSL_shadow_filtered;
SplitCalcMode _SplitCalcMode;
osg::Uniform* _ambientBiasUniform;
osg::Vec2d _ambientBias;

View File

@ -53,83 +53,101 @@ using namespace osgShadow;
#define TEXTURE_RESOLUTION 1024
#define LINEAR_SPLIT false
//#define SMOOTH_SHADOW //experimental
#define ZNEAR_MIN_FROM_LIGHT_SOURCE 2.0
#define ZNEAR_MIN_FROM_LIGHT_SOURCE 5.0
#define MOVE_VIRTUAL_CAMERA_BEHIND_REAL_CAMERA_FACTOR 0.0
//#define SHOW_SHADOW_TEXTURE_DEBUG // DEPTH instead of color for debug information texture display in a rectangle
//#define SHADOW_TEXTURE_DEBUG // COLOR instead of DEPTH
#ifndef SHADOW_TEXTURE_DEBUG
#define SHADOW_TEXTURE_GLSL
#endif
std::string ParallelSplitShadowMap::generateGLSL_FragmentShader_BaseTex(bool debug, unsigned int splitCount) {
//////////////////////////////////////////////////////////////////////////
// FragmentShaderGenerator
std::string ParallelSplitShadowMap::FragmentShaderGenerator::generateGLSL_FragmentShader_BaseTex(
bool debug,
unsigned int splitCount,
double textureRes,
bool filtered,
unsigned int nbrSplits,
unsigned int textureOffset
) {
std::stringstream sstr;
/// base texture
sstr << "uniform sampler2D baseTexture; " << std::endl;
#ifdef SMOOTH_SHADOW
sstr << "uniform sampler2D randomTexture; " << std::endl;
#endif
sstr << "uniform float enableBaseTexture; " << std::endl;
sstr << "uniform vec2 ambientBias;" << std::endl;
for (unsigned int i=0;i<_number_of_splits;i++) {
for (unsigned int i=0;i<nbrSplits;i++) {
sstr << "uniform sampler2DShadow shadowTexture" << i <<"; " << std::endl;
sstr << "uniform float zShadow" << i <<"; " << std::endl;
}
sstr << "void main(void)" << std::endl;
sstr << "{" << std::endl;
/// select the shadow map : split
sstr << "float testZ = gl_FragCoord.z*2.0-1.0;" <<std::endl;
sstr << "float map0 = step(testZ, zShadow0);"<< std::endl;//DEBUG
for (unsigned int i=1;i<nbrSplits;i++) {
sstr << "float map" << i << " = step(zShadow"<<i-1<<",testZ)*step(testZ, zShadow"<<i<<");"<< std::endl;//DEBUG
}
if (filtered) {
sstr << " float fTexelSize="<< (sqrt(2.0) / textureRes ) <<";" << std::endl;
}
for (unsigned int i=0;i<nbrSplits;i++) {
if (!filtered) {
sstr << " float shadow" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]).r;" << std::endl;
} else {
// filter the shadow (look up)
sstr << " float shadowOrg" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]).r;" << std::endl;
sstr << " float shadow0" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]+vec4(-fTexelSize,-fTexelSize,0,0) ).r;" << std::endl;
sstr << " float shadow1" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]+vec4(fTexelSize,-fTexelSize,0,0)).r;" << std::endl;
sstr << " float shadow2" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]+vec4(fTexelSize,fTexelSize,0,0) ).r;" << std::endl;
sstr << " float shadow3" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+textureOffset) <<"]+vec4(-fTexelSize,fTexelSize,0,0) ).r;" << std::endl;
sstr << " float shadow02" << i <<" = (shadow0" << i <<"+shadow1" << i <<")*0.5;"<< std::endl;
sstr << " float shadow13" << i <<" = (shadow1" << i <<"+shadow3" << i <<")*0.5;"<< std::endl;
sstr << " float shadowSoft" << i <<" = (shadow02" << i <<"+shadow13" << i <<")*0.5;"<< std::endl;
sstr << " float shadow" << i <<" = (shadowSoft" << i <<"+shadowOrg" << i <<")*0.5;"<< std::endl;
}
sstr << " shadow" << i <<" = step(0.25,shadow" << i <<");" << std::endl; // reduce shadow artefacts
}
if ( debug ) {
sstr << " vec4 coord = vec4(0,0,0,1);"<<std::endl;
} else {
sstr << " vec4 coord = gl_FragCoord;"<<std::endl;
sstr << " float term0 = (1.0-shadow0)*map0; " << std::endl;
for (unsigned int i=1;i<nbrSplits;i++) {
sstr << " float term" << i << " = map"<< i << "*(1.0-shadow"<<i<<");"<< std::endl;
}
#ifdef SMOOTH_SHADOW
for (unsigned int i=0;i<_number_of_splits;i++) {
sstr << " float shadow" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]).r;" << std::endl;
sstr << " vec4 random" << i <<" = "<<(1.15/(double)_resolution)<<"*coord.z*texture2D(randomTexture,gl_TexCoord[" << (i+_textureUnitOffset) <<"].st); " << std::endl;
sstr << " float shadow1" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]+random" << i <<".r*vec4(-1,-1,0,0)).r;" << std::endl;
sstr << " float shadow2" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]+random" << i <<".g*vec4(1,-1,0,0)).r;" << std::endl;
sstr << " float shadow3" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]+random" << i <<".b*vec4(1,1,0,0)).r;" << std::endl;
sstr << " float shadow4" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]+random" << i <<".a*vec4(-1,1,0,0)).r;" << std::endl;
sstr << " shadow" << i <<" = shadow" << i <<" + shadow1" << i <<" + shadow2" << i <<" + shadow3" << i <<" + shadow4" << i <<";" << std::endl;
sstr << " shadow" << i <<" = shadow" << i <<"*0.2;" << std::endl;
}
#else
for (unsigned int i=0;i<_number_of_splits;i++) {
sstr << " float shadow" << i <<" = shadow2DProj( shadowTexture" << i <<",gl_TexCoord[" << (i+_textureUnitOffset) <<"]).r;" << std::endl;
}
#endif
sstr << " float term0 = (1.0-shadow0); " << std::endl;
for (unsigned int i=1;i<_number_of_splits;i++) {
sstr << " float term" << i << " = (1.0-shadow"<<i<<");"<< std::endl;
}
// v => SHADOW filter; " << std::endl;
/// build shadow factor value v
sstr << " float v = clamp(";
for (unsigned int i=0;i<_number_of_splits;i++) {
sstr << "term" << i;
if ( i+1 < _number_of_splits ){
for (unsigned int i=0;i<nbrSplits;i++) {
sstr << "term" << i;
if ( i+1 < nbrSplits ){
sstr << "+";
}
}
sstr << ",0.0,1.0);" << std::endl;
if ( _debug_color_in_GLSL ) {
if ( debug ) {
sstr << " float c0=0.0;" << std::endl;
@ -138,35 +156,54 @@ std::string ParallelSplitShadowMap::generateGLSL_FragmentShader_BaseTex(bool deb
sstr << " float sumTerm=0.0;" << std::endl;
for (unsigned int i=0;i<_number_of_splits;i++) {
for (unsigned int i=0;i<nbrSplits;i++) {
if ( i < 3 ) sstr << " c" << i << "=term" << i << ";" << std::endl;
sstr << " sumTerm=sumTerm+term" << i << ";" << std::endl;
}
sstr << " vec4 color = gl_Color*( 1.0 - sumTerm ) + (sumTerm)* gl_Color*vec4(c0,(1.0-c0)*c1,(1.0-c0)*(1.0-c1)*c2,1.0); " << std::endl;
switch(nbrSplits){
case 1: sstr << " color = color*0.75 + vec4(map0,0,0,1.0)*0.25; " << std::endl;break;
case 2: sstr << " color = color*0.75 + vec4(map0,map1,0,1.0)*0.25; " << std::endl;break;
case 3: sstr << " color = color*0.75 + vec4(map0,map1,map2,1.0)*0.25; " << std::endl; break;
case 4: sstr << " color = color*0.75 + vec4(map0+map3,map1+map3,map2,1.0)*0.25; " << std::endl; break;
case 5: sstr << " color = color*0.75 + vec4(map0+map3,map1+map3+map4,map2+map4,1.0)*0.25; " << std::endl;break;
case 6: sstr << " color = color*0.75 + vec4(map0+map3+map5,map1+map3+map4,map2+map4+map5,1.0)*0.25; " << std::endl; break;
default: break;
}
} else {
sstr << " vec4 color = gl_Color; "<< std::endl;
}
sstr << " vec4 texcolor = texture2D(baseTexture,gl_TexCoord[0].st); " << std::endl;
sstr << " float enableBaseTextureFilter = enableBaseTexture*(1.0 - step(texcolor.x+texcolor.y+texcolor.z+texcolor.a,0.0)); " << std::endl; //18
sstr << " vec4 colorTex = color*texcolor;" << std::endl;
sstr << " gl_FragColor = ((color*(ambientBias.x+1.0)*(1.0-enableBaseTextureFilter)) + colorTex*(1.0+ambientBias.x)*enableBaseTextureFilter)*(1.0-ambientBias.y*v); "<< std::endl;
sstr << " gl_FragColor.rgb = (((color*(ambientBias.x+1.0)*(1.0-enableBaseTextureFilter)) + colorTex*(1.0+ambientBias.x)*enableBaseTextureFilter)*(1.0-ambientBias.y*v)).rgb; "<< std::endl;
sstr << " gl_FragColor.a = (color*(1.0-enableBaseTextureFilter) + colorTex*enableBaseTextureFilter).a; "<< std::endl;
sstr << "}"<< std::endl;
if ( splitCount == _number_of_splits-1 ) osg::notify(osg::INFO) << std::endl << "ParallelSplitShadowMap: GLSL shader code:" << std::endl << "-------------------------------------------------------------------" << std::endl << sstr.str() << std::endl;
//std::cout << sstr.str() << std::endl;
if ( splitCount == nbrSplits-1 ) osg::notify(osg::INFO) << std::endl << "ParallelSplitShadowMap: GLSL shader code:" << std::endl << "-------------------------------------------------------------------" << std::endl << sstr.str() << std::endl;
return sstr.str();
}
//////////////////////////////////////////////////////////////////////////
// clamp variables of any type
template<class Type> inline Type Clamp(Type A, Type Min, Type Max) {
if(A<Min) return Min;
@ -177,25 +214,27 @@ template<class Type> inline Type Clamp(Type A, Type Min, Type Max) {
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
//////////////////////////////////////////////////////////////////////////
ParallelSplitShadowMap::ParallelSplitShadowMap(osg::Geode** gr, int icountplanes) :
_textureUnitOffset(1),
_debug_color_in_GLSL(false),
_user_polgyonOffset_set(false),
_resolution(TEXTURE_RESOLUTION),
_isSetMaxFarDistance(false),
_split_min_near_dist(ZNEAR_MIN_FROM_LIGHT_SOURCE),
_linearSplit(LINEAR_SPLIT),
_move_vcam_behind_rcam_factor(MOVE_VIRTUAL_CAMERA_BEHIND_REAL_CAMERA_FACTOR),
_userLight(NULL),
_ambientBias(0.1,0.3),
_ambientBiasUniform(NULL)
_textureUnitOffset(1),
_debug_color_in_GLSL(false),
_user_polgyonOffset_set(false),
_resolution(TEXTURE_RESOLUTION),
_isSetMaxFarDistance(false),
_split_min_near_dist(ZNEAR_MIN_FROM_LIGHT_SOURCE),
_move_vcam_behind_rcam_factor(MOVE_VIRTUAL_CAMERA_BEHIND_REAL_CAMERA_FACTOR),
_userLight(NULL),
_ambientBias(0.1,0.3),
_ambientBiasUniform(NULL),
_GLSL_shadow_filtered(true)
{
_displayTexturesGroupingNode = gr;
_number_of_splits = icountplanes;
_polgyonOffset.set(0.01f,0.01f);
}
_polgyonOffset.set(1.0f,1.0f);
setFragmentShaderGenerator(new FragmentShaderGenerator());
setSplitCalculationMode(SPLIT_EXP);
}
ParallelSplitShadowMap::ParallelSplitShadowMap(const ParallelSplitShadowMap& copy, const osg::CopyOp& copyop):
ShadowTechnique(copy,copyop),
@ -205,13 +244,15 @@ _user_polgyonOffset_set(copy._user_polgyonOffset_set),
_resolution(copy._resolution),
_isSetMaxFarDistance(copy._isSetMaxFarDistance),
_split_min_near_dist(copy._split_min_near_dist),
_linearSplit(copy._linearSplit),
_SplitCalcMode(copy._SplitCalcMode),
_number_of_splits(copy._number_of_splits),
_polgyonOffset(copy._polgyonOffset),
_setMaxFarDistance(copy._setMaxFarDistance),
_move_vcam_behind_rcam_factor(copy._move_vcam_behind_rcam_factor),
_userLight(copy._userLight),
_ambientBias(copy._ambientBias)
_ambientBias(copy._ambientBias),
_GLSL_shadow_filtered(copy._GLSL_shadow_filtered),
_FragmentShaderGenerator(copy._FragmentShaderGenerator)
{
}
@ -303,24 +344,25 @@ void ParallelSplitShadowMap::init(){
osg::StateSet* stateset = pssmShadowSplitTexture._camera->getOrCreateStateSet();
pssmShadowSplitTexture._depth = new osg::Depth;
stateset->setAttribute(pssmShadowSplitTexture._depth.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
//////////////////////////////////////////////////////////////////////////
float factor = _polgyonOffset.x();
float units = _polgyonOffset.y();
osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
polygon_offset->setFactor(factor);
osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset;
polygon_offset->setFactor(factor);
polygon_offset->setUnits(units);
stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
//////////////////////////////////////////////////////////////////////////
osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
cull_face->setMode(osg::CullFace::FRONT);
stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
if ( ! _GLSL_shadow_filtered ) {
// if not glsl filtering enabled then we should force front face culling to reduce the number of shadow artefacts.
osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace;
cull_face->setMode(osg::CullFace::FRONT);
stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
}
//////////////////////////////////////////////////////////////////////////
osg::ShadeModel* shademodel = dynamic_cast<osg::ShadeModel*>(stateset->getAttribute(osg::StateAttribute::SHADEMODEL));
@ -354,7 +396,15 @@ void ParallelSplitShadowMap::init(){
//////////////////////////////////////////////////////////////////////////
// GLSL PROGRAMS
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, generateGLSL_FragmentShader_BaseTex(_displayTexturesGroupingNode!=NULL,iCameras).c_str());
osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT,
_FragmentShaderGenerator->generateGLSL_FragmentShader_BaseTex(
_debug_color_in_GLSL,
iCameras,
pssmShadowSplitTexture._resolution,
_GLSL_shadow_filtered,
_number_of_splits,
_textureUnitOffset
).c_str());
program->addShader(fragment_shader);
@ -422,43 +472,6 @@ void ParallelSplitShadowMap::init(){
pssmShadowSplitTexture._stateset->setTextureMode(textLoop,GL_TEXTURE_2D,osg::StateAttribute::ON);
pssmShadowSplitTexture._stateset->setTextureMode(textLoop,GL_TEXTURE_3D,osg::StateAttribute::OFF);
}
#ifdef SMOOTH_SHADOW
{
// texture for randomTexture (for smoothing shadow edges)
osg::Image* image = new osg::Image;
// allocate the image data, noPixels x noPixels x 1 with 4 rgba floats - equivalent to a Vec4!
int noPixels = 128;
image->allocateImage(noPixels,noPixels,1,GL_RGBA,GL_FLOAT);
image->setInternalTextureFormat(GL_RGBA);
// fill in the image data.
osg::Vec4* dataPtr = (osg::Vec4*)image->data();
for (int s=0;s<noPixels;s++) {
for (int t=0;t<noPixels;t++) {
float randr=(rand()/(RAND_MAX+1.0));
float randg=(rand()/(RAND_MAX+1.0));
float randb=(rand()/(RAND_MAX+1.0));
float randa=(rand()/(RAND_MAX+1.0));
(*dataPtr).set(randr,randg,randb,randa);
dataPtr++;
}
}
// make fake texture
osg::Texture2D* texture = new osg::Texture2D;
texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
texture->setImage(image);
// add fake texture
pssmShadowSplitTexture._stateset->setTextureAttribute(_textureUnitOffset+_number_of_splits,texture,osg::StateAttribute::ON);
pssmShadowSplitTexture._stateset->setTextureMode(_textureUnitOffset+_number_of_splits,GL_TEXTURE_1D,osg::StateAttribute::OFF);
pssmShadowSplitTexture._stateset->setTextureMode(_textureUnitOffset+_number_of_splits,GL_TEXTURE_2D,osg::StateAttribute::ON);
pssmShadowSplitTexture._stateset->setTextureMode(_textureUnitOffset+_number_of_splits,GL_TEXTURE_3D,osg::StateAttribute::OFF);
}
#endif
#endif
@ -591,7 +604,7 @@ void ParallelSplitShadowMap::cull(osgUtil::CullVisitor& cv){
// take the user light as light source
lightpos = _userLight->getPosition();
lightDirection = _userLight->getDirection();
selectLight = _userLight;
selectLight = _userLight.get();
}
if (selectLight)
@ -699,14 +712,14 @@ void ParallelSplitShadowMap::cleanSceneGraph(){
//
//
//unit box representing frustum in clip space
const osg::Vec3f const_pointFarBR(1.0f, -1.0f, 1.0f);
const osg::Vec3f const_pointNearBR(1.0f, -1.0f, -1.0f);
const osg::Vec3f const_pointNearTR(1.0f, 1.0f, -1.0f);
const osg::Vec3f const_pointFarTR(1.0f, 1.0f, 1.0f);
const osg::Vec3f const_pointFarBR(1.0f, -1.0f, 1.0f);
const osg::Vec3f const_pointFarTL(-1.0f, 1.0f, 1.0f);
const osg::Vec3f const_pointFarBL(-1.0f, -1.0f, 1.0f);
const osg::Vec3f const_pointNearBL(-1.0f, -1.0f, -1.0f);
const osg::Vec3f const_pointNearTR(1.0f, 1.0f, -1.0f);
const osg::Vec3f const_pointNearBR(1.0f, -1.0f, -1.0f);
const osg::Vec3f const_pointNearTL(-1.0f, 1.0f, -1.0f);
const osg::Vec3f const_pointNearBL(-1.0f, -1.0f, -1.0f);
//////////////////////////////////////////////////////////////////////////
@ -731,7 +744,7 @@ void ParallelSplitShadowMap::calculateFrustumCorners(
osg::Vec3d camEye,camCenter,camUp;
pssmShadowSplitTexture._cameraView.getLookAt(camEye,camCenter,camUp);
osg::Vec3d viewDir = camCenter - camEye;
viewDir.normalize();
//viewDir.normalize(); //we can assume that viewDir is still normalized in the viewMatrix
camEye = camEye - viewDir * _move_vcam_behind_rcam_factor;
camFar += _move_vcam_behind_rcam_factor * viewDir.length();
viewMat.makeLookAt(camEye,camCenter,camUp);
@ -743,7 +756,7 @@ void ParallelSplitShadowMap::calculateFrustumCorners(
double maxFar = camFar;
double minNear = camNear;
double camNearFar_Dist = maxFar - camNear;
if ( _linearSplit ) {
if ( _SplitCalcMode == SPLIT_LINEAR ) {
camFar = camNear + (camNearFar_Dist) * ((double)(pssmShadowSplitTexture._splitID+1))/((double)(_number_of_splits));
camNear = camNear + (camNearFar_Dist) * ((double)(pssmShadowSplitTexture._splitID))/((double)(_number_of_splits));
} else {
@ -768,26 +781,20 @@ void ParallelSplitShadowMap::calculateFrustumCorners(
delete[] pSplitDistances;
}
//pssmShadowSplitTexture._depth->setRange((camNear - minNear) / camNearFar_Dist,(camFar - minNear)/ camNearFar_Dist);
pssmShadowSplitTexture._depth->setRange(0.0,1.0);
pssmShadowSplitTexture._depth->setFunction(osg::Depth::LEQUAL);
#ifdef SHADOW_TEXTURE_GLSL
float fVal = (float)((camFar-minNear)/camNearFar_Dist);
//std::cout << pssmShadowSplitTexture._farDistanceSplit->getName() << " " << fVal << std::endl;
pssmShadowSplitTexture._farDistanceSplit->set(fVal);
#endif
pssmShadowSplitTexture._split_far = camFar;
//////////////////////////////////////////////////////////////////////////
/// TRANSFORM frustum corners (Optimized for Orthogonal)
osg::Matrixf invProjViewMat;
osg::Matrixf projMat;
projMat.makePerspective(fovy,aspectRatio,camNear,camFar);
osg::Matrixf projViewMat(viewMat*projMat);
osg::Matrixf invProjViewMat;
invProjViewMat.invert(projViewMat);
//transform frustum vertices to world space
@ -798,8 +805,7 @@ void ParallelSplitShadowMap::calculateFrustumCorners(
frustumCorners[4] = const_pointFarTL * invProjViewMat;
frustumCorners[5] = const_pointFarBL * invProjViewMat;
frustumCorners[6] = const_pointNearBL* invProjViewMat;
frustumCorners[7] = const_pointNearTL* invProjViewMat;
frustumCorners[7] = const_pointNearTL* invProjViewMat;
//std::cout << "camFar : "<<pssmShadowSplitTexture._splitID << " / " << camNear << "," << camFar << std::endl;
}
@ -813,17 +819,18 @@ void ParallelSplitShadowMap::calculateLightInitalPosition(PSSMShadowSplitTexture
pssmShadowSplitTexture._frustumSplitCenter +=frustumCorners[i];
}
pssmShadowSplitTexture._frustumSplitCenter /= 8.0;
//
//
// To avoid edge problems, scale the frustum so
// that it's at least a few pixels larger
//
for(int i=0;i<8;i++)
{
// scale by adding offset from center
frustumCorners[i]+=(frustumCorners[i]-pssmShadowSplitTexture._frustumSplitCenter)*(0.25);
frustumCorners[i]+=(frustumCorners[i]-pssmShadowSplitTexture._frustumSplitCenter)*(0.75);
}
}
void ParallelSplitShadowMap::calculateLightNearFarFormFrustum(
@ -843,10 +850,7 @@ void ParallelSplitShadowMap::calculateLightNearFarFormFrustum(
// update camera position and look at center
pssmShadowSplitTexture._lightCameraSource = pssmShadowSplitTexture._frustumSplitCenter - pssmShadowSplitTexture._lightDirection*(zFar+_split_min_near_dist);
pssmShadowSplitTexture._lightCameraTarget = pssmShadowSplitTexture._frustumSplitCenter + pssmShadowSplitTexture._lightDirection*(zFar);
// update near - far plane
pssmShadowSplitTexture._lightNear = 0.01;
pssmShadowSplitTexture._lightFar = zFar*2.0 + _split_min_near_dist;
// calculate [zNear,zFar]
zFar = (-DBL_MAX);
double zNear(DBL_MAX);
@ -856,7 +860,7 @@ void ParallelSplitShadowMap::calculateLightNearFarFormFrustum(
if ( zNear > dist_z_from_light ) zNear = dist_z_from_light;
}
// update near - far plane
pssmShadowSplitTexture._lightNear = zNear - _split_min_near_dist + 0.01;
pssmShadowSplitTexture._lightNear = max(zNear - _split_min_near_dist - 0.01,0.01);
pssmShadowSplitTexture._lightFar = zFar;
}
@ -870,42 +874,52 @@ void ParallelSplitShadowMap::calculateLightViewProjectionFormFrustum(PSSMShadowS
// calculate the camera's coordinate system
osg::Vec3d camEye,camCenter,camUp;
pssmShadowSplitTexture._cameraView.getLookAt(camEye,camCenter,camUp);
osg::Vec3d viewDir(camCenter-camEye);
osg::Vec3d camRight(camUp^viewDir);
osg::Vec3d viewDir(camCenter-camEye);
// we force to have normalized vectors (camera's view)
camUp.normalize();
viewDir.normalize();
osg::Vec3d camLeft(camUp ^ viewDir);
camLeft.normalize();
osg::Vec3d top(pssmShadowSplitTexture._lightDirection ^ camLeft);
if(top.length2() < 0.5) top = pssmShadowSplitTexture._lightDirection ^ camUp;
osg::Vec3d left(top ^ pssmShadowSplitTexture._lightDirection);
// calculate the camera's frustum left,right,bottom,top parameters
double maxLeft(-DBL_MAX),maxTop(-DBL_MAX);
double minLeft(DBL_MAX),minTop(DBL_MAX);
camRight.normalize();
// use quaternion -> numerical more robust
osg::Quat qRot;
qRot.makeRotate(viewDir,pssmShadowSplitTexture._lightDirection);
osg::Vec3d top = qRot * camUp;
osg::Vec3d right = qRot * camRight;
// calculate the camera's frustum right,right,bottom,top parameters
double maxRight(-DBL_MAX),maxTop(-DBL_MAX);
double minRight(DBL_MAX),minTop(DBL_MAX);
for(int i(0); i < 8; i++)
{
{
osg::Vec3d diffCorner(pssmShadowSplitTexture._lightCameraSource - frustumCorners[i]);
double lLeft(diffCorner*left);
double lright(diffCorner*right);
double lTop(diffCorner*top);
if ( lLeft > maxLeft ) maxLeft = lLeft;
if ( lright > maxRight ) maxRight = lright;
if ( lTop > maxTop ) maxTop = lTop;
if ( lLeft < minLeft ) minLeft = lLeft;
if ( lright < minRight ) minRight = lright;
if ( lTop < minTop ) minTop = lTop;
}
}
// make the camera view matrix
pssmShadowSplitTexture._camera->setViewMatrixAsLookAt(pssmShadowSplitTexture._lightCameraSource,pssmShadowSplitTexture._lightCameraTarget,top);
// use ortho projection for light (directional light only supported)
pssmShadowSplitTexture._camera->setProjectionMatrixAsOrtho(minLeft,maxLeft,minTop,maxTop,pssmShadowSplitTexture._lightNear,pssmShadowSplitTexture._lightFar);
pssmShadowSplitTexture._camera->setProjectionMatrixAsOrtho(minRight,maxRight,minTop,maxTop,pssmShadowSplitTexture._lightNear,pssmShadowSplitTexture._lightFar);
#ifdef SHADOW_TEXTURE_GLSL
// get user cameras
osg::Vec3d vProjCamFraValue = (camEye + viewDir * pssmShadowSplitTexture._split_far) * (pssmShadowSplitTexture._cameraView * pssmShadowSplitTexture._cameraProj);
pssmShadowSplitTexture._farDistanceSplit->set((float)vProjCamFraValue.z());
#endif
}