vpenades / SharpGLTF

glTF reader and writer for .NET Standard
MIT License
476 stars 75 forks source link

Missing lines #182

Closed gentilinigm closed 1 year ago

gentilinigm commented 1 year ago

Hello,

I'm trying to add edges (lines) to a mesh, but I have some problems. This below is the mesh that I'm trying to convert into GLTF, a simple 10x10x10 cube: image

This is my code:

if (Edges != null && meshBuilder != null)
{
    //edge material color is by entity
    if (edgeMaterial == null)
    {
        Material temp = new Material("", this.Color);
        temp.WriteGLTF("edgeMaterial", out edgeMaterial, null);
    }
    var edgesPrimitiveBuilder = meshBuilder.UsePrimitive(edgeMaterial, 2);

    foreach (var edge in Edges)
    {
        var v1EdgeBuilder = new VertexBuilder<VertexPosition, VertexEmpty, VertexEmpty>(Vertices[edge.V1].ToVertexPosition());
        var v2EdgeBuilder = new VertexBuilder<VertexPosition, VertexEmpty, VertexEmpty>(Vertices[edge.V2].ToVertexPosition());
        edgesPrimitiveBuilder.AddLine(v1EdgeBuilder, v2EdgeBuilder);
    }
}

And this is the result: image

As you can see some lines are missing. This is the list of edges (contains the Vertices indexes): ["0, 1", "1, 2", "2, 3", "3, 0", "4, 5", "5, 6", "6, 7", "7, 4", "0, 4", "1, 5", "2, 6", "3, 7"].

My code seems correct to me, what am I doing wrong?

vpenades commented 1 year ago

Hmm... I don't see any lines missing, in your edge list you have 12 lines, 4 lines per polygon, which produces 3 polygons, and what I see in the capture is also 3 polygons.

It is missing half of the cube? yes, but then, your edge list needs to have 24 edges, not 12.

Notice that you're not sharing edges between polygons: If you share edges, it's 12 edges, if you don't share edges, it's 24 edges

gentilinigm commented 1 year ago

Thanks for the quick reply!

Yes, the edges are actually shared:

Like this: image

Maybe I'm writing the vertices wrong? I did the same things for writing the triangles and it worked very well...

gentilinigm commented 1 year ago

Update: I found the issue.

I'm creating vertices as VertexPositionNormal while constructing the Mesh. Then, when drawing edges, I'm creating some of that vertices again but as a VertexPosition object.

I found that if I keep them as VertexPositionNormal it works, all the lines are present and perfectly visible. But, if I change them to VertexPosition, it skips some lines at AddLine(IVertexBuilder a, IVertexBuilder b);.

I don't really need normals in the second case, is there something I can change to make it work with VertexPosition (after using VertexPositionNormal before)?

vpenades commented 1 year ago

It makes sense.... there's a limitation in how MeshBuilder works, in that it only supports one type of vertex for all the primitives of the mesh. glTF specification does not have that kind of limitation, but I had to compromise making MeshBuilder to be easy to use, versus supporting all the features glTF has.

As I see it, you have three options:

1- skip MeshBuilder completely and create your meshes at low level, using the Schema2 API of the library (not recomended) 2- create two meshes instead of one.... one for faces, and the other for lines using different vertex types on each mesh. (ugly) 3- Have you considered using EXT_Outline extension? it's an extension specifically designed to add outlines to a mesh. The drawback is that it's not supported by many rendering pipelines, so depending on your use case it might be useful or not.

I don't know how complex your geometry is... but it's not too much, maybe having lines defined with vertices that have normals is not too bad after all (specially compered to the alternatives)

gentilinigm commented 1 year ago

Thank you for the suggestions.

I'm currently using some simple unit vectors as normals, just to make it work.

Unfortunately, the geometry is often very complex, but seems like it's fine most of the time. I'll probably try your third option to see how much I can optimize it.

We can close the issue!