Added a local Vec3Array cache to the HeightFieldDrawable to facilitate efficient intersection testing

git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14656 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield 2015-01-12 10:31:58 +00:00
parent ed57c8718c
commit 3e3d7e4dc1
2 changed files with 157 additions and 48 deletions

View File

@ -27,6 +27,33 @@ namespace osgTerrain {
extern OSGTERRAIN_EXPORT const osgTerrain::Locator* computeMasterLocator(const osgTerrain::TerrainTile* tile);
class OSGTERRAIN_EXPORT SharedGeometry : public osg::Geometry
{
public:
SharedGeometry();
SharedGeometry(const SharedGeometry&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Node(osgTerrain, SharedGeometry);
typedef std::vector<unsigned int> VertexToHeightFieldMapping;
void setVertexToHeightFieldMapping(const VertexToHeightFieldMapping& vthfm) { _vertexToHeightFieldMapping = vthfm; }
VertexToHeightFieldMapping& getVertexToHeightFieldMapping() { return _vertexToHeightFieldMapping; }
const VertexToHeightFieldMapping& getVertexToHeightFieldMapping() const { return _vertexToHeightFieldMapping; }
using osg::Geometry::supports;
using osg::Geometry::accept;
protected:
virtual ~SharedGeometry();
VertexToHeightFieldMapping _vertexToHeightFieldMapping;
};
class OSGTERRAIN_EXPORT GeometryPool : public osg::Referenced
{
public:
@ -61,7 +88,7 @@ class OSGTERRAIN_EXPORT GeometryPool : public osg::Referenced
int ny;
};
typedef std::map< GeometryKey, osg::ref_ptr<osg::Geometry> > GeometryMap;
typedef std::map< GeometryKey, osg::ref_ptr<SharedGeometry> > GeometryMap;
bool createKeyForTile(TerrainTile* tile, GeometryKey& key);
@ -77,7 +104,7 @@ class OSGTERRAIN_EXPORT GeometryPool : public osg::Referenced
osg::ref_ptr<osg::Program> getOrCreateProgram(LayerTypes& layerTypes);
osg::ref_ptr<osg::Geometry> getOrCreateGeometry(osgTerrain::TerrainTile* tile);
osg::ref_ptr<SharedGeometry> getOrCreateGeometry(osgTerrain::TerrainTile* tile);
osg::ref_ptr<osg::MatrixTransform> getTileSubgraph(osgTerrain::TerrainTile* tile);
@ -107,9 +134,13 @@ class OSGTERRAIN_EXPORT HeightFieldDrawable : public osg::Drawable
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(); }
void setGeometry(SharedGeometry* geom) { _geometry = geom; }
SharedGeometry* getGeometry() { return _geometry.get(); }
const SharedGeometry* getGeometry() const { return _geometry.get(); }
void setVertices(osg::Vec3Array* vertices) { _vertices = vertices; }
osg::Vec3Array* getVertices() { return _vertices.get(); }
const osg::Vec3Array* getVertices() const { return _vertices.get(); }
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
virtual void compileGLObjects(osg::RenderInfo& renderInfo) const;
@ -129,13 +160,13 @@ class OSGTERRAIN_EXPORT HeightFieldDrawable : public osg::Drawable
virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return true; }
virtual void accept(osg::PrimitiveIndexFunctor&) const;
protected:
osg::ref_ptr<osg::HeightField> _heightField;
osg::ref_ptr<osg::Geometry> _geometry;
virtual ~HeightFieldDrawable();
osg::ref_ptr<osg::HeightField> _heightField;
osg::ref_ptr<SharedGeometry> _geometry;
osg::ref_ptr<osg::Vec3Array> _vertices;
};

View File

@ -87,10 +87,7 @@ bool GeometryPool::createKeyForTile(TerrainTile* tile, GeometryKey& key)
return true;
}
static int numberGeometryCreated = 0;
static int numberSharedGeometry = 0;
osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile)
osg::ref_ptr<SharedGeometry> GeometryPool::getOrCreateGeometry(osgTerrain::TerrainTile* tile)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_geometryMapMutex);
@ -100,16 +97,15 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
GeometryMap::iterator itr = _geometryMap.find(key);
if (itr != _geometryMap.end())
{
++numberSharedGeometry;
// OSG_NOTICE<<"Sharing geometry "<<itr->second.get()<<", number shared = "<<std::dec<<numberSharedGeometry<<", number created "<<numberGeometryCreated<<std::endl;
// OSG_NOTICE<<" GeometryKey "<<key.y<<", sx="<<key.sx<<", sy="<<key.sy<<", "<<key.nx<<", "<<key.ny<<std::endl;
return itr->second.get();
}
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::ref_ptr<SharedGeometry> geometry = new SharedGeometry;
_geometryMap[key] = geometry;
SharedGeometry::VertexToHeightFieldMapping& vthfm = geometry->getVertexToHeightFieldMapping();
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices.get());
@ -133,6 +129,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
vertices->reserve(numVertices);
normals->reserve(numVertices);
texcoords->reserve(numVertices);
vthfm.reserve(numVertices);
double c_mult = 1.0/static_cast<double>(nx-1);
double r_mult = 1.0/static_cast<double>(ny-1);
@ -179,6 +176,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
double skirtRatio = 0.02;
double skirtHeight = -diagonalLength*skirtRatio;
// set up the vertex data
{
// bottom row for skirt
@ -191,6 +189,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
normals->push_back(normal);
texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
vthfm.push_back(0*nx + c);
}
// main body
@ -206,6 +205,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
normals->push_back(normal);
texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
vthfm.push_back(r*nx + 0);
}
pos.z() = 0;
@ -216,6 +216,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
normals->push_back(normal);
texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
vthfm.push_back(r*nx + c);
}
// end skirt vertex
@ -226,6 +227,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
normals->push_back(normal);
texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
vthfm.push_back((r+1)*nx-1);
}
}
@ -240,6 +242,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
normals->push_back(normal);
texcoords->push_back(osg::Vec4(pos.x(), pos.y(), 1.0f, 1.0f));
locationCoords.push_back(osg::Vec4d(pos.x(), pos.y(),c_mult, r_mult));
vthfm.push_back((ny-1)*nx + c);
}
}
@ -436,8 +439,6 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
//osgDB::writeNodeFile(*geometry, "geometry.osgt");
++ numberGeometryCreated;
// OSG_NOTICE<<"Creating new geometry "<<geometry.get()<<std::endl;
return geometry;
@ -446,7 +447,7 @@ osg::ref_ptr<osg::Geometry> GeometryPool::getOrCreateGeometry(osgTerrain::Terrai
osg::ref_ptr<osg::MatrixTransform> GeometryPool::getTileSubgraph(osgTerrain::TerrainTile* tile)
{
// create or reuse Geometry
osg::ref_ptr<osg::Geometry> geometry = getOrCreateGeometry(tile);
osg::ref_ptr<SharedGeometry> geometry = getOrCreateGeometry(tile);
osg::ref_ptr<HeightFieldDrawable> hfDrawable = new HeightFieldDrawable();
@ -489,37 +490,57 @@ osg::ref_ptr<osg::MatrixTransform> GeometryPool::getTileSubgraph(osgTerrain::Ter
}
}
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
if (hf && vertices && normals && (vertices->size()==normals->size()))
osg::Vec3Array* shared_vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
osg::Vec3Array* shared_normals = dynamic_cast<osg::Vec3Array*>(geometry->getNormalArray());
osg::FloatArray* heights = hf->getFloatArray();
const SharedGeometry::VertexToHeightFieldMapping& vthfm = geometry->getVertexToHeightFieldMapping();
if (hf && shared_vertices && shared_normals && (shared_vertices->size()==shared_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; r<nr; ++r)
if (vthfm.size()==shared_vertices->size())
{
for(unsigned int c=0; c<nc; ++c)
// Using cache VertexArray
unsigned int numVertices = shared_vertices->size();
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
vertices->resize(numVertices);
for(unsigned int i=0; i<numVertices; ++i)
{
unsigned int i = r*nc+c;
float h = (*heights)[i];
const osg::Vec3& v = (*vertices)[i];
const osg::Vec3& n = (*normals)[i];
const osg::Vec3 vt(v+n*h);
bb.expandBy(vt);
unsigned int hi = vthfm[i];
(*vertices)[i] = (*shared_vertices)[i] + (*shared_normals)[i] * (*heights)[hi];
}
hfDrawable->setVertices(vertices.get());
}
else
{
// Setting local bounding
unsigned int nr = hf->getNumRows();
unsigned int nc = hf->getNumColumns();
osg::BoundingBox bb;
for(unsigned int r=0; r<nr; ++r)
{
for(unsigned int c=0; c<nc; ++c)
{
unsigned int i = r*nc+c;
float h = (*heights)[i];
const osg::Vec3& v = (*shared_vertices)[i];
const osg::Vec3& n = (*shared_normals)[i];
const osg::Vec3 vt(v+n*h);
bb.expandBy(vt);
}
}
hfDrawable->setInitialBound(bb);
// OSG_NOTICE<<"Assigning initial bound ("<<bb.xMin()<<", "<<bb.xMax()<<") , ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
// bb = hfDrawable->getBoundingBox();
//OSG_NOTICE<<" getBoundingBox ("<<bb.xMin()<<", "<<bb.xMax()<<") , ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
}
hfDrawable->setInitialBound(bb);
// OSG_NOTICE<<"Assigning initial bound ("<<bb.xMin()<<", "<<bb.xMax()<<") , ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
// bb = hfDrawable->getBoundingBox();
//OSG_NOTICE<<" getBoundingBox ("<<bb.xMin()<<", "<<bb.xMax()<<") , ("<<bb.yMin()<<", "<<bb.yMax()<<") ("<<bb.zMin()<<", "<<bb.zMax()<<")"<< std::endl;
}
osg::ref_ptr<osg::StateSet> stateset = transform->getOrCreateStateSet();
// apply colour layers
@ -756,6 +777,29 @@ void GeometryPool::applyLayers(osgTerrain::TerrainTile* tile, osg::StateSet* sta
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// SharedGeometry
//
SharedGeometry::SharedGeometry()
{
// setSupportsDisplayList(false);
}
SharedGeometry::SharedGeometry(const SharedGeometry& rhs,const osg::CopyOp& copyop):
osg::Geometry(rhs, copyop),
_vertexToHeightFieldMapping(rhs._vertexToHeightFieldMapping)
{
// setSupportsDisplayList(false);
}
SharedGeometry::~SharedGeometry()
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// HeightFieldDrawable
@ -768,11 +812,16 @@ HeightFieldDrawable::HeightFieldDrawable()
HeightFieldDrawable::HeightFieldDrawable(const HeightFieldDrawable& rhs,const osg::CopyOp& copyop):
osg::Drawable(rhs, copyop),
_heightField(rhs._heightField),
_geometry(rhs._geometry)
_geometry(rhs._geometry),
_vertices(rhs._vertices)
{
setSupportsDisplayList(false);
}
HeightFieldDrawable::~HeightFieldDrawable()
{
}
void HeightFieldDrawable::drawImplementation(osg::RenderInfo& renderInfo) const
{
if (_geometry.valid()) _geometry->draw(renderInfo);
@ -805,10 +854,39 @@ void HeightFieldDrawable::accept(osg::Drawable::ConstAttributeFunctor& caf) cons
void HeightFieldDrawable::accept(osg::PrimitiveFunctor& pf) const
{
if (_geometry) _geometry->accept(pf);
// use the cached vertex positions for PrimitiveFunctor operations
if (!_geometry) return;
if (_vertices.valid())
{
pf.setVertexArray(_vertices->size(), &((*_vertices)[0]));
for(osg::Geometry::PrimitiveSetList::const_iterator itr = _geometry->getPrimitiveSetList().begin();
itr != _geometry->getPrimitiveSetList().end();
++itr)
{
(*itr)->accept(pf);
}
}
else
{
_geometry->accept(pf);
}
}
void HeightFieldDrawable::accept(osg::PrimitiveIndexFunctor& pif) const
{
if (_geometry) _geometry->accept(pif);
if (_vertices.valid())
{
pif.setVertexArray(_vertices->size(), &((*_vertices)[0]));
for(osg::Geometry::PrimitiveSetList::const_iterator itr = _geometry->getPrimitiveSetList().begin();
itr != _geometry->getPrimitiveSetList().end();
++itr)
{
(*itr)->accept(pif);
}
}
else
{
_geometry->accept(pif);
}
}