osgEarth 2.1.1
|
Classes | |
struct | BuildData |
class | StencilVolumeNodeFactory |
class | FeatureStencilModelSource |
Functions | |
osg::Node * | createColorNode (const osg::Vec4f &color) |
void | tessellate (osg::Geometry *geom) |
osg::Geode * | createVolume (osgEarth::Symbology::Geometry *geom, double offset, double height, const FilterContext &context) |
osg::Node* anonymous_namespace{FeatureStencilModelSource.cpp}::createColorNode | ( | const osg::Vec4f & | color | ) |
Creates a full-screen quad to fill in the colors on the stencil volume.
Definition at line 60 of file FeatureStencilModelSource.cpp.
{ // make a full screen quad: osg::Geometry* quad = new osg::Geometry(); osg::Vec3Array* verts = new osg::Vec3Array(4); (*verts)[0].set( 0, 1, 0 ); (*verts)[1].set( 0, 0, 0 ); (*verts)[2].set( 1, 0, 0 ); (*verts)[3].set( 1, 1, 0 ); quad->setVertexArray( verts ); quad->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) ); osg::Vec4Array* colors = new osg::Vec4Array(1); (*colors)[0] = color; quad->setColorArray( colors ); quad->setColorBinding( osg::Geometry::BIND_OVERALL ); osg::Geode* quad_geode = new osg::Geode(); quad_geode->addDrawable( quad ); osg::StateSet* quad_ss = quad->getOrCreateStateSet(); quad_ss->setMode( GL_CULL_FACE, OFF_PROTECTED ); quad_ss->setMode( GL_DEPTH_TEST, OFF_PROTECTED ); quad_ss->setMode( GL_LIGHTING, OFF_PROTECTED ); osg::MatrixTransform* abs = new osg::MatrixTransform(); abs->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); abs->setMatrix( osg::Matrix::identity() ); abs->addChild( quad_geode ); osg::Projection* proj = new osg::Projection(); proj->setMatrix( osg::Matrix::ortho(0, 1, 0, 1, 0, -1) ); proj->addChild( abs ); proj->getOrCreateStateSet()->setMode( GL_BLEND, 1 ); return proj; }
osg::Geode* anonymous_namespace{FeatureStencilModelSource.cpp}::createVolume | ( | osgEarth::Symbology::Geometry * | geom, |
double | offset, | ||
double | height, | ||
const FilterContext & | context | ||
) |
Definition at line 106 of file FeatureStencilModelSource.cpp.
{ if ( !geom ) return 0L; int numRings = 0; // start by offsetting the input data and counting the number of rings { osgEarth::Symbology::GeometryIterator i( geom ); while( i.hasMore() ) { osgEarth::Symbology::Geometry* part = i.next(); if (offset != 0.0) { for( osg::Vec3dArray::iterator j = part->begin(); j != part->end(); j++ ) { if ( context.isGeocentric() ) { osg::Vec3d world = context.toWorld( *j ); // TODO: get the proper up vector; this is spherical.. or does it really matter for // stencil volumes? osg::Vec3d offset_vec = world; offset_vec.normalize(); *j = context.toLocal( world + offset_vec * offset ); //(*j) += offset_vec * offset; } else { (*j).z() += offset; } } } // in the meantime, count the # of closed geoms. We will need to know this in // order to pre-allocate the proper # of verts. if ( part->getType() == osgEarth::Symbology::Geometry::TYPE_POLYGON || part->getType() == osgEarth::Symbology::Geometry::TYPE_RING ) { numRings++; } } } // now, go thru and remove any coplanar segments from the geometry. The tesselator will // not work include a vert connecting two colinear segments in the tesselation, and this // will break the stenciling logic. #define PARALLEL_EPSILON 0.01 osgEarth::Symbology::GeometryIterator i( geom ); while( i.hasMore() ) { osgEarth::Symbology::Geometry* part = i.next(); if ( part->size() >= 3 ) { osg::Vec3d prevVec = part->front() - part->back(); prevVec.normalize(); for( osg::Vec3dArray::iterator j = part->begin(); part->size() >= 3 && j != part->end(); ) { osg::Vec3d& p0 = *j; osg::Vec3d& p1 = j+1 != part->end() ? *(j+1) : part->front(); osg::Vec3d vec = p1-p0; vec.normalize(); // if the vectors are essentially parallel, remove the extraneous vertex. if ( (prevVec ^ vec).length() < PARALLEL_EPSILON ) { j = part->erase( j ); //OE_NOTICE << "removed colinear segment" << std::endl; } else { ++j; prevVec = vec; } } } } bool made_geom = true; const SpatialReference* srs = context.profile()->getSRS(); // total up all the points so we can pre-allocate the vertex arrays. int num_cap_verts = geom->getTotalPointCount(); int num_wall_verts = 2 * (num_cap_verts + numRings); // add in numRings b/c we need to close each wall osg::Geometry* walls = new osg::Geometry(); osg::Vec3Array* verts = new osg::Vec3Array( num_wall_verts ); walls->setVertexArray( verts ); osg::Geometry* top_cap = new osg::Geometry(); osg::Vec3Array* top_verts = new osg::Vec3Array( num_cap_verts ); top_cap->setVertexArray( top_verts ); osg::Geometry* bottom_cap = new osg::Geometry(); osg::Vec3Array* bottom_verts = new osg::Vec3Array( num_cap_verts ); bottom_cap->setVertexArray( bottom_verts ); int wall_vert_ptr = 0; int top_vert_ptr = 0; int bottom_vert_ptr = 0; //double target_len = height; // now generate the extruded geometry. osgEarth::Symbology::GeometryIterator k( geom ); while( k.hasMore() ) { osgEarth::Symbology::Geometry* part = k.next(); unsigned int wall_part_ptr = wall_vert_ptr; unsigned int top_part_ptr = top_vert_ptr; unsigned int bottom_part_ptr = bottom_vert_ptr; double part_len = 0.0; GLenum prim_type = part->getType() == osgEarth::Symbology::Geometry::TYPE_POINTSET ? GL_LINES : GL_TRIANGLE_STRIP; for( osg::Vec3dArray::const_iterator m = part->begin(); m != part->end(); ++m ) { osg::Vec3d extrude_vec; if ( srs ) { osg::Vec3d m_world = context.toWorld( *m ); //*m * context.inverseReferenceFrame(); if ( context.isGeocentric() ) { osg::Vec3d p_vec = m_world; // todo: not exactly right; spherical osg::Vec3d unit_vec = p_vec; unit_vec.normalize(); p_vec = p_vec + unit_vec*height; extrude_vec = context.toLocal( p_vec ); //p_vec * context.referenceFrame(); } else { extrude_vec.set( m_world.x(), m_world.y(), height ); extrude_vec = context.toLocal( extrude_vec ); //extrude_vec * context.referenceFrame(); } } else { extrude_vec.set( m->x(), m->y(), height ); } (*top_verts)[top_vert_ptr++] = extrude_vec; (*bottom_verts)[bottom_vert_ptr++] = *m; part_len += wall_vert_ptr > (int)wall_part_ptr? (extrude_vec - (*verts)[wall_vert_ptr-2]).length() : 0.0; int p; p = wall_vert_ptr++; (*verts)[p] = extrude_vec; p = wall_vert_ptr++; (*verts)[p] = *m; } // close the wall if it's a ring/poly: if ( part->getType() == osgEarth::Symbology::Geometry::TYPE_RING || part->getType() == osgEarth::Symbology::Geometry::TYPE_POLYGON ) { part_len += wall_vert_ptr > (int)wall_part_ptr? ((*verts)[wall_part_ptr] - (*verts)[wall_vert_ptr-2]).length() : 0.0; int p; p = wall_vert_ptr++; (*verts)[p] = (*verts)[wall_part_ptr]; p = wall_vert_ptr++; (*verts)[p] = (*verts)[wall_part_ptr+1]; } walls->addPrimitiveSet( new osg::DrawArrays( prim_type, wall_part_ptr, wall_vert_ptr - wall_part_ptr ) ); top_cap->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, top_part_ptr, top_vert_ptr - top_part_ptr ) ); // reverse the bottom verts so the front face is down: std::reverse( bottom_verts->begin()+bottom_part_ptr, bottom_verts->begin()+bottom_vert_ptr ); bottom_cap->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, bottom_part_ptr, bottom_vert_ptr - bottom_part_ptr ) ); } // build solid surfaces for the caps: tessellate( top_cap ); tessellate( bottom_cap ); osg::Geode* geode = new osg::Geode(); geode->addDrawable( walls ); geode->addDrawable( top_cap ); geode->addDrawable( bottom_cap ); return geode; }
void anonymous_namespace{FeatureStencilModelSource.cpp}::tessellate | ( | osg::Geometry * | geom | ) |
Definition at line 96 of file FeatureStencilModelSource.cpp.
{
osgUtil::Tessellator tess;
tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
// tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE );
tess.retessellatePolygons( *geom );
}