From Aurélien Chatelain, "adds support for

* quad primitives
* face definition with the "vertex_index" label (previously only "vertex_indices" was supported)
* replaces normal computation by the SmoothingVisitor to avoid code duplication
"

Submitted by Marc Helbling.


git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14640 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield
2014-12-24 11:02:18 +00:00
parent a331680cec
commit 50203023c7
3 changed files with 96 additions and 122 deletions

View File

@@ -45,6 +45,8 @@ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <string>
#include <vector>
#include <osg/Math>
#include <osgDB/FileUtils>
@@ -1052,6 +1054,35 @@ void ply_get_element_setup( PlyFile *plyfile, char *elem_name, int nprops,
}
}
void ply_set_property(
PlyProperty *prop,
PlyProperty *prop_ptr,
PlyElement *elem,
const int &index
)
{
prop_ptr->internal_type = prop->internal_type;
prop_ptr->offset = prop->offset;
prop_ptr->count_internal = prop->count_internal;
prop_ptr->count_offset = prop->count_offset;
/* specify that the user wants this property */
elem->store_prop[index] = STORE_PROP;
}
// Tokenize a property using the given delimiter
void tokenizeProperties(const char* pnames, std::vector<std::string> &tokens, const std::string &delimiter)
{
std::string propNames(pnames);
std::string::size_type lastPos = propNames.find_first_not_of(delimiter, 0);
std::string::size_type pos = propNames.find_first_of(delimiter, lastPos);
while (std::string::npos != pos || std::string::npos != lastPos) {
tokens.push_back(propNames.substr(lastPos, pos - lastPos));
lastPos = propNames.find_first_not_of(delimiter, pos);
pos = propNames.find_first_of(delimiter, lastPos);
}
}
/******************************************************************************
Specify a property of an element that is to be returned. This should be
@@ -1072,7 +1103,7 @@ void ply_get_property(
)
{
PlyElement *elem;
PlyProperty *prop_ptr;
PlyProperty *prop_ptr = 0;
int index;
/* find information about the element */
@@ -1080,20 +1111,27 @@ void ply_get_property(
plyfile->which_elem = elem;
/* deposit the property information into the element's description */
/* Properties may have several names, separated by | with no spaces */
std::vector<std::string> tokens;
tokenizeProperties(prop->name, tokens, "|");
prop_ptr = find_property (elem, prop->name, &index);
if (prop_ptr == NULL) {
for(std::vector<std::string>::iterator it_property = tokens.begin();
!prop_ptr && it_property != tokens.end();
++it_property)
{
prop_ptr = find_property(elem, it_property->c_str(), &index);
}
if(prop_ptr)
{
ply_set_property(prop, prop_ptr, elem, index);
}
else
{
fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
prop->name, elem_name);
return;
}
prop_ptr->internal_type = prop->internal_type;
prop_ptr->offset = prop->offset;
prop_ptr->count_internal = prop->count_internal;
prop_ptr->count_offset = prop->count_offset;
/* specify that the user wants this property */
elem->store_prop[index] = STORE_PROP;
}

View File

@@ -17,25 +17,12 @@
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/io_utils>
#include <osgUtil/SmoothingVisitor>
using namespace std;
using namespace ply;
struct Normal{
osg::Vec3 triNormal;
void normal(osg::Vec3 v1, osg::Vec3 v2, osg::Vec3 v3)
{
osg::Vec3 u,v;
// right hand system, CCW triangle
u = v2 - v1;
v = v3 - v1;
triNormal = u^v;
triNormal.normalize();
}
};
/* Contructor. */
VertexData::VertexData()
: _invertFaces( false )
@@ -215,7 +202,7 @@ void VertexData::readTriangles( PlyFile* file, const int nFaces )
PlyProperty faceProps[] =
{
{ "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ),
{ "vertex_indices|vertex_index", PLY_INT, PLY_INT, offsetof( _Face, vertices ),
1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) }
};
@@ -225,25 +212,31 @@ void VertexData::readTriangles( PlyFile* file, const int nFaces )
//triangles.reserve( nFaces );
if(!_triangles.valid())
_triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);
if(!_quads.valid())
_quads = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
// read in the faces, asserting that they are only triangles
int ind1 = _invertFaces ? 2 : 0;
int ind3 = _invertFaces ? 0 : 2;
for( int i = 0; i < nFaces; ++i )
// read the faces, reversing the reading direction if _invertFaces is true
for( int i = 0 ; i < nFaces; i++ )
{
ply_get_element( file, static_cast< void* >( &face ) );
MESHASSERT( face.vertices != 0 );
if( (unsigned int)(face.nVertices) != 3 )
if( (unsigned int)(face.nVertices) > 4 )
{
free( face.vertices );
throw MeshException( "Error reading PLY file. Encountered a "
"face which does not have three vertices." );
"face which does not have three or four vertices." );
}
unsigned short index;
for(int j = 0 ; j < face.nVertices ; j++)
{
index = ( _invertFaces ? face.nVertices - 1 - j : j );
if(face.nVertices == 4)
_quads->push_back(face.vertices[index]);
else
_triangles->push_back(face.vertices[index]);
}
// Add the face indices in the premitive set
_triangles->push_back( face.vertices[ind1]);
_triangles->push_back( face.vertices[1]);
_triangles->push_back( face.vertices[ind3] );
// free the memory that was allocated by ply_get_element
free( face.vertices );
@@ -353,7 +346,7 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
fields |= DIFFUSE;
if( equal_strings( props[j]->name, "specular_red" ) )
fields |= SPECULAR;
}
}
if( ignoreColors )
{
@@ -408,7 +401,10 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
// Read Triangles
readTriangles( file, nElems );
// Check whether all face elements read or not
MESHASSERT( _triangles->size()/3 == static_cast< size_t >( nElems ) );
unsigned int nbTriangles = (_triangles.valid() ? _triangles->size() / 3 : 0) ;
unsigned int nbQuads = (_quads.valid() ? _quads->size() / 4 : 0 );
MESHASSERT( (nbTriangles + nbQuads) == static_cast< size_t >( nElems ) );
result = true;
}
catch( exception& e )
@@ -442,23 +438,22 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
// set the vertex array
geom->setVertexArray(_vertices.get());
// If the normals are not calculated calculate the normals for faces
if(_triangles.valid())
// Add the primitive set
bool hasTriOrQuads = false;
if (_triangles.valid() && _triangles->size() > 0 )
{
if(!_normals.valid())
_calculateNormals();
}
// Set the normals
if (_normals.valid())
{
geom->setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX);
geom->addPrimitiveSet(_triangles.get());
hasTriOrQuads = true;
}
// Add the primitive set
if (_triangles.valid() && _triangles->size() > 0 )
geom->addPrimitiveSet(_triangles.get());
else
if (_quads.valid() && _quads->size() > 0 )
{
geom->addPrimitiveSet(_quads.get());
hasTriOrQuads = true;
}
// Print points if the file contains unsupported primitives
if(!hasTriOrQuads)
geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size()));
@@ -483,6 +478,17 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
geom->setColorArray(_specular.get(), osg::Array::BIND_PER_VERTEX );
}
// If the model has normals, add them to the geometry
if(_normals.valid())
{
geom->setNormalArray(_normals.get(), osg::Array::BIND_PER_VERTEX);
}
else
{ // If not, use the smoothing visitor to generate them
// (quads will be triangulated by the smoothing visitor)
osgUtil::SmoothingVisitor::smooth((*geom), osg::PI/2);
}
// set flage true to activate the vertex buffer object of drawable
geom->setUseVertexBufferObjects(true);
@@ -496,69 +502,3 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
}
/* Calculate the face or vertex normals of the current vertex data. */
void VertexData::_calculateNormals( const bool vertexNormals )
{
if(_normals.valid())
return;
#ifndef NDEBUG
int wrongNormals = 0;
#endif
if(!_normals.valid())
{
_normals = new osg::Vec3Array;
}
//normals.clear();
if( vertexNormals )
{
// initialize all normals to zero
for( size_t i = 0; i < _vertices->size(); ++i )
{
_normals->push_back( osg::Vec3( 0, 0, 0 ) );
}
}
for( size_t i = 0; i < ((_triangles->size())); i += 3 )
{
// iterate over all triangles and add their normals to adjacent vertices
Normal triangleNormal;
unsigned int i0, i1, i2;
i0 = (*_triangles)[i+0];
i1 = (*_triangles)[i+1];
i2 = (*_triangles)[i+2];
triangleNormal.normal((*_vertices)[i0],
(*_vertices)[i1],
(*_vertices)[i2] );
// count emtpy normals in debug mode
#ifndef NDEBUG
if( triangleNormal.triNormal.length() == 0.0f )
++wrongNormals;
#endif
if( vertexNormals )
{
(*_normals)[i0] += triangleNormal.triNormal;
(*_normals)[i1] += triangleNormal.triNormal;
(*_normals)[i2] += triangleNormal.triNormal;
}
else
_normals->push_back( triangleNormal.triNormal );
}
// normalize all the normals
if( vertexNormals )
for( size_t i = 0; i < _normals->size(); ++i )
(*_normals)[i].normalize();
#ifndef NDEBUG
if( wrongNormals > 0 )
MESHINFO << wrongNormals << " faces had no valid normal." << endl;
#endif
}

View File

@@ -66,11 +66,6 @@ namespace ply
// Reads the triangle indices from the ply file
void readTriangles( PlyFile* file, const int nFaces );
// Calculates the normals according to passed flag
// if vertexNormals is true then computes normal per vertices
// otherwise per triangle means per face
void _calculateNormals( const bool vertexNormals = true );
bool _invertFaces;
// Vertex array in osg format
@@ -85,6 +80,7 @@ namespace ply
osg::ref_ptr<osg::Vec3Array> _normals;
// The indices of the faces in premitive set
osg::ref_ptr<osg::DrawElementsUInt> _triangles;
osg::ref_ptr<osg::DrawElementsUInt> _quads;
};
}