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<MeshFilter>();
// 再下面的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<MeshFilter>().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<MeshFilter>().mesh);
srcMeshInfo = null;
PrintSame("after meshInfo recovery");
}
}
}
}
private void PrintSame(string title = null)
{
var sm1 = GameObject.Find("Cube").GetComponent<MeshFilter>().sharedMesh;
var sm2 = GameObject.Find("Cube (1)").GetComponent<MeshFilter>().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; }
}
操作:
上面的总结,就第一条和倒数第一、第二条的潜规则代码需要注意就好
MeshFilter.mesh大概做了类似的以下处理:
public class MeshFilter ...
{
...
private Mesh _mesh;
public Mesh mesh
{
get
{
if (_mesh == null)
{
_mesh = new Mesh();
Copy(sharedMehs, _mesh);
}
return _mesh;
}
}
...
}