潍坊网站建设品牌,淄博网站设计丨致信网络,西安做网站的公司哪家好,文字类wordpress主题在Unity中#xff0c;如果将一个模型文件#xff08;比如从max里面导出一个fbx文件#xff09;导入到编辑器中之后#xff0c;Unity会把所有在原来在面列表中公用的顶点复制一份#xff0c;保证每个三角形使用的顶点都是单独的#xff0c;不与其它三角形共用顶点#xf… 在Unity中如果将一个模型文件比如从max里面导出一个fbx文件导入到编辑器中之后Unity会把所有在原来在面列表中公用的顶点复制一份保证每个三角形使用的顶点都是单独的不与其它三角形共用顶点Unityh这么做应该有他的道理但我尚未想明白Unity这么做的原因是什么。 但是考虑到在有些应用中使用共用顶点能够更好的处理一些问题这里写了一个将Unity中Mesh重叠顶点合并成公用顶点的代码目的是将位置重叠的顶点去掉同时也将面列表的内容更新由一个原来有重叠顶点的Mesh获得一个新的使用公用顶点的Mesh参考如下
Mesh GetWeldMesh(Mesh mesh)
{Vector3[] vs mesh.vertices;int[] ts mesh.triangles;Debug.Log(ts.Length);DictionaryVector3, int dicVert new();for (int i 0; i ts.Length; i){bool hasSamePos false;Vector3 vert vs[ts[i]];foreach (var kv in dicVert){Vector3 key kv.Key;if (vert key){if (kv.Value ts[i]){ts[i] kv.Value;}else{dicVert[kv.Key] ts[i];}hasSamePos true;break;}}if (!hasSamePos){dicVert.Add(vert, ts[i]);}}ListVector3 listVertice new();foreach (var kv in dicVert){listVertice.Add(kv.Key);}Mesh meshNew new(){vertices vs,triangles ts};meshNew.RecalculateNormals();return meshNew;
} 目前我能想到的这么做的用处有两个第一个是在一种描边方法中Shader需要将要描边的物体增加一次渲染在这次渲染中Shader会将网格的每个顶点沿着该顶点的法线方向向外挤出一点点形成一个更大的轮廓然后反面渲染这样就形成了原物体的勾边效果不过这里有个问题如果使用的Unity默认的Mesh当物体的光滑组是连续的时候挤出的效果是没问题的当光滑组不连续例如一个Box顶点挤出后会出现分离问题。你当然可以在类似max这种软件中将Box的光滑组强行编成一组这样导入Untiy中之后挤出效果倒是没问题了但是本身显示效果就不是硬边的效果了这也不对啊。但是如果在使用Shader渲染Mesh的时候使用的不是原始的Mesh而是通过上述代码生成的新的Mesh由于顶点是共用的就不存在出现挤出分离的问题。关于具体的Shader就不说了玩过Shader的都懂。 第二个是查找物体的边界一般来说查找物体边界的方法是找到不被两个三角形共用的边但是Unity中Mesh默认所有的顶点都是单独被面列表使用的根本没有所谓被两个三角形共用的边的情况这中情况会发现所有的三角形的边都是边界貌似行不通所以还是需要上述方法将Unity中Mesh重叠顶点合并再去查找边界。其查找边界的代码参考如下由于Mesh的编辑可能不止一组所以用的返回值是Listint[]是顶点编号数组的列表 Listint[] GetEdgeIndexes(Mesh mesh){Vector3[] vs mesh.vertices;int[] ts mesh.triangles;DictionaryEdge, int dicEdge new();for (int i 0; i ts.Length; i 3){int indexA ts[i];int indexB ts[i 1];int indexC ts[i 2];bool hasSameEdge01 false;bool hasSameEdge02 false;bool hasSameEdge03 false;KeyValuePairEdge, int[] kvs dicEdge.ToArray();for (int j 0; j kvs.Length; j){Edge edge kvs[j].Key;if (edge.IsSame(indexA, indexB)) { hasSameEdge01 true; dicEdge[edge] 1; continue; }if (edge.IsSame(indexB, indexC)) { hasSameEdge02 true; dicEdge[edge] 1; continue; }if (edge.IsSame(indexC, indexA)) { hasSameEdge03 true; dicEdge[edge] 1; continue; }}if (!hasSameEdge01) { dicEdge.Add(new Edge(indexA, indexB), 1); }if (!hasSameEdge02) { dicEdge.Add(new Edge(indexB, indexC), 1); }if (!hasSameEdge03) { dicEdge.Add(new Edge(indexC, indexA), 1); }}ListEdge edges new ListEdge();foreach (var kv in dicEdge){if (kv.Value 1){edges.Add(kv.Key);}}foreach (var item in edges){Debug.Log(item.a , item.b);}Listint[] listEdgeIndexes new();while (edges.Count 0){Listint listTriangle new(){edges[0].a,edges[0].b};edges.RemoveAt(0);while (true){int indexLast listTriangle[^1];bool hasAddIndex false;for (int i 0; i edges.Count; i){Edge edge edges[i];if (indexLast edge.a){listTriangle.Add(edge.b);hasAddIndex true;edges.RemoveAt(i);break;}if (indexLast edge.b){listTriangle.Add(edge.a);hasAddIndex true;edges.RemoveAt(i);break;}}if (!hasAddIndex){listEdgeIndexes.Add(listTriangle.ToArray());break;}}}return listEdgeIndexes;}
其中所用到的Edge类代码如下
public class Edge
{public readonly int a;public readonly int b;public Edge(int a, int b){this.a a;this.b b;}public bool IsSame(Edge edge) { return (a edge.a b edge.b) || (a edge.b b edge.a); }public bool IsSame(int a, int b) { return (a this.a b this.b) || (a this.b b this.a); }
} 下图将一个球体挖了三个洞洞通过上述方法查找到边界并用LineRenderer渲染了边界。