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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user