很多时候美术在出一个特效的时候往往会用到MeshRenderer以及本文主角SkinnedMeshRenderer(蒙皮渲染组件),那么在UGUI上由于没有深度概念(其实是有,但这里我们姑且认为没有,因为我不可能也不想去调整他的排序层或者渲染层。)
那这个时候怎么办?因为mesh的的渲染永远都是最早的,UI没法遮挡,最后想了一个折中方案,那就是把Mesh渲染到UI上,大家应该都知道UGUI的渲染依靠网格,那么我们把模型的mesh填充进去就可以了(这个很简单,这里不做阐述了)。
那么问题又来了!正常的MeshRenderer是可以正常填充,SkinnedMeshRenderer也可以填充,但是!!如果SkinnedMeshRenderer用到了骨骼动画,怎么办??因为它的动画是基于骨骼,不是基于网格点,所以在我们的网格点不变化的情况下 SkinnedMeshRenderer 渲染出来的永远是静态的。
下面进入代码模式。(首先你要会怎么把网格填充到UGUI上,如果对 OnPopulateMesh ,SetMaterialDirty等等这些函数不清楚的话,建议先忽略本文)
m_SkinnedMesh.GetUVs(0, Uvs);
m_SkinnedMesh.GetVertices(Vertices);
m_SkinnedMesh.GetColors(Colors);
m_SkinnedMesh.GetTriangles(Triangles, 0);
m_SkinnedMesh.GetBindposes(bindposesMatrix4x4);
m_SkinnedMesh.GetBoneWeights(boneWeights);
bones = this.skinnedMeshRenderer.bones;
上述代码片段是我们需要的一下数据,可以从mesh网格中获取,里面包含骨骼的权重以及Matrix的矩阵信息,还有骨骼,对应的权重信息和顶点数相同,矩阵信息与骨骼数量相同.
//遍历顶点数,LBS蒙皮算法
for (int i = 0; i < Vertices.Count; i++){
BoneWeight boneWeight = boneWeights[i];
Vector3 point = Vertices[i];
Transform trans0 = bones[boneWeight.boneIndex0];
Transform trans1 = bones[boneWeight.boneIndex1];
Transform trans2 = bones[boneWeight.boneIndex2];
Transform trans3 = bones[boneWeight.boneIndex3];
Matrix4x4 tempMat0 = trans0.localToWorldMatrix * bindposesMatrix4x4[boneWeight.boneIndex0];
Matrix4x4 tempMat1 = trans1.localToWorldMatrix * bindposesMatrix4x4[boneWeight.boneIndex1];
Matrix4x4 tempMat2 = trans2.localToWorldMatrix * bindposesMatrix4x4[boneWeight.boneIndex2];
Matrix4x4 tempMat3 = trans3.localToWorldMatrix * bindposesMatrix4x4[boneWeight.boneIndex3];
Vector3 temp = tempMat0.MultiplyPoint(point) * boneWeight.weight0 +
tempMat1.MultiplyPoint(point) * boneWeight.weight1 +
tempMat2.MultiplyPoint(point) * boneWeight.weight2 +
tempMat3.MultiplyPoint(point) * boneWeight.weight3;
Vertices[i] = this.skinnedMeshRenderer.worldToLocalMatrix.MultiplyPoint(temp);
vh.AddVert(Vertices[i], Color.white, Uvs[i]);
}
//填充三角面
for (int i = 0; i < Triangles.Count; i++)
{
try
{
vh.AddTriangle(Triangles[i], Triangles[i + 1], Triangles[i + 2]);
i += 2;
}
catch (System.Exception ex)
{
Debug.LogError(ex.Message);
}
}
换句大白话来说就是透过骨骼的偏移来改变顶点信息。
注意!!!前方高能警告!!!
此方式的渲染会很大提高CPU的计算量,一个mesh我本地计算预计是增加4ms左右,但是这样可以使用UGUI批处理合批(记得把 SkinnedMeshRenderer 的mesh去掉,不然UGUI渲染一份,SkinnedMeshRenderer渲染一份,多余垃圾)
大家根据自己的项目来使用,毕竟这样就可以不用给UGUI造轮子(如果不渲染到UGUI上,那么就得需要自己管理整个UI层的 (SortingOrder || SortingLayer),反正笔者是不想管理这些东西,希望UIElements能够早点出来,也希望Unity轮子已经造好,毕竟作者懒。)
网友评论