| 20 | | #include <osgDB/ReadFile> |
| 21 | | #include <osgDB/Registry> |
| 22 | | |
| 23 | | #include <osgGA/TrackballManipulator> |
| 24 | | #include <osgGA/FlightManipulator> |
| 25 | | #include <osgGA/DriveManipulator> |
| 26 | | |
| 27 | | #include <osgProducer/Viewer> |
| 28 | | |
| 29 | | #include <iostream> |
| 30 | | #include <string> |
| 31 | | #include <vector> |
| 32 | | |
| 33 | | #define UPDATE_ONE_IMAGE_PER_FRAME 1 |
| 34 | | |
| 35 | | |
| 36 | | class PrerenderAppCallback : public osg::NodeCallback |
| | 23 | #include <osg/CameraNode> |
| | 24 | #include <osg/TexGenNode> |
| | 25 | |
| | 26 | using namespace osg; |
| | 27 | |
| | 28 | |
| | 29 | ref_ptr<Group> _create_scene() |
| | 30 | { |
| | 31 | ref_ptr<Group> scene = new Group; |
| | 32 | ref_ptr<Geode> geode_1 = new Geode; |
| | 33 | scene->addChild(geode_1.get()); |
| | 34 | |
| | 35 | ref_ptr<Geode> geode_2 = new Geode; |
| | 36 | ref_ptr<MatrixTransform> transform_2 = new MatrixTransform; |
| | 37 | transform_2->addChild(geode_2.get()); |
| | 38 | transform_2->setUpdateCallback(new osgUtil::TransformCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f))); |
| | 39 | scene->addChild(transform_2.get()); |
| | 40 | |
| | 41 | ref_ptr<Geode> geode_3 = new Geode; |
| | 42 | ref_ptr<MatrixTransform> transform_3 = new MatrixTransform; |
| | 43 | transform_3->addChild(geode_3.get()); |
| | 44 | transform_3->setUpdateCallback(new osgUtil::TransformCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f))); |
| | 45 | scene->addChild(transform_3.get()); |
| | 46 | |
| | 47 | const float radius = 0.8f; |
| | 48 | const float height = 1.0f; |
| | 49 | ref_ptr<TessellationHints> hints = new TessellationHints; |
| | 50 | hints->setDetailRatio(2.0f); |
| | 51 | ref_ptr<ShapeDrawable> shape; |
| | 52 | |
| | 53 | shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get()); |
| | 54 | shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f)); |
| | 55 | geode_1->addDrawable(shape.get()); |
| | 56 | |
| | 57 | |
| | 58 | shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get()); |
| | 59 | shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f)); |
| | 60 | geode_2->addDrawable(shape.get()); |
| | 61 | |
| | 62 | shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get()); |
| | 63 | shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f)); |
| | 64 | geode_2->addDrawable(shape.get()); |
| | 65 | |
| | 66 | shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get()); |
| | 67 | shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f)); |
| | 68 | geode_2->addDrawable(shape.get()); |
| | 69 | |
| | 70 | shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get()); |
| | 71 | shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f)); |
| | 72 | geode_2->addDrawable(shape.get()); |
| | 73 | |
| | 74 | shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get()); |
| | 75 | shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f)); |
| | 76 | geode_3->addDrawable(shape.get()); |
| | 77 | |
| | 78 | // material |
| | 79 | ref_ptr<Material> matirial = new Material; |
| | 80 | matirial->setColorMode(Material::DIFFUSE); |
| | 81 | matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 0, 0, 1)); |
| | 82 | matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 1, 1, 1)); |
| | 83 | matirial->setShininess(Material::FRONT_AND_BACK, 64.0f); |
| | 84 | scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON); |
| | 85 | |
| | 86 | return scene; |
| | 87 | } |
| | 88 | |
| | 89 | osg::RefNodePath createReflector() |
| | 90 | { |
| | 91 | ref_ptr<Group> scene = new Group; |
| | 92 | ref_ptr<Geode> geode_1 = new Geode; |
| | 93 | scene->addChild(geode_1.get()); |
| | 94 | |
| | 95 | const float radius = 0.8f; |
| | 96 | ref_ptr<TessellationHints> hints = new TessellationHints; |
| | 97 | hints->setDetailRatio(2.0f); |
| | 98 | ref_ptr<ShapeDrawable> shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 1.5f), hints.get()); |
| | 99 | shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f)); |
| | 100 | geode_1->addDrawable(shape.get()); |
| | 101 | |
| | 102 | osg::RefNodePath refNodeList; |
| | 103 | refNodeList.push_back(scene.get()); |
| | 104 | refNodeList.push_back(geode_1.get()); |
| | 105 | |
| | 106 | return refNodeList; |
| | 107 | } |
| | 108 | |
| | 109 | class UpdateCameraAndTexGenCallback : public osg::NodeCallback |
| | 125 | |
| | 126 | // compute the position of the center of the reflector subgraph |
| | 127 | osg::Matrixd matrix = osg::computeLocalToWorld(_reflectorNodePath); |
| | 128 | osg::BoundingSphere bs = _reflectorNodePath.back()->getBound(); |
| | 129 | osg::Vec3 position = bs.center() * matrix; |
| | 130 | |
| | 131 | typedef std::pair<osg::Vec3, osg::Vec3> ImageData; |
| | 132 | const ImageData id[] = |
| | 133 | { |
| | 134 | ImageData( osg::Vec3( 1, 0, 0), osg::Vec3( 0, -1, 0) ), // +X |
| | 135 | ImageData( osg::Vec3(-1, 0, 0), osg::Vec3( 0, -1, 0) ), // -X |
| | 136 | ImageData( osg::Vec3( 0, 1, 0), osg::Vec3( 0, 0, 1) ), // +Y |
| | 137 | ImageData( osg::Vec3( 0, -1, 0), osg::Vec3( 0, 0, -1) ), // -Y |
| | 138 | ImageData( osg::Vec3( 0, 0, 1), osg::Vec3( 0, -1, 0) ), // +Z |
| | 139 | ImageData( osg::Vec3( 0, 0, -1), osg::Vec3( 0, -1, 0) ) // -Z |
| | 140 | }; |
| | 141 | |
| | 142 | for(unsigned int i=0; |
| | 143 | i<6 && i<_cameraNodes.size(); |
| | 144 | ++i) |
| | 145 | { |
| | 146 | _cameraNodes[i]->setReferenceFrame(osg::CameraNode::ABSOLUTE_RF); |
| | 147 | _cameraNodes[i]->setProjectionMatrixAsFrustum(-1.0,1.0,-1.0,1.0,1.0,10000.0); |
| | 148 | _cameraNodes[i]->setViewMatrixAsLookAt(position,position+id[i].first,id[i].second); |
| | 149 | } |
| | 150 | |
| 85 | | const osg::Vec4 clearColArray[] = |
| 86 | | { |
| 87 | | osg::Vec4(0, 0, 1, 1), // +X |
| 88 | | osg::Vec4(1, 0.7f, 0, 1), // -X |
| 89 | | osg::Vec4(0, 1, 1, 1), // +Y |
| 90 | | osg::Vec4(1, 1, 0, 1), // -Y |
| 91 | | osg::Vec4(1, 0, 0, 1), // +Z |
| 92 | | osg::Vec4(0, 1, 0, 1) // -Z |
| 93 | | }; |
| 94 | | |
| 95 | | osg::Quat q; |
| 96 | | cv->getModelViewMatrix().get(q); |
| 97 | | const osg::Matrix C = osg::Matrix::rotate( q.inverse() ); |
| 98 | | _texmat->setMatrix(C); |
| 99 | | |
| 100 | | #if UPDATE_ONE_IMAGE_PER_FRAME |
| 101 | | if ((_updateCubemapFace >= 0) && (_updateCubemapFace <= 5)) |
| 102 | | { |
| 103 | | _clearColor = clearColArray[_updateCubemapFace]; |
| 104 | | doPreRender(*node, *cv, _updateCubemapFace++); |
| 105 | | } |
| 106 | | #else |
| 107 | | while (_updateCubemapFace<6) |
| 108 | | { |
| 109 | | _clearColor = clearColArray[_updateCubemapFace]; |
| 110 | | doPreRender(*node, *cv, _updateCubemapFace++); |
| 111 | | } |
| 112 | | #endif |
| | 178 | osg::Quat quat; |
| | 179 | cv->getModelViewMatrix().get(quat); |
| | 180 | _texmat->setMatrix(osg::Matrix::rotate(quat.inverse())); |
| | 182 | } |
| | 183 | |
| | 184 | protected: |
| | 185 | |
| | 186 | osg::ref_ptr<TexMat> _texmat; |
| | 187 | }; |
| | 188 | |
| | 189 | |
| | 190 | osg::Group* createShadowedScene(osg::Node* reflectedSubgraph, osg::RefNodePath reflectorNodePath, unsigned int unit, const osg::Vec4& clearColor) |
| | 191 | { |
| | 192 | |
| | 193 | osg::Group* group = new osg::Group; |
| | 194 | |
| | 195 | unsigned int tex_width = 512; |
| | 196 | unsigned int tex_height = 512; |
| | 197 | |
| | 198 | osg::TextureCubeMap* texture = new osg::TextureCubeMap; |
| | 199 | texture->setTextureSize(tex_width, tex_height); |
| | 200 | |
| | 201 | texture->setInternalFormat(GL_RGB); |
| | 202 | texture->setFilter(osg::TextureCubeMap::MIN_FILTER,osg::TextureCubeMap::LINEAR); |
| | 203 | texture->setFilter(osg::TextureCubeMap::MAG_FILTER,osg::TextureCubeMap::LINEAR); |
| | 204 | |
| | 205 | // set up the render to texture cameras. |
| | 206 | UpdateCameraAndTexGenCallback::CameraList cameraNodes; |
| | 207 | for(unsigned int i=0; i<6; ++i) |
| | 208 | { |
| | 209 | |
| | 210 | // create the camera |
| | 211 | osg::CameraNode* camera = new osg::CameraNode; |
| | 212 | |
| | 213 | camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| | 214 | camera->setClearColor(clearColor); |
| | 215 | |
| | 216 | // set viewport |
| | 217 | camera->setViewport(0,0,tex_width,tex_height); |
| | 218 | |
| | 219 | // set the camera to render before the main camera. |
| | 220 | camera->setRenderOrder(osg::CameraNode::PRE_RENDER); |
| | 221 | |
| | 222 | // tell the camera to use OpenGL frame buffer object where supported. |
| | 223 | camera->setRenderTargetImplmentation(osg::CameraNode::FRAME_BUFFER_OBJECT); |
| | 224 | |
| | 225 | // attach the texture and use it as the color buffer. |
| | 226 | camera->attach(osg::CameraNode::COLOR_BUFFER, texture, 0, i); |
| | 227 | |
| | 228 | // add subgraph to render |
| | 229 | camera->addChild(reflectedSubgraph); |
| | 230 | |
| | 231 | group->addChild(camera); |
| | 232 | |
| | 233 | cameraNodes.push_back(camera); |
| | 234 | } |
| | 235 | |
| | 236 | // create the texgen node to project the tex coords onto the subgraph |
| | 237 | osg::TexGenNode* texgenNode = new osg::TexGenNode; |
| | 238 | texgenNode->getTexGen()->setMode(osg::TexGen::REFLECTION_MAP); |
| | 239 | texgenNode->setTextureUnit(unit); |
| | 240 | group->addChild(texgenNode); |
| | 241 | |
| | 242 | // set the reflected subgraph so that it uses the texture and tex gen settings. |
| | 243 | { |
| | 244 | osg::Node* reflectorNode = reflectorNodePath.front().get(); |
| | 245 | group->addChild(reflectorNode); |
| 115 | | // must traverse the subgraph |
| 116 | | traverse(node,nv); |
| 117 | | } |
| 118 | | |
| 119 | | void doPreRender(osg::Node& node, osgUtil::CullVisitor& cv, const int nFace); |
| 120 | | |
| 121 | | struct ImageData |
| 122 | | { |
| 123 | | ImageData(const osg::Vec3& dir, const osg::Vec3& up) : _dir(dir), _up(up) {} |
| 124 | | osg::Vec3 _dir; |
| 125 | | osg::Vec3 _up; |
| 126 | | }; |
| 127 | | |
| 128 | | osg::ref_ptr<osg::Node> _subgraph; |
| 129 | | osg::ref_ptr<osg::TextureCubeMap> _cubemap; |
| 130 | | osg::ref_ptr<osg::StateSet> _localState[6]; |
| 131 | | osg::ref_ptr<osg::TexMat> _texmat; |
| 132 | | osg::Vec4 _clearColor; |
| 133 | | int _updateCubemapFace; |
| 134 | | }; |
| 135 | | |
| 136 | | |
| 137 | | void PrerenderCullCallback::doPreRender(osg::Node& /*node*/, osgUtil::CullVisitor& cv, const int nFace) |
| 138 | | { |
| 139 | | const ImageData id[] = |
| 140 | | { |
| 141 | | ImageData( osg::Vec3( 1, 0, 0), osg::Vec3( 0, -1, 0) ), // +X |
| 142 | | ImageData( osg::Vec3(-1, 0, 0), osg::Vec3( 0, -1, 0) ), // -X |
| 143 | | ImageData( osg::Vec3( 0, 1, 0), osg::Vec3( 0, 0, 1) ), // +Y |
| 144 | | ImageData( osg::Vec3( 0, -1, 0), osg::Vec3( 0, 0, -1) ), // -Y |
| 145 | | ImageData( osg::Vec3( 0, 0, 1), osg::Vec3( 0, -1, 0) ), // +Z |
| 146 | | ImageData( osg::Vec3( 0, 0, -1), osg::Vec3( 0, -1, 0) ) // -Z |
| 147 | | }; |
| 148 | | |
| 149 | | osg::Image* image = _cubemap->getImage((osg::TextureCubeMap::Face)nFace); |
| 150 | | osg::Vec3 dir = id[nFace]._dir; |
| 151 | | osg::Vec3 up = id[nFace]._up; |
| 152 | | |
| 153 | | const osg::BoundingSphere& bs = _subgraph->getBound(); |
| 154 | | if (!bs.valid()) |
| 155 | | { |
| 156 | | osg::notify(osg::WARN) << "bb invalid"<<_subgraph.get()<<std::endl; |
| 157 | | return; |
| 158 | | } |
| 159 | | |
| 160 | | // create the render to texture stage. |
| 161 | | osg::ref_ptr<osgUtil::RenderToTextureStage> rtts = new osgUtil::RenderToTextureStage; |
| 162 | | |
| 163 | | // set up lighting. |
| 164 | | // currently ignore lights in the scene graph itself.. |
| 165 | | // will do later. |
| 166 | | osgUtil::RenderStage* previous_stage = cv.getCurrentRenderBin()->getStage(); |
| 167 | | |
| 168 | | // set up the background color and clear mask. |
| 169 | | rtts->setClearColor(_clearColor); |
| 170 | | |
| 171 | | // ABJ: use default (color+depth) |
| 172 | | rtts->setClearMask(previous_stage->getClearMask()); |
| 173 | | |
| 174 | | // set up to charge the same RenderStageLighting is the parent previous stage. |
| 175 | | rtts->setRenderStageLighting(previous_stage->getRenderStageLighting()); |
| 176 | | |
| 177 | | // record the render bin, to be restored after creation |
| 178 | | // of the render to text |
| 179 | | osgUtil::RenderBin* previousRenderBin = cv.getCurrentRenderBin(); |
| 180 | | |
| 181 | | // set the current renderbin to be the newly created stage. |
| 182 | | cv.setCurrentRenderBin(rtts.get()); |
| 183 | | |
| 184 | | |
| 185 | | float znear = 1.0f*bs.radius(); |
| 186 | | float zfar = 3.0f*bs.radius(); |
| 187 | | |
| 188 | | znear *= 0.9f; |
| 189 | | zfar *= 1.1f; |
| 190 | | |
| 191 | | // set up projection. |
| 192 | | const double fovy = 90.0; |
| 193 | | const double aspectRatio = 1.0; |
| 194 | | osg::RefMatrix* projection = new osg::RefMatrix; |
| 195 | | projection->makePerspective(fovy, aspectRatio, znear, zfar); |
| 196 | | |
| 197 | | cv.pushProjectionMatrix(projection); |
| 198 | | |
| 199 | | osg::RefMatrix* matrix = new osg::RefMatrix; |
| 200 | | osg::Vec3 eye = bs.center(); eye.z() = 0.0f; |
| 201 | | osg::Vec3 center = eye + dir; |
| 202 | | matrix->makeLookAt(eye, center, up); |
| 203 | | |
| 204 | | cv.pushModelViewMatrix(matrix); |
| 205 | | |
| 206 | | cv.pushStateSet(_localState[nFace].get()); |
| 207 | | |
| 208 | | { |
| 209 | | // traverse the subgraph |
| 210 | | _subgraph->accept(cv); |
| 211 | | } |
| 212 | | |
| 213 | | cv.popStateSet(); |
| 214 | | |
| 215 | | // restore the previous model view matrix. |
| 216 | | cv.popModelViewMatrix(); |
| 217 | | |
| 218 | | // restore the previous model view matrix. |
| 219 | | cv.popProjectionMatrix(); |
| 220 | | |
| 221 | | // restore the previous renderbin. |
| 222 | | cv.setCurrentRenderBin(previousRenderBin); |
| 223 | | |
| 224 | | if (rtts->getRenderGraphList().size()==0 && rtts->getRenderBinList().size()==0) |
| 225 | | { |
| 226 | | // getting to this point means that all the subgraph has been |
| 227 | | // culled by small feature culling or is beyond LOD ranges. |
| 228 | | return; |
| 229 | | } |
| 230 | | |
| 231 | | int height = 512; |
| 232 | | int width = 512; |
| 233 | | |
| 234 | | const osg::Viewport& viewport = *cv.getViewport(); |
| 235 | | |
| 236 | | // offset the impostor viewport from the center of the main window |
| 237 | | // viewport as often the edges of the viewport might be obscured by |
| 238 | | // other windows, which can cause image/reading writing problems. |
| 239 | | int center_x = viewport.x()+viewport.width()/2; |
| 240 | | int center_y = viewport.y()+viewport.height()/2; |
| 241 | | |
| 242 | | osg::Viewport* new_viewport = new osg::Viewport; |
| 243 | | new_viewport->setViewport(center_x-width/2,center_y-height/2,width,height); |
| 244 | | rtts->setViewport(new_viewport); |
| 245 | | |
| 246 | | _localState[nFace]->setAttribute(new_viewport); |
| 247 | | |
| 248 | | // and the render to texture stage to the current stages |
| 249 | | // dependancy list. |
| 250 | | cv.getCurrentRenderBin()->getStage()->addToDependencyList(rtts.get()); |
| 251 | | |
| 252 | | // if one exist attach image to the RenderToTextureStage. |
| 253 | | // if (image.valid()) rtts->setImage(_image.get()); |
| 254 | | if (image) rtts->setImage(image); |
| | 247 | osg::StateSet* stateset = reflectorNode->getOrCreateStateSet(); |
| | 248 | stateset->setTextureAttributeAndModes(unit,texture,osg::StateAttribute::ON); |
| | 249 | stateset->setTextureMode(unit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); |
| | 250 | stateset->setTextureMode(unit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); |
| | 251 | stateset->setTextureMode(unit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); |
| | 252 | stateset->setTextureMode(unit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); |
| | 253 | |
| | 254 | osg::TexMat* texmat = new osg::TexMat; |
| | 255 | stateset->setTextureAttributeAndModes(unit,texmat,osg::StateAttribute::ON); |
| | 256 | |
| | 257 | reflectorNode->setCullCallback(new TexMatCullCallback(texmat)); |
| | 258 | } |
| | 259 | |
| | 260 | // add the reflector scene to draw just as normal |
| | 261 | group->addChild(reflectedSubgraph); |
| | 262 | |
| | 263 | // set an update callback to keep moving the camera and tex gen in the right direction. |
| | 264 | group->setUpdateCallback(new UpdateCameraAndTexGenCallback(reflectorNodePath, cameraNodes)); |
| | 265 | |
| | 266 | return group; |
| 258 | | osg::Drawable* makeGeometry() |
| 259 | | { |
| 260 | | const float radius = 20; |
| 261 | | return new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius)); |
| 262 | | } |
| 263 | | |
| 264 | | osg::Node* createPreRenderSubGraph(osg::Node* subgraph) |
| 265 | | { |
| 266 | | if (!subgraph) return 0; |
| 267 | | |
| 268 | | // create the quad to visualize. |
| 269 | | osg::Drawable* geom = makeGeometry(); |
| 270 | | geom->setSupportsDisplayList(false); |
| 271 | | |
| 272 | | // new we need to add the texture to the Drawable, we do so by creating a |
| 273 | | // StateSet to contain the Texture StateAttribute. |
| 274 | | osg::StateSet* stateset = new osg::StateSet; |
| 275 | | |
| 276 | | osg::TextureCubeMap* cubemap = new osg::TextureCubeMap; |
| 277 | | |
| 278 | | // set up the textures |
| 279 | | osg::Image* imagePosX = new osg::Image; |
| 280 | | osg::Image* imageNegX = new osg::Image; |
| 281 | | osg::Image* imagePosY = new osg::Image; |
| 282 | | osg::Image* imageNegY = new osg::Image; |
| 283 | | osg::Image* imagePosZ = new osg::Image; |
| 284 | | osg::Image* imageNegZ = new osg::Image; |
| 285 | | |
| 286 | | imagePosX->setInternalTextureFormat(GL_RGB); |
| 287 | | imageNegX->setInternalTextureFormat(GL_RGB); |
| 288 | | imagePosY->setInternalTextureFormat(GL_RGB); |
| 289 | | imageNegY->setInternalTextureFormat(GL_RGB); |
| 290 | | imagePosZ->setInternalTextureFormat(GL_RGB); |
| 291 | | imageNegZ->setInternalTextureFormat(GL_RGB); |
| 292 | | |
| 293 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX); |
| 294 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX); |
| 295 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY); |
| 296 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY); |
| 297 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ); |
| 298 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ); |
| 299 | | |
| 300 | | cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); |
| 301 | | cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); |
| 302 | | cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE); |
| 303 | | cubemap->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); |
| 304 | | cubemap->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); |
| 305 | | stateset->setTextureAttributeAndModes(0, cubemap, osg::StateAttribute::ON); |
| 306 | | |
| 307 | | osg::TexGen *texgen = new osg::TexGen; |
| 308 | | texgen->setMode(osg::TexGen::REFLECTION_MAP); |
| 309 | | stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON); |
| 310 | | |
| 311 | | osg::TexMat* texmat = new osg::TexMat; |
| 312 | | stateset->setTextureAttribute(0, texmat); |
| 313 | | |
| 314 | | stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); |
| 315 | | |
| 316 | | geom->setStateSet(stateset); |
| 317 | | |
| 318 | | osg::Geode* geode = new osg::Geode; |
| 319 | | geode->addDrawable(geom); |
| 320 | | |
| 321 | | // Geodes can't have cull callback so create extra Group to attach cullcallback. |
| 322 | | osg::Group* parent = new osg::Group; |
| 323 | | |
| 324 | | parent->setUpdateCallback(new PrerenderAppCallback(subgraph)); |
| 325 | | |
| 326 | | parent->setCullCallback(new PrerenderCullCallback(subgraph, cubemap, texmat)); |
| 327 | | |
| 328 | | parent->addChild(geode); |
| 329 | | |
| 330 | | return parent; |
| 331 | | } |
| 332 | | |
| 333 | | |
| 334 | | struct DrawableCullCallback : public osg::Drawable::CullCallback |
| 335 | | { |
| 336 | | DrawableCullCallback(osg::TexMat* texmat) : _texmat(texmat) |
| 337 | | {} |
| 338 | | |
| 339 | | virtual bool cull(osg::NodeVisitor* nv, osg::Drawable* /*drawable*/, osg::State* /*state*/) const |
| 340 | | { |
| 341 | | osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv); |
| 342 | | if (cv) |
| 343 | | { |
| 344 | | osg::Quat q; |
| 345 | | cv->getModelViewMatrix().get(q); |
| 346 | | const osg::Matrix C = osg::Matrix::rotate( q.inverse() ); |
| 347 | | _texmat->setMatrix(C); |
| 348 | | } |
| 349 | | return false; |
| 350 | | } |
| 351 | | |
| 352 | | mutable osg::ref_ptr<osg::TexMat> _texmat; |
| 353 | | }; |
| 354 | | |
| 355 | | osg::Node* createReferenceSphere() |
| 356 | | { |
| 357 | | const float radius = 10; |
| 358 | | osg::Drawable* sphere = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius)); |
| 359 | | |
| 360 | | osg::StateSet* stateset = new osg::StateSet; |
| 361 | | sphere->setStateSet(stateset); |
| 362 | | |
| 363 | | osg::TextureCubeMap* cubemap = new osg::TextureCubeMap; |
| 364 | | #define CUBEMAP_FILENAME(face) "Cubemap_axis/" #face ".png" |
| 365 | | |
| 366 | | osg::Image* imagePosX = osgDB::readImageFile(CUBEMAP_FILENAME(posx)); |
| 367 | | osg::Image* imageNegX = osgDB::readImageFile(CUBEMAP_FILENAME(negx)); |
| 368 | | osg::Image* imagePosY = osgDB::readImageFile(CUBEMAP_FILENAME(posy)); |
| 369 | | osg::Image* imageNegY = osgDB::readImageFile(CUBEMAP_FILENAME(negy)); |
| 370 | | osg::Image* imagePosZ = osgDB::readImageFile(CUBEMAP_FILENAME(posz)); |
| 371 | | osg::Image* imageNegZ = osgDB::readImageFile(CUBEMAP_FILENAME(negz)); |
| 372 | | |
| 373 | | if (imagePosX && imageNegX && imagePosY && imageNegY && imagePosZ && imageNegZ) |
| 374 | | { |
| 375 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX); |
| 376 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX); |
| 377 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY); |
| 378 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY); |
| 379 | | cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ); |
| 380 | | cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ); |
| 381 | | |
| 382 | | cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); |
| 383 | | cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); |
| 384 | | cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE); |
| 385 | | cubemap->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); |
| 386 | | cubemap->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); |
| 387 | | stateset->setTextureAttributeAndModes(0, cubemap, osg::StateAttribute::ON); |
| 388 | | } |
| 389 | | |
| 390 | | osg::TexGen *texgen = new osg::TexGen; |
| 391 | | texgen->setMode(osg::TexGen::REFLECTION_MAP); |
| 392 | | stateset->setTextureAttributeAndModes(0, texgen, osg::StateAttribute::ON); |
| 393 | | |
| 394 | | osg::TexMat* texmat = new osg::TexMat; |
| 395 | | stateset->setTextureAttribute(0, texmat); |
| 396 | | |
| 397 | | stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); |
| 398 | | |
| 399 | | |
| 400 | | sphere->setCullCallback(new DrawableCullCallback(texmat)); |
| 401 | | |
| 402 | | osg::Geode* geode = new osg::Geode(); |
| 403 | | geode->addDrawable(sphere); |
| 404 | | |
| 405 | | return geode; |
| 406 | | } |
| 407 | | |
| 408 | | int main( int argc, char **argv ) |
| | 270 | int main(int argc, char** argv) |
| 440 | | arguments.writeErrorMessages(std::cout); |
| 441 | | return 1; |
| 442 | | } |
| 443 | | /* |
| 444 | | if (arguments.argc()<=1) |
| 445 | | { |
| 446 | | arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); |
| 447 | | return 1; |
| 448 | | } |
| 449 | | */ |
| 450 | | |
| 451 | | osg::Group* rootNode = new osg::Group(); |
| 452 | | |
| 453 | | #if 1 |
| 454 | | osg::Node* sky = osgDB::readNodeFile("skydome.osg"); |
| 455 | | |
| 456 | | // Proof of concept to see if the skydome really rotates and that the cubemap gets updated. |
| 457 | | // create a transform to spin the model. |
| 458 | | |
| 459 | | osg::MatrixTransform* loadedModelTransform = new osg::MatrixTransform; |
| 460 | | loadedModelTransform->addChild(sky); |
| 461 | | |
| 462 | | osg::NodeCallback* nc = new osgUtil::TransformCallback(loadedModelTransform->getBound().center(),osg::Vec3(0.0f,0.0f,1.0f),osg::inDegrees(5.0f)); |
| 463 | | loadedModelTransform->setUpdateCallback(nc); |
| 464 | | |
| 465 | | // osg::Group* rootNode = new osg::Group(); |
| 466 | | // rootNode->addChild(loadedModelTransform); |
| 467 | | // rootNode->addChild(createPreRenderSubGraph(loadedModelTransform)); |
| 468 | | |
| 469 | | |
| 470 | | if (loadedModelTransform) |
| 471 | | { |
| 472 | | rootNode->addChild(createPreRenderSubGraph(loadedModelTransform)); |
| 473 | | } |
| 474 | | #endif |
| 475 | | |
| 476 | | #if 1 |
| 477 | | osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform; |
| 478 | | pat->setPosition(osg::Vec3(0,0,50)); |
| 479 | | pat->addChild(createReferenceSphere()); |
| 480 | | rootNode->addChild(pat); |
| 481 | | #endif |
| 482 | | |
| 483 | | // load the nodes from the commandline arguments. |
| 484 | | osg::Node* loadedModel = osgDB::readNodeFiles(arguments); |
| 485 | | if (loadedModel) |
| 486 | | rootNode->addChild(loadedModel); |
| 487 | | |
| 488 | | // add model to the viewer. |
| 489 | | viewer.setSceneData( rootNode ); |
| | 302 | arguments.writeErrorMessages(std::cout); |
| | 303 | return 1; |
| | 304 | } |
| | 305 | |
| | 306 | ref_ptr<MatrixTransform> scene = new MatrixTransform; |
| | 307 | scene->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(125.0),1.0,0.0,0.0)); |
| | 308 | |
| | 309 | ref_ptr<Group> reflectedSubgraph = _create_scene(); |
| | 310 | if (!reflectedSubgraph.valid()) return 1; |
| | 311 | |
| | 312 | ref_ptr<Group> reflectedScene = createShadowedScene(reflectedSubgraph.get(),createReflector(),0, viewer.getClearColor()); |
| | 313 | |
| | 314 | scene->addChild(reflectedScene.get()); |
| | 315 | |
| | 316 | viewer.setSceneData(scene.get()); |