From Simon Julier, "I have been using the ply plugin to read files created by bundler and pmvs2 (http://grail.cs.washington.edu/software/pmvs/). This program generates models in the form of vertices only. However, the existing ply reader implementation was not able to handle the models generated in a satisfactory manner for two reasons:

1. It did not support normals applied to individual vertices.
2. It would only support red / green / blue colour triples, but the pmvs models are generated with diffuse colours. (The PLY format, http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/, lists specular and ambient colour forms as well.)

To partially overcome these limitations, please find attached modified versions of

src/osgPlugins/ply/vertexData.cpp
src/osgPlugins/ply/vertexData.h

The changes I've made are:

1. I have changed the boolean hasColor flag to a vertexField (which is a boolean operation on an enum) to indicate what fields are present in the ply file. (This is required because Turk's ply reader spits out warnings for every line where you try to read fields which do not exist.)
2. I have modified the code to apply valid normals to either triangles or vertices.
3. I have kludged in "support" for the various colour variants. Specifically, all the colour specified can be read from the file. However, they are all applied in the same way (namely as a colour array, bound to each vertex)."
This commit is contained in:
Robert Osfield 2011-01-20 12:23:04 +00:00
parent d21009c323
commit 34aca88715
2 changed files with 186 additions and 26 deletions

View File

@ -45,13 +45,15 @@ VertexData::VertexData()
_colors = NULL;
_normals = NULL;
_triangles = NULL;
_diffuse = NULL;
_ambient = NULL;
_specular = NULL;
}
/* Read the vertex and (if available/wanted) color data from the open file. */
void VertexData::readVertices( PlyFile* file, const int nVertices,
const bool readColors )
const int fields )
{
// temporary vertex structure for ply loading
struct _Vertex
@ -59,9 +61,23 @@ void VertexData::readVertices( PlyFile* file, const int nVertices,
float x;
float y;
float z;
unsigned char r;
unsigned char g;
unsigned char b;
float nx;
float ny;
float nz;
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char ambient_red;
unsigned char ambient_green;
unsigned char ambient_blue;
unsigned char diffuse_red;
unsigned char diffuse_green;
unsigned char diffuse_blue;
unsigned char specular_red;
unsigned char specular_green;
unsigned char specular_blue;
float specular_coeff;
float specular_power;
} vertex;
PlyProperty vertexProps[] =
@ -69,34 +85,109 @@ void VertexData::readVertices( PlyFile* file, const int nVertices,
{ "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 },
{ "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 },
{ "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 },
{ "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 },
{ "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 },
{ "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 }
{ "nx", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, nx ), 0, 0, 0, 0 },
{ "ny", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, ny ), 0, 0, 0, 0 },
{ "nz", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, nz ), 0, 0, 0, 0 },
{ "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, red ), 0, 0, 0, 0 },
{ "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, green ), 0, 0, 0, 0 },
{ "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, blue ), 0, 0, 0, 0 },
{ "ambient_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_red ), 0, 0, 0, 0 },
{ "ambient_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_green ), 0, 0, 0, 0 },
{ "ambient_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, ambient_blue ), 0, 0, 0, 0 },
{ "diffuse_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_red ), 0, 0, 0, 0 },
{ "diffuse_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_green ), 0, 0, 0, 0 },
{ "diffuse_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, diffuse_blue ), 0, 0, 0, 0 },
{ "specular_red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_red ), 0, 0, 0, 0 },
{ "specular_green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_green ), 0, 0, 0, 0 },
{ "specular_blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, specular_blue ), 0, 0, 0, 0 },
{ "specular_coeff", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, specular_coeff ), 0, 0, 0, 0 },
{ "specular_power", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, specular_power ), 0, 0, 0, 0 },
};
// use all 6 properties when reading colors, only the first 3 otherwise
int limit = readColors ? 6 : 3;
for( int i = 0; i < limit; ++i )
for( int i = 0; i < 3; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
if (fields & NORMALS)
for( int i = 3; i < 6; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
if (fields & RGB)
for( int i = 6; i < 9; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
if (fields & AMBIENT)
for( int i = 9; i < 12; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
if (fields & DIFFUSE)
for( int i = 12; i < 15; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
if (fields & SPECULAR)
for( int i = 15; i < 20; ++i )
ply_get_property( file, "vertex", &vertexProps[i] );
// check whether array is valid otherwise allocate the space
if(!_vertices.valid())
_vertices = new osg::Vec3Array;
if( fields & NORMALS )
{
if(!_normals.valid())
_normals = new osg::Vec3Array;
}
// If read colors allocate space for color array
if( readColors )
if( fields & RGB )
{
if(!_colors.valid())
_colors = new osg::Vec4Array;
}
if( fields & AMBIENT )
{
if(!_ambient.valid())
_ambient = new osg::Vec4Array;
}
if( fields & DIFFUSE )
{
if(!_diffuse.valid())
_diffuse = new osg::Vec4Array;
}
if( fields & SPECULAR )
{
if(!_specular.valid())
_specular = new osg::Vec4Array;
}
// read in the vertices
for( int i = 0; i < nVertices; ++i )
{
ply_get_element( file, static_cast< void* >( &vertex ) );
_vertices->push_back( osg::Vec3( vertex.x, vertex.y, vertex.z ) );
if( readColors )
_colors->push_back( osg::Vec4( (unsigned int) vertex.r / 256.0, (unsigned int) vertex.g / 256.0 , (unsigned int) vertex.b/ 256.0, 0.0 ) );
if (fields & NORMALS)
_normals->push_back( osg::Vec3( vertex.nx, vertex.ny, vertex.nz ) );
if( fields & RGB )
_colors->push_back( osg::Vec4( (unsigned int) vertex.red / 256.0,
(unsigned int) vertex.green / 256.0 ,
(unsigned int) vertex.blue / 256.0, 0.0 ) );
if( fields & AMBIENT )
_ambient->push_back( osg::Vec4( (unsigned int) vertex.ambient_red / 256.0,
(unsigned int) vertex.ambient_green / 256.0 ,
(unsigned int) vertex.ambient_blue / 256.0, 0.0 ) );
if( fields & DIFFUSE )
_diffuse->push_back( osg::Vec4( (unsigned int) vertex.diffuse_red / 256.0,
(unsigned int) vertex.diffuse_green / 256.0 ,
(unsigned int) vertex.diffuse_blue / 256.0, 0.0 ) );
if( fields & SPECULAR )
_specular->push_back( osg::Vec4( (unsigned int) vertex.specular_red / 256.0,
(unsigned int) vertex.specular_green / 256.0 ,
(unsigned int) vertex.specular_blue / 256.0, 0.0 ) );
}
}
@ -232,26 +323,58 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
// if the string is vertex means vertex data is started
if( equal_strings( elemNames[i], "vertex" ) )
{
bool hasColors = false;
int fields = NONE;
// determine if the file stores vertex colors
for( int j = 0; j < nProps; ++j )
{
// if the string have the red means color info is there
if( equal_strings( props[j]->name, "x" ) )
fields |= XYZ;
if( equal_strings( props[j]->name, "nx" ) )
fields |= NORMALS;
if( equal_strings( props[j]->name, "red" ) )
hasColors = true;
fields |= RGB;
if( equal_strings( props[j]->name, "ambient" ) )
fields |= AMBIENT;
if( equal_strings( props[j]->name, "diffuse_red" ) )
fields |= DIFFUSE;
if( equal_strings( props[j]->name, "specular_red" ) )
fields |= SPECULAR;
}
if( ignoreColors )
{
fields &= ~(XYZ | NORMALS);
MESHINFO << "Colors in PLY file ignored per request." << endl;
}
try {
// Read vertices and store in a std::vector array
readVertices( file, nElems, hasColors && !ignoreColors );
readVertices( file, nElems, fields );
// Check whether all vertices are loaded or not
MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) );
// Check all color elements read or not
if( hasColors && !ignoreColors )
// Check if all the optional elements were read or not
if( fields & NORMALS )
{
MESHASSERT( _normals->size() == static_cast< size_t >( nElems ) );
}
if( fields & RGB )
{
MESHASSERT( _colors->size() == static_cast< size_t >( nElems ) );
}
if( fields & AMBIENT )
{
MESHASSERT( _ambient->size() == static_cast< size_t >( nElems ) );
}
if( fields & DIFFUSE )
{
MESHASSERT( _diffuse->size() == static_cast< size_t >( nElems ) );
}
if( fields & SPECULAR )
{
MESHASSERT( _specular->size() == static_cast< size_t >( nElems ) );
}
result = true;
}
@ -311,27 +434,47 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor
{
if(!_normals.valid())
_calculateNormals();
}
// set the normals
// Set the normals
if (_normals.valid())
{
geom->setNormalArray(_normals.get());
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
// Add the premetive set
// Add the primitive set
if (_triangles.valid() && _triangles->size() > 0 )
geom->addPrimitiveSet(_triangles.get());
else
geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size()));
// if color info is given set the color array
// Apply the colours to the model; at the moment this is a
// kludge because we only use one kind and apply them all the
// same way. Also, the priority order is completely arbitrary
if(_colors.valid())
{
geom->setColorArray(_colors.get());
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
else if(_ambient.valid())
{
geom->setColorArray(_ambient.get());
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
else if(_diffuse.valid())
{
geom->setColorArray(_diffuse.get());
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
else if(_specular.valid())
{
geom->setColorArray(_specular.get());
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
// set flage true to activate the vertex buffer object of drawable
geom->setUseVertexBufferObjects(true);

View File

@ -36,6 +36,7 @@ namespace ply
public:
// Default constructor
VertexData();
// Reads ply file and convert in to osg::Node and returns the same
osg::Node* readPlyFile( const char* file, const bool ignoreColors = false );
@ -44,10 +45,22 @@ namespace ply
void useInvertedFaces() { _invertFaces = true; }
private:
enum VertexFields
{
NONE = 0,
XYZ = 1,
NORMALS = 2,
RGB = 4,
AMBIENT = 8,
DIFFUSE = 16,
SPECULAR = 32
};
// Function which reads all the vertices and colors if color info is
// given and also if the user wants that information
void readVertices( PlyFile* file, const int nVertices,
const bool readColors );
const int vertexFields );
// Reads the triangle indices from the ply file
void readTriangles( PlyFile* file, const int nFaces );
@ -63,6 +76,10 @@ namespace ply
osg::ref_ptr<osg::Vec3Array> _vertices;
// Color array in osg format
osg::ref_ptr<osg::Vec4Array> _colors;
osg::ref_ptr<osg::Vec4Array> _ambient;
osg::ref_ptr<osg::Vec4Array> _diffuse;
osg::ref_ptr<osg::Vec4Array> _specular;
// Normals in osg format
osg::ref_ptr<osg::Vec3Array> _normals;
// The indices of the faces in premitive set