From edee9d09463bfc57ae992b81ac775d2122f85c19 Mon Sep 17 00:00:00 2001 From: Uwe Woessner Date: Tue, 15 Aug 2017 15:42:22 +0100 Subject: [PATCH] Extension to the PLY plugin to read files with textures. --- src/osgPlugins/ply/vertexData.cpp | 166 ++++++++++++++++++++++-------- src/osgPlugins/ply/vertexData.h | 4 +- 2 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/osgPlugins/ply/vertexData.cpp b/src/osgPlugins/ply/vertexData.cpp index a74406116..00ce08758 100644 --- a/src/osgPlugins/ply/vertexData.cpp +++ b/src/osgPlugins/ply/vertexData.cpp @@ -18,6 +18,10 @@ #include #include #include +#include +#include +#include +#include using namespace std; using namespace ply; @@ -35,6 +39,7 @@ VertexData::VertexData() _diffuse = NULL; _ambient = NULL; _specular = NULL; + _texcoord = NULL; } @@ -66,6 +71,8 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, unsigned char specular_blue; float specular_coeff; float specular_power; + float texture_u; + float texture_v; } vertex; PlyProperty vertexProps[] = @@ -74,8 +81,8 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 }, { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 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 }, + { "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 }, @@ -91,6 +98,8 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, { "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 }, + { "texture_u", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, texture_u), 0, 0, 0, 0 }, + { "texture_v", PLY_FLOAT, PLY_FLOAT, offsetof(_Vertex, texture_v), 0, 0, 0, 0 }, }; // use all 6 properties when reading colors, only the first 3 otherwise @@ -120,6 +129,10 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, for( int i = 16; i < 21; ++i ) ply_get_property( file, "vertex", &vertexProps[i] ); + if (fields & TEXCOORD) + for (int i = 21; i < 23; ++i) + ply_get_property(file, "vertex", &vertexProps[i]); + // check whether array is valid otherwise allocate the space if(!_vertices.valid()) _vertices = new osg::Vec3Array; @@ -154,6 +167,11 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, if(!_specular.valid()) _specular = new osg::Vec4Array; } + if (fields & TEXCOORD) + { + if (!_texcoord.valid()) + _texcoord = new osg::Vec2Array; + } // read in the vertices for( int i = 0; i < nVertices; ++i ) @@ -186,6 +204,8 @@ void VertexData::readVertices( PlyFile* file, const int nVertices, _specular->push_back( osg::Vec4( (unsigned int) vertex.specular_red / 255.0, (unsigned int) vertex.specular_green / 255.0 , (unsigned int) vertex.specular_blue / 255.0, 1.0 ) ); + if (fields & TEXCOORD) + _texcoord->push_back(osg::Vec2(vertex.texture_u,vertex.texture_v)); } } @@ -208,38 +228,41 @@ void VertexData::readTriangles( PlyFile* file, const int nFaces ) ply_get_property( file, "face", &faceProps[0] ); - //triangles.clear(); - //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); + _triangles = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES); + if(!_quads.valid()) + _quads = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS); + + + const char NUM_VERTICES_TRIANGLE(3); + const char NUM_VERTICES_QUAD(4); // read the faces, reversing the reading direction if _invertFaces is true for( int i = 0 ; i < nFaces; i++ ) { + // initialize face values + face.nVertices = 0; + face.vertices = 0; + ply_get_element( file, static_cast< void* >( &face ) ); - MESHASSERT( face.vertices != 0 ); - if( (unsigned int)(face.nVertices) > 4 ) + if (face.vertices) { + if (face.nVertices == NUM_VERTICES_TRIANGLE || face.nVertices == NUM_VERTICES_QUAD) + { + 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]); + } + } + // free the memory that was allocated by ply_get_element free( face.vertices ); - throw MeshException( "Error reading PLY file. Encountered a " - "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]); - } - - // free the memory that was allocated by ply_get_element - free( face.vertices ); } } @@ -288,13 +311,47 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor MESHINFO << filename << ": " << nPlyElems << " elements, file type = " << fileType << ", version = " << version << endl; #endif - + char *textureFile = NULL; for( int i = 0; i < nComments; i++ ) { if( equal_strings( comments[i], "modified by flipply" ) ) { _invertFaces = true; } + if (strncmp(comments[i], "TextureFile",11)==0) + { + textureFile = comments[i]+12; + char * path = new char[strlen(const_cast(filename)) + 1 + strlen(comments[i])]; + if (textureFile[0] == '\\' || textureFile[0] == '/' || textureFile[1] == ':') + { + // texture filename is absolute + strcpy(path, textureFile); + } + else + { + // texture filename is relative + // add directory of ply file + strcpy(path, const_cast(filename)); + char *pp = path + strlen(path); + while (pp >= path) + { + if (*pp == '\\' || *pp == '/') + { + pp++; + *pp = '\0'; + break; + } + pp--; + } + if (pp == path - 1) + { + pp++; + *pp = '\0'; + } + strcat(path, textureFile); + } + textureFile = path; + } } for( int i = 0; i < nPlyElems; ++i ) @@ -327,10 +384,10 @@ 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" ) ) { - int fields = NONE; + 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; @@ -344,15 +401,19 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor fields |= AMBIENT; if( equal_strings( props[j]->name, "diffuse_red" ) ) fields |= DIFFUSE; - if( equal_strings( props[j]->name, "specular_red" ) ) + if (equal_strings(props[j]->name, "specular_red")) fields |= SPECULAR; - } + if (equal_strings(props[j]->name, "texture_u")) + fields |= TEXCOORD; + if (equal_strings(props[j]->name, "texture_v")) + fields |= TEXCOORD; + } if( ignoreColors ) - { - fields &= ~(XYZ | NORMALS); - MESHINFO << "Colors in PLY file ignored per request." << endl; - } + { + fields &= ~(XYZ | NORMALS); + MESHINFO << "Colors in PLY file ignored per request." << endl; + } try { // Read vertices and store in a std::vector array @@ -360,7 +421,7 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor // Check whether all vertices are loaded or not MESHASSERT( _vertices->size() == static_cast< size_t >( nElems ) ); - // Check if all the optional elements were read or not + // Check if all the optional elements were read or not if( fields & NORMALS ) { MESHASSERT( _normals->size() == static_cast< size_t >( nElems ) ); @@ -377,9 +438,13 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor { MESHASSERT( _diffuse->size() == static_cast< size_t >( nElems ) ); } - if( fields & SPECULAR ) + if (fields & SPECULAR) { - MESHASSERT( _specular->size() == static_cast< size_t >( nElems ) ); + MESHASSERT(_specular->size() == static_cast< size_t >(nElems)); + } + if (fields & TEXCOORD) + { + MESHASSERT(_texcoord->size() == static_cast< size_t >(nElems)); } result = true; @@ -459,9 +524,9 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor geom->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, _vertices->size())); - // 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 + // 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()) { @@ -475,10 +540,14 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor { geom->setColorArray(_diffuse.get(), osg::Array::BIND_PER_VERTEX ); } - else if(_specular.valid()) + else if(_specular.valid()) { geom->setColorArray(_specular.get(), osg::Array::BIND_PER_VERTEX ); } + else if (_texcoord.valid()) + { + geom->setTexCoordArray(0, _texcoord); + } // If the model has normals, add them to the geometry if(_normals.valid()) @@ -494,11 +563,26 @@ osg::Node* VertexData::readPlyFile( const char* filename, const bool ignoreColor // set flage true to activate the vertex buffer object of drawable geom->setUseVertexBufferObjects(true); + osg::Image *image = NULL; + if (textureFile && (image = osgDB::readImageFile(textureFile)) != NULL) + { + osg::Texture2D *texture = new osg::Texture2D; + texture->setImage(image); + texture->setResizeNonPowerOfTwoHint(false); + + osg::TexEnv *texenv = new osg::TexEnv; + texenv->setMode(osg::TexEnv::REPLACE); + + osg::StateSet *stateset = geom->getOrCreateStateSet(); + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + stateset->setTextureAttribute(0, texenv); + delete[] textureFile; + } osg::Geode* geode = new osg::Geode; geode->addDrawable(geom); return geode; - } + } return NULL; } diff --git a/src/osgPlugins/ply/vertexData.h b/src/osgPlugins/ply/vertexData.h index dec0a663a..e2cd3a646 100644 --- a/src/osgPlugins/ply/vertexData.h +++ b/src/osgPlugins/ply/vertexData.h @@ -55,7 +55,8 @@ namespace ply AMBIENT = 8, DIFFUSE = 16, SPECULAR = 32, - RGBA = 64 + RGBA = 64, + TEXCOORD = 128 }; // Function which reads all the vertices and colors if color info is @@ -75,6 +76,7 @@ namespace ply osg::ref_ptr _ambient; osg::ref_ptr _diffuse; osg::ref_ptr _specular; + osg::ref_ptr _texcoord; // Normals in osg format osg::ref_ptr _normals;