void GenerateBoneInstanceMeshAndTexture(GameObject _targetFBX, AnimationClip[] _clips, string exposeBones) { if (!UEAsset.SelectDirectory(_targetFBX, out string savePath, out string meshName)) { Debug.LogWarning("Invalid Folder Selected"); return; } GameObject _instantiatedObj = GameObject.Instantiate(m_TargetPrefab); SkinnedMeshRenderer _skinnedMeshRenderer = _instantiatedObj.GetComponentInChildren <SkinnedMeshRenderer>(); try { Matrix4x4[] bindPoses = _skinnedMeshRenderer.sharedMesh.bindposes; Transform[] bones = _skinnedMeshRenderer.bones; #region Record Expose Bone List <AnimationInstanceExposeBone> exposeBoneParam = new List <AnimationInstanceExposeBone>(); if (exposeBones != "") { Transform[] activeTransforms = _instantiatedObj.GetComponentsInChildren <Transform>(); for (int i = 0; i < activeTransforms.Length; i++) { if (!System.Text.RegularExpressions.Regex.Match(activeTransforms[i].name, exposeBones).Success) { continue; } int relativeBoneIndex = -1; Transform relativeBone = activeTransforms[i]; while (relativeBone != null) { relativeBoneIndex = System.Array.FindIndex(bones, p => p == relativeBone); if (relativeBoneIndex != -1) { break; } relativeBone = relativeBone.parent; } if (relativeBoneIndex == -1) { continue; } Matrix4x4 rootWorldToLocal = _skinnedMeshRenderer.transform.worldToLocalMatrix; exposeBoneParam.Add(new AnimationInstanceExposeBone() { m_BoneIndex = relativeBoneIndex, m_BoneName = activeTransforms[i].name, m_Position = rootWorldToLocal.MultiplyPoint(activeTransforms[i].transform.position), m_Direction = rootWorldToLocal.MultiplyVector(activeTransforms[i].transform.forward) }); } } #endregion #region Bake Animation Atlas int boneCount = _skinnedMeshRenderer.sharedMesh.bindposes.Length; int totalWdith = boneCount * 3; int totalFrame = GetInstanceParams(_clips, out AnimationInstanceParam[] instanceParams); List <AnimationInstanceEvent> instanceEvents = new List <AnimationInstanceEvent>(); Texture2D atlasTexture = new Texture2D(Mathf.NextPowerOfTwo(totalWdith), Mathf.NextPowerOfTwo(totalFrame), TextureFormat.RGBAHalf, false); atlasTexture.filterMode = FilterMode.Point; atlasTexture.wrapModeU = TextureWrapMode.Clamp; atlasTexture.wrapModeV = TextureWrapMode.Repeat; UBoundsChecker.Begin(); for (int i = 0; i < _clips.Length; i++) { AnimationClip clip = _clips[i]; float length = clip.length; float frameRate = clip.frameRate; int frameCount = (int)(length * frameRate); int startFrame = instanceParams[i].m_FrameBegin; for (int j = 0; j < frameCount; j++) { clip.SampleAnimation(_instantiatedObj, length * j / frameCount); for (int k = 0; k < boneCount; k++) { Matrix4x4 curFrameBoneMatrix = _skinnedMeshRenderer.transform.worldToLocalMatrix * bones[k].localToWorldMatrix * bindPoses[k]; atlasTexture.SetPixel(k * 3, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(0))); atlasTexture.SetPixel(k * 3 + 1, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(1))); atlasTexture.SetPixel(k * 3 + 2, startFrame + j, UColor.VectorToColor(curFrameBoneMatrix.GetRow(2))); } Mesh boundsCheckMesh = new Mesh(); _skinnedMeshRenderer.BakeMesh(boundsCheckMesh); Vector3[] verticies = boundsCheckMesh.vertices; for (int k = 0; k < verticies.Length; k++) { UBoundsChecker.CheckBounds(verticies[k].Divide(_skinnedMeshRenderer.transform.localScale)); } boundsCheckMesh.Clear(); } } atlasTexture.Apply(); #endregion #region Bake Mesh Mesh instanceMesh = _skinnedMeshRenderer.sharedMesh.Copy(); BoneWeight[] boneWeights = instanceMesh.boneWeights; Vector4[] uv1 = new Vector4[boneWeights.Length]; Vector4[] uv2 = new Vector4[boneWeights.Length]; for (int i = 0; i < boneWeights.Length; i++) { uv1[i] = new Vector4(boneWeights[i].boneIndex0, boneWeights[i].boneIndex1, boneWeights[i].boneIndex2, boneWeights[i].boneIndex3); uv2[i] = new Vector4(boneWeights[i].weight0, boneWeights[i].weight1, boneWeights[i].weight2, boneWeights[i].weight3); } instanceMesh.SetUVs(1, uv1); instanceMesh.SetUVs(2, uv2); instanceMesh.boneWeights = null; instanceMesh.bindposes = null; instanceMesh.bounds = UBoundsChecker.CalculateBounds(); #endregion DestroyImmediate(_instantiatedObj); GPUAnimationData data = ScriptableObject.CreateInstance <GPUAnimationData>(); data.m_Animations = instanceParams; data.m_ExposeBones = exposeBoneParam.ToArray(); data = UEAsset.CreateAssetCombination(savePath + meshName + "_GPU_Bone.asset", data, new KeyValuePair <string, Object>(meshName + "_AnimationAtlas", atlasTexture), new KeyValuePair <string, Object>(meshName + "_InstanceMesh", instanceMesh)); Object[] assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(data)); foreach (var asset in assets) { Texture2D atlas = asset as Texture2D; Mesh mesh = asset as Mesh; if (atlas) { data.m_AnimationAtlas = atlas; } if (mesh) { data.m_InstancedMesh = mesh; } } AssetDatabase.SaveAssets(); } catch (System.Exception e) { Debug.LogError("Generate Failed:" + e.Message); DestroyImmediate(_instantiatedObj); } }
void GenerateVertexTexture(GameObject _targetFBX, AnimationClip[] _clips) { if (!UEAsset.SelectDirectory(_targetFBX, out string savePath, out string meshName)) { Debug.LogWarning("Invalid Folder Selected"); return; } GameObject instantiatedObj = GameObject.Instantiate(m_TargetPrefab); SkinnedMeshRenderer skinnedMeshRenderer = instantiatedObj.GetComponentInChildren <SkinnedMeshRenderer>(); #region Bake Animation Atlas int vertexCount = skinnedMeshRenderer.sharedMesh.vertexCount; int totalVertexRecord = vertexCount * 2; int totalFrame = GetInstanceParams(_clips, out AnimationInstanceParam[] instanceParams); Texture2D atlasTexture = new Texture2D(Mathf.NextPowerOfTwo(totalVertexRecord), Mathf.NextPowerOfTwo(totalFrame), TextureFormat.RGBAHalf, false); atlasTexture.filterMode = FilterMode.Point; atlasTexture.wrapModeU = TextureWrapMode.Clamp; atlasTexture.wrapModeV = TextureWrapMode.Repeat; UBoundsChecker.Begin(); for (int i = 0; i < _clips.Length; i++) { AnimationClip clip = _clips[i]; Mesh vertexBakeMesh = new Mesh(); float length = clip.length; float frameRate = clip.frameRate; int frameCount = (int)(length * frameRate); int startFrame = instanceParams[i].m_FrameBegin; for (int j = 0; j < frameCount; j++) { clip.SampleAnimation(instantiatedObj, length * j / frameCount); skinnedMeshRenderer.BakeMesh(vertexBakeMesh); Vector3[] vertices = vertexBakeMesh.vertices; Vector3[] normals = vertexBakeMesh.normals; for (int k = 0; k < vertexCount; k++) { UBoundsChecker.CheckBounds(vertices[k]); atlasTexture.SetPixel(k * 2, startFrame + j, UColor.VectorToColor(vertices[k])); atlasTexture.SetPixel(k * 2 + 1, startFrame + j, UColor.VectorToColor(normals[k])); } } vertexBakeMesh.Clear(); } atlasTexture.Apply(); #endregion #region Bake Mesh Mesh instanceMesh = skinnedMeshRenderer.sharedMesh.Copy(); instanceMesh.normals = null; instanceMesh.tangents = null; instanceMesh.boneWeights = null; instanceMesh.bindposes = null; instanceMesh.bounds = UBoundsChecker.CalculateBounds(); #endregion DestroyImmediate(instantiatedObj); GPUAnimationData data = ScriptableObject.CreateInstance <GPUAnimationData>(); data.m_Animations = instanceParams; data = UEAsset.CreateAssetCombination(savePath + meshName + "_GPU_Vertex.asset", data, new KeyValuePair <string, Object>(meshName + "_AnimationAtlas", atlasTexture), new KeyValuePair <string, Object>(meshName + "_InstanceMesh", instanceMesh)); Object[] assets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(data)); foreach (var asset in assets) { Texture2D atlas = asset as Texture2D; Mesh mesh = asset as Mesh; if (atlas) { data.m_AnimationAtlas = atlas; } if (mesh) { data.m_InstancedMesh = mesh; } } AssetDatabase.SaveAssets(); }