您当前的位置: 首页 >  ar

Jave.Lin

暂无认证

  • 4浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

unity - MeshFilter.mesh与sharedMesh的区别

Jave.Lin 发布时间:2019-05-27 12:11:43 ,浏览量:4

Code
using UnityEngine;
using UnityEngine.Rendering;

public class ModifySharedMesh : MonoBehaviour
{
    public Transform t1;
    public Transform t2;
    public Transform t3;

    public bool usingSharedMesh;
    private bool initUsing;

    public MeshInfo srcMeshInfo;
    public Mesh srcMesh;
    public Mesh srcSharedMesh;

    // Start is called before the first frame update
    void Start()
    {
        initUsing = usingSharedMesh;

        PrintSame("On Start");
    }

    // Update is called once per frame
    void Update()
    {
        // modify mesh/sharedmesh
        if (Input.GetKeyDown(KeyCode.Space)) 
        {
            var meshFilter = GetComponent();

            // 再下面的CopyMesh使用MeshInfo的方式,发现MeshFilter很可疑,所以这里就测试了一下
            // 经过测试果然发现.mesh getter执行一次后, .sharedMesh就不同和其他的 .sharedMesh共享了
            // 我就懒得去Spy或是reflector看源代码了,反正只能看到表面层,很多底层逻辑都封装再c++层

            PrintSame("before backup");

            if (usingSharedMesh)
            {
                srcSharedMesh = CopyMesh(meshFilter.sharedMesh); // sharedMesh 的数据copy不会导致与其他实例的sharedMesh实例的引用不同
            }
            else
            {
                PrintSame("before getter");
                var tempMesh = meshFilter.mesh;
                PrintSame("after getter");

                PrintSame("before CopyMesh(meshFilter.mesh)");
                // 第一种
                //srcMesh = CopyMesh(meshFilter.mesh); // 一旦Copy的是.mesh,而不是.sharedMesh的话,就会导致原本所有.sharedMesh与其他cube的 .sharedMesh相同引用的,就变成不一样了
                // 第二种
                srcMeshInfo = CopyMesh(meshFilter.mesh, ref srcMeshInfo); // 甚至copy到MeshInfo也不行,不知道是不是.mesh的getter被执行后,sharedMesh就会与其他的不一样了
                PrintSame("after CopyMesh(meshFilter.mesh)");
            }

            var mesh = usingSharedMesh ? meshFilter.sharedMesh : meshFilter.mesh;

            PrintSame("before modify");

            mesh.Clear();
            mesh.vertices = new Vector3[] { t1.position, t2.position, t3.position };
            mesh.triangles = new int[] { 0, 1, 2 };

            PrintSame("after modify");
        }
        // recovery mesh/sharemesh
        if (Input.GetKeyDown(KeyCode.S))
        {
            if (usingSharedMesh)
            {
                if (srcSharedMesh != null)
                {
                    PrintSame("before sharedMesh recovery");
                    var mesh = GetComponent().sharedMesh;
                    CopyMesh(srcSharedMesh, ref mesh);
                    PrintSame("after sharedMesh recovery");
                    srcSharedMesh = null;
                }
            }
            else
            {
                //if (srcMesh != null)
                //{
                //    PrintSame("before mesh recovery");
                //    var mesh = GetComponent().mesh;
                //    CopyMesh(srcMesh, ref mesh);
                //    srcMesh = null;
                //    PrintSame("after mesh recovery");
                //}
                if (srcMeshInfo != null)
                {
                    PrintSame("before meshInfo recovery");
                    CopyMesh(srcMeshInfo, GetComponent().mesh);
                    srcMeshInfo = null;
                    PrintSame("after meshInfo recovery");
                }
            }
        }
    }

    private void PrintSame(string title = null)
    {
        var sm1 = GameObject.Find("Cube").GetComponent().sharedMesh;
        var sm2 = GameObject.Find("Cube (1)").GetComponent().sharedMesh;
        if (string.IsNullOrEmpty(title)) Debug.Log($"sharedMesh same:{sm1 == sm2}");
        else Debug.Log($"title : {title}, sharedMesh same:{sm1 == sm2}");
    }

    private Mesh CopyMesh(Mesh mesh)
    {
        Mesh result = null;
        if (mesh)
        {
            result = new Mesh();
            var t = typeof(Mesh);
            var ps = t.GetProperties();
            foreach (var item in ps)
            {
                if (item.CanWrite == false) continue;
                item.SetValue(result, t.GetProperty(item.Name).GetValue(mesh));
            }
        }
        return result;
    }

    private Mesh CopyMesh(Mesh mesh, ref Mesh result)
    {
        if (mesh)
        {
            if (result == null) result = new Mesh();
            var t = typeof(Mesh);
            var ps = t.GetProperties();
            foreach (var item in ps)
            {
                if (item.CanWrite == false) continue;
                item.SetValue(result, t.GetProperty(item.Name).GetValue(mesh));
            }
        }
        return result;
    }

    private MeshInfo CopyMesh(Mesh mesh, ref MeshInfo result)
    {
        if (mesh)
        {
            if (result == null) result = new MeshInfo();
            var meshType = typeof(Mesh);
            var meshInfoType = typeof(MeshInfo);
            var ps = meshInfoType.GetProperties();
            foreach (var item in ps)
            {
                if (item.CanWrite == false) continue;
                item.SetValue(result, meshType.GetProperty(item.Name).GetValue(mesh));
            }
        }
        return result;
    }

    private void CopyMesh(MeshInfo info, Mesh result)
    {
        if (info == null || result == null) return;
        var meshType = typeof(Mesh);
        var meshInfoType = typeof(MeshInfo);
        var ps = meshType.GetProperties();
        foreach (var item in ps)
        {
            if (item.CanWrite == false) continue;
            var p = meshInfoType.GetProperty(item.Name);
            if (p == null) continue;
            item.SetValue(result, p.GetValue(info));
        }
    }
}

public class MeshInfo
{
    public IndexFormat indexFormat { get; set; }
    public BoneWeight[] boneWeights { get; set; }
    public Matrix4x4[] bindposes { get; set; }
    public int subMeshCount { get; set; }
    public Bounds bounds { get; set; }
    public Vector3[] vertices { get; set; }
    public Vector3[] normals { get; set; }
    public Vector4[] tangents { get; set; }
    public Vector2[] uv { get; set; }
    public Vector2[] uv2 { get; set; }
    public Vector2[] uv3 { get; set; }
    public Vector2[] uv4 { get; set; }
    public Vector2[] uv5 { get; set; }
    public Vector2[] uv6 { get; set; }
    public Vector2[] uv7 { get; set; }
    public Vector2[] uv8 { get; set; }
    public Color[] colors { get; set; }
    public Vector2[] uv1 { get; set; }
    public Color32[] colors32 { get; set; }
    public int[] triangles { get; set; }

}

Runtime

操作:

  • 选中场景中的名称为:Cube对象,调整ModifySharedMesh脚本的usingSharedMesh来决定修改sharedMesh还是mesh的方式
  • 激活Game视图,按space键:修改
  • 激活Game视图,按s键:还原
runtime - pics of snapshot 运行前

在这里插入图片描述

不使用sharedMesh

在这里插入图片描述

按下Space键,修改模型,发现MeshFilter.mesh的property getter执行后sharedMesh与其他实例引用不同了

在这里插入图片描述

对mesh修改后

在这里插入图片描述

使用sharedMesh

在这里插入图片描述

按下space键后,可以发现modify前后,recovery前后,都没有影响在这里插入图片描述 对一个sharedMesh修改后,另一个没修改的Cube (1)也自动修改了,因为Cube与Cube (1)的sharedMesh是同一个实例引用

在这里插入图片描述

总结
  • MeshFilter.mesh只要执行过getter就会导致该meshFilter的.sharedMesh与其他本身同一实例引用的,变成了不同的
  • 对MeshFilter.sharedMesh getter执行就没有这个问题丢失统一引用的问题
  • 对MeshFilter.sharedMesh修改,其他相同实例的sharedMesh都会同时修改
  • 对MeshFilter.mesh修改,再退出unity play模式后,就会还原数据
  • 对MeshFilter.sharedMesh修改,退出了unity play模式一样会保留模型外观,应该是再哪里的文件cache了持久化
  • 对MeshFilter.sharedMesh修改后,如果想还原被修改后的mesh,只要关掉(退出unity进程),再重新打开unity的对应项目就可以看到模型还原了

上面的总结,就第一条和倒数第一、第二条的潜规则代码需要注意就好

MeshFilter.mesh大概做了类似的以下处理:

public class MeshFilter ...
{
	...
	private Mesh _mesh;
	public Mesh mesh
	{
		get
		{
			if (_mesh == null) 
			{
				_mesh = new Mesh();
				Copy(sharedMehs, _mesh);
			}
			return _mesh;
		}
	}
	...
}
References
  • mesh和sharedMesh的区别
  • MeshFilter.mesh和MeshFilter.sharedMesh什么区别
关注
打赏
1664331872
查看更多评论
立即登录/注册

微信扫码登录

0.0693s