| | 52 | "} \n"; |
| | 53 | |
| | 54 | static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] = |
| | 55 | "uniform sampler2D baseTexture; \n" |
| | 56 | "uniform int baseTextureUnit; \n" |
| | 57 | "uniform sampler2DShadow shadowTexture0; \n" |
| | 58 | "uniform int shadowTextureUnit0; \n" |
| | 59 | "uniform sampler2DShadow shadowTexture1; \n" |
| | 60 | "uniform int shadowTextureUnit1; \n" |
| | 61 | " \n" |
| | 62 | "void main(void) \n" |
| | 63 | "{ \n" |
| | 64 | " vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor; \n" |
| | 65 | " vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy ); \n" |
| | 66 | " float shadow0 = shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r; \n" |
| | 67 | " float shadow1 = shadow2DProj( shadowTexture1, gl_TexCoord[shadowTextureUnit1] ).r; \n" |
| | 68 | " color *= mix( colorAmbientEmissive, gl_Color, shadow0*shadow1 ); \n" |
| | 69 | " gl_FragColor = color; \n" |
| | 250 | |
| | 251 | class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack |
| | 252 | { |
| | 253 | public: |
| | 254 | ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix): |
| | 255 | osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) |
| | 256 | { |
| | 257 | pushViewport(viewport); |
| | 258 | pushProjectionMatrix(new osg::RefMatrix(projectionMatrix)); |
| | 259 | pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF); |
| | 260 | } |
| | 261 | |
| | 262 | void apply(osg::Node& node) |
| | 263 | { |
| | 264 | if (isCulled(node)) return; |
| | 265 | |
| | 266 | traverse(node); |
| | 267 | } |
| | 268 | |
| | 269 | void apply(osg::Geode& node) |
| | 270 | { |
| | 271 | if (isCulled(node)) return; |
| | 272 | |
| | 273 | for(unsigned int i=0; i<node.getNumDrawables();++i) |
| | 274 | { |
| | 275 | if (node.getDrawable(i)) |
| | 276 | { |
| | 277 | updateBound(node.getDrawable(i)->getBound()); |
| | 278 | } |
| | 279 | } |
| | 280 | } |
| | 281 | |
| | 282 | void apply(osg::Billboard&) |
| | 283 | { |
| | 284 | OSG_INFO<<"Warning Billboards not yet supported"<<std::endl; |
| | 285 | return; |
| | 286 | } |
| | 287 | |
| | 288 | void apply(osg::Projection&) |
| | 289 | { |
| | 290 | // projection nodes won't affect a shadow map so their subgraphs should be ignored |
| | 291 | return; |
| | 292 | } |
| | 293 | |
| | 294 | void apply(osg::Transform& transform) |
| | 295 | { |
| | 296 | if (isCulled(transform)) return; |
| | 297 | |
| | 298 | // absolute transforms won't affect a shadow map so their subgraphs should be ignored. |
| | 299 | if (transform.getReferenceFrame()==osg::Transform::ABSOLUTE_RF) return; |
| | 300 | |
| | 301 | osg::ref_ptr<osg::RefMatrix> matrix = new osg::RefMatrix(*getModelViewMatrix()); |
| | 302 | transform.computeLocalToWorldMatrix(*matrix,this); |
| | 303 | pushModelViewMatrix(matrix.get(), transform.getReferenceFrame()); |
| | 304 | |
| | 305 | traverse(transform); |
| | 306 | |
| | 307 | popModelViewMatrix(); |
| | 308 | } |
| | 309 | |
| | 310 | void apply(osg::Camera&) |
| | 311 | { |
| | 312 | // camera nodes won't affect a shadow map so their subgraphs should be ignored |
| | 313 | return; |
| | 314 | } |
| | 315 | |
| | 316 | void updateBound(const osg::BoundingBox& bb) |
| | 317 | { |
| | 318 | if (!bb.valid()) return; |
| | 319 | |
| | 320 | const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix(); |
| | 321 | |
| | 322 | update(bb.corner(0) * matrix); |
| | 323 | update(bb.corner(1) * matrix); |
| | 324 | update(bb.corner(2) * matrix); |
| | 325 | update(bb.corner(3) * matrix); |
| | 326 | update(bb.corner(4) * matrix); |
| | 327 | update(bb.corner(5) * matrix); |
| | 328 | update(bb.corner(6) * matrix); |
| | 329 | update(bb.corner(7) * matrix); |
| | 330 | } |
| | 331 | |
| | 332 | void update(const osg::Vec3& v) |
| | 333 | { |
| | 334 | if (v.z()<0.0f) |
| | 335 | { |
| | 336 | //OSG_NOTICE<<"discarding("<<v<<")"<<std::endl; |
| | 337 | return; |
| | 338 | } |
| | 339 | |
| | 340 | float x = v.x(); |
| | 341 | if (x<-1.0f) x=-1.0f; |
| | 342 | if (x>1.0f) x=1.0f; |
| | 343 | float y = v.y(); |
| | 344 | if (y<-1.0f) y=-1.0f; |
| | 345 | if (y>1.0f) y=1.0f; |
| | 346 | |
| | 347 | _bb.expandBy(osg::Vec3(x,y,v.z())); |
| | 348 | } |
| | 349 | |
| | 350 | osg::BoundingBox _bb; |
| | 351 | }; |
| | 352 | |
| | 817 | // 3.1 compute light space polytope |
| | 818 | // |
| | 819 | osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl); |
| | 820 | |
| | 821 | // if polytope is empty then no rendering. |
| | 822 | if (polytope.empty()) |
| | 823 | { |
| | 824 | OSG_NOTICE<<"Polytope empty no shadow to render"<<std::endl; |
| | 825 | continue; |
| | 826 | } |
| | 827 | |
| | 828 | // 3.2 compute RTT camera view+projection matrix settings |
| | 829 | // |
| | 830 | osg::Matrixd projectionMatrix; |
| | 831 | osg::Matrixd viewMatrix; |
| | 832 | if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix)) |
| | 833 | { |
| | 834 | OSG_NOTICE<<"No valid Camera settings, no shadow to render"<<std::endl; |
| | 835 | continue; |
| | 836 | } |
| | 837 | |
| | 838 | // if we are using multiple shadow maps and CastShadowTraversalMask is being used |
| | 839 | // traverse the scene to compute the extents of the objects |
| | 840 | if (numShadowMapsPerLight>1 && _shadowedScene->getCastsShadowTraversalMask()!=0xffffffff) |
| | 841 | { |
| | 842 | // osg::ElapsedTime timer; |
| | 843 | |
| | 844 | osg::ref_ptr<osg::Viewport> viewport = new osg::Viewport(0,0,2048,2048); |
| | 845 | ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix); |
| | 846 | clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask()); |
| | 847 | |
| | 848 | osg::Matrixd invertModelView; |
| | 849 | invertModelView.invert(viewMatrix); |
| | 850 | osg::Polytope local_polytope(polytope); |
| | 851 | local_polytope.transformProvidingInverse(invertModelView); |
| | 852 | |
| | 853 | osg::CullingSet& cs = clsb.getProjectionCullingStack().back(); |
| | 854 | cs.setFrustum(local_polytope); |
| | 855 | |
| | 856 | clsb.pushCullingSet(); |
| | 857 | |
| | 858 | _shadowedScene->accept(clsb); |
| | 859 | |
| | 860 | // OSG_NOTICE<<"Extents of LightSpace "<<clsb._bb.xMin()<<", "<<clsb._bb.xMax()<<", "<<clsb._bb.yMin()<<", "<<clsb._bb.yMax()<<", "<<clsb._bb.zMin()<<", "<<clsb._bb.zMax()<<std::endl; |
| | 861 | // OSG_NOTICE<<" time "<<timer.elapsedTime_m()<<"ms, mask = "<<std::hex<<_shadowedScene->getCastsShadowTraversalMask()<<std::endl; |
| | 862 | |
| | 863 | if (clsb._bb.xMin()>-1.0f || clsb._bb.xMax()<1.0f || clsb._bb.yMin()>-1.0f || clsb._bb.yMax()<1.0f) |
| | 864 | { |
| | 865 | // OSG_NOTICE<<"Need to clamp projection matrix"<<std::endl; |
| | 866 | |
| | 867 | #if 0 |
| | 868 | double xMid = (clsb._bb.xMin()+clsb._bb.xMax())*0.5f; |
| | 869 | double xRange = clsb._bb.xMax()-clsb._bb.xMin(); |
| | 870 | #else |
| | 871 | double xMid = 0.0; |
| | 872 | double xRange = 2.0; |
| | 873 | #endif |
| | 874 | double yMid = (clsb._bb.yMin()+clsb._bb.yMax())*0.5f; |
| | 875 | double yRange = (clsb._bb.yMax()-clsb._bb.yMin()); |
| | 876 | |
| | 877 | // OSG_NOTICE<<" xMid="<<xMid<<", yMid="<<yMid<<", xRange="<<xRange<<", yRange="<<yRange<<std::endl; |
| | 878 | |
| | 879 | projectionMatrix = |
| | 880 | projectionMatrix * |
| | 881 | osg::Matrixd::translate(osg::Vec3d(-xMid,-yMid,0.0)) * |
| | 882 | osg::Matrixd::scale(osg::Vec3d(2.0/xRange, 2.0/yRange,1.0)); |
| | 883 | |
| | 884 | } |
| | 885 | |
| | 886 | } |
| | 887 | |
| | 888 | double splitPoint = 0.0; |
| | 889 | |
| | 890 | if (numShadowMapsPerLight>1) |
| | 891 | { |
| | 892 | osg::Vec3d eye_v = frustum.eye * viewMatrix; |
| | 893 | osg::Vec3d center_v = frustum.center * viewMatrix; |
| | 894 | osg::Vec3d viewdir_v = center_v-eye_v; viewdir_v.normalize(); |
| | 895 | osg::Vec3d lightdir(0.0,0.0,-1.0); |
| | 896 | |
| | 897 | double dotProduct_v = lightdir * viewdir_v; |
| | 898 | double angle = acosf(dotProduct_v); |
| | 899 | |
| | 900 | osg::Vec3d eye_ls = eye_v * projectionMatrix; |
| | 901 | |
| | 902 | OSG_INFO<<"Angle between view vector and eye "<<osg::RadiansToDegrees(angle)<<std::endl; |
| | 903 | OSG_INFO<<"eye_ls="<<eye_ls<<std::endl; |
| | 904 | |
| | 905 | if (eye_ls.y()>=-1.0 && eye_ls.y()<=1.0) |
| | 906 | { |
| | 907 | OSG_INFO<<"Eye point inside light space clip region "<<std::endl; |
| | 908 | splitPoint = 0.0; |
| | 909 | } |
| | 910 | else |
| | 911 | { |
| | 912 | double n = -1.0-eye_ls.y(); |
| | 913 | double f = 1.0-eye_ls.y(); |
| | 914 | double sqrt_nf = sqrt(n*f); |
| | 915 | double mid = eye_ls.y()+sqrt_nf; |
| | 916 | double ratioOfMidToUseForSplit = 0.8; |
| | 917 | splitPoint = mid * ratioOfMidToUseForSplit; |
| | 918 | |
| | 919 | OSG_INFO<<" n="<<n<<", f="<<f<<", sqrt_nf="<<sqrt_nf<<" mid="<<mid<<std::endl; |
| | 920 | } |
| | 921 | } |
| | 922 | |
| 736 | | polytope.transformProvidingInverse(invertModelView); |
| 737 | | |
| 738 | | osg::ref_ptr<VDSMCameraCullCallback> vdsmCallback = new VDSMCameraCullCallback(this, polytope); |
| | 955 | osg::Polytope local_polytope(polytope); |
| | 956 | local_polytope.transformProvidingInverse(invertModelView); |
| | 957 | |
| | 958 | |
| | 959 | if (numShadowMapsPerLight>1) |
| | 960 | { |
| | 961 | // compute the start and end range in non-dimensional coords |
| | 962 | #if 0 |
| | 963 | double r_start = (sm_i==0) ? -1.0 : (double(sm_i)/double(numShadowMapsPerLight)*2.0-1.0); |
| | 964 | double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : (double(sm_i+1)/double(numShadowMapsPerLight)*2.0-1.0); |
| | 965 | #endif |
| | 966 | |
| | 967 | // hardwired for 2 splits |
| | 968 | double r_start = (sm_i==0) ? -1.0 : splitPoint; |
| | 969 | double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : splitPoint; |
| | 970 | |
| | 971 | // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap |
| | 972 | // to prevent a seam showing through between the shadowmaps |
| | 973 | if (sm_i+1<numShadowMapsPerLight) r_end+=0.01; |
| | 974 | |
| | 975 | |
| | 976 | if (sm_i>0) |
| | 977 | { |
| | 978 | // not the first shadowmap so insert a polytope to clip the scene from before r_start |
| | 979 | |
| | 980 | // plane in clip space coords |
| | 981 | osg::Plane plane(0.0,1.0,0.0,-r_start); |
| | 982 | |
| | 983 | // transform into eye coords |
| | 984 | plane.transformProvidingInverse(projectionMatrix); |
| | 985 | local_polytope.getPlaneList().push_back(plane); |
| | 986 | |
| | 987 | //OSG_NOTICE<<"Adding r_start plane "<<plane<<std::endl; |
| | 988 | |
| | 989 | } |
| | 990 | |
| | 991 | if (sm_i+1<numShadowMapsPerLight) |
| | 992 | { |
| | 993 | // not the last shadowmap so insert a polytope to clip the scene from beyond r_end |
| | 994 | |
| | 995 | // plane in clip space coords |
| | 996 | osg::Plane plane(0.0,-1.0,0.0,r_end); |
| | 997 | |
| | 998 | // transform into eye coords |
| | 999 | plane.transformProvidingInverse(projectionMatrix); |
| | 1000 | local_polytope.getPlaneList().push_back(plane); |
| | 1001 | |
| | 1002 | //OSG_NOTICE<<"Adding r_end plane "<<plane<<std::endl; |
| | 1003 | } |
| | 1004 | |
| | 1005 | local_polytope.setupMask(); |
| | 1006 | |
| | 1007 | |
| | 1008 | // OSG_NOTICE<<"Need to adjust RTT camera projection and view matrix here, r_start="<<r_start<<", r_end="<<r_end<<std::endl; |
| | 1009 | // OSG_NOTICE<<" textureUnit = "<<textureUnit<<std::endl; |
| | 1010 | |
| | 1011 | double mid_r = (r_start+r_end)*0.5; |
| | 1012 | double range_r = (r_end-r_start); |
| | 1013 | |
| | 1014 | // OSG_NOTICE<<" mid_r = "<<mid_r<<", range_r = "<<range_r<<std::endl; |
| | 1015 | |
| | 1016 | camera->setProjectionMatrix( |
| | 1017 | camera->getProjectionMatrix() * |
| | 1018 | osg::Matrixd::translate(osg::Vec3d(0.0,-mid_r,0.0)) * |
| | 1019 | osg::Matrixd::scale(osg::Vec3d(1.0,2.0/range_r,1.0))); |
| | 1020 | |
| | 1021 | } |
| | 1022 | |
| | 1023 | |
| | 1024 | osg::ref_ptr<VDSMCameraCullCallback> vdsmCallback = new VDSMCameraCullCallback(this, local_polytope); |
| 890 | | osg::ref_ptr<osg::Uniform> shadowTextureSampler = new osg::Uniform("shadowTexture",(int)(settings->getBaseShadowTextureUnit())); |
| 891 | | _uniforms.push_back(shadowTextureSampler.get()); |
| 892 | | |
| 893 | | osg::ref_ptr<osg::Uniform> shadowTextureUnit = new osg::Uniform("shadowTextureUnit",(int)(settings->getBaseShadowTextureUnit())); |
| 894 | | _uniforms.push_back(shadowTextureUnit.get()); |
| | 1174 | for(unsigned int sm_i=0; sm_i<settings->getNumShadowMapsPerLight(); ++sm_i) |
| | 1175 | { |
| | 1176 | { |
| | 1177 | std::stringstream sstr; |
| | 1178 | sstr<<"shadowTexture"<<sm_i; |
| | 1179 | osg::ref_ptr<osg::Uniform> shadowTextureSampler = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); |
| | 1180 | _uniforms.push_back(shadowTextureSampler.get()); |
| | 1181 | } |
| | 1182 | |
| | 1183 | { |
| | 1184 | std::stringstream sstr; |
| | 1185 | sstr<<"shadowTextureUnit"<<sm_i; |
| | 1186 | osg::ref_ptr<osg::Uniform> shadowTextureUnit = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i)); |
| | 1187 | _uniforms.push_back(shadowTextureUnit.get()); |
| | 1188 | } |
| | 1189 | } |