diff --git a/src/osgPlugins/fbx/CMakeLists.txt b/src/osgPlugins/fbx/CMakeLists.txt index 44bb89b8d..df997b4bd 100644 --- a/src/osgPlugins/fbx/CMakeLists.txt +++ b/src/osgPlugins/fbx/CMakeLists.txt @@ -7,6 +7,7 @@ SET(TARGET_SRC fbxRMesh.cpp fbxRNode.cpp ReaderWriterFBX.cpp + WriterCompareTriangle.cpp WriterNodeVisitor.cpp fbxMaterialToOsgStateSet.cpp ) @@ -18,6 +19,7 @@ SET(TARGET_H fbxRMesh.h fbxRNode.h ReaderWriterFBX.h + WriterCompareTriangle.h WriterNodeVisitor.h fbxMaterialToOsgStateSet.h ) diff --git a/src/osgPlugins/fbx/ReaderWriterFBX.h b/src/osgPlugins/fbx/ReaderWriterFBX.h index 845999a97..aee1d8eaf 100644 --- a/src/osgPlugins/fbx/ReaderWriterFBX.h +++ b/src/osgPlugins/fbx/ReaderWriterFBX.h @@ -13,7 +13,7 @@ public: ReaderWriterFBX() { supportsExtension("fbx", "FBX format"); - supportsOption("Embedded", "Embed textures in FBX file when writing"); + supportsOption("Embedded", "(Write option) Embed textures in FBX file"); supportsOption("UseFbxRoot", "(Read/write option) If the source OSG root node is a simple group with no stateset, the writer will put its children directly under the FBX root, and vice-versa for reading"); } diff --git a/src/osgPlugins/fbx/WriterCompareTriangle.cpp b/src/osgPlugins/fbx/WriterCompareTriangle.cpp new file mode 100644 index 000000000..ec69a5a70 --- /dev/null +++ b/src/osgPlugins/fbx/WriterCompareTriangle.cpp @@ -0,0 +1,150 @@ +#include "WriterCompareTriangle.h" + +WriterCompareTriangle::WriterCompareTriangle(const osg::Geode & geode, + unsigned int nbVertices) + : geode(geode) +{ + cutscene(nbVertices, geode.getDrawable ( 0 )->asGeometry()->getBound()); +} + +bool +WriterCompareTriangle::operator()(const std::pair & t1, + const std::pair & t2) const +{ + const osg::Geometry *g = geode.getDrawable( t1.second )->asGeometry(); + + const osg::Vec3Array * vecs= static_cast(g->getVertexArray()); + const osg::Vec3::value_type x1 = (*vecs)[t1.first.t1].x(); + const osg::Vec3::value_type y1 = (*vecs)[t1.first.t1].y(); + const osg::Vec3::value_type z1 = (*vecs)[t1.first.t1].z(); + + if (t1.second != t2.second) + { + const osg::Geometry *g = geode.getDrawable( t2.second )->asGeometry(); + vecs = static_cast(g->getVertexArray()); + }; + const osg::Vec3::value_type x2 = (*vecs)[t2.first.t1].x(); + const osg::Vec3::value_type y2 = (*vecs)[t2.first.t1].y(); + const osg::Vec3::value_type z2 = (*vecs)[t2.first.t1].z(); + int val1 = inWhichBox(x1,y1,z1); + int val2 = inWhichBox(x2,y2,z2); + + return (val1 < val2); +}; + +void +WriterCompareTriangle::setMaxMin(unsigned int & nbVerticesX, + unsigned int & nbVerticesY, + unsigned int & nbVerticesZ) const +{ + static const unsigned int min = 1; + if (nbVerticesX < min) + nbVerticesX = min; + if (nbVerticesY < min) + nbVerticesY = min; + if (nbVerticesZ < min) + nbVerticesZ = min; + + static const unsigned int max = 20; + + if (nbVerticesX > max) + nbVerticesX = max; + if (nbVerticesY > max) + nbVerticesY = max; + if (nbVerticesZ > max) + nbVerticesZ = max; +} + +void +WriterCompareTriangle::cutscene(int nbVertices, + const osg::BoundingBox & sceneBox) +{ + osg::BoundingBox::vec_type length = sceneBox._max - sceneBox._min; + + static const unsigned int k = 4; + + unsigned int nbVerticesX = (nbVertices * k) / (length.z() * length.y()); + unsigned int nbVerticesY = (nbVertices * k) / (length.z() * length.x()); + unsigned int nbVerticesZ = (nbVertices * k) / (length.x() * length.y()); + + setMaxMin (nbVerticesX, nbVerticesY, nbVerticesZ); // This function prevent from cut scene in too many blocs + + osg::notify(osg::DEBUG_INFO) << "Cutting x by " << nbVerticesX << std::endl + << "Cutting y by " << nbVerticesY << std::endl + << "Cutting z by " << nbVerticesZ << std::endl; + + osg::BoundingBox::value_type blocX = length.x() / nbVerticesX; //This 3 lines set the size of a bloc in x, y and z + osg::BoundingBox::value_type blocY = length.y() / nbVerticesY; + osg::BoundingBox::value_type blocZ = length.z() / nbVerticesZ; + + boxList.reserve(nbVerticesX * nbVerticesY * nbVerticesZ); + short yinc = 1; + short xinc = 1; + unsigned int y = 0; + unsigned int x = 0; + for (unsigned int z = 0; z < nbVerticesZ; ++z) + { + while (x < nbVerticesX && x >= 0) + { + while (y < nbVerticesY && y >= 0) + { + osg::BoundingBox::value_type xMin = sceneBox.xMin() + x * blocX; + if (x == 0) //to prevent from mesh with no case + xMin -= 10; + + osg::BoundingBox::value_type yMin = sceneBox.yMin() + y * blocY; + if (y == 0) //to prevent from mesh with no case + yMin -= 10; + + osg::BoundingBox::value_type zMin = sceneBox.zMin() + z * blocZ; + if (z == 0) //to prevent from mesh with no case + zMin -= 10; + + osg::BoundingBox::value_type xMax = sceneBox.xMin() + (x + 1) * blocX; + if (x == nbVerticesX - 1) //to prevent from mesh with no case + xMax += 10; + + osg::BoundingBox::value_type yMax = sceneBox.yMin() + (y + 1) * blocY; + if (y == nbVerticesY - 1) //to prevent from mesh with no case + yMax += 10; + + osg::BoundingBox::value_type zMax = sceneBox.zMin() + (z + 1) * blocZ; + if (z == nbVerticesZ - 1) //to prevent from mesh with no case + zMax += 10; + + boxList.push_back(osg::BoundingBox(xMin, // Add a bloc to the list + yMin, + zMin, + xMax, + yMax, + zMax)); + y += yinc; + } + yinc = -yinc; + y += yinc; + x += xinc; + } + xinc = -xinc; + x += xinc; + } +} + +int +WriterCompareTriangle::inWhichBox(const osg::Vec3::value_type x, + const osg::Vec3::value_type y, + const osg::Vec3::value_type z) const +{ + for (unsigned int i = 0; i < boxList.size(); ++i) + { + if (x >= boxList[i].xMin() && + x < boxList[i].xMax() && + y >= boxList[i].yMin() && + y < boxList[i].yMax() && + z >= boxList[i].zMin() && + z < boxList[i].zMax()) + { + return i; + } + } + throw "Point is not in any blocs"; +} \ No newline at end of file diff --git a/src/osgPlugins/fbx/WriterCompareTriangle.h b/src/osgPlugins/fbx/WriterCompareTriangle.h new file mode 100644 index 000000000..bcfec0035 --- /dev/null +++ b/src/osgPlugins/fbx/WriterCompareTriangle.h @@ -0,0 +1,51 @@ +#ifndef _3DS_WRITER_COMPARE_TRIANGLE_HEADER__ +#define _3DS_WRITER_COMPARE_TRIANGLE_HEADER__ + +#include +#include +#include + +struct Triangle +{ + unsigned int t1; + unsigned int t2; + unsigned int t3; + unsigned int material; +}; + +class WriterCompareTriangle { +public: + WriterCompareTriangle(const osg::Geode & geode, + unsigned int nbVertices); + + bool operator()(const std::pair & t1, + const std::pair & t2) const; +private: + void // This function prevent from cut scene in too many blocs + setMaxMin(unsigned int & nbVerticesX, + unsigned int & nbVerticesY, + unsigned int & nbVerticesZ) const; + + /** + * Cut the scene in different bloc to sort. + * \param nbVertices is the number of vertice in mesh. + * \param sceneBox contain the size of the scene. + */ + void + cutscene(int nbVertices, + const osg::BoundingBox & sceneBox); + + /** + * Find in which box those points are. + * \return the place of the box in the vector. + * \sa See cutScene() about the definition of the boxes for faces sorting. + */ + int inWhichBox(const osg::Vec3::value_type x, + const osg::Vec3::value_type y, + const osg::Vec3::value_type z) const; + + const osg::Geode & geode; + std::vector boxList; +}; + +#endif // _3DS_WRITER_COMPARE_TRIANGLE_HEADER__ \ No newline at end of file diff --git a/src/osgPlugins/fbx/WriterNodeVisitor.cpp b/src/osgPlugins/fbx/WriterNodeVisitor.cpp index d8e00564a..08c80001a 100644 --- a/src/osgPlugins/fbx/WriterNodeVisitor.cpp +++ b/src/osgPlugins/fbx/WriterNodeVisitor.cpp @@ -39,10 +39,20 @@ public: _lastFaceIndex(0), _listTriangles(listTriangles), _drawable_n(drawable_n), - _material(material) + _material(material), + //_iPrimitiveSet(iPrimitiveSet), + _curNormalIndex(0), + _normalBinding(geo->getNormalBinding()) { + if (!geo->getNormalArray() || geo->getNormalArray()->getNumElements()==0) + { + _normalBinding = osg::Geometry::BIND_OFF; // Turn off binding if there is no normal data + } + reset(); } + void reset() { _curNormalIndex = 0; } + unsigned int getNextFaceIndex() { return _lastFaceIndex; } virtual void setVertexArray(unsigned int, const osg::Vec2*) {} @@ -64,6 +74,7 @@ public: triangle.t1 = i1; triangle.t2 = i2; triangle.t3 = i3; + triangle.normalIndex = _curNormalIndex; triangle.material = _material; _listTriangles.push_back(std::make_pair(triangle, _drawable_n)); } @@ -117,8 +128,10 @@ protected: { IndexPointer ilast = indices + count; for (IndexPointer iptr = indices; iptr < ilast; iptr+=3) + { writeTriangle(iptr[0], iptr[1], iptr[2]); - + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; + } break; } case GL_TRIANGLE_STRIP: @@ -129,6 +142,7 @@ protected: if (i & 1) writeTriangle(iptr[0], iptr[2], iptr[1]); else writeTriangle(iptr[0], iptr[1], iptr[2]); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; } case GL_QUADS: @@ -138,6 +152,7 @@ protected: { writeTriangle(iptr[0], iptr[1], iptr[2]); writeTriangle(iptr[0], iptr[2], iptr[3]); + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; } break; } @@ -149,6 +164,7 @@ protected: writeTriangle(iptr[0], iptr[1], iptr[2]); writeTriangle(iptr[1], iptr[3], iptr[2]); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; } case GL_POLYGON: // treat polygons as GL_TRIANGLE_FAN @@ -161,6 +177,7 @@ protected: { writeTriangle(first, iptr[0], iptr[1]); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; } case GL_POINTS: @@ -173,10 +190,11 @@ protected: // uhm should never come to this point :) break; } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE_SET) ++_curNormalIndex; } private: - PrimitiveIndexWriter& operator = (const PrimitiveIndexWriter&) { return *this; } + PrimitiveIndexWriter& operator = (const PrimitiveIndexWriter&); // { return *this; } unsigned int _drawable_n; ListTriangle& _listTriangles; @@ -186,6 +204,8 @@ private: const osg::Geometry* _geo; unsigned int _lastFaceIndex; int _material; + unsigned int _curNormalIndex; + osg::Geometry::AttributeBinding _normalBinding; KFbxMesh* _mesh; }; @@ -198,6 +218,7 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) for (GLsizei i = 2; i < count; i += 3, pos += 3) { writeTriangle(pos, pos + 1, pos + 2); + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; } break; case GL_TRIANGLE_STRIP: @@ -206,12 +227,14 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) if (i & 1) writeTriangle(pos, pos + 2, pos + 1); else writeTriangle(pos, pos + 1, pos + 2); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; case GL_QUADS: for (GLsizei i = 3; i < count; i += 4, pos += 4) { writeTriangle(pos, pos + 1, pos + 2); writeTriangle(pos, pos + 2, pos + 3); + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; } break; case GL_QUAD_STRIP: @@ -220,6 +243,7 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) writeTriangle(pos, pos + 1, pos + 2); writeTriangle(pos + 1, pos + 3, pos + 2); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; case GL_POLYGON: // treat polygons as GL_TRIANGLE_FAN case GL_TRIANGLE_FAN: @@ -228,6 +252,7 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) { writeTriangle(first, pos, pos+1); } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE) ++_curNormalIndex; break; case GL_POINTS: case GL_LINES: @@ -237,6 +262,7 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) osg::notify(osg::WARN) << "WriterNodeVisitor :: can't handle mode " << mode << std::endl; break; } + if (_normalBinding == osg::Geometry::BIND_PER_PRIMITIVE_SET) ++_curNormalIndex; } // If 'to' is in a subdirectory of 'from' then this function returns the @@ -398,6 +424,10 @@ WriterNodeVisitor::Material::Material(WriterNodeVisitor& writerNodeVisitor, destPath = osgDB::getRealPath(osgDB::convertFileNameToNativeStyle( osgDB::concatPaths(_directory, relativePath) )); if (destPath != canonicalPath) { + if (!osgDB::makeDirectoryForFile(destPath)) + { + osg::notify(osg::NOTICE) << "Can't create directory for file '" << destPath << "'. May fail creating the image file." << std::endl; + } osgDB::writeImageFile(*_osgImage, destPath); } } @@ -438,28 +468,27 @@ int WriterNodeVisitor::processStateSet(const osg::StateSet* ss) return -1; } -/** -* Add a vertex to the index and link him with the Triangle index and the drawable. -* \param index_vert is the map where the vertices are stored. -* \param index is the index of the vertices position in the vec3. -* \param drawable_n is the number of the drawable. -* \return the position of the vertex in the final mesh. -*/ -unsigned int -WriterNodeVisitor::getMeshIndexForGeometryIndex(MapIndices& index_vert, - unsigned int index, - unsigned int drawable_n) +unsigned int addPolygon(MapIndices & index_vert, unsigned int vertIndex, unsigned int normIndex, unsigned int drawableNum) { - MapIndices::iterator itIndex = index_vert.find(std::make_pair(index, drawable_n)); + VertexIndex vert(vertIndex, drawableNum, normIndex); + MapIndices::iterator itIndex = index_vert.find(vert); if (itIndex == index_vert.end()) { unsigned int indexMesh = index_vert.size(); - index_vert.insert(std::make_pair(std::make_pair(index, drawable_n), indexMesh)); + index_vert.insert(std::make_pair(vert, indexMesh)); return indexMesh; } return itIndex->second; } +void addPolygon(KFbxMesh * mesh, MapIndices & index_vert, const Triangle & tri, unsigned int drawableNum) +{ + mesh->AddPolygon(addPolygon(index_vert, tri.t1, tri.normalIndex, drawableNum)); + mesh->AddPolygon(addPolygon(index_vert, tri.t2, tri.normalIndex, drawableNum)); + mesh->AddPolygon(addPolygon(index_vert, tri.t3, tri.normalIndex, drawableNum)); +} + + void WriterNodeVisitor::setLayerTextureAndMaterial(KFbxMesh* mesh) { @@ -495,6 +524,7 @@ WriterNodeVisitor::setControlPointAndNormalsAndUV(const osg::Geode& geo, { mesh->InitControlPoints(index_vert.size()); KFbxLayerElementNormal* lLayerElementNormal= KFbxLayerElementNormal::Create(mesh, ""); + // For now, FBX writer only supports normals bound per vertices lLayerElementNormal->SetMappingMode(KFbxLayerElement::eBY_CONTROL_POINT); lLayerElementNormal->SetReferenceMode(KFbxLayerElement::eDIRECT); lLayerElementNormal->GetDirectArray().SetCount(index_vert.size()); @@ -511,53 +541,100 @@ WriterNodeVisitor::setControlPointAndNormalsAndUV(const osg::Geode& geo, for (MapIndices::iterator it = index_vert.begin(); it != index_vert.end(); ++it) { - const osg::Geometry* pGeometry = geo.getDrawable(it->first.second)->asGeometry(); - assert(pGeometry->getVertexArray()); + const osg::Geometry* pGeometry = geo.getDrawable(it->first.drawableIndex)->asGeometry(); + unsigned int vertexIndex = it->first.vertexIndex; + unsigned int normalIndex = it->first.normalIndex; - if (pGeometry->getVertexArray()->getType() != osg::Array::Vec3ArrayType) + const osg::Array * basevecs = pGeometry->getVertexArray(); + assert(basevecs); + if (!basevecs || basevecs->getNumElements()==0) { - throw "Vertex array is not Vec3. Not implemented"; // TODO + //OSG_NOTIFY() + continue; } - - const osg::Vec3Array* vecs= static_cast(pGeometry->getVertexArray()); - if (vecs) + KFbxVector4 vertex; + if (basevecs->getType() == osg::Array::Vec3ArrayType) { - mesh->SetControlPointAt(*new KFbxVector4( - (*vecs)[it->first.first].x(), - (*vecs)[it->first.first].y(), - (*vecs)[it->first.first].z()), it->second); + const osg::Vec3 & vec = (*static_cast(basevecs))[vertexIndex]; + // Sukender: "*new KFbxVector4"? Shouldn't it be "KFbxVector4" alone? + //mesh->SetControlPointAt(*new KFbxVector4(vec.x(), vec.y(), vec.z()), it->second); + vertex.Set(vec.x(), vec.y(), vec.z()); } - - const osg::Vec3Array* pNormals = static_cast(pGeometry->getNormalArray()); - - if (pNormals) + else if (basevecs->getType() == osg::Array::Vec3dArrayType) { - switch (pGeometry->getNormalBinding()) + const osg::Vec3d & vec = (*static_cast(basevecs))[vertexIndex]; + // Sukender: "*new KFbxVector4"? Shouldn't it be "KFbxVector4" alone? + //mesh->SetControlPointAt(*new KFbxVector4(vec.x(), vec.y(), vec.z()), it->second); + vertex.Set(vec.x(), vec.y(), vec.z()); + } + else + { + OSG_NOTIFY(osg::FATAL) << "Vertex array is not Vec3 or Vec3d. Not implemented" << std::endl; + throw "Vertex array is not Vec3 or Vec3d. Not implemented"; + //_succeeded = false; + //return; + } + mesh->SetControlPointAt(vertex, it->second); + + + const osg::Array * basenormals = pGeometry->getNormalArray(); + if (basenormals && basenormals->getNumElements()>0) + { + KFbxVector4 normal; + if (basenormals->getType() == osg::Array::Vec3ArrayType) { - case osg::Geometry::BIND_PER_PRIMITIVE_SET: - case osg::Geometry::BIND_PER_PRIMITIVE: - lLayerElementNormal->GetDirectArray().SetAt(it->second, - KFbxVector4( - (*pNormals)[0].x(), - (*pNormals)[0].y(), - (*pNormals)[0].z(), 0)); - break; + const osg::Vec3 & vec = (*static_cast(basenormals))[normalIndex]; + normal.Set(vec.x(), vec.y(), vec.z(), 0); + } + else if (basenormals->getType() == osg::Array::Vec3dArrayType) + { + const osg::Vec3d & vec = (*static_cast(basenormals))[normalIndex]; + normal.Set(vec.x(), vec.y(), vec.z(), 0); + } + else + { + OSG_NOTIFY(osg::FATAL) << "Normal array is not Vec3 or Vec3d. Not implemented" << std::endl; + throw "Normal array is not Vec3 or Vec3d. Not implemented"; + //_succeeded = false; + //return; + } - case osg::Geometry::BIND_PER_VERTEX: - lLayerElementNormal->GetDirectArray().SetAt(it->second, - KFbxVector4( - (*pNormals)[it->first.first].x(), - (*pNormals)[it->first.first].y(), - (*pNormals)[it->first.first].z(), 0)); - break; - } + //switch (pGeometry->getNormalBinding()) + //{ + //case osg::Geometry::BIND_PER_PRIMITIVE_SET: + //case osg::Geometry::BIND_PER_PRIMITIVE: + //case osg::Geometry::BIND_PER_VERTEX: + // break; + //} + lLayerElementNormal->GetDirectArray().SetAt(it->second, normal); } if (texcoords) { - const osg::Vec2Array* vec2= static_cast(pGeometry->getTexCoordArray(0)); - if (vec2) - lUVDiffuseLayer->GetDirectArray().SetAt(it->second, KFbxVector2((*vec2)[it->first.first].x(), (*vec2)[it->first.first].y())); + const osg::Array * basetexcoords = pGeometry->getTexCoordArray(0); + if (basetexcoords && basetexcoords->getNumElements()>0) + { + KFbxVector2 texcoord; + if (basetexcoords->getType() == osg::Array::Vec2ArrayType) + { + const osg::Vec2 & vec = (*static_cast(basetexcoords))[vertexIndex]; + texcoord.Set(vec.x(), vec.y()); + } + else if (basetexcoords->getType() == osg::Array::Vec2dArrayType) + { + const osg::Vec2d & vec = (*static_cast(basetexcoords))[vertexIndex]; + texcoord.Set(vec.x(), vec.y()); + } + else + { + OSG_NOTIFY(osg::FATAL) << "Texture coords array is not Vec2 or Vec2d. Not implemented" << std::endl; + throw "Texture coords array is not Vec2 or Vec2d. Not implemented"; + //_succeeded = false; + //return; + } + + lUVDiffuseLayer->GetDirectArray().SetAt(it->second, texcoord); + } } } } @@ -593,9 +670,7 @@ void WriterNodeVisitor::buildFaces(const osg::Geode& geo, lLayer->GetDiffuseTextures()->GetIndexArray().SetAt(i, it->first.material); lLayer->GetMaterials()->GetIndexArray().SetAt(i, it->first.material); } - mesh->AddPolygon(getMeshIndexForGeometryIndex(index_vert, it->first.t1, it->second)); - mesh->AddPolygon(getMeshIndexForGeometryIndex(index_vert, it->first.t2, it->second)); - mesh->AddPolygon(getMeshIndexForGeometryIndex(index_vert, it->first.t3, it->second)); + addPolygon(mesh, index_vert, it->first, it->second); mesh->EndPolygon(); } setControlPointAndNormalsAndUV(geo, index_vert, texcoords, mesh); @@ -607,33 +682,23 @@ void WriterNodeVisitor::createListTriangle(const osg::Geometry* geo, unsigned int& drawable_n) { unsigned int nbVertices = 0; + texcoords = false; { - if (geo->getVertexArray() && geo->getVertexArray()->getType() != osg::Array::Vec3ArrayType) - { - throw "Vertex array is not Vec3. Not implemented"; // TODO - } - - const osg::Vec3Array* vecs = static_cast(geo->getVertexArray()); + const osg::Array * vecs = geo->getVertexArray(); if (vecs) { - nbVertices = geo->getVertexArray()->getNumElements(); + nbVertices = vecs->getNumElements(); + // Texture coords - if (geo->getTexCoordArray(0) && geo->getTexCoordArray(0)->getType() != osg::Array::Vec2ArrayType) + const osg::Array * texvec = geo->getTexCoordArray(0); + if (texvec) { - throw "Texture coords array is not Vec2. Not implemented"; // TODO - } - - const osg::Vec2Array* texvecs = static_cast(geo->getTexCoordArray(0)); - if (texvecs) - { - unsigned int nb = geo->getTexCoordArray(0)->getNumElements(); - - if (nb != geo->getVertexArray()->getNumElements()) + unsigned int nb = texvec->getNumElements(); + if (nb == nbVertices) texcoords = true; + else { - throw "There are more/less texture coords than vertices!"; + OSG_NOTIFY(osg::WARN) << "There are more/less texture coords than vertices! Ignoring texture coords."; } - - texcoords = true; } } } @@ -642,10 +707,10 @@ void WriterNodeVisitor::createListTriangle(const osg::Geometry* geo, int material = processStateSet(_currentStateSet.get()); - for (unsigned int i = 0; i < geo->getNumPrimitiveSets(); ++i) //Fill the Triangle List + PrimitiveIndexWriter pif(geo, listTriangles, drawable_n, material); + for (unsigned int iPrimSet = 0; iPrimSet < geo->getNumPrimitiveSets(); ++iPrimSet) //Fill the Triangle List { - const osg::PrimitiveSet* ps = geo->getPrimitiveSet(i); - PrimitiveIndexWriter pif(geo, listTriangles, drawable_n, material); + const osg::PrimitiveSet* ps = geo->getPrimitiveSet(iPrimSet); const_cast(ps)->accept(pif); } } diff --git a/src/osgPlugins/fbx/WriterNodeVisitor.h b/src/osgPlugins/fbx/WriterNodeVisitor.h index 381c27ffb..ef4240a32 100644 --- a/src/osgPlugins/fbx/WriterNodeVisitor.h +++ b/src/osgPlugins/fbx/WriterNodeVisitor.h @@ -35,13 +35,32 @@ struct Triangle unsigned int t1; unsigned int t2; unsigned int t3; + unsigned int normalIndex; ///< Normal index for all bindings except BIND_PER_VERTEX and BIND_OFF. int material; }; -typedef std::map, unsigned int> MapIndices; -typedef std::vector > ListTriangle; //the int is the drawable of the triangle +struct VertexIndex +{ + VertexIndex(unsigned int vertexIndex, unsigned int drawableIndex, unsigned int normalIndex) + : vertexIndex(vertexIndex), drawableIndex(drawableIndex), normalIndex(normalIndex) + {} + VertexIndex(const VertexIndex & v) : vertexIndex(v.vertexIndex), drawableIndex(v.drawableIndex), normalIndex(v.normalIndex) {} -///\author Capo (Thibault Caporal) + unsigned int vertexIndex; ///< Index of the vertice position in the vec3 array + unsigned int drawableIndex; + unsigned int normalIndex; ///< Normal index for all bindings except BIND_PER_VERTEX and BIND_OFF. + + bool operator<(const VertexIndex & v) const { + if (drawableIndex!=v.drawableIndex) return drawableIndex > ListTriangle; //the int is the drawable of the triangle +typedef std::map MapIndices; ///< Map OSG indices to FBX mesh indices + + +///\author Capo (Thibault Caporal), Sukender (Benoit Neil) class WriterNodeVisitor: public osg::NodeVisitor { public: @@ -192,17 +211,6 @@ class WriterNodeVisitor: public osg::NodeVisitor bool texcoords, KFbxMesh* fbxMesh); - /** - * Add a vertex to the index and link him with the Triangle index and the drawable. - * \param index_vert is the map where the vertices are stored. - * \param index is the indices of the vertices position in the vec3. - * \param drawable_n is the number of the drawable. - * \return the position of the vertices in the final mesh. - */ - unsigned int getMeshIndexForGeometryIndex(MapIndices& index_vert, - unsigned int index, - unsigned int drawable_n); - /** * Create the list of faces from the geode. * \param geo is the geode to study.