Jump to content

how am I supposed to export an indexed mesh from another applicaiton?


photo

Recommended Posts

I know that Unigine::Mesh is just a wrapper for internal Mesh class, and max/maya plugin use only internal Mesh class to export meshes into Unigine.

 

Objects need to manually triangulated in many DCC application, so the Mesh class gives best option to export this kind of geometry.

 

But what if I already have a indexed triangulated geometry?

 

Recently I need to export geometries from Revit( directly, not through fbx option), and in revit you always get a indexed triangluated geometry by using it's special interface called IExportContext. so I decided to use these codes ( in c# of course)

 

            foreach (XYZ vert in node.GetPoints())
                mesh.addVertex(current_surface, vert.X, vert.Y, vert.Z);

            foreach (UV uv in node.GetUVs())
                mesh.addTexCoord(current_surface, uv.U, uv.V);

            switch(node.DistributionOfNormals)
            {
                case DistributionOfNormals.AtEachPoint:
                    foreach(XYZ vnormal in node.GetNormals())
                    {
                        XYZ n = vnormal.Normalize();
                        mesh.addNormal(current_surface, n.X, n.Y, n.Z);
                    }
                    break;
                case DistributionOfNormals.OnePerFace:
                    XYZ fnormal = node.GetNormal(0).Normalize();
                    for (int i = 0; i < node.NumberOfPoints; i++)
                        mesh.addNormal(current_surface, fnormal.X, fnormal.Y, fnormal.Z);
                    break;
                case DistributionOfNormals.OnEachFacet:
                    foreach(XYZ enormal in node.GetNormals())
                    {
                        XYZ n = enormal.Normalize();
                        mesh.addNormal(current_surface, n.X, n.Y, n.Z);
                        mesh.addNormal(current_surface, n.X, n.Y, n.Z);
                        mesh.addNormal(current_surface, n.X, n.Y, n.Z);
                    }
                    break;

            }

            int start = mesh.getNumTIndices(current_surface);

            foreach(PolymeshFacet face in node.GetFacets())
            {
                mesh.addTIndex(face.V1 + start, current_surface);
                mesh.addTIndex(face.V2 + start, current_surface);
                mesh.addTIndex(face.V3 + start, current_surface);
            }

 

but after I save the mesh and load it into resourceeditor, I can see the surfaces, and uv all correct, but there is no geometry because resourceeditor told me there is no index data. I also tried to add the CIndex, it will cause the application to crash. If I choose to only add vertex, normal, uv and use Mesh::createIndex(), then everything works fine.

 

So my question is how can I directly export a indexed triangulated geometry use Mesh class? and what's difference of CIndex and TIndex?

Link to comment

Hello Steve,

 

Internally, mesh has two vertex and two index buffers. Let's clarify this:

 

1) CVertices — stores only vertex coordinates

2) TVertices — stores vertex attributes such as normals/tangents/color/uv and all that stuff

 

And here's the catch — in order to reduce data we can duplicate only for tvertices data and keep all cvertices without duplicates at all. More info here: https://developer.unigine.com/en/docs/1.0/scripting/library/class.mesh (see Vertex Indices section)

 

The idea is very very simple "let's not duplicate vertex positions and duplicate only their parameters if we have to do so". So on a basic level cvertex count may not be equal to tvertex count. 

 

And we have two index buffers as well so we can get proper cvertex and tvertex data for each mesh triangle.

 

3) CIndex — link to a cvertex

3) TIndex — link to a tvertex

 

CIndex count and TIndex count must be equal.

 

So make sure you're adding correct amount of cvertex and tvertex data and both cindex and tindex buffers have valid indices. Also, look at samples/objects/dynamic_01 - dynamic_05 samples.

 

Also, don't forget to call mesh.addTriangles(1) before you add its indices.

Link to comment

Also, don't forget to call mesh.addTriangles(1) before you add its indices.

 

thanks for this info, I'll try it tomorrow, and seems there is no addTriangles member function in mesh class?

 

and another info, revit's indexed meshes are using traditional way, which is every vertex contains position, normal, uv. so I think the unigine way is much better and much efficient. and every mesh exported from revit is very complex, so I want to know if it's own indexed format will create a smaller mesh file(smaller mesh file means smaller buffer, means smaller video memory usage, right?)

Link to comment

still can not make this work:

 

            foreach (XYZ vert in node.GetPoints())
                mesh.addVertex(current_surface, vert.X, vert.Y, vert.Z);

            foreach (UV uv in node.GetUVs())
                mesh.addTexCoord(current_surface, uv.U, uv.V);

            switch(node.DistributionOfNormals)
            {
                case DistributionOfNormals.AtEachPoint:
                    foreach(XYZ vnormal in node.GetNormals())
                        mesh.addNormal(current_surface, vnormal.X, vnormal.Y, vnormal.Z);
                    break;
                case DistributionOfNormals.OnePerFace:
                    XYZ fnormal = node.GetNormal(0);
                    for (int i = 0; i < node.NumberOfPoints; i++)
                        mesh.addNormal(current_surface, fnormal.X, fnormal.Y, fnormal.Z);
                    break;
                case DistributionOfNormals.OnEachFacet:
                    foreach(XYZ enormal in node.GetNormals())
                    {
                        mesh.addNormal(current_surface, enormal.X, enormal.Y, enormal.Z);
                        mesh.addNormal(current_surface, enormal.X, enormal.Y, enormal.Z);
                        mesh.addNormal(current_surface, enormal.X, enormal.Y, enormal.Z);
                    }
                    break;

            }

            int start = mesh.getNumTIndices(current_surface);

            foreach(PolymeshFacet face in node.GetFacets())
            {
                mesh.addTIndex(face.V1 + start, current_surface);
                mesh.addTIndex(face.V2 + start, current_surface);
                mesh.addTIndex(face.V3 + start, current_surface);

                mesh.addCIndex(face.V1 + start, current_surface);
                mesh.addCIndex(face.V2 + start, current_surface);
                mesh.addCIndex(face.V3 + start, current_surface);
            }

 

each object in revit contains multiple PolymeshTopology node, and every PolymeshTopology is a indexed mesh, it's index is exact same way of old unigine mesh. after each element( equals a actual object ) is finished, I call mesh.createTangents(-1) and mesh.createBounds(-1); then the plugin just crashed.

 

I think I should give up this way and use these code to convert to a non-indexed mesh:

 

            foreach(PolymeshFacet facet in node.GetFacets())
            {
                XYZ pos = node.GetPoint(facet.V1);
                mesh.addVertex(current_surface, pos.X, pos.Y, pos.Z);
                pos = node.GetPoint(facet.V2);
                mesh.addVertex(current_surface, pos.X, pos.Y, pos.Z);
                pos = node.GetPoint(facet.V3);
                mesh.addVertex(current_surface, pos.X, pos.Y, pos.Z);

                switch(node.DistributionOfNormals)
                {
                    case DistributionOfNormals.AtEachPoint:
                        pos = node.GetNormal(facet.V1);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        pos = node.GetNormal(facet.V2);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        pos = node.GetNormal(facet.V3);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        break;
                    case DistributionOfNormals.OnePerFace:
                        pos = node.GetNormal(0);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        break;
                    case DistributionOfNormals.OnEachFacet:
                        pos = node.GetNormal(index++);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        mesh.addNormal(current_surface, pos.X, pos.Y, pos.Z);
                        break;
                }

                UV uv = node.GetUV(facet.V1);
                mesh.addTexCoord(current_surface, uv.U, uv.V);
                uv = node.GetUV(facet.V2);
                mesh.addTexCoord(current_surface, uv.U, uv.V);
                uv = node.GetUV(facet.V3);
                mesh.addTexCoord(current_surface, uv.U, uv.V);

            }

 

and Thanks again, unclebob :)

Link to comment

Hey Steve!

 

Don't give up! Just make sure you properly added cindices to your mesh. I think there should be some errors when you first time tried to add cindex values. Could you please try to do this again?

 

Please don't hesitate to post that sample here even if it won't work. Looking forward to read more from you!

Link to comment

let me explain it with more detail, each element in revit equals like one object in unigine, but each element might have multiple solid/mesh/something class, so by using the IExportContext class in revit api, each element will still be just one element, but after a IExportContext::BeginElement callback, there will be multiple BeginNode calls, each call will give one solid/mesh/something, lets call solid/mesh/something is just a subelement, then after BeginNode, there will be mulitple OnPolymesh call, this function is the real export, because this callback will give me a PolymeshTopology class, this class is a triangluated and indexed mesh for real export.

 

and each PolymeshTopology will have exact same number of vertex/uv, but depends on the normal distribution method, there will be exact same count of normals, or just one normal if this face is planar, and the other normal distribution method - DistributionOfNormals.OnEachFacet which I have not encountered yet. all my scene elements don't have this type of normal distribution.

 

so based on these information, the PolymeshTopology object will have same tindex and same cindex. I just don't know why it don't work.

 

and I ran some debug, I found that crash is just because the save function will access beyond the upper bound of tindex. this is strange.

 

and one more question, if I just added cindex, and tindex, should I use these codes to write the mesh?

                // revit don't have the concept of tangents
                mesh.createTangents(-1);
                mesh.createBounds(-1);
                mesh.save("filename.mesh");
Link to comment

Steve,

 

Is it possible to get a working sample (with revit API) from you so I can have a look at it?

 

P.S. createTangents call will also affect your mesh normals so use it wisely. You don't have to pass -1 parameter to createTangents and createBounds methods as it'll be passed by default.

Link to comment
×
×
  • Create New...