/* -*-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. */ #include #include #include #include #include #include #include #include #include using namespace osgSim; using namespace osg; namespace osgSim { class CustomPolytope { public: CustomPolytope() {} typedef std::vector Vertices; struct Face { std::string name; osg::Plane plane; Vertices vertices; }; Face& createFace() { _faces.push_back(Face()); return _faces.back(); } /** Create a Polytope which is a cube, centered at 0,0,0, with sides of 2 units.*/ void setToUnitFrustum(bool withNear=true, bool withFar=true) { const osg::Vec3d v000(-1.0,-1.0,-1.0); const osg::Vec3d v010(-1.0,1.0,-1.0); const osg::Vec3d v001(-1.0,-1.0,1.0); const osg::Vec3d v011(-1.0,1.0,1.0); const osg::Vec3d v100(1.0,-1.0,-1.0); const osg::Vec3d v110(1.0,1.0,-1.0); const osg::Vec3d v101(1.0,-1.0,1.0); const osg::Vec3d v111(1.0,1.0,1.0); _faces.clear(); { // left plane. Face& face = createFace(); face.name = "left"; face.plane.set(1.0,0.0,0.0,1.0); face.vertices.push_back(v000); face.vertices.push_back(v001); face.vertices.push_back(v011); face.vertices.push_back(v010); } { // right plane. Face& face = createFace(); face.name = "right"; face.plane.set(-1.0,0.0,0.0,1.0); face.vertices.push_back(v100); face.vertices.push_back(v110); face.vertices.push_back(v111); face.vertices.push_back(v101); } { // bottom plane. Face& face = createFace(); face.name = "bottom"; face.plane.set(0.0,1.0,0.0,1.0); face.vertices.push_back(v000); face.vertices.push_back(v100); face.vertices.push_back(v101); face.vertices.push_back(v001); } { // top plane. Face& face = createFace(); face.name = "top"; face.plane.set(0.0,-1.0,0.0,1.0); face.vertices.push_back(v111); face.vertices.push_back(v011); face.vertices.push_back(v010); face.vertices.push_back(v110); } if (withNear) { // near plane Face& face = createFace(); face.name = "near"; face.plane.set(0.0,0.0,1.0,1.0); face.vertices.push_back(v000); face.vertices.push_back(v010); face.vertices.push_back(v110); face.vertices.push_back(v100); } if (withFar) { // far plane Face& face = createFace(); face.name = "far"; face.plane.set(0.0,0.0,-1.0,1.0); face.vertices.push_back(v001); face.vertices.push_back(v101); face.vertices.push_back(v111); face.vertices.push_back(v011); } } void setToBoundingBox(const osg::BoundingBox& bb) { #if 0 osg::notify(osg::NOTICE)<<"setToBoundingBox xrange "< Edge; typedef std::map Edges; Edges edges; double numVerticesAdded=0.0; osg::Vec3d center; for(itr = removedFaces.begin(); itr != removedFaces.end(); ++itr) { Face& face = *itr; Vertices& vertices = face.vertices; for(unsigned int i=0; i VertexSet; VertexSet uniqueVertices; for(Edges::iterator eitr = edges.begin(); eitr != edges.end(); ++eitr) { if (eitr->second==1) { // osg::notify(osg::NOTICE)<<" edge Ok"<first; Face face; face.name = "baseSide"; face.plane.set(vertex, edge.first, edge.second); face.vertices.push_back(vertex); face.vertices.push_back(edge.first); face.vertices.push_back(edge.second); if (face.plane.distance(center)<0.0) face.plane.flip(); _faces.push_back(face); uniqueVertices.insert(edge.first); uniqueVertices.insert(edge.second); } } // now trim the new polytope back the desired height if (em) { // compute the base vertices at the new height Vertices baseVertices; for(VertexSet::iterator itr = uniqueVertices.begin(); itr != uniqueVertices.end(); ++itr) { const osg::Vec3d& point = *itr; double latitude, longitude, height; em->convertXYZToLatLongHeight(point.x(), point.y(), point.z(), latitude, longitude, height); osg::Vec3d normal(point); normal.normalize(); baseVertices.push_back(point - normal * (height - minHeight)); } //compute centroid of the base vertices osg::Vec3d center; double totalArea = 0; for(unsigned int i=0; i=0.0) { removedFaces.push_back(face); itr = _faces.erase(itr); } else { ++itr; } } if (removedFaces.empty()) return; typedef std::pair Edge; typedef std::map Edges; Edges edges; double numVerticesAdded=0.0; osg::Vec3d center; for(itr = removedFaces.begin(); itr != removedFaces.end(); ++itr) { Face& face = *itr; Vertices& vertices = face.vertices; for(unsigned int i=0; i VertexSet; VertexSet uniqueVertices; for(Edges::iterator eitr = edges.begin(); eitr != edges.end(); ++eitr) { if (eitr->second==1) { // osg::notify(osg::NOTICE)<<" edge Ok"<first; double h_first = (edge.first-control) * normal; osg::Vec3d projected_first = edge.first - normal * h_first; double h_second = (edge.second-control) * normal; osg::Vec3d projected_second = edge.second - normal * h_second; Face face; face.name = "baseSide"; face.plane.set(projected_first, edge.first, edge.second); face.vertices.push_back(projected_first); face.vertices.push_back(projected_second); face.vertices.push_back(edge.second); face.vertices.push_back(edge.first); if (face.plane.distance(center)<0.0) face.plane.flip(); _faces.push_back(face); uniqueVertices.insert(projected_first); uniqueVertices.insert(projected_second); } } Face newFace; newFace.name = "basePlane"; newFace.plane.set(normal,control); osg::Vec3d side = ( fabs(normal.x()) < fabs(normal.y()) ) ? osg::Vec3(1.0, 0.0, 0.0) : osg::Vec3(0.0, 1.0, 0.0); osg::Vec3 v = normal ^ side; v.normalize(); osg::Vec3 u = v ^ normal; u.normalize(); typedef std::map AnglePositions; AnglePositions anglePositions; for(VertexSet::iterator vitr = uniqueVertices.begin(); vitr != uniqueVertices.end(); ++vitr) { osg::Vec3d delta = *vitr - center; double angle = atan2(delta * u, delta * v); if (angle<0.0) angle += 2.0*osg::PI; anglePositions[angle] = *vitr; } for(AnglePositions::iterator aitr = anglePositions.begin(); aitr != anglePositions.end(); ++aitr) { newFace.vertices.push_back(aitr->second); } _faces.push_back(newFace); } void computeSilhoette(const osg::Vec3d& normal, Vertices& vertices) { typedef std::pair EdgePair; typedef std::vector EdgeFaces; typedef std::map EdgeMap; EdgeMap edgeMap; for(Faces::iterator itr = _faces.begin(); itr != _faces.end(); ++itr) { Face& face = *itr; for(unsigned int i=0; i VertexSet; VertexSet uniqueVertices; for(EdgeMap::iterator eitr = edgeMap.begin(); eitr != edgeMap.end(); ++eitr) { const EdgePair& edge = eitr->first; const EdgeFaces& edgeFaces = eitr->second; if (edgeFaces.size()==1) { // osg::notify(osg::NOTICE)<<"Open edge found "<name<plane.getNormal() * normal; double dotProduct1 = edgeFaces[1]->plane.getNormal() * normal; if (dotProduct0 * dotProduct1 <0.0) { // osg::notify(osg::NOTICE)<<" Silhoette edge found "<name<<" "<name<name<<" "<name< AnglePositions; AnglePositions anglePositions; for(vitr = uniqueVertices.begin(); vitr != uniqueVertices.end(); ++vitr) { osg::Vec3d delta = *vitr - center; double angle = atan2(delta * u, delta * v); if (angle<0.0) angle += 2.0*osg::PI; anglePositions[angle] = *vitr; } for(AnglePositions::iterator aitr = anglePositions.begin(); aitr != anglePositions.end(); ++aitr) { vertices.push_back(aitr->second); } } void cut(const osg::Polytope& polytope) { // osg::notify(osg::NOTICE)<<"Cutting with polytope "<plane, itr->name); } } void cut(const osg::Plane& plane, const std::string& name=std::string()) { // osg::notify(osg::NOTICE)<<" Cutting plane "< Distances; Distances distances; distances.reserve(face.vertices.size()); for(Vertices::iterator vitr = vertices.begin(); vitr != vertices.end(); ++vitr) { distances.push_back(plane.distance(*vitr)); } for(unsigned int i=0; i=0.0) newVertices.push_back(vertices[i]); // add point to new face if point exactly on a plane if (distance_a==0.0) newFace.vertices.push_back(vertices[i]); // does edge intersect plane if (distance_a * distance_b<0.0) { // inserting vertex osg::Vec3d intersection = (vb*distance_a - va*distance_b)/(distance_a-distance_b); newVertices.push_back(intersection); newFace.vertices.push_back(intersection); // osg::notify(osg::NOTICE)<<" intersection distance "< AnglePositions; AnglePositions anglePositions; for(vitr = vertices.begin(); vitr != vertices.end(); ++vitr) { osg::Vec3d delta = *vitr - center; double angle = atan2(delta * u, delta * v); if (angle<0.0) angle += 2.0*osg::PI; anglePositions[angle] = *vitr; } Vertices newVertices; for(AnglePositions::iterator aitr = anglePositions.begin(); aitr != anglePositions.end(); ++aitr) { newVertices.push_back(aitr->second); } newVertices.swap(vertices); // osg::notify(osg::NOTICE)<<" after angle sort "<plane); } } void getPoints(Vertices& vertices) { typedef std::set VerticesSet; VerticesSet verticesSet; for(Faces::iterator itr = _faces.begin(); itr != _faces.end(); ++itr) { Face& face = *itr; for(Vertices::iterator vitr = face.vertices.begin(); vitr != face.vertices.end(); ++vitr) { verticesSet.insert(*vitr); } } for(VerticesSet::iterator sitr = verticesSet.begin(); sitr != verticesSet.end(); ++sitr) { vertices.push_back(*sitr); } } osg::Drawable* createDrawable(const osg::Vec4d& colour) { osg::Geometry* geometry = new osg::Geometry; osg::Vec3Array* vertices = new osg::Vec3Array; geometry->setVertexArray(vertices); for(Faces::iterator itr = _faces.begin(); itr != _faces.end(); ++itr) { Face& face = *itr; geometry->addPrimitiveSet( new osg::DrawArrays(GL_LINE_LOOP, vertices->size(), face.vertices.size()) ); for(Vertices::iterator vitr = face.vertices.begin(); vitr != face.vertices.end(); ++vitr) { vertices->push_back(*vitr); } } osg::Vec4Array* colours = new osg::Vec4Array; colours->push_back(colour); geometry->setColorArray(colours); geometry->setColorBinding(osg::Geometry::BIND_OVERALL); osg::StateSet* stateset = geometry->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF); stateset->setTextureMode(1, GL_TEXTURE_2D, osg::StateAttribute::OFF); return geometry; } protected: typedef std::list Faces; Faces _faces; }; } OverlayNode::OverlayNode(OverlayTechnique technique): _overlayTechnique(technique), _texEnvMode(GL_DECAL), _textureUnit(1), _textureSizeHint(1024), _overlayClearColor(0.0f,0.0f,0.0f,0.0f), _continuousUpdate(false), _overlayBaseHeight(-100.0), _updateCamera(false), _renderTargetImpl(osg::Camera::FRAME_BUFFER_OBJECT) { setNumChildrenRequiringUpdateTraversal(1); init(); } OverlayNode::OverlayNode(const OverlayNode& copy, const osg::CopyOp& copyop): osg::Group(copy,copyop), _overlayTechnique(copy._overlayTechnique), _overlaySubgraph(copy._overlaySubgraph), _texEnvMode(copy._texEnvMode), _textureUnit(copy._textureUnit), _textureSizeHint(copy._textureSizeHint), _overlayClearColor(copy._overlayClearColor), _continuousUpdate(copy._continuousUpdate), _overlayBaseHeight(copy._overlayBaseHeight), _renderTargetImpl(copy._renderTargetImpl) { setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1); init(); } void OverlayNode::OverlayData::setThreadSafeRefUnref(bool threadSafe) { if (_camera.valid()) _camera->setThreadSafeRefUnref(threadSafe); if (_texgenNode.valid()) _texgenNode->setThreadSafeRefUnref(threadSafe); if (_overlayStateSet.valid()) _overlayStateSet->setThreadSafeRefUnref(threadSafe); if (_mainSubgraphStateSet.valid()) _mainSubgraphStateSet->setThreadSafeRefUnref(threadSafe); if (_texture.valid()) _texture->setThreadSafeRefUnref(threadSafe); } void OverlayNode::OverlayData::resizeGLObjectBuffers(unsigned int maxSize) { if (_camera.valid()) _camera->resizeGLObjectBuffers(maxSize); if (_texgenNode.valid()) _texgenNode->resizeGLObjectBuffers(maxSize); if (_overlayStateSet.valid()) _overlayStateSet->resizeGLObjectBuffers(maxSize); if (_mainSubgraphStateSet.valid()) _mainSubgraphStateSet->resizeGLObjectBuffers(maxSize); if (_texture.valid()) _texture->resizeGLObjectBuffers(maxSize); } void OverlayNode::OverlayData::releaseGLObjects(osg::State* state) const { if (_camera.valid()) _camera->releaseGLObjects(state); if (_texgenNode.valid()) _texgenNode->releaseGLObjects(state); if (_overlayStateSet.valid()) _overlayStateSet->releaseGLObjects(state); if (_mainSubgraphStateSet.valid()) _mainSubgraphStateSet->releaseGLObjects(state); if (_texture.valid()) _texture->releaseGLObjects(state); } void OverlayNode::setThreadSafeRefUnref(bool threadSafe) { osg::Group::setThreadSafeRefUnref(threadSafe); if (_overlaySubgraph.valid()) _overlaySubgraph->setThreadSafeRefUnref(threadSafe); for(OverlayDataMap::iterator itr = _overlayDataMap.begin(); itr != _overlayDataMap.end(); ++itr) { itr->second->setThreadSafeRefUnref(threadSafe); } } void OverlayNode::resizeGLObjectBuffers(unsigned int maxSize) { osg::Group::resizeGLObjectBuffers(maxSize); if (_overlaySubgraph.valid()) _overlaySubgraph->resizeGLObjectBuffers(maxSize); for(OverlayDataMap::iterator itr = _overlayDataMap.begin(); itr != _overlayDataMap.end(); ++itr) { itr->second->resizeGLObjectBuffers(maxSize); } } void OverlayNode::releaseGLObjects(osg::State* state) const { osg::Group::releaseGLObjects(state); if (_overlaySubgraph.valid()) _overlaySubgraph->releaseGLObjects(state); for(OverlayDataMap::const_iterator itr = _overlayDataMap.begin(); itr != _overlayDataMap.end(); ++itr) { itr->second->releaseGLObjects(state); } } void OverlayNode::setOverlayTechnique(OverlayTechnique technique) { if (_overlayTechnique==technique) return; _overlayTechnique = technique; init(); } void OverlayNode::setRenderTargetImplementation(osg::Camera::RenderTargetImplementation impl) { if(_renderTargetImpl==impl) return; _renderTargetImpl = impl; init(); for(OverlayDataMap::const_iterator itr = _overlayDataMap.begin(); itr != _overlayDataMap.end(); ++itr) { itr->second->_camera->setRenderTargetImplementation(_renderTargetImpl); } } OverlayNode::OverlayData* OverlayNode::getOverlayData(osgUtil::CullVisitor* cv) { OpenThreads::ScopedLock lock(_overlayDataMapMutex); OverlayDataMap::iterator itr = _overlayDataMap.find(cv); if (itr != _overlayDataMap.end()) return itr->second.get(); _overlayDataMap[cv] = new OverlayData; OverlayData* overlayData = _overlayDataMap[cv].get(); unsigned int tex_width = _textureSizeHint; unsigned int tex_height = _textureSizeHint; if (!overlayData->_texture) { // osg::notify(osg::NOTICE)<<" setting up texture"<setTextureSize(tex_width, tex_height); texture->setInternalFormat(GL_RGBA); texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR); texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER); texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER); #if 1 texture->setBorderColor(osg::Vec4(_overlayClearColor)); #else texture->setBorderColor(osg::Vec4(1.0,0.0,0.0,0.5)); #endif overlayData->_texture = texture; } // set up the render to texture camera. if (!overlayData->_camera || overlayData->_camera->getRenderTargetImplementation() != _renderTargetImpl) { // osg::notify(osg::NOTICE)<<" setting up camera"<_camera = new osg::Camera; overlayData->_camera->setClearColor(_overlayClearColor); overlayData->_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); // set viewport overlayData->_camera->setViewport(0,0,tex_width,tex_height); overlayData->_camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); // set the camera to render before the main camera. overlayData->_camera->setRenderOrder(osg::Camera::PRE_RENDER); // tell the camera to use OpenGL frame buffer object where supported. overlayData->_camera->setRenderTargetImplementation(_renderTargetImpl); // attach the texture and use it as the color buffer. overlayData->_camera->attach(osg::Camera::COLOR_BUFFER, overlayData->_texture.get()); if (_overlaySubgraph.valid()) overlayData->_camera->addChild(_overlaySubgraph.get()); } if (!overlayData->_texgenNode) { overlayData->_texgenNode = new osg::TexGenNode; overlayData->_texgenNode->setTextureUnit(_textureUnit); } if (!overlayData->_y0) overlayData->_y0 = new osg::Uniform("y0",0.0f); if (!overlayData->_lightingEnabled) overlayData->_lightingEnabled = new osg::Uniform("lightingEnabled",true); if (!overlayData->_overlayStateSet) { overlayData->_overlayStateSet = new osg::StateSet; overlayData->_overlayStateSet->addUniform(overlayData->_y0.get()); overlayData->_overlayStateSet->addUniform(overlayData->_lightingEnabled.get()); osg::Program* program = new osg::Program; overlayData->_overlayStateSet->setAttribute(program); // get shaders from source std::string vertexShaderFile = osgDB::findDataFile("shaders/overlay_perspective_rtt.vert"); if (!vertexShaderFile.empty()) { program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, vertexShaderFile)); } else { char vertexShaderSource[] = "uniform float y0; \n" "uniform bool lightingEnabled; \n" " \n" "vec4 warp(in vec4 source) \n" "{ \n" " float divisor = source.y + y0; \n" " return vec4(source.x * (1.0 + y0 ), source.y * y0 + 1.0, (source.z * y0 + 1.0)*0.01, source.w * divisor); \n" "} \n" " \n" "vec3 fnormal(void) \n" "{ \n" " //Compute the normal \n" " vec3 normal = gl_NormalMatrix * gl_Normal; \n" " normal = normalize(normal); \n" " return normal; \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, normalize(vec3 (gl_LightSource[i].position)))); \n" " nDotHV = max(0.0, dot(normal, vec3 (gl_LightSource[i].halfVector))); \n" " \n" " if (nDotVP == 0.0) \n" " { \n" " pf = 0.0; \n" " } \n" " else \n" " { \n" " pf = pow(nDotHV, gl_FrontMaterial.shininess); \n" " \n" " } \n" " ambient += gl_LightSource[i].ambient; \n" " diffuse += gl_LightSource[i].diffuse * nDotVP; \n" " specular += gl_LightSource[i].specular * pf; \n" "} \n" "void main() \n" "{ \n" " gl_Position = warp(ftransform()); \n" " \n" " if (lightingEnabled) \n" " { \n" " vec4 ambient = vec4(0.0); \n" " vec4 diffuse = vec4(0.0); \n" " vec4 specular = vec4(0.0); \n" " \n" " vec3 normal = fnormal(); \n" " \n" " directionalLight(0, normal, ambient, diffuse, specular); \n" " \n" " vec4 color = gl_FrontLightModelProduct.sceneColor + \n" " ambient * gl_FrontMaterial.ambient + \n" " diffuse * gl_FrontMaterial.diffuse + \n" " specular * gl_FrontMaterial.specular; \n" " \n" " gl_FrontColor = color; \n" " \n" " } \n" " else \n" " { \n" " gl_FrontColor = gl_Color; \n" " } \n" " \n" "} \n"; osg::Shader* vertex_shader = new osg::Shader(osg::Shader::VERTEX, vertexShaderSource); program->addShader(vertex_shader); } } if (!overlayData->_mainSubgraphProgram) { overlayData->_mainSubgraphProgram = new osg::Program; // get shaders from source std::string fragmentShaderFile = osgDB::findDataFile("shaders/overlay_perspective_main.frag"); if (!fragmentShaderFile.empty()) { overlayData->_mainSubgraphProgram->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, fragmentShaderFile)); } else { char fragmentShaderSource[] = "uniform sampler2D texture_0; \n" "uniform sampler2D texture_1; \n" " \n" "uniform float y0; \n" " \n" "vec2 warp(in vec2 source) \n" "{ \n" " float inv_divisor = 1.0 / (source.y + y0); \n" " return vec2(source.x * (1.0 + y0 ) * inv_divisor , (source.y * y0 + 1.0 ) * inv_divisor); \n" "} \n" " \n" "void main() \n" "{ \n" " vec2 coord = gl_TexCoord[1].xy; \n" " coord.x = coord.x*2.0 - 1.0; \n" " coord.y = coord.y*2.0 - 1.0; \n" " \n" " vec2 warped = warp(coord); \n" " warped.x = (warped.x + 1.0)*0.5; \n" " warped.y = (warped.y + 1.0)*0.5; \n" " \n" " vec4 base_color = texture2D(texture_0, gl_TexCoord[0].xy); \n" " vec4 overlay_color = texture2D(texture_1, warped ); \n" " vec3 mixed_color = mix(base_color.rgb, overlay_color.rgb, overlay_color.a); \n" " gl_FragColor = vec4(mixed_color, base_color.a); \n" "} \n"; osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource); overlayData->_mainSubgraphProgram->addShader(fragment_shader); } } if (!overlayData->_mainSubgraphStateSet) { overlayData->_mainSubgraphStateSet = new osg::StateSet; overlayData->_mainSubgraphStateSet->addUniform(overlayData->_y0.get()); overlayData->_mainSubgraphStateSet->addUniform(new osg::Uniform("texture_0",0)); overlayData->_mainSubgraphStateSet->addUniform(new osg::Uniform("texture_1",1)); overlayData->_mainSubgraphStateSet->setTextureAttributeAndModes(_textureUnit, overlayData->_texture.get(), osg::StateAttribute::ON); overlayData->_mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON); overlayData->_mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON); overlayData->_mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON); overlayData->_mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON); if (_texEnvMode!=GL_NONE) { overlayData->_mainSubgraphStateSet->setTextureAttribute(_textureUnit, new osg::TexEnv((osg::TexEnv::Mode)_texEnvMode)); } } return overlayData; } void OverlayNode::init() { switch(_overlayTechnique) { case(OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY): init_OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY(); break; case(VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY): init_VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY(); break; case(VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY): init_VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY(); break; } } void OverlayNode::init_OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY() { osg::notify(osg::INFO)<<"OverlayNode::init() - OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY"<getNumChildren(); ++i) { bs.expandBy(camera->getChild(i)->getBound()); } if (bs.valid()) { // see if we are within a coordinate system node. osg::CoordinateSystemNode* csn = 0; osg::NodePath& nodePath = nv.getNodePath(); for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); itr != nodePath.rend() && csn==0; ++itr) { csn = dynamic_cast(*itr); } osg::EllipsoidModel* em = csn ? csn->getEllipsoidModel() : 0; if (em) { osg::Vec3d eyePoint(0.0,0.0,0.0); // center of the planet double centerDistance = (eyePoint-osg::Vec3d(bs.center())).length(); double znear = centerDistance-bs.radius(); double zfar = centerDistance+bs.radius(); double zNearRatio = 0.001f; if (znearsetProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); camera->setViewMatrixAsLookAt(eyePoint, bs.center(), osg::Vec3(0.0f,1.0f,0.0f)); } else { osg::Vec3d upDirection(0.0,1.0,0.0); osg::Vec3d viewDirection(0.0,0.0,1.0); double viewDistance = 2.0*bs.radius(); osg::Vec3d center = bs.center(); osg::Vec3d eyePoint = center+viewDirection*viewDistance; double znear = viewDistance-bs.radius(); double zfar = viewDistance+bs.radius(); float top = bs.radius(); float right = top; camera->setProjectionMatrixAsOrtho(-right,right,-top,top,znear,zfar); camera->setViewMatrixAsLookAt(eyePoint,center,upDirection); } // compute the matrix which takes a vertex from local coords into tex coords // will use this later to specify osg::TexGen.. osg::Matrix MVP = camera->getViewMatrix() * camera->getProjectionMatrix(); osg::Matrix MVPT = MVP * osg::Matrix::translate(1.0,1.0,1.0) * osg::Matrix::scale(0.5,0.5,0.5); overlayData._texgenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR); overlayData._texgenNode->getTexGen()->setPlanesFromMatrix(MVPT); overlayData._textureFrustum.setToUnitFrustum(false,false); overlayData._textureFrustum.transformProvidingInverse(MVP); } _updateCamera = false; } return; } if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) { Group::traverse(nv); return; } osgUtil::CullVisitor* cv = dynamic_cast(&nv); if (!cv) { Group::traverse(nv); return; } unsigned int contextID = cv->getState()!=0 ? cv->getState()->getContextID() : 0; // if we need to redraw then do cull traversal on camera. if (!_textureObjectValidList[contextID] || _continuousUpdate) { camera->setClearColor(_overlayClearColor); camera->accept(*cv); _textureObjectValidList[contextID] = 1; } // now set up the drawing of the main scene. { overlayData._texgenNode->accept(*cv); const osg::Matrix modelView = *(cv->getModelViewMatrix()); osg::Polytope viewTextureFrustum; viewTextureFrustum.setAndTransformProvidingInverse(overlayData._textureFrustum, osg::Matrix::inverse(modelView)); cv->getProjectionCullingStack().back().addStateFrustum(overlayData._mainSubgraphStateSet.get(), viewTextureFrustum); cv->getCurrentCullingSet().addStateFrustum(overlayData._mainSubgraphStateSet.get(), overlayData._textureFrustum); // push the stateset. // cv->pushStateSet(_mainSubgraphStateSet.get()); Group::traverse(nv); // cv->popStateSet(); cv->getCurrentCullingSet().getStateFrustumList().pop_back(); cv->getProjectionCullingStack().back().getStateFrustumList().pop_back(); } } void OverlayNode::traverse_VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY(osg::NodeVisitor& nv) { // osg::notify(osg::NOTICE)<<"OverlayNode::traverse() - VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY"<(&nv); if (!cv) { Group::traverse(nv); return; } OverlayData& overlayData = *getOverlayData(cv); osg::Camera* camera = overlayData._camera.get(); if (_overlaySubgraph.valid()) { #if 0 if (!overlayData._geode) { overlayData._geode = new osg::Geode; } #endif // see if we are within a coordinate system node. osg::CoordinateSystemNode* csn = 0; osg::NodePath& nodePath = nv.getNodePath(); for(osg::NodePath::reverse_iterator itr = nodePath.rbegin(); itr != nodePath.rend() && csn==0; ++itr) { csn = dynamic_cast(*itr); } osg::EllipsoidModel* em = csn ? csn->getEllipsoidModel() : 0; osg::BoundingSphere bs = _overlaySubgraph->getBound(); // push the stateset. cv->pushStateSet(overlayData._mainSubgraphStateSet.get()); Group::traverse(nv); cv->popStateSet(); osg::Matrix pm = *(cv->getProjectionMatrix()); double znear = cv->getCalculatedNearPlane(); double zfar = cv->getCalculatedFarPlane(); // osg::notify(osg::NOTICE)<<" before znear ="<second->_camera.get(); if (camera) { camera->removeChildren(0, camera->getNumChildren()); camera->addChild(node); } } dirtyOverlayTexture(); } void OverlayNode::dirtyOverlayTexture() { _textureObjectValidList.setAllElementsTo(0); _updateCamera = true; } void OverlayNode::setTexEnvMode(GLenum mode) { _texEnvMode = mode; updateMainSubgraphStateSet(); } void OverlayNode::setOverlayTextureUnit(unsigned int unit) { _textureUnit = unit; updateMainSubgraphStateSet(); } void OverlayNode::setOverlayTextureSizeHint(unsigned int size) { if (_textureSizeHint == size) return; _textureSizeHint = size; for(OverlayDataMap::iterator itr = _overlayDataMap.begin(); itr != _overlayDataMap.end(); ++itr) { if (itr->second->_texture.valid()) itr->second->_texture->setTextureSize(_textureSizeHint, _textureSizeHint); if (itr->second->_camera.valid()) itr->second->_camera->setViewport(0,0,_textureSizeHint,_textureSizeHint); } //_texture->dirtyTextureObject(); } void OverlayNode::updateMainSubgraphStateSet() { osg::notify(osg::INFO)<<"OverlayNode::updateMainSubgraphStateSet()"<second->_texgenNode.get(); if (texgenNode) texgenNode->setTextureUnit(_textureUnit); osg::StateSet* mainSubgraphStateSet = itr->second->_mainSubgraphStateSet.get(); if (mainSubgraphStateSet) { mainSubgraphStateSet->clear(); mainSubgraphStateSet->setTextureAttributeAndModes(_textureUnit, itr->second->_texture.get(), osg::StateAttribute::ON); mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON); mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON); mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON); mainSubgraphStateSet->setTextureMode(_textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON); if (_texEnvMode!=GL_NONE) { mainSubgraphStateSet->setTextureAttribute(_textureUnit, new osg::TexEnv((osg::TexEnv::Mode)_texEnvMode)); } } } }