【问题标题】:UNITY creating blendshape from script problemUNITY 从脚本问题创建 blendshape
【发布时间】:2020-02-17 17:20:52
【问题描述】:

我制作了一个脚本,将网格转换为 SkinnedMeshRenderer,并为其创建一个 BlendShape

根据编辑器中的所有调试信息,一切看起来都是正确的!

但是当我移动 BlendShape 滑块时,移动了错误的顶点。

这里:

GREEN - 顶点的当前位置。

MAGENTA - 每个顶点从初始位置到增量位置的路径。

BLUE - 每个顶点在其最终增量位置中的位置。

RED - 不在 _selection 范围内的每个顶点的位置。保持等于 Vector3.zero。

但是,当我尝试查看实际的混合形状时,我得到了这个:

当我尝试相同的脚本,但只是将顶点移动到它们的增量时,它看起来也不错:

我的问题很简单。 在为网格制作新的 BlendShape 数据的过程中我做错了什么?

这是我的 C# 代码:

private void AddMorph(GameObject _ref, GameObject selection_mesh) {
    Mesh _m = new Mesh();

    // _selection - Bounds for selecting group of vertices within.
    _selection = new Bounds(selection_mesh.transform.position, selection_mesh.transform.localScale);

    // movement delta for future group of vertices.
    Vector3 newDelta = new Vector3(0, -0.4f, 0);

    // name for the future blend shape.
    string MorphName = "Custom[50-250]";

    //
    // Convert Mesh Renderer to Skinned Mesh Renderer, and create and instance of the shared mesh.
    //
    if (_ref.GetComponent < SkinnedMeshRenderer > () == null && _ref.GetComponent < MeshRenderer > () != null) {
        _m = Instantiate(_ref.GetComponent < MeshFilter > ().sharedMesh);
        Destroy(_ref.GetComponent < MeshRenderer > ());
        Destroy(_ref.GetComponent < MeshFilter > ());
        _ref.AddComponent < SkinnedMeshRenderer > ();
        _ref.GetComponent < SkinnedMeshRenderer > ().sharedMesh = _m;
    }
    else if (_ref.GetComponent < SkinnedMeshRenderer > () != null) // Create instance of shared mesh.
    {
        _m = Instantiate(_ref.GetComponent < SkinnedMeshRenderer > ().sharedMesh);
        _ref.GetComponent < SkinnedMeshRenderer > ().sharedMesh = _m;
    }
    else return; // if object has no renderer at all, stop the script execution.

    // Assign the new mesh we instantiated before.
    _ref.GetComponent < SkinnedMeshRenderer > ().sharedMesh = _m;
    // create array with deltas.
    Vector3[] newVertexDeltas = new Vector3[_m.vertices.Length];

    for (int y = 0; y < newVertexDeltas.Length; y++) {
        if (_selection.Contains(_ref.transform.TransformPoint(_m.vertices[y]))) {
            // each vertex found within the _selection bounds, gets the delta.
            newVertexDeltas[y] = newDelta;

            //GREEN draw line - current position of vertices.
            Debug.DrawLine(
            _ref.transform.TransformPoint(_m.vertices[y]), _ref.transform.TransformPoint(_m.vertices[y] + _m.normals[y] * 0.05f), Color.green, 1000000.0f);

            //MAGENTA draw line - path of each vertex from initial position to delta position.
            Debug.DrawLine(
            _ref.transform.TransformPoint(_m.vertices[y]), _ref.transform.TransformPoint(_m.vertices[y] + newDelta), Color.magenta, 1000000.0f);

            //BLUE draw line - position of each vertex in it's delta position.
            Debug.DrawLine(
            _ref.transform.TransformPoint(_m.vertices[y] + newDelta), _ref.transform.TransformPoint((_m.vertices[y] - _m.normals[y] * 0.05f) + newDelta), Color.blue, 1000000.0f);
        }
        else {
            //RED draw line - position of each vertex that are not within the _selection bounds.
            newVertexDeltas[y] = Vector3.zero;
            Debug.DrawLine(
            _ref.transform.TransformPoint(_m.vertices[y]), _ref.transform.TransformPoint(_m.vertices[y] - _m.normals[y] * 0.05f), Color.red, 1000000.0f);
        }
    }

    // Create the new blendshape with vertecies deltas.
    _m.AddBlendShapeFrame(MorphName, 100f, newVertexDeltas, null, null);
}

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    已修复。 在添加新的 BlendShape 后立即执行法线和切线重新计算。 现在一切正常。

    }
    
        // Create the new blendshape with vertecies deltas.
        _m.AddBlendShapeFrame(MorphName, 100f, newVertexDeltas, null, null);        
        _m.RecalculateNormals();
        _m.RecalculateTangents();
    

    【讨论】:

      【解决方案2】:

      我的行为完全相同(使用 Khronos Unity GLTF 插件)。

      确实,使用RecalculateNormals 可以解决问题。

      我们也可以使用UploadMeshData(&lt;true/false&gt;) 来更新网格。

      但我还是不太明白为什么……

      【讨论】:

        【解决方案3】:

        使用源和目标将 blendshape 添加到蒙皮网格渲染器对我来说就像这样。请注意,您所要做的就是从目标顶点中减去源顶点以创建增量数组。然后重新计算法线和切线。

        using UnityEngine;
        
        public class BlendShape : MonoBehaviour
        {
            public SkinnedMeshRenderer source;
            public SkinnedMeshRenderer target;
        
            // Start is called before the first frame update
            void Start()
            {
                Vector3[] verts = new Vector3[target.sharedMesh.vertexCount];
        
                source.sharedMesh.ClearBlendShapes();
                target.sharedMesh.ClearBlendShapes();
        
                // Calculate delta verts from source to target
                for (int i = 0; i < verts.Length; i++)
                    verts[i] = target.sharedMesh.vertices[i] - source.sharedMesh.vertices[i];
        
                source.sharedMesh.AddBlendShapeFrame("test", 1, verts, null, null);
        
                source.sharedMesh.RecalculateNormals();
                source.sharedMesh.RecalculateTangents();
            }
        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-18
          • 2020-12-14
          相关资源
          最近更新 更多