Skip to content

Commit

Permalink
GLTF Import - Edge and Vertex support #242
Browse files Browse the repository at this point in the history
Added functionality to import Points and Lines from GLTF format
  • Loading branch information
mzernova committed Jan 21, 2025
1 parent 82bad1a commit e1127c2
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 163 deletions.
125 changes: 99 additions & 26 deletions src/RWGltf/RWGltf_GltfJsonParser.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "RWGltf_GltfJsonParser.hxx"

#include <BRep_Builder.hxx>
#include <gp_Quaternion.hxx>
#include <FSD_Base64.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <Message_ProgressScope.hxx>
Expand All @@ -24,11 +24,13 @@
#include <OSD_Path.hxx>
#include <OSD_ThreadPool.hxx>
#include <Precision.hxx>
#include <FSD_Base64.hxx>
#include <RWGltf_TriangulationReader.hxx>
#include <TDataStd_NamedData.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Iterator.hxx>
#include <gp_Quaternion.hxx>

#include <fstream>

Expand Down Expand Up @@ -1530,7 +1532,9 @@ bool RWGltf_GltfJsonParser::gltfParseSceneNodes (TopTools_SequenceOfShape& theSh
continue;
}
else if (myToSkipEmptyNodes
&& !TopExp_Explorer (aNodeShape, TopAbs_FACE).More())
&& !TopExp_Explorer (aNodeShape, TopAbs_FACE).More()
&& !TopExp_Explorer (aNodeShape, TopAbs_EDGE).More()
&& !TopExp_Explorer (aNodeShape, TopAbs_VERTEX).More())
{
continue;
}
Expand Down Expand Up @@ -1782,7 +1786,9 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape,
return false;
}
}
if (aMode != RWGltf_GltfPrimitiveMode_Triangles)
if (aMode != RWGltf_GltfPrimitiveMode_Triangles
&& aMode != RWGltf_GltfPrimitiveMode_Lines
&& aMode != RWGltf_GltfPrimitiveMode_Points)
{
Message::SendWarning (TCollection_AsciiString() + "Primitive array within Mesh '" + theMeshId + "' skipped due to unsupported mode");
return true;
Expand Down Expand Up @@ -1827,19 +1833,15 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape,
{
if (myAttribMap != NULL)
{
// sharing just triangulation is not much useful
//Handle(RWGltf_GltfLatePrimitiveArray) aLateData = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast (BRep_Tool::Triangulation (TopoDS::Face (thePrimArrayShape), aDummy));
//TopoDS_Face aFaceCopy; BRep_Builder().MakeFace (aFaceCopy, aLateData);

// make a located Face copy
TopoDS_Shape aFaceCopy = thePrimArrayShape;
aFaceCopy.Location (TopLoc_Location (gp_Trsf()));
// make a located Shape copy
TopoDS_Shape aShapeCopy = thePrimArrayShape;
aShapeCopy.Location (TopLoc_Location (gp_Trsf()));
RWMesh_NodeAttributes aShapeAttribs;
aShapeAttribs.RawName = theMeshName;
aShapeAttribs.Style.SetMaterial (aMat);
myAttribMap->Bind (aFaceCopy, aShapeAttribs);
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aFaceCopy);
thePrimArrayShape = aFaceCopy;
myAttribMap->Bind (aShapeCopy, aShapeAttribs);
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aShapeCopy);
thePrimArrayShape = aShapeCopy;
}
return true;
}
Expand Down Expand Up @@ -1906,32 +1908,95 @@ bool RWGltf_GltfJsonParser::gltfParsePrimArray (TopoDS_Shape& thePrimArrayShape,
return false;
}
}
else
else if (aMode == RWGltf_GltfPrimitiveMode_Triangles)
{
aMeshData->SetNbDeferredTriangles (aMeshData->NbDeferredNodes() / 3);
}
else
{
aMeshData->SetNbDeferredTriangles (0);
}

if (!aMeshData->Data().IsEmpty())
{
TopoDS_Face aFace;
BRep_Builder aBuilder;
aBuilder.MakeFace (aFace, aMeshData);
if (aMode != RWGltf_GltfPrimitiveMode_Triangles)
{
Message::SendWarning("Deferred loading is available only for triangulations. Other elements "
"will be loaded immediately.");
Handle(RWGltf_TriangulationReader) aReader = new RWGltf_TriangulationReader();
aReader->SetCoordinateSystemConverter(myCSTrsf);
aMeshData->SetReader(aReader);
aMeshData->LoadDeferredData();
}

TopoDS_Shape aShape;
switch (aMode)
{
case RWGltf_GltfPrimitiveMode_Points: {
BRep_Builder aBuilder;
TopoDS_Compound aVertices;
aBuilder.MakeCompound(aVertices);
for (Standard_Integer aNodeIdx = 1; aNodeIdx <= aMeshData->NbNodes(); ++aNodeIdx)
{
//gp_Pnt point = aMeshData->Node(aNodeIdx);
//Message::SendInfo() << "Node Points " << i << ": (" << point.X() << ", " << point.Y()
// << ", " << point.Z() << ")";

TopoDS_Vertex aVertex;
aBuilder.MakeVertex(aVertex, aMeshData->Node(aNodeIdx), Precision::Confusion());
aBuilder.Add(aVertices, aVertex);
}
aShape = aVertices;
break;
}
case RWGltf_GltfPrimitiveMode_Lines: {
TColgp_Array1OfPnt aNodes(1, aMeshData->NbEdges());
for (Standard_Integer anEdgeIdx = 1; anEdgeIdx <= aMeshData->NbEdges(); ++anEdgeIdx)
{
Standard_Integer aNodeIdx = aMeshData->Edge(anEdgeIdx);
aNodes.SetValue(anEdgeIdx, aMeshData->Node(aNodeIdx));

//gp_Pnt point = aMeshData->Node(aNodeIdx);
//Message::SendInfo() << "Node Lines " << aNodeIdx << ": (" << point.X() << ", "
// << point.Y() << ", " << point.Z() << ")";
}
TopoDS_Edge anEdge;
BRep_Builder aBuilder;
Handle(Poly_Polygon3D) aPoly = new Poly_Polygon3D(aNodes);
aBuilder.MakeEdge(anEdge, aPoly);

aShape = anEdge;
break;
}
case RWGltf_GltfPrimitiveMode_Triangles: {
TopoDS_Face aFace;
BRep_Builder aBuilder;
aBuilder.MakeFace(aFace, aMeshData);
aShape = aFace;
myFaceList.Append(aFace);
break;
}
default: {
Message::SendFail("Unsupported primitive mode.");
return false;
break;
}
}
if (myAttribMap != NULL
&& aMeshData->HasStyle())
&& aMeshData->HasStyle())
{
RWMesh_NodeAttributes aShapeAttribs;
aShapeAttribs.RawName = theMeshName;

// assign material and not color
//aShapeAttribs.Style.SetColorSurf (aMeshData->BaseColor());
aShapeAttribs.Style.SetMaterial (aMat);
aShapeAttribs.Style.SetMaterial(aMat);

myAttribMap->Bind (aFace, aShapeAttribs);
myAttribMap->Bind (aShape, aShapeAttribs);
}
myFaceList.Append (aFace);
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayId, aFace);
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aFace);
thePrimArrayShape = aFace;
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayId, aShape);
myShapeMap[ShapeMapGroup_PrimArray].Bind (aPrimArrayIdWithMat, aShape);
thePrimArrayShape = aShape;
}
return true;
}
Expand Down Expand Up @@ -2085,7 +2150,15 @@ bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimi
}
else if (theType == RWGltf_GltfArrayType_Indices)
{
theMeshData->SetNbDeferredTriangles ((Standard_Integer )(aStruct.Count / 3));
if (theMeshData->PrimitiveMode() == RWGltf_GltfPrimitiveMode_Triangles)
{
theMeshData->SetNbDeferredTriangles ((Standard_Integer)(aStruct.Count / 3));
}
else
{
theMeshData->SetNbDeferredNodes ((Standard_Integer)(aStruct.Count));
theMeshData->SetNbDeferredTriangles (0);
}
}

const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
Expand Down
2 changes: 1 addition & 1 deletion src/RWGltf/RWGltf_GltfLatePrimitiveArray.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Handle(Poly_Triangulation) RWGltf_GltfLatePrimitiveArray::LoadStreamData() const
{
return Handle(Poly_Triangulation)();
}
Handle(Poly_Triangulation) aResult = createNewEntity();
Handle(RWMesh_TriangulationSource) aResult = new RWMesh_TriangulationSource();
if (!aGltfReader->LoadStreamData (this, aResult))
{
return Handle(Poly_Triangulation)();
Expand Down
2 changes: 1 addition & 1 deletion src/RWGltf/RWGltf_GltfLatePrimitiveArray.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public:
//! that can be loaded using LoadDeferredData().
virtual Standard_Boolean HasDeferredData() const Standard_OVERRIDE
{
return !myData.IsEmpty() && RWMesh_TriangulationSource::HasDeferredData();
return !myData.IsEmpty() && (NbDeferredTriangles() > 0 || NbDeferredNodes() > 0);
}

//! Load primitive array saved as stream buffer to new triangulation object.
Expand Down
85 changes: 51 additions & 34 deletions src/RWGltf/RWGltf_TriangulationReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void RWGltf_TriangulationReader::reportError (const TCollection_AsciiString& the
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::LoadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh) const
const Handle(RWMesh_TriangulationSource)& theDestMesh) const
{
Standard_ASSERT_RETURN (!theDestMesh.IsNull(), "The destination mesh should be initialized before loading data to it", false);
theDestMesh->Clear();
Expand All @@ -132,7 +132,7 @@ bool RWGltf_TriangulationReader::LoadStreamData (const Handle(RWMesh_Triangulati
// =======================================================================
bool RWGltf_TriangulationReader::readStreamData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh) const
const Handle(RWMesh_TriangulationSource)& theDestMesh) const
{
Standard_ArrayStreamBuffer aStreamBuffer ((const char* )theGltfData.StreamData->Data(), theGltfData.StreamData->Size());
std::istream aStream (&aStreamBuffer);
Expand All @@ -150,7 +150,7 @@ bool RWGltf_TriangulationReader::readStreamData (const Handle(RWGltf_GltfLatePri
// =======================================================================
bool RWGltf_TriangulationReader::readFileData (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(RWMesh_TriangulationSource)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const Handle(OSD_FileSystem)& aFileSystem = !theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
Expand All @@ -174,7 +174,7 @@ bool RWGltf_TriangulationReader::readFileData (const Handle(RWGltf_GltfLatePrimi
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::loadStreamData (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(RWMesh_TriangulationSource)& theDestMesh,
bool theToResetStream) const
{
const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
Expand Down Expand Up @@ -210,7 +210,7 @@ bool RWGltf_TriangulationReader::loadStreamData (const Handle(RWMesh_Triangulati
// =======================================================================
bool RWGltf_TriangulationReader::readDracoBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(RWMesh_TriangulationSource)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const TCollection_AsciiString& aName = theSourceGltfMesh->Id();
Expand Down Expand Up @@ -422,7 +422,7 @@ bool RWGltf_TriangulationReader::readDracoBuffer (const Handle(RWGltf_GltfLatePr
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(RWMesh_TriangulationSource)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh = Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
Expand Down Expand Up @@ -477,7 +477,7 @@ bool RWGltf_TriangulationReader::load (const Handle(RWMesh_TriangulationSource)&
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::finalizeLoading (const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh) const
const Handle(RWMesh_TriangulationSource)& theDestMesh) const
{
if (theDestMesh->NbNodes() < 1)
{
Expand Down Expand Up @@ -514,16 +514,19 @@ bool RWGltf_TriangulationReader::finalizeLoading (const Handle(RWMesh_Triangulat
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(RWMesh_TriangulationSource)& theDestMesh,
std::istream& theStream,
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType) const

{
const TCollection_AsciiString& aName = theSourceMesh->Id();
if (theSourceMesh->PrimitiveMode() != RWGltf_GltfPrimitiveMode_Triangles)
const TCollection_AsciiString& aName = theSourceMesh->Id();
const RWGltf_GltfPrimitiveMode aPrimMode = theSourceMesh->PrimitiveMode();
if (aPrimMode != RWGltf_GltfPrimitiveMode_Triangles && aPrimMode != RWGltf_GltfPrimitiveMode_Lines
&& aPrimMode != RWGltf_GltfPrimitiveMode_Points)
{
Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' skipped unsupported primitive array");
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' skipped unsupported primitive array");
return true;
}

Expand All @@ -545,50 +548,64 @@ bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimiti
return false;
}

const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
if (!setNbTriangles (theDestMesh, aNbTris))
const Standard_Boolean isTriangles = aPrimMode == RWGltf_GltfPrimitiveMode_Triangles;
const Standard_Integer aCounter = isTriangles
? (Standard_Integer )(theAccessor.Count / 3)
: (Standard_Integer )(theAccessor.Count);
if ((isTriangles && !setNbTriangles(theDestMesh, aCounter))
|| !setNbEdges(theDestMesh, aCounter))
{
return false;
}
const size_t aStride = theAccessor.ByteStride != 0
? theAccessor.ByteStride
: sizeof(uint16_t);
Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
Standard_Integer aLastTriIndex = 0;
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
Standard_Integer aLastIndex = 0;
for (Standard_Integer aTriIter = 0; aTriIter < aCounter; ++aTriIter)
{
if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
}
if (const uint16_t* anIndex1 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
}
if (const uint16_t* anIndex2 = aBuffer.ReadChunk<uint16_t> (theStream))
{
aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
Standard_Integer wasSet = false;
if (isTriangles)
{
for (Standard_Integer anIter = 1; anIter <= 3; ++anIter)
{
const uint16_t* anIndex = aBuffer.ReadChunk<uint16_t>(theStream);
if (anIndex == nullptr)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
aVec3.ChangeValue(anIter) = THE_LOWER_NODE_INDEX + *anIndex;
}
wasSet = setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastIndex, aVec3);
}
else
{
reportError (TCollection_AsciiString ("Buffer '") + aName + "' reading error.");
return false;
const uint16_t* anIndex = aBuffer.ReadChunk<uint16_t>(theStream);
if (anIndex == nullptr)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
wasSet = setEdge(theDestMesh,
THE_LOWER_TRI_INDEX + aLastIndex,
THE_LOWER_NODE_INDEX + *anIndex);
}

const Standard_Integer wasSet = setTriangle (theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
if (!wasSet)
{
reportError (TCollection_AsciiString ("Buffer '") + aName + "' refers to invalid indices.");
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to invalid indices.");
}
if (wasSet > 0)
{
aLastTriIndex++;
aLastIndex++;
}
}
const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
const Standard_Integer aNbDegenerate = aCounter - aLastIndex;
if (aNbDegenerate > 0)
{
if (aNbDegenerate == aNbTris)
if (aNbDegenerate == aCounter)
{
Message::SendWarning (TCollection_AsciiString("Buffer '") + aName + "' has been skipped (all elements are degenerative in)");
return false;
Expand All @@ -599,7 +616,7 @@ bool RWGltf_TriangulationReader::readBuffer (const Handle(RWGltf_GltfLatePrimiti
Message::SendTrace (TCollection_AsciiString() + aNbDegenerate
+ " degenerate triangles have been skipped while reading glTF triangulation '" + aName + "'");
}
if (!setNbTriangles (theDestMesh, aLastTriIndex, true))
if (!setNbTriangles (theDestMesh, aLastIndex, true))
{
return false;
}
Expand Down
Loading

0 comments on commit e1127c2

Please sign in to comment.