| 25 | | ShadowTechnique(copy,copyop) |
| 26 | | { |
| 27 | | } |
| | 58 | ShadowTechnique(copy,copyop), |
| | 59 | _textureUnit(copy._textureUnit) |
| | 60 | { |
| | 61 | } |
| | 62 | |
| | 63 | void ShadowMap::setTextureUnit(unsigned int unit) |
| | 64 | { |
| | 65 | _textureUnit = unit; |
| | 66 | } |
| | 67 | |
| | 68 | void ShadowMap::init() |
| | 69 | { |
| | 70 | if (!_shadowedScene) return; |
| | 71 | |
| | 72 | unsigned int tex_width = 1024; |
| | 73 | unsigned int tex_height = 1024; |
| | 74 | |
| | 75 | _texture = new osg::Texture2D; |
| | 76 | _texture->setTextureSize(tex_width, tex_height); |
| | 77 | _texture->setInternalFormat(GL_DEPTH_COMPONENT); |
| | 78 | _texture->setShadowComparison(true); |
| | 79 | _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE); |
| | 80 | _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); |
| | 81 | _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); |
| | 82 | |
| | 83 | // set up the render to texture camera. |
| | 84 | { |
| | 85 | // create the camera |
| | 86 | _camera = new osg::Camera; |
| | 87 | |
| | 88 | _camera->setCullCallback(new CameraCullCallback(this)); |
| | 89 | |
| | 90 | _camera->setClearMask(GL_DEPTH_BUFFER_BIT); |
| | 91 | //_camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); |
| | 92 | _camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); |
| | 93 | _camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); |
| | 94 | |
| | 95 | // set viewport |
| | 96 | _camera->setViewport(0,0,tex_width,tex_height); |
| | 97 | |
| | 98 | // set the camera to render before the main camera. |
| | 99 | _camera->setRenderOrder(osg::Camera::PRE_RENDER); |
| | 100 | |
| | 101 | // tell the camera to use OpenGL frame buffer object where supported. |
| | 102 | _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); |
| | 103 | //_camera->setRenderTargetImplementation(osg::Camera::SEPERATE_WINDOW); |
| | 104 | |
| | 105 | // attach the texture and use it as the color buffer. |
| | 106 | _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get()); |
| | 107 | |
| | 108 | osg::StateSet* stateset = _camera->getOrCreateStateSet(); |
| | 109 | |
| | 110 | float factor = 0.0f; |
| | 111 | float units = 1.0f; |
| | 112 | |
| | 113 | osg::ref_ptr<osg::PolygonOffset> polygon_offset = new osg::PolygonOffset; |
| | 114 | polygon_offset->setFactor(factor); |
| | 115 | polygon_offset->setUnits(units); |
| | 116 | stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); |
| | 117 | stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); |
| | 118 | |
| | 119 | osg::ref_ptr<osg::CullFace> cull_face = new osg::CullFace; |
| | 120 | cull_face->setMode(osg::CullFace::FRONT); |
| | 121 | stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); |
| | 122 | stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); |
| | 123 | |
| | 124 | } |
| | 125 | |
| | 126 | { |
| | 127 | _stateset = new osg::StateSet; |
| | 128 | _stateset->setTextureAttributeAndModes(_textureUnit,_texture.get(),osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); |
| | 129 | _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); |
| | 130 | _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); |
| | 131 | _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); |
| | 132 | _stateset->setTextureMode(_textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); |
| | 133 | |
| | 134 | _texgen = new osg::TexGen; |
| | 135 | |
| | 136 | #if 1 |
| | 137 | osg::Program* program = new osg::Program; |
| | 138 | _stateset->setAttribute(program); |
| | 139 | |
| | 140 | if (_textureUnit==0) |
| | 141 | { |
| | 142 | osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture); |
| | 143 | program->addShader(fragment_shader); |
| | 144 | |
| | 145 | osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); |
| | 146 | _stateset->addUniform(shadowTextureSampler); |
| | 147 | } |
| | 148 | else |
| | 149 | { |
| | 150 | osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture); |
| | 151 | program->addShader(fragment_shader); |
| | 152 | |
| | 153 | osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); |
| | 154 | _stateset->addUniform(baseTextureSampler); |
| | 155 | |
| | 156 | osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)_textureUnit); |
| | 157 | _stateset->addUniform(shadowTextureSampler); |
| | 158 | } |
| | 159 | |
| | 160 | osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f)); |
| | 161 | _stateset->addUniform(ambientBias); |
| | 162 | |
| | 163 | #endif |
| | 164 | } |
| | 165 | |
| | 166 | _dirty = false; |
| | 167 | } |
| | 168 | |
| | 169 | |
| | 170 | void ShadowMap::update(osg::NodeVisitor& nv) |
| | 171 | { |
| | 172 | _shadowedScene->osg::Group::traverse(nv); |
| | 173 | } |
| | 174 | |
| | 175 | void ShadowMap::cull(osgUtil::CullVisitor& cv) |
| | 176 | { |
| | 177 | // record the traversal mask on entry so we can reapply it later. |
| | 178 | unsigned int traversalMask = cv.getTraversalMask(); |
| | 179 | |
| | 180 | osgUtil::RenderStage* orig_rs = cv.getRenderStage(); |
| | 181 | |
| | 182 | // do traversal of shadow recieving scene which does need to be decorated by the shadow map |
| | 183 | { |
| | 184 | cv.pushStateSet(_stateset.get()); |
| | 185 | |
| | 186 | _shadowedScene->osg::Group::traverse(cv); |
| | 187 | |
| | 188 | cv.popStateSet(); |
| | 189 | |
| | 190 | } |
| | 191 | |
| | 192 | // need to compute view frustum for RTT camera. |
| | 193 | // 1) get the light position |
| | 194 | // 2) get the center and extents of the view frustum |
| | 195 | |
| | 196 | const osg::Light* selectLight = 0; |
| | 197 | osg::Vec4 lightpos; |
| | 198 | |
| | 199 | osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); |
| | 200 | for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); |
| | 201 | itr != aml.end(); |
| | 202 | ++itr) |
| | 203 | { |
| | 204 | const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get()); |
| | 205 | if (light) |
| | 206 | { |
| | 207 | osg::RefMatrix* matrix = itr->second.get(); |
| | 208 | if (matrix) lightpos = light->getPosition() * (*matrix); |
| | 209 | else lightpos = light->getPosition(); |
| | 210 | |
| | 211 | selectLight = light; |
| | 212 | } |
| | 213 | } |
| | 214 | |
| | 215 | osg::Matrix eyeToWorld; |
| | 216 | eyeToWorld.invert(cv.getModelViewMatrix()); |
| | 217 | |
| | 218 | lightpos = lightpos * eyeToWorld; |
| | 219 | |
| | 220 | if (selectLight) |
| | 221 | { |
| | 222 | |
| | 223 | // get the bounds of the model. |
| | 224 | osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); |
| | 225 | cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); |
| | 226 | |
| | 227 | _shadowedScene->osg::Group::traverse(cbbv); |
| | 228 | |
| | 229 | osg::BoundingBox bb = cbbv.getBoundingBox(); |
| | 230 | |
| | 231 | if (lightpos[3]!=0.0) |
| | 232 | { |
| | 233 | osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); |
| | 234 | |
| | 235 | float centerDistance = (position-bb.center()).length(); |
| | 236 | |
| | 237 | float znear = centerDistance-bb.radius(); |
| | 238 | float zfar = centerDistance+bb.radius(); |
| | 239 | float zNearRatio = 0.001f; |
| | 240 | if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; |
| | 241 | |
| | 242 | float top = (bb.radius()/centerDistance)*znear; |
| | 243 | float right = top; |
| | 244 | |
| | 245 | _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); |
| | 246 | _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); |
| | 247 | _camera->setViewMatrixAsLookAt(position,bb.center(),osg::Vec3(0.0f,1.0f,0.0f)); |
| | 248 | |
| | 249 | |
| | 250 | // compute the matrix which takes a vertex from local coords into tex coords |
| | 251 | // will use this later to specify osg::TexGen.. |
| | 252 | osg::Matrix MVPT = _camera->getViewMatrix() * |
| | 253 | _camera->getProjectionMatrix() * |
| | 254 | osg::Matrix::translate(1.0,1.0,1.0) * |
| | 255 | osg::Matrix::scale(0.5f,0.5f,0.5f); |
| | 256 | |
| | 257 | _texgen->setMode(osg::TexGen::EYE_LINEAR); |
| | 258 | _texgen->setPlanesFromMatrix(MVPT); |
| | 259 | } |
| | 260 | |
| | 261 | |
| | 262 | cv.setTraversalMask( traversalMask & |
| | 263 | getShadowedScene()->getCastsShadowTraversalMask() ); |
| | 264 | |
| | 265 | // do RTT camera traversal |
| | 266 | _camera->accept(cv); |
| | 267 | |
| | 268 | orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, &cv.getModelViewMatrix(), _texgen.get()); |
| | 269 | } |
| | 270 | |
| | 271 | |
| | 272 | // reapply the original traversal mask |
| | 273 | cv.setTraversalMask( traversalMask ); |
| | 274 | } |
| | 275 | |
| | 276 | void ShadowMap::cleanSceneGraph() |
| | 277 | { |
| | 278 | } |