For now, I process each file sequentially and update the geometry vertices with some transformations based on PROJ4. To do so, I simply change the vertexArray with the new computed coordinates. To avoid high coordinates, I center them around (0,0,0) and add a translation MatrixTransform as a Parent of each Geode (thus, the MatrixTransform is now the child of each PagedLOD). the translation is simply the mean of coordinates on x, y and z after transformation. To center the coordinates, I simply substract the real coordinates with the mean coordinate. From this, I also need to update parent PagedLOD. I update the ranges according to the new dounding sphere radius of my Geode (only changes slightly), and set the center with the mean coordinates previously computed.
So, after conversion, the structure of each graph has been changed and "between" each PagedLOD and its Geode child, i have a translation MatrixTransform.
Here is the code, the "main" method being 'process':
*************************************************************************************
bool file_converter::transform_pagedlod( PagedLOD* pagedlod, Vec3d& new_center, double& new_radius, double& old_radius )
{
NodeFinder<Geode> geode_finder;
pagedlod->accept(geode_finder);
if (!geode_finder.getNodeList().size())
{
_converter->_warning_callback( "PagedLOD does not contain any Geode" );
return false;
}
ref_ptr<Geode> input_geode = geode_finder.getFirst();
// TODO?
if (geode_finder.getNodeList().size()>1)
_converter->_warning_callback( "PagedLOD has more than 1 Geode (" + boost::lexical_cast<string>(geode_finder.getNodeList().size()) + " Geodes)! Only the FIRST one will be processed" );
if(!transform_geode(input_geode, new_center, new_radius, old_radius))
return false;
ref_ptr<MatrixTransform> translation_from_center = _converter->create_translate_from_center_matrix(new_center);
pagedlod->setDatabasePath( "" );
pagedlod->setCenter(new_center);
pagedlod->setRadius(new_radius);
// Update PagedLOD ranges according to the following formula:
// range = lod_threshold * radius / tolerance
LOD::RangeList ranges = pagedlod->getRangeList();
double r01 = ranges[0].second;
double r10 = ranges[1].first;
// 1) Compute tolerance...
double tolerance01 = 2. * old_radius / r01;
double tolerance10 = 2. * old_radius / r10;
// 2) Update and set new ranges
ranges[0].second = 2. * new_radius / tolerance01;
ranges[1].first = 2. * new_radius / tolerance10;
pagedlod->setRangeList(ranges);
// TODO
ref_ptr<Node> firstChild = pagedlod->getChild(0);
pagedlod->replaceChild(firstChild, translation_from_center);
translation_from_center->addChild( firstChild );
return true;
}
bool file_converter::transform_geode( Geode* geode, Vec3d& new_center, double& new_radius, double& old_radius )
{
if (geode != NULL)
{
// TODO: Assume there is a single drawable and that it is a geometry ....
if(geode->getNumDrawables()>0)
{
double x_mean, y_mean, z_mean;
ref_ptr<Geometry> input_geometry = (Geometry *) geode->getDrawable(0);
ref_ptr<Vec3Array> l93_vertex_vector = _converter->_geodesy->process_geometry(input_geometry, x_mean, y_mean, z_mean);
if (!l93_vertex_vector.valid())
{
_converter->_last_error = "[Error propagated from geodesy]" + _converter->_geodesy->last_error();
_converter->_error_callback( _converter->_last_error );
return false;
}// Here: stuffs on textures
/* ... */
old_radius = input_geometry->getBound().radius();
input_geometry->setVertexArray( l93_vertex_vector );
new_center = Vec3d(x_mean, y_mean, z_mean);
new_radius = input_geometry->getBound().radius();
}
else
{
_converter->_last_error = "No drawable found!";
return false;
}
}
else
{
_converter->_last_error = "NULL geode!!!";
return false;
}
return true;
}
bool file_converter::process(ref_ptr<Node>& input_node, string output)
{
// Retrieve PagedLOD from imput_node
NodeFinder<PagedLOD> pagedlod_finder;
input_node->accept(pagedlod_finder);
vector<PagedLOD*> pagedlods = pagedlod_finder.getNodeList();
Vec3d new_center;
double old_radius, new_radius;
if ( pagedlods.size() )
{
NodeFinder<PagedLOD>::iterator it = pagedlods.begin(), ite = pagedlods.end();
for(;it!=ite;++it)
{
if ( !transform_pagedlod(*it, new_center, new_radius, old_radius) )
{
_converter->_error_callback("Error processing (pagedlod) input ...");
return false;
}
}
write_output( input_node, output );
return true;
}
else
{
NodeFinder<Geode> geode_finder;
input_node->accept(geode_finder);
ref_ptr<Geode> input_geode = geode_finder.getFirst();
if (geode_finder.getNodeList().size()>1)
_converter->_warning_callback( "PagedLOD has more than 1 geode (" + boost::lexical_cast<string>(geode_finder.getNodeList().size()) + " geodes)" );
if ( !transform_geode(input_geode, new_center, new_radius, old_radius) )
{
_converter->_error_callback("Error processing (geode) input ...");
return false;
}
ref_ptr<MatrixTransform> translation_from_center = _converter->create_translate_from_center_matrix(new_center);
translation_from_center->addChild( input_node );
write_output( translation_from_center, output );
return true;
}
return true;
}
*************************************************************************************
And here is the code for the visitor:
*************************************************************************************
template <class NodeType>
class NodeFinder : public osg::NodeVisitor
{
public:
NodeFinder() : NodeVisitor (osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(NodeType &searchNode)
{
foundNodes.push_back ((NodeType*) &searchNode);
traverse(searchNode);
}
NodeType* getFirst()
{
if (foundNodes.size() > 0)
return foundNodes.front();
else
return NULL;
}
std::vector<NodeType*> getNodeList() { return foundNodes; }
typedef typename std::vector<NodeType*>::const_iterator const_iterator;
typedef typename std::vector<NodeType*>::iterator iterator;
private:
std::vector<NodeType*> foundNodes;
};
*************************************************************************************
At a first glance, it seems to work. However, when I zoom in and get close to the terrain, that is to say when I display high resolution LOD, sometimes, a small part disappear. If I move a few, the disappeared part comes back. See here: http://imageshack.us/photo/my-images/109/badtiles.png/
I also noticed that, my conversion seems to "add" geometries ... Do not understand why. I used this visitor to count the number of triangles in a PagedLOD:
*************************************************************************************
void InfoVisitor::apply(Geode& geode)
{
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
ref_ptr<Drawable> drawable = geode.getDrawable(i);
if (drawable.valid())
{
ref_ptr<Geometry> geometry = drawable->asGeometry();
if (geometry.valid())
{
for (unsigned int j=0; j<geometry->getNumPrimitiveSets(); ++j)
{
ref_ptr<PrimitiveSet> ps = geometry->getPrimitiveSet(j);
if (ps.valid())
{
switch (ps->getMode())
{
case PrimitiveSet::TRIANGLES:
_numTriangles += ps->getNumIndices() / 3;
break;
case PrimitiveSet::TRIANGLE_STRIP:
_numTriangles += ps->getNumIndices() - 2;
break;
case PrimitiveSet::TRIANGLE_FAN:
_numTriangles += ps->getNumIndices() - 2;
break;
case PrimitiveSet::QUADS:
_numTriangles += ps->getNumIndices() / 2;
break;
case PrimitiveSet::QUAD_STRIP:
_numTriangles += ps->getNumIndices() - 2;
break;
case PrimitiveSet::POLYGON:
_numTriangles += ps->getNumIndices() - 2;
break;
}
}
}
}
}
}
}
*************************************************************************************
When i use it on a root file before conversion, it return 52092 triangles. After conversion, on the same root file, it returns 53803 triangles...
I am completely lost on this issue and would be interested to have your opinion. I know that I could use a visitor for the conversion but, for now, I would prefer to first fix the problem. I am not able to locate and struggle with this tricky bug for a few days. Maybe something with the PagedLOD visitor?
Hope you could help and sorry for a so long message (just wanted to be clear enough).
Regards,
Olivier
Hi Olivier,
The PageLOD's coordinate frame is in world coordinates while the leaf
On 13 March 2013 18:44, Olivier Tournaire <oli...@gmail.com> wrote:
> However, having a detailed look at the original data, I saw that (A PagedLOD
> has always a single Geode with a single Drawable):
> * PagedLOD center/radius is not the same as the Geode bound center/radius
nodes that sit below the MatrixTransform are in local coordinates so
one should expect the values of the bounding volume and center/radius
to be different.