atteneder / glTFast

Efficient glTF 3D import / export package for Unity
Other
1.21k stars 240 forks source link

Different boneWeights accuracy in edit mode and run mode #693

Open ijinfeng opened 2 months ago

ijinfeng commented 2 months ago

Describe the bug I found a problem, the same glb, previewed in edit mode, and dragged into the scene, the model behaves normally, but the dynamically loaded glb behaves abnormally. Through tracking, I found that the boneWeights of the two are slightly different, so far it seems that the difference is in precision.

Files

Below is a comparison of boneWeights between the two glb loads.

0F28874DCB86D8AC1825DBDFA5C3FA78

image

And you can try this by use this glb file. uplimbs001.glb.zip

Code

async void Update()
    {
        if(Input.GetKeyDown(KeyCode.A))
        {
            string path = HaiSdkManager.GetPersistentPath();
            path = Path.Combine(path, "uplimbs001.glb");
            Dowork(Path.GetFullPath(path));
        }
    }

async void Dowork(string filePath)
    {
        var downloadProvider = new GLTFast.Loading.DefaultDownloadProvider();

        var m_Gltf = new GltfImport(
            downloadProvider,
            new UninterruptedDeferAgent(),
            null,
            null
            );

        var importSettings = new ImportSettings
        {
            // Avoid naming conflicts by default
            NodeNameMethod = NameImportMethod.OriginalUnique,
            GenerateMipMaps = true,
            AnimationMethod = AnimationMethod.Mecanim,
        };

        var instantiationSettings = new InstantiationSettings();

        bool success = await m_Gltf.Load(filePath, importSettings);

        if (success)
        {

            if (instantiationSettings.SceneObjectCreation == SceneObjectCreation.Never)
            {

                // There *has* to be a common parent GameObject that gets
                // added to the ScriptedImporter, so we overrule this
                // setting.

                instantiationSettings.SceneObjectCreation = SceneObjectCreation.WhenMultipleRootNodes;
                Debug.LogWarning("SceneObjectCreation setting \"Never\" is not available for Editor (design-time) imports. Falling back to WhenMultipleRootNodes.", this);
            }

            for (var sceneIndex = 0; sceneIndex < m_Gltf.SceneCount; sceneIndex++)
            {
                var scene = m_Gltf.GetSourceScene(sceneIndex);
                var sceneName = m_Gltf.GetSceneName(sceneIndex);
                var go = new GameObject(sceneName);
                var instantiator = new GameObjectInstantiator(m_Gltf, go.transform, null, instantiationSettings);
                var index = sceneIndex;
                success = await m_Gltf.InstantiateSceneAsync(instantiator, index);
            }
        }
    }

Looking forward to your reply!

atteneder commented 1 week ago

Thanks for the report.

Can you please check in your Projects settings under Quality how many skin weights bones you have set? It's possible you've set it to just two. In that case glTFast ignores bone weights 3 and 4 and re-normalizes the first two so that their sum is 1.0 again.

hth

ijinfeng commented 3 days ago

Thanks for the report.

Can you please check in your Projects settings under Quality how many skin weights bones you have set? It's possible you've set it to just two. In that case glTFast ignores bone weights 3 and 4 and re-normalizes the first two so that their sum is 1.0 again.

hth

In my project settings, Skin Weights is set to Unlimited. You are right, it works fine when I set it to 2 Bones, but the problem above occurs when it is set to Unlimited or 4 Bones.

I fixed this bug when there are more than 4 bones, and it works well now.

// In file `VertexBufferBones.cs`
public override void ApplyOnMesh(UnityEngine.Mesh msh, int stream, MeshUpdateFlags flags = PrimitiveCreateContextBase.defaultMeshUpdateFlags)
        {
            Profiler.BeginSample("ApplyBones");
            // FIX by jinfeng
            unsafe
            {
                for (int i = 0; i < m_Data.Length; i++)
                {
                    VBones bones = m_Data[i];
                    float total = bones.weights[0] + bones.weights[1] + bones.weights[2] + bones.weights[3];
                    if (total > 0)
                    {
                        float mult = 1f / total;
                        bones.weights[0] *= mult;
                        bones.weights[1] *= mult;
                        bones.weights[2] *= mult;
                        bones.weights[3] *= mult;
                        m_Data[i] = bones;
                    }
                }
            }
            msh.SetVertexBufferData(m_Data, 0, 0, m_Data.Length, stream, flags);
            Profiler.EndSample();
        }