diff --git a/examples/osgterrain/CMakeLists.txt b/examples/osgterrain/CMakeLists.txt index 550c633a4..3e1422f13 100644 --- a/examples/osgterrain/CMakeLists.txt +++ b/examples/osgterrain/CMakeLists.txt @@ -1,4 +1,11 @@ -SET(TARGET_SRC osgterrain.cpp) +SET(TARGET_H + ShaderTerrain.h +) + +SET(TARGET_SRC + ShaderTerrain.cpp + osgterrain.cpp +) SET(TARGET_ADDED_LIBRARIES osgTerrain ) diff --git a/examples/osgterrain/ShaderTerrain.cpp b/examples/osgterrain/ShaderTerrain.cpp new file mode 100644 index 000000000..b8d24adc7 --- /dev/null +++ b/examples/osgterrain/ShaderTerrain.cpp @@ -0,0 +1,676 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ShaderTerrain.h" + +using namespace osgTerrain; + + +const osgTerrain::Locator* osgTerrain::computeMasterLocator(const osgTerrain::TerrainTile* tile) +{ + const osgTerrain::Layer* elevationLayer = tile->getElevationLayer(); + const osgTerrain::Layer* colorLayer = tile->getColorLayer(0); + + const Locator* elevationLocator = elevationLayer ? elevationLayer->getLocator() : 0; + const Locator* colorLocator = colorLayer ? colorLayer->getLocator() : 0; + + const Locator* masterLocator = elevationLocator ? elevationLocator : colorLocator; + if (!masterLocator) + { + OSG_NOTICE<<"Problem, no locator found in any of the terrain layers"<getTransform(); + osg::Vec3d bottom_left = osg::Vec3d(0.0,0.0,0.0) * matrix; + osg::Vec3d bottom_right = osg::Vec3d(1.0,0.0,0.0) * matrix; + osg::Vec3d top_left = osg::Vec3d(1.0,1.0,0.0) * matrix; + key.sx = static_cast((bottom_right-bottom_left).length()); + key.sy = static_cast((top_left-bottom_left).length()); + + if (masterLocator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) + { + // need to differentiate between tiles based of latitude, so use y position of bottom left corner. + key.y = static_cast(bottom_left.y()); + } + else + { + // when the projection is linear there is no need to differentiate tiles according to their latitude + key.y = 0.0; + } + + } + + osgTerrain::HeightFieldLayer* layer = dynamic_cast(tile->getElevationLayer()); + if (layer) + { + osg::HeightField* hf = layer->getHeightField(); + if (hf) + { + key.nx = hf->getNumColumns(); + key.ny = hf->getNumRows(); + } + } + return true; +} + +static int numberGeometryCreated = 0; +static int numberSharedGeometry = 0; + +osg::Geometry* GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile) +{ + OpenThreads::ScopedLock lock(_geometryMapMutex); + + GeometryKey key; + createKeyForTile(tile, key); + + GeometryMap::iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) + { + + ++numberSharedGeometry; +// OSG_NOTICE<<"Sharing geometry "<second.get()<<", number shared = "<second.get(); + } + + osg::ref_ptr geometry = new osg::Geometry; + _geometryMap[key] = geometry; + + osg::ref_ptr vertices = new osg::Vec3Array; + geometry->setVertexArray(vertices.get()); + + osg::ref_ptr normals = new osg::Vec3Array; + geometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX); + + osg::ref_ptr colours = new osg::Vec4Array; + geometry->setColorArray(colours.get(), osg::Array::BIND_OVERALL); + colours->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + + osg::ref_ptr texcoords = new osg::Vec2Array; + geometry->setTexCoordArray(0, texcoords.get(), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(1, texcoords.get(), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(2, texcoords.get(), osg::Array::BIND_PER_VERTEX); + geometry->setTexCoordArray(3, texcoords.get(), osg::Array::BIND_PER_VERTEX); + + int nx = key.nx; + int ny = key.nx; + int numVertices = nx * ny; + + + vertices->reserve(numVertices); + normals->reserve(numVertices); + texcoords->reserve(numVertices); + + double r_mult = 1.0/static_cast(ny-1); + double c_mult = 1.0/static_cast(nx-1); + + typedef std::vector LocationCoords; + LocationCoords locationCoords; + locationCoords.reserve(numVertices); + + osg::Vec3d pos(0.0, 0.0, 0.0); + osg::Vec3d normal(0.0, 0.0, 1.0); + for(int r=0; r(r)*r_mult; + for(int c=0; c(c)*c_mult; + vertices->push_back(pos); + normals->push_back(normal); + texcoords->push_back(osg::Vec2(pos.x(), pos.y())); + locationCoords.push_back(osg::Vec2d(pos.x(), pos.y())); + } + } + + bool smallTile = numVertices <= 16384; + osg::ref_ptr elements = smallTile ? + static_cast(new osg::DrawElementsUShort(GL_QUADS)) : + static_cast(new osg::DrawElementsUInt(GL_QUADS)); + + elements->reserveElements((nx-1) * (ny-1) * 4); + geometry->addPrimitiveSet(elements.get()); + + for(int r=0; raddElement(i); + elements->addElement(i+1); + elements->addElement(i+nx+1); + elements->addElement(i+nx); + } + } + + osg::Matrixd matrix; + + osg::Vec3d center(0.5, 0.5, 0.0); + + osg::Vec3d bottom_left(0.0,0.0,0.0); + osg::Vec3d bottom_right(1.0,0.0,0.0); + osg::Vec3d top_left(0.0,1.0,0.0); + + const osgTerrain::Locator* locator = computeMasterLocator(tile); + if (locator) + { + matrix = locator->getTransform(); + + center = center * matrix; + bottom_left = bottom_left * matrix; + bottom_right = bottom_right * matrix; + top_left = top_left * matrix; + + // shift to center.x() to x=0 and carry all the corners with it. + bottom_left.x() -= center.x(); + bottom_right.x() -= center.x(); + top_left.x() -= center.x(); + //center.x() = 0.0; + + // OSG_NOTICE<<" in lat/longs : bottom_left = "<convertLatLongHeightToXYZ(center.y(), center.x(), center.z(), center.x(), center.y(),center.z()); + em->convertLatLongHeightToXYZ(bottom_left.y(), bottom_left.x(), bottom_left.z(), bottom_left.x(), bottom_left.y(),bottom_left.z()); + em->convertLatLongHeightToXYZ(bottom_right.y(), bottom_right.x(), bottom_right.z(), bottom_right.x(), bottom_right.y(),bottom_right.z()); + em->convertLatLongHeightToXYZ(top_left.y(), top_left.x(), top_left.z(), top_left.x(), top_left.y(),top_left.z()); + + osg::Matrixd worldToLocalTransform; + worldToLocalTransform.invert(localToWorldTransform); + + center = center * worldToLocalTransform; + bottom_left = bottom_left * worldToLocalTransform; + bottom_right = bottom_right * worldToLocalTransform; + top_left = top_left * worldToLocalTransform; + + + for(int i=0; iconvertLatLongHeightToXYZ(pos.y(), pos.x(), 0.0, pos.x(), pos.y(),pos.z()); + + osg::Vec3d normal(pos); + normal = osg::Matrixd::transform3x3(localToWorldTransform, normal); + normal.normalize(); + + pos = pos * worldToLocalTransform; + pos -= center; + + (*vertices)[i] = pos; + (*normals)[i] = normal; + } + + } + } + + // double tileWidth = (bottom_right-bottom_left).length(); + // double skirtHeight = tileWidth*0.05; + + // OSG_NOTICE<<" in local coords : center = "< geometry = getOrCreateGeometry(tile); + + + osg::ref_ptr hfDrawable = new HeightFieldDrawable(); + + osgTerrain::HeightFieldLayer* hfl = dynamic_cast(tile->getElevationLayer()); + osg::HeightField* hf = hfl ? hfl->getHeightField() : 0; + hfDrawable->setHeightField(hf); + hfDrawable->setGeometry(geometry.get()); + + + // create a transform to place the geometry in the appropriate place + osg::ref_ptr transform = new osg::MatrixTransform; + +// transform->addChild(geometry.get()); + transform->addChild(hfDrawable.get()); + + const osgTerrain::Locator* locator = computeMasterLocator(tile); + if (locator) + { + osg::Matrixd matrix = locator->getTransform(); + + osg::Vec3d center = osg::Vec3d(0.5, 0.5, 0.0) * matrix; + + // shift to center.x() to x=0 and carry all the corners with it. + const osg::EllipsoidModel* em = locator->getEllipsoidModel(); + if (em && locator->getCoordinateSystemType()==osgTerrain::Locator::GEOCENTRIC) + { + osg::Matrixd localToWorldTransform; + // note y axis maps to latitude, x axis to longitude + em->computeLocalToWorldTransformFromLatLongHeight(center.y(), center.x(), center.z(), localToWorldTransform); + // OSG_NOTICE<<"We have a EllipsoidModel to take account of "<setMatrix(localToWorldTransform); + + //osgDB::writeNodeFile(*transform, "subgraph.osgt"); + } + else + { + transform->setMatrix(locator->getTransform()); + } + } + + osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); + osg::Vec3Array* normals = dynamic_cast(geometry->getNormalArray()); + if (hf && vertices && normals && (vertices->size()==normals->size())) + { + unsigned int nr = hf->getNumRows(); + unsigned int nc = hf->getNumColumns(); + + osg::BoundingBox bb; + osg::FloatArray* heights = hf->getFloatArray(); + + for(unsigned int r=0; rsetInitialBound(bb); + // OSG_NOTICE<<"Assigning initial bound ("<getBoundingBox(); + //OSG_NOTICE<<" getBoundingBox ("< stateset = transform->getOrCreateStateSet(); + + // apply colour layers + applyLayers(tile, stateset.get()); + + return transform.release(); +} + +osg::Program* GeometryPool::getOrCreateProgram(LayerTypes& layerTypes) +{ +#if 0 + OSG_NOTICE<<"getOrCreateProgram("; + for(LayerTypes::iterator itr = layerTypes.begin(); + itr != layerTypes.end(); + ++itr) + { + if (itr!= layerTypes.begin()) OSG_NOTICE<<", "; + switch(*itr) + { + case(HEIGHTFIELD_LAYER): OSG_NOTICE<<"HeightField"; break; + case(COLOR_LAYER): OSG_NOTICE<<"Colour"; break; + case(CONTOUR_LAYER): OSG_NOTICE<<"Contour"; break; + } + } +#endif + + ProgramMap::iterator itr = _programMap.find(layerTypes); + if (itr!=_programMap.end()) + { + // OSG_NOTICE<<") returning exisitng Program "<second.get()<second.get(); + } + + osg::ref_ptr program = new osg::Program; + _programMap[layerTypes] = program; + + OSG_NOTICE<<") creating new Program "< vertex_shader = osgDB::readShaderFile("terrain.vert"); + program->addShader(vertex_shader.get()); + + osg::ref_ptr fragment_shader = osgDB::readShaderFile("terrain.frag"); + program->addShader(fragment_shader.get()); + + return program.get(); +} + +void GeometryPool::applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset) +{ + typedef std::map LayerToTextureMap; + LayerToTextureMap layerToTextureMap; + + // OSG_NOTICE<<"tile->getNumColorLayers() = "<getNumColorLayers()<(tile->getElevationLayer()); + if (hfl) + { + osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[hfl]); + if (!texture2D) + { + texture2D = new osg::Texture2D; + + osg::ref_ptr image = new osg::Image; + + const void* dataPtr = hfl->getHeightField()->getFloatArray()->getDataPointer(); + + image->setImage(hfl->getNumRows(), hfl->getNumColumns(), 1, + GL_LUMINANCE32F_ARB, + GL_LUMINANCE, GL_FLOAT, + reinterpret_cast(const_cast(dataPtr)), + osg::Image::NO_DELETE); + + texture2D->setImage(image.get()); + texture2D->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST); + texture2D->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST); + texture2D->setResizeNonPowerOfTwoHint(false); + + layerToTextureMap[hfl] = texture2D; + } + + int textureUnit = layerTypes.size(); + stateset->setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); + stateset->addUniform(new osg::Uniform("terrainTexture",textureUnit)); + + layerTypes.push_back(HEIGHTFIELD_LAYER); + } +#if 1 + for(unsigned int layerNum=0; layerNumgetNumColorLayers(); ++layerNum) + { + osgTerrain::Layer* colorLayer = tile->getColorLayer(layerNum); + if (!colorLayer) continue; + + osgTerrain::SwitchLayer* switchLayer = dynamic_cast(colorLayer); + if (switchLayer) + { + if (switchLayer->getActiveLayer()<0 || + static_cast(switchLayer->getActiveLayer())>=switchLayer->getNumLayers()) + { + continue; + } + + colorLayer = switchLayer->getLayer(switchLayer->getActiveLayer()); + if (!colorLayer) continue; + } + + osg::Image* image = colorLayer->getImage(); + if (!image) continue; + + osgTerrain::ImageLayer* imageLayer = dynamic_cast(colorLayer); + osgTerrain::ContourLayer* contourLayer = dynamic_cast(colorLayer); + if (imageLayer) + { + osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[colorLayer]); + if (!texture2D) + { + texture2D = new osg::Texture2D; + texture2D->setImage(image); + texture2D->setMaxAnisotropy(16.0f); + texture2D->setResizeNonPowerOfTwoHint(false); + + texture2D->setFilter(osg::Texture::MIN_FILTER, colorLayer->getMinFilter()); + texture2D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); + + texture2D->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_EDGE); + texture2D->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_EDGE); + + bool mipMapping = !(texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::LINEAR || texture2D->getFilter(osg::Texture::MIN_FILTER)==osg::Texture::NEAREST); + bool s_NotPowerOfTwo = image->s()==0 || (image->s() & (image->s() - 1)); + bool t_NotPowerOfTwo = image->t()==0 || (image->t() & (image->t() - 1)); + + if (mipMapping && (s_NotPowerOfTwo || t_NotPowerOfTwo)) + { + OSG_INFO<<"Disabling mipmapping for non power of two tile size("<s()<<", "<t()<<")"<setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); + } + + + layerToTextureMap[colorLayer] = texture2D; + + // OSG_NOTICE<<"Creating new ImageLayer texture "<s()="<s()<<" image->t()="<t()<setTextureAttributeAndModes(textureUnit, texture2D, osg::StateAttribute::ON); + + std::stringstream str; + str<<"colorTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); + + layerTypes.push_back(COLOR_LAYER); + + } + else if (contourLayer) + { + osg::Texture1D* texture1D = dynamic_cast(layerToTextureMap[colorLayer]); + if (!texture1D) + { + texture1D = new osg::Texture1D; + texture1D->setImage(image); + texture1D->setResizeNonPowerOfTwoHint(false); + texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); + texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); + + layerToTextureMap[colorLayer] = texture1D; + } + + int textureUnit = layerTypes.size(); + stateset->setTextureAttributeAndModes(textureUnit, texture1D, osg::StateAttribute::ON); + + std::stringstream str; + str<<"contourTexture"<addUniform(new osg::Uniform(str.str().c_str(),textureUnit)); + + layerTypes.push_back(CONTOUR_LAYER); + } + } +#endif + + osg::Program* program = getOrCreateProgram(layerTypes); + if (program) + { + stateset->setAttribute(program); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// HeightFieldDrawable +// +HeightFieldDrawable::HeightFieldDrawable() +{ + setSupportsDisplayList(false); +} + +HeightFieldDrawable::HeightFieldDrawable(const HeightFieldDrawable& rhs,const osg::CopyOp& copyop): + osg::Drawable(rhs, copyop), + _heightField(rhs._heightField), + _geometry(rhs._geometry) +{ + setSupportsDisplayList(false); +} + +void HeightFieldDrawable::drawImplementation(osg::RenderInfo& renderInfo) const +{ + if (_geometry.valid()) _geometry->draw(renderInfo); +} + +void HeightFieldDrawable::compileGLObjects(osg::RenderInfo& renderInfo) const +{ + if (_geometry.valid()) _geometry->compileGLObjects(renderInfo); +} + +void HeightFieldDrawable::resizeGLObjectBuffers(unsigned int maxSize) +{ + if (_geometry.valid()) _geometry->resizeGLObjectBuffers(maxSize); +} + +void HeightFieldDrawable::releaseGLObjects(osg::State* state) const +{ + if (_geometry.valid()) _geometry->releaseGLObjects(state); +} + +void HeightFieldDrawable::accept(osg::Drawable::AttributeFunctor& af) +{ + if (_geometry) _geometry->accept(af); +} + +void HeightFieldDrawable::accept(osg::Drawable::ConstAttributeFunctor& caf) const +{ + if (_geometry) _geometry->accept(caf); +} + +void HeightFieldDrawable::accept(osg::PrimitiveFunctor& pf) const +{ + if (_geometry) _geometry->accept(pf); +} + +void HeightFieldDrawable::accept(osg::PrimitiveIndexFunctor& pif) const +{ + if (_geometry) _geometry->accept(pif); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// ShaderTerrain +// +ShaderTerrain::ShaderTerrain() +{ + // OSG_NOTICE<<"ShaderTerrain::ShaderTerrain()"<getTileSubgraph(_terrainTile); + + // set tile as no longer dirty. + _terrainTile->setDirtyMask(0); +} + +void ShaderTerrain::update(osgUtil::UpdateVisitor* uv) +{ + if (_terrainTile) _terrainTile->osg::Group::traverse(*uv); + + if (_transform.valid()) _transform->accept(*uv); +} + + +void ShaderTerrain::cull(osgUtil::CullVisitor* cv) +{ + if (_transform.valid()) _transform->accept(*cv); +} + + +void ShaderTerrain::traverse(osg::NodeVisitor& nv) +{ + if (!_terrainTile) return; + + // if app traversal update the frame count. + if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR) + { + if (_terrainTile->getDirty()) _terrainTile->init(_terrainTile->getDirtyMask(), false); + + osgUtil::UpdateVisitor* uv = dynamic_cast(&nv); + if (uv) + { + update(uv); + return; + } + } + else if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) + { + osgUtil::CullVisitor* cv = dynamic_cast(&nv); + if (cv) + { + cull(cv); + return; + } + } + + + if (_terrainTile->getDirty()) + { + // OSG_INFO<<"******* Doing init ***********"<init(_terrainTile->getDirtyMask(), false); + } + + if (_transform.valid()) + { + _transform->accept(nv); + } +} + + +void ShaderTerrain::cleanSceneGraph() +{ +} + +void ShaderTerrain::releaseGLObjects(osg::State* state) const +{ + _transform->releaseGLObjects(state); +} diff --git a/examples/osgterrain/ShaderTerrain.h b/examples/osgterrain/ShaderTerrain.h new file mode 100644 index 000000000..8a510b8c5 --- /dev/null +++ b/examples/osgterrain/ShaderTerrain.h @@ -0,0 +1,147 @@ +#ifndef OSGTERRAIN_SHADERTERRAIN +#define OSGTERRAIN_SHADERTERRAIN + +#include +#include +#include +#include + +namespace osgTerrain +{ + +extern const osgTerrain::Locator* computeMasterLocator(const osgTerrain::TerrainTile* tile); + +class GeometryPool : public osg::Referenced +{ + public: + GeometryPool() {} + + struct GeometryKey + { + GeometryKey(): sx(0.0), sy(0.0), y(0.0), nx(0), ny(0) {} + + bool operator < (const GeometryKey& rhs) const + { + if (sxrhs.sx) return false; + + if (sxrhs.sx) return false; + + if (yrhs.y) return false; + + if (nxrhs.nx) return false; + + return (ny > GeometryMap; + + bool createKeyForTile(TerrainTile* tile, GeometryKey& key); + + enum LayerType + { + HEIGHTFIELD_LAYER, + COLOR_LAYER, + CONTOUR_LAYER + }; + + typedef std::vector LayerTypes; + typedef std::map > ProgramMap; + + ProgramMap& getProgramMap() { return _programMap; } + osg::Program* getOrCreateProgram(LayerTypes& layerTypes); + + osg::Geometry* getOrCreateGeometry(osgTerrain::TerrainTile* tile); + osg::MatrixTransform* getTileSubgraph(osgTerrain::TerrainTile* tile); + void applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* stateset); + + protected: + virtual ~GeometryPool() {} + + OpenThreads::Mutex _geometryMapMutex; + GeometryMap _geometryMap; + ProgramMap _programMap; +}; + +class HeightFieldDrawable : public osg::Drawable +{ + public: + HeightFieldDrawable(); + + HeightFieldDrawable(const HeightFieldDrawable&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Node(osgTerrain, HeightFieldDrawable); + + void setHeightField(osg::HeightField* hf) { _heightField = hf; } + osg::HeightField* getHeightField() { return _heightField.get(); } + const osg::HeightField* getHeightField() const { return _heightField.get(); } + + void setGeometry(osg::Geometry* geom) { _geometry = geom; } + osg::Geometry* getGeometry() { return _geometry.get(); } + const osg::Geometry* getGeometry() const { return _geometry.get(); } + + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const; + virtual void resizeGLObjectBuffers(unsigned int maxSize); + virtual void releaseGLObjects(osg::State* state=0) const; + + + virtual bool supports(const osg::Drawable::AttributeFunctor&) const { return true; } + virtual void accept(osg::Drawable::AttributeFunctor&); + + virtual bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return true; } + virtual void accept(osg::Drawable::ConstAttributeFunctor&) const; + + virtual bool supports(const osg::PrimitiveFunctor&) const { return true; } + virtual void accept(osg::PrimitiveFunctor&) const; + + virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return true; } + virtual void accept(osg::PrimitiveIndexFunctor&) const; + + + +protected: + + osg::ref_ptr _heightField; + osg::ref_ptr _geometry; + +}; + +class ShaderTerrain : public osgTerrain::TerrainTechnique +{ + public: + + ShaderTerrain(); + + ShaderTerrain(const ShaderTerrain&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Object(osgTerrain, ShaderTerrain); + + virtual void init(int dirtyMask, bool assumeMultiThreaded); + virtual void update(osgUtil::UpdateVisitor* uv); + virtual void cull(osgUtil::CullVisitor* cv); + virtual void traverse(osg::NodeVisitor& nv); + virtual void cleanSceneGraph(); + virtual void releaseGLObjects(osg::State* state) const; + + protected: + + osg::ref_ptr _geometryPool; + + osg::ref_ptr _transform; +}; + +} + +#endif diff --git a/examples/osgterrain/osgterrain.cpp b/examples/osgterrain/osgterrain.cpp index d57c6b404..126839b2a 100644 --- a/examples/osgterrain/osgterrain.cpp +++ b/examples/osgterrain/osgterrain.cpp @@ -35,6 +35,8 @@ #include #include +#include "ShaderTerrain.h" + #include template @@ -125,6 +127,53 @@ protected: osg::ref_ptr _terrain; }; + +class CleanTechniqueReadFileCallback : public osgDB::ReadFileCallback +{ + + public: + + class CleanTechniqueVisitor : public osg::NodeVisitor + { + public: + CleanTechniqueVisitor(): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::Node& node) + { + osgTerrain::TerrainTile* tile = dynamic_cast(&node); + if (tile) + { + if (tile->getTerrainTechnique()) + { + // OSG_NOTICE<<"Resetting TerrainTechnhique "<getTerrainTechnique()->className()<<" to 0"<setTerrainTechnique(0); + } + } + else + { + traverse(node); + } + } + }; + + + virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& filename, const osgDB::Options* options) + { + osgDB::ReaderWriter::ReadResult rr = ReadFileCallback::readNode(filename, options); + if (rr.validNode()) + { + CleanTechniqueVisitor ctv; + rr.getNode()->accept(ctv); + } + return rr; + } + + protected: + virtual ~CleanTechniqueReadFileCallback() {} +}; + + int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc, argv); @@ -146,7 +195,7 @@ int main(int argc, char** argv) while (arguments.read("-p",pathfile)) { osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile); - if (apm || !apm->valid()) + if (apm || !apm->valid()) { unsigned int num = keyswitchManipulator->getNumMatrixManipulators(); keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm ); @@ -189,6 +238,13 @@ int main(int argc, char** argv) else if (strBlendingPolicy == "ENABLE_BLENDING_WHEN_ALPHA_PRESENT") blendingPolicy = osgTerrain::TerrainTile::ENABLE_BLENDING_WHEN_ALPHA_PRESENT; } + bool useShaderTerrain = arguments.read("--shader") || arguments.read("-s"); + if (useShaderTerrain) + { + osgDB::Registry::instance()->setReadFileCallback(new CleanTechniqueReadFileCallback()); + } + + // load the nodes from the commandline arguments. osg::ref_ptr rootnode = osgDB::readNodeFiles(arguments); @@ -226,6 +282,12 @@ int main(int argc, char** argv) terrain->setVerticalScale(verticalScale); terrain->setBlendingPolicy(blendingPolicy); + if (useShaderTerrain) + { + terrain->setTerrainTechniquePrototype(new osgTerrain::ShaderTerrain()); + } + + // register our custom handler for adjust Terrain settings viewer.addEventHandler(new TerrainHandler(terrain.get())); diff --git a/src/osgTerrain/TerrainTile.cpp b/src/osgTerrain/TerrainTile.cpp index 47ff2178a..e8d81b61c 100644 --- a/src/osgTerrain/TerrainTile.cpp +++ b/src/osgTerrain/TerrainTile.cpp @@ -80,7 +80,7 @@ TerrainTile::TerrainTile(const TerrainTile& terrain,const osg::CopyOp& copyop): { if (terrain.getTerrainTechnique()) { - setTerrainTechnique(dynamic_cast(terrain.getTerrainTechnique()->cloneType())); + setTerrainTechnique(dynamic_cast(terrain.getTerrainTechnique()->clone(osg::CopyOp::SHALLOW_COPY))); } }