vpenades / SharpGLTF

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

Help Please.... #247

Open mikeoverbay opened 1 week ago

mikeoverbay commented 1 week ago

This is how I create my vertex data. It throws no errors but the vertex colors are not being loading in blender 4.1 or any app. Any Ideas?

                Dim vertices As New List(Of VertexBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty))()
                For i As UInt32 = 0 To _group(item).nVertices_ - 1
                    Dim v As New VertexBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty)(
            New VertexPositionNormal(
                New Vector3(_group(item).vertices(i).x, _group(item).vertices(i).y, _group(item).vertices(i).z),
                New Vector3(_group(item).vertices(i).nx, _group(item).vertices(i).ny, _group(item).vertices(i).nz)
            ),
            New VertexColor1Texture1(
                New Vector4(_group(item).vertices(i).r, _group(item).vertices(i).g, _group(item).vertices(i).b, _group(item).vertices(i).a),
                New Vector2(_group(item).vertices(i).u, _group(item).vertices(i).v)
            ),
            New VertexEmpty()
        )
vpenades commented 1 week ago

And don't see any problem in your code have you tried to load the model in babylonJS as recomended?

mikeoverbay commented 1 week ago

First vpenades, thank you!! I understand the person you are! I write tools for World of Tanks. I also share it freely. I'm adding your tools to my app! I'll put it on a splash screen with the others at some point. I say I a lot LOL

Yes.. I have tried it in every online glTF viewer I can find. It simply isn't creating or adding them to the attribute. Blender shows No color attribute. I'm creating rigid node meshes, I Wonder if it thinks vertex color is a morph control? These functions need tested by someone to verify what I'm getting.

mikeoverbay commented 1 week ago

I'm not using a NodeBuilder. I don't understand how to. Examples of writing out existing model data is hard to find.

vpenades commented 1 week ago

vertex colors, when they're defined, are automatically blended with the material's color, it has nothing to do with morph control.

Have you verified the glTF being written, actually has vertex colors attributes?

mikeoverbay commented 1 week ago

Vertex colors should be part of the material stack. This is true and yes, every viewer blends them with Base color. The models in world of tanks uses them as morph controls. They uses a file format that can't be opened any any thing but their game and my app. It's used by people to customize the tanks. it's limited because of what I can put in a FBX file. I have tried everything. They also use a 2nd color as a indexing of some kind. I have never tried to find out how they use them. The app I have been working on converts the formats back and forth. I uploaded a couple to my server. here

mikeoverbay commented 1 week ago

image

mikeoverbay commented 1 week ago

I really need some help with this. Its the ideal way to transport files for what I'm doing but I can not get vertex colors out to the file.

vpenades commented 5 days ago

With the little information you've provided, it's impossible for me to help you. glTF is complex, and I am extremely busy at work. I barely have an hour per week to attend requests.

I suggest you to look into the sharpGLTF unit tests code, specifically the MeshBuilder tests, I think some tests show how to use color and textures in the vertices.

mikeoverbay commented 3 days ago

I understand the time issue. I'll dig more. Thanks!

mikeoverbay commented 2 days ago

I found it! This is important for each vertex type. I missed it somehow.

               'I create them as objects before so they can be redefined.
                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)

                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexColor2Texture2, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)

                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexTexture1, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)
mikeoverbay commented 2 days ago

here is the entire sub for those that need it. I would make this more visible for noobs like me :)

    Public Sub write_glTF()
        Dim ar() As String
        If PRIMITIVES_MODE Then
            ar = Path.GetFileNameWithoutExtension(frmMain.OpenFileDialog1.FileName).Split("~")
        Else
            ar = TANK_NAME.Split(":")
        End If

        frmMain.SaveFileDialog1.InitialDirectory = My.Settings.GLTF_path

        frmMain.SaveFileDialog1.Filter = "glb|*.glb"
        frmMain.SaveFileDialog1.Title = "Save glb.."
        frmMain.SaveFileDialog1.FileName = Path.GetFileName(ar(0)) + ".glb"

        frmMain.SaveFileDialog1.AddExtension = True
        frmMain.SaveFileDialog1.RestoreDirectory = True

        Dim result = frmMain.SaveFileDialog1.ShowDialog
        Dim out_path = frmMain.SaveFileDialog1.FileName
        My.Settings.fbx_path = out_path
        My.Settings.Save()

        'file_name = current_tank_name

        If Not result = DialogResult.OK Then
            Return
        End If

        My.Settings.GLTF_path = out_path

        Dim name As String = Path.GetFileName(ar(0))
        Dim save_path = Path.GetDirectoryName(out_path) + "\" + name
        export_fbx_textures(False, 1) 'export all textures. converts from dds to png.

        Dim MySceneBuilder As New SceneBuilder()
        MySceneBuilder.Name = name

        ' Create a root node
        For item = 1 To object_count
            Dim extras As New ExtrasData()

            ' Create a material and assign texture maps if available
            Dim MyMaterialBuilder As New MaterialBuilder("Material00" + item.ToString) With {.ShaderStyle = "PBRMetallicRoughness"}

            Dim baseColorTexture = save_path + "\" + Path.GetFileNameWithoutExtension(_group(item).color_name.Replace("\tracks", "")) + ".png"
            Dim aoTexture As String = save_path + "\" + Path.GetFileNameWithoutExtension(_group(item).ao_name.Replace("\tracks", "")) + ".png"
            Dim metalRoughTexture = save_path + "\" + Path.GetFileNameWithoutExtension(_group(item).metalGMM_name.Replace("\tracks", "")) + ".png"
            Dim normalTexture = save_path + "\" + Path.GetFileNameWithoutExtension(_group(item).normal_name.Replace("\tracks", "")) + ".png"

            ' Assign Base Color Texture if exists
            If Not String.IsNullOrEmpty(baseColorTexture) Then
                Try
                    MyMaterialBuilder.WithBaseColor(baseColorTexture)
                Catch ex As Exception
                End Try
            End If
            ' Check its there!
            If Not String.IsNullOrEmpty(aoTexture) Then
                Try
                    MyMaterialBuilder.WithOcclusion(aoTexture)
                Catch ex As Exception
                End Try
            End If
            ' Assign Metallic and Roughness Texture if exists
            If Not String.IsNullOrEmpty(metalRoughTexture) Then
                ' GLTF PBR Metallic-Roughness uses a combined texture with metallic in the B channel and roughness in the G channel
                Try
                    MyMaterialBuilder.WithMetallicRoughness(metalRoughTexture)
                Catch ex As Exception
                End Try
            End If
            ' Assign Normal Map if exists
            If Not String.IsNullOrEmpty(normalTexture) Then
                Try
                    MyMaterialBuilder.WithNormal(normalTexture)
                Catch ex As Exception
                End Try
            End If

            Dim off = _group(item).startVertex_

            Dim model_name = _group(item).name.Replace("/", "\")
            model_name = model_name.Replace(":", "~")
            model_name = model_name.Replace("vehicles\", "")
            model_name = model_name.Replace("primitives_processed", "pri")
            model_name = model_name.Replace("\lod0\", "\l\")

            Dim MyMeshBuilder As Object
            Dim prim As Object

            If Not _group(item).has_uv2 = 1 And _group(item).has_color = 1 Then
                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)

                ' Handle vertices with color and single texture coordinates
                Dim vertices As New List(Of VertexBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty))()

                For i As UInt32 = 0 To _group(item).nVertices_ - 1
                    Dim color1 = New Vector4(_group(item).vertices(i).r, _group(item).vertices(i).g, _group(item).vertices(i).b, _group(item).vertices(i).a)

                    Dim v As New VertexBuilder(Of VertexPositionNormal, VertexColor1Texture1, VertexEmpty)(
            New VertexPositionNormal(
                New Vector3(_group(item).vertices(i).x, _group(item).vertices(i).y, _group(item).vertices(i).z),
                New Vector3(_group(item).vertices(i).nx, _group(item).vertices(i).ny, _group(item).vertices(i).nz)
            ),
            New VertexColor1Texture1(color1, New Vector2(_group(item).vertices(i).u, _group(item).vertices(i).v))
        )
                    vertices.Add(v)
                Next

                ' Create mesh primitives using triangle indices
                For i As UInt32 = 1 To _group(item).nPrimitives_
                    prim.AddTriangle(
            vertices(_group(item).indices(i).v1 - off),
            vertices(_group(item).indices(i).v2 - off),
            vertices(_group(item).indices(i).v3 - off)
        )
                Next

            ElseIf _group(item).has_uv2 = 1 Then
                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexColor2Texture2, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)

                ' Handle vertices with two colors and two sets of texture coordinates
                Dim vertices As New List(Of VertexBuilder(Of VertexPositionNormal, VertexColor2Texture2, VertexEmpty))()

                For i As UInt32 = 0 To _group(item).nVertices_ - 1
                    Dim color1 = New Vector4(_group(item).vertices(i).r, _group(item).vertices(i).g, _group(item).vertices(i).b, _group(item).vertices(i).a)
                    Dim color2 = New Vector4(_group(item).vertices(i).ir, _group(item).vertices(i).ig, _group(item).vertices(i).ib, _group(item).vertices(i).ia)

                    Dim v As New VertexBuilder(Of VertexPositionNormal, VertexColor2Texture2, VertexEmpty)(
            New VertexPositionNormal(
                New Vector3(_group(item).vertices(i).x, _group(item).vertices(i).y, _group(item).vertices(i).z),
                New Vector3(_group(item).vertices(i).nx, _group(item).vertices(i).ny, _group(item).vertices(i).nz)
            ),
            New VertexColor2Texture2(color1, color2, New Vector2(_group(item).vertices(i).u, _group(item).vertices(i).v), New Vector2(_group(item).vertices(i).u2, _group(item).vertices(i).v2))
        )
                    vertices.Add(v)
                Next

                ' Create mesh primitives using triangle indices
                For i As UInt32 = 1 To _group(item).nPrimitives_
                    prim.AddTriangle(
            vertices(_group(item).indices(i).v1 - off),
            vertices(_group(item).indices(i).v2 - off),
            vertices(_group(item).indices(i).v3 - off)
        )
                Next

            ElseIf Not _group(item).has_color = 1 Then
                MyMeshBuilder = New MeshBuilder(Of VertexPositionNormal, VertexTexture1, VertexEmpty)(model_name)
                prim = MyMeshBuilder.UsePrimitive(MyMaterialBuilder)

                ' Handle vertices with only position, normal, and texture coordinates
                Dim vertices As New List(Of VertexBuilder(Of VertexPositionNormal, VertexTexture1, VertexEmpty))()

                For i As UInt32 = 0 To _group(item).nVertices_ - 1
                    Dim v As New VertexBuilder(Of VertexPositionNormal, VertexTexture1, VertexEmpty)(
            New VertexPositionNormal(
                New Vector3(_group(item).vertices(i).x, _group(item).vertices(i).y, _group(item).vertices(i).z),
                New Vector3(_group(item).vertices(i).nx, _group(item).vertices(i).ny, _group(item).vertices(i).nz)
            ),
            New VertexTexture1(New Vector2(_group(item).vertices(i).u, _group(item).vertices(i).v))
        )
                    vertices.Add(v)
                Next

                ' Create mesh primitives using triangle indices
                For i As UInt32 = 1 To _group(item).nPrimitives_
                    prim.AddTriangle(
            vertices(_group(item).indices(i).v1 - off),
            vertices(_group(item).indices(i).v2 - off),
            vertices(_group(item).indices(i).v3 - off)
        )
                Next
            End If

            ' Create a node and add the mesh to it
            ' Convert the matrix directly from _group(item).matrix to System.Numerics.Matrix4x4
            Dim matrix As New Matrix4x4(
            _object(item).matrix(0), _object(item).matrix(1), _object(item).matrix(2), _object(item).matrix(3),
            _object(item).matrix(4), _object(item).matrix(5), _object(item).matrix(6), _object(item).matrix(7),
            _object(item).matrix(8), _object(item).matrix(9), _object(item).matrix(10), _object(item).matrix(11),
            _object(item).matrix(12), _object(item).matrix(13), _object(item).matrix(14), _object(item).matrix(15)
)
            matrix.M11 *= -1.0
            If _object(item).name.ToLower.Contains("turret") Or _object(item).name.ToLower.Contains("gun") Then
                matrix.M41 *= -1.0
            End If

            ' Create a dictionary to hold the texture paths
            Dim texturePaths As New Dictionary(Of String, String)

            'save the actual parts name in the game
            Dim lts As String = _group(item).long_tank_name
            texturePaths.Add("rootfolder", lts)

            ' Collect the full texture paths for PBR textures
            If Not String.IsNullOrEmpty(baseColorTexture) Then
                texturePaths.Add("baseColorTexture", baseColorTexture)
            End If
            If Not String.IsNullOrEmpty(aoTexture) Then
                texturePaths.Add("aoTexture", aoTexture)
            End If
            If Not String.IsNullOrEmpty(metalRoughTexture) Then
                texturePaths.Add("metalRoughTexture", metalRoughTexture)
            End If
            If Not String.IsNullOrEmpty(normalTexture) Then
                texturePaths.Add("normalTexture", normalTexture)
            End If

            Dim jsonExtras As JsonNode = JsonNode.Parse(JsonSerializer.Serialize(texturePaths))

            Dim affineTransform As AffineTransform = AffineTransform.CreateDecomposed(matrix)

            ' Attach the extras data to the empty node

            MyMeshBuilder.Extras = jsonExtras

            ' Add the node to the scene

            MySceneBuilder.AddRigidMesh(MyMeshBuilder, affineTransform)

        Next

        ' Add the root node to the scene

        ' Save the scene to a GLTF file with settings
        Dim settings As New SharpGLTF.Schema2.WriteSettings
        settings.JsonIndented = True
        settings.ImageWriting = ResourceWriteMode.Default
        settings.MergeBuffers = False

        MySceneBuilder.ToGltf2().SaveGLB(out_path, settings)
    End Sub