private void CaptureSnapShot(AnimationClip animClip, float bakeFrames, GPUAnimation meshAnim, GameObject sampleGO) { List <GPUAnimationFrameData> verts = new List <GPUAnimationFrameData>(); List <Vector3> meshesInFrame = new List <Vector3>(); float lastFrameTime = 0; for (int i = 0; i <= bakeFrames; i += frameSkips[animClip.name]) { float bakeDelta = Mathf.Clamp01(((float)i / bakeFrames)); EditorUtility.DisplayProgressBar("Baking Animation", string.Format("Processing: {0} Frame: {1}", animClip.name, i), bakeDelta); float animationTime = bakeDelta * animClip.length; if (requiresAnimator) { float normalizedTime = animationTime / animClip.length; animator.Play(animClip.name, 0, normalizedTime); if (lastFrameTime == 0) { float nextBakeDelta = Mathf.Clamp01(((float)(i += frameSkips[animClip.name]) / bakeFrames)); float nextAnimationTime = nextBakeDelta * animClip.length; lastFrameTime = animationTime - nextAnimationTime; } animator.Update(animationTime - lastFrameTime); lastFrameTime = animationTime; } else { GameObject sampleObject = sampleGO; Animation legacyAnimation = sampleObject.GetComponentInChildren <Animation>(); if (animator && animator.gameObject != sampleObject) { sampleObject = animator.gameObject; } else if (legacyAnimation && legacyAnimation.gameObject != sampleObject) { sampleObject = legacyAnimation.gameObject; } animClip.SampleAnimation(sampleObject, animationTime); } meshesInFrame.Clear(); Mesh m = null; SkinnedMeshRenderer sampleSr = sampleGO.GetComponentInChildren <SkinnedMeshRenderer>(); m = new Mesh(); sampleSr.BakeMesh(m); Vector3[] v = m.vertices; for (int vIndex = 0; vIndex < v.Length; vIndex++) { v[vIndex] = sampleSr.transform.TransformPoint(v[vIndex]); } meshesInFrame.AddRange(v); DestroyImmediate(m); GPUAnimationFrameData data = new GPUAnimationFrameData(); data.SetVerts(meshesInFrame.ToArray()); verts.Add(data); } meshAnim.verts = verts.ToArray(); }
internal GPUAnimationState(GPUAnimation owner, GPUAnimations.Animation animation) { _owner = owner; WrapMode wrapMode = animation._wrapMode; if (wrapMode == WrapMode.Default) { wrapMode = WrapMode.Once; } _player = new GPUAnimationPlayer(animation, wrapMode); }
private void InitAnimationBones(GameObject animationTarget, GPUAnimation meshAnim) { bonesMap.Clear(); Transform child = animationTarget.transform.Find("Bip01"); joints = child.GetComponentsInChildren <Transform>(); skeletonPoses = new Matrix4x4[joints.Length]; bindSkeletonPoses = new Matrix4x4[joints.Length]; //meshAnim.bones = new string[bones.Length]; for (int i = 0; i < joints.Length; i++) { Transform bone = joints[i]; bonesMap.Add(bone.name, i); skeletonPoses[i] = bone.transform.localToWorldMatrix; bindSkeletonPoses[i] = bone.transform.worldToLocalMatrix; //meshAnim.bones[i] = bone.name; } }
private void Initialization() { defaultAnimation = meshAnimationList.meshAnimations[0]; totalJoints = meshAnimationList.totalJoints; animations = meshAnimationList.meshAnimations; if (defaultAnimation.isVertsAnimation) { skinningTexSize = defaultAnimation.textureSize; pixelsStartIndex = 0; } else { skinningTexSize = meshAnimationList.skinningTexSize; pixelsStartIndex = defaultAnimation.startIndex; } meshRenderer = gameObject.GetComponent <MeshRenderer>(); meshRenderer.material.SetInt("_StartPixelIndex", pixelsStartIndex); meshRenderer.material.SetInt("_SkinningTexSize", skinningTexSize); currentAnimIndex = 0; totalVerts = defaultAnimation.totalVerts; }
public void UpdateTick(float time) { GPUAnimation cAnim = currentAnimation; float lodFPS = FPS; float totalSpeed = speed; float tickRate = Mathf.Max(0.0001f, 1f / lodFPS / totalSpeed); float actualDelta = time - lastFrameTime; bool finished = false; float pingPongMult = pingPong ? -1 : 1; if (speed * playbackSpeed < 0) { currentAnimTime -= actualDelta * pingPongMult * totalSpeed; } else { currentAnimTime += actualDelta * pingPongMult * totalSpeed; } if (currentAnimTime < 0) { currentAnimTime = cAnim.length; finished = true; } else if (currentAnimTime > cAnim.length) { if (cAnim.wrapMode == WrapMode.Loop) { currentAnimTime = 0; } finished = true; } nextTick = time + tickRate; lastFrameTime = time; float normalizedTime = currentAnimTime / cAnim.length; int previousFrame = currentFrame; currentFrame = Mathf.Min(Mathf.RoundToInt(normalizedTime * cAnim.totalFrames), cAnim.totalFrames - 1); if (cAnim.wrapMode == WrapMode.PingPong) { if (finished) { pingPong = !pingPong; } } if (finished) { bool stopUpdate = false; if (cAnim.wrapMode != WrapMode.Loop && cAnim.wrapMode != WrapMode.PingPong) { nextTick = float.MaxValue; stopUpdate = true; } currentAnimation.FireFinishedEvents(currentFrame); if (stopUpdate) { return; } } if (currentAnimation.isVertsAnimation) { currentPixelIndex = totalVerts * currentFrame; } else { currentPixelIndex = pixelsStartIndex + totalJoints * currentFrame * perFramePixelsCount; } meshRenderer.material.SetInt("_StartPixelIndex", currentPixelIndex); }
internal Enumerator(GPUAnimation outer) { _outer = outer; }
private void CreateSnapshots() { UnityEditor.Animations.AnimatorController bakeController = null; string assetPath = GetPrefabPath(); if (string.IsNullOrEmpty(assetPath)) { EditorUtility.DisplayDialog("Mesh Animator", "Unable to locate the asset path for prefab: " + prefab.name, "OK"); return; } HashSet <string> allAssets = new HashSet <string>(); List <AnimationClip> clips = GetClips(); foreach (var clip in clips) { allAssets.Add(AssetDatabase.GetAssetPath(clip)); } string[] split = assetPath.Split("/".ToCharArray()); string assetFolder = string.Empty; for (int s = 0; s < split.Length - 1; s++) { assetFolder += split[s] + "/"; } var sampleGO = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity) as GameObject; if (meshFilters.Count(q => q) == 0 && skinnedRenderers.Count(q => q) == 0) { throw new System.Exception("Bake Error! No MeshFilter's or SkinnedMeshRender's found to bake!"); } else { animator = sampleGO.GetComponent <Animator>(); if (animator == null) { animator = sampleGO.GetComponentInChildren <Animator>(); } InitAnimationBones(sampleGO, null); if (requiresAnimator) { bakeController = CreateBakeController(); if (animator == null) { animator = sampleGO.AddComponent <Animator>(); animator.runtimeAnimatorController = bakeController; animator.avatar = GetAvatar(); } else { animator.runtimeAnimatorController = bakeController; animator.avatar = GetAvatar(); } animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; animator.applyRootMotion = rootMotionMode == GPUAnimation.RootMotionMode.Baked; } GPUAnimationList meshAnimationList = ScriptableObject.CreateInstance <GPUAnimationList>(); meshAnimationList.meshAnimations = new GPUAnimation[clips.Count]; int startIndex = bonesMap.Count * 3; Transform rootMotionBaker = new GameObject().transform; for (int x = 0; x < clips.Count; x++) { AnimationClip animClip = clips[x]; InitAnimationClipHashPath(animClip); if (bakeAnims.ContainsKey(animClip.name) && bakeAnims[animClip.name] == false) { continue; } if (frameSkips.ContainsKey(animClip.name) == false) { Debug.LogWarningFormat("No animation with name {0} in frame skips", animClip.name); continue; } string meshAnimationPath = string.Format("{0}{1}.asset", assetFolder, FormatClipName(animClip.name)); GPUAnimation meshAnim = new GPUAnimation(); meshAnim.length = animClip.length; int bakeFrames = Mathf.CeilToInt(animClip.length * fps); meshAnim.animationName = animClip.name; meshAnim.startIndex = startIndex; meshAnim.clipJoints = new Skeleton[bonesMap.Count]; startIndex += bonesMap.Count * bakeFrames * 3; for (int i = 0; i < bonesMap.Count; i++) { meshAnim.clipJoints[i] = new Skeleton(); meshAnim.clipJoints[i].jontFrameMatrixs = new Matrix4x4[bakeFrames]; } if (animClip.isLooping) { meshAnim.wrapMode = WrapMode.Loop; } else { meshAnim.wrapMode = animClip.wrapMode; } meshAnim.frameSkip = frameSkips[animClip.name]; meshAnimationList.meshAnimations[x] = meshAnim; } Color[] meshTexturePixels = null; Texture2D meshTexture = null; int textureSize = 2; int pixelIndex = 0; if (bakeVertices == false) { while (textureSize * textureSize < startIndex) { textureSize = textureSize << 1; } meshTexture = new Texture2D(textureSize, textureSize, TextureFormat.RGBAHalf, false, true); meshTexture.filterMode = FilterMode.Point; meshTexturePixels = meshTexture.GetPixels(); Matrix4x4 matrix = Matrix4x4.identity; for (int i = 0; i < bonesMap.Count; i++) { meshTexturePixels[pixelIndex] = new Color(matrix.m00, matrix.m01, matrix.m02, matrix.m03); pixelIndex++; meshTexturePixels[pixelIndex] = new Color(matrix.m10, matrix.m11, matrix.m12, matrix.m13); pixelIndex++; meshTexturePixels[pixelIndex] = new Color(matrix.m20, matrix.m21, matrix.m22, matrix.m23); pixelIndex++; } } int animCount = 0; for (int j = 0; j < clips.Count; j++) { AnimationClip animClip = clips[j]; GPUAnimation meshAnim = meshAnimationList.meshAnimations[j]; int bakeFrames = Mathf.CeilToInt(animClip.length * fps); meshAnim.totalFrames = bakeFrames; int frame = 0; for (int i = 0; i <= bakeFrames; i += frameSkips[animClip.name]) { if (bakeVertices) { CaptureSnapShot(animClip, bakeFrames, meshAnim, sampleGO); } else { float bakeDelta = Mathf.Clamp01(((float)i / bakeFrames)); EditorUtility.DisplayProgressBar("Baking Animation", string.Format("Processing: {0} Frame: {1}", animClip.name, i), bakeDelta); CaptureSnapShot(animClip, bakeFrames, bakeDelta, meshAnim, meshTexturePixels, ref pixelIndex); } frame++; } meshAnim.meshTexturePixels = meshTexturePixels; animCount++; } if (bakeVertices) { for (int i = 0; i < meshAnimationList.meshAnimations.Length; i++) { GPUAnimation animation = meshAnimationList.meshAnimations[i]; animation.isVertsAnimation = true; int smallTextureSize = 0; int totalCountPixels = 0; for (int j = 0; j < animation.verts.Length; j++) { totalCountPixels += animation.verts[j].decompressed.Length; } CalculateTextureSize(ref smallTextureSize, totalCountPixels); Texture2D meshSmallTexture = new Texture2D(smallTextureSize, smallTextureSize, TextureFormat.RGBAHalf, false, true); animation.textureSize = smallTextureSize; Color[] meshSmallTextureData = meshSmallTexture.GetPixels(); meshSmallTexture.filterMode = FilterMode.Point; int meshSmallTextureDataIndex = 0; for (int k = 0; k < animation.verts.Length; k++) { GPUAnimationFrameData animationFrameData = animation.verts[k]; animation.totalVerts = animationFrameData.decompressed.Length; for (int n = 0; n < animationFrameData.decompressed.Length; n++) { Vector3 vert = animationFrameData.decompressed[n]; meshSmallTextureData[meshSmallTextureDataIndex] = new Color(vert.x, vert.y, vert.z); meshSmallTextureDataIndex++; //meshSmallTexture.SetPixel(n, k, new Color(vert.x, vert.y, vert.z)); } } meshSmallTexture.SetPixels(meshSmallTextureData); meshSmallTexture.Apply(); AssetDatabase.CreateAsset(meshSmallTexture, assetFolder + "_VertsAnimationTexture.asset"); } AssetDatabase.CreateAsset(meshAnimationList, assetFolder + "_VertsAnimationConfig.asset"); } else { meshTexture.SetPixels(meshTexturePixels); meshTexture.Apply(); AssetDatabase.CreateAsset(meshTexture, assetFolder + "_AnimationTexture.asset"); meshAnimationList.totalJoints = bonesMap.Count; meshAnimationList.skinningTexSize = textureSize; AssetDatabase.CreateAsset(meshAnimationList, assetFolder + "_AnimationConfig.asset"); SkinnedMeshRenderer skinnedMeshRenderer = sampleGO.GetComponentInChildren <SkinnedMeshRenderer>(); Mesh sharedMesh = skinnedMeshRenderer.sharedMesh; Transform[] transforms = skinnedMeshRenderer.bones; int vertexCount = sharedMesh.vertexCount; List <Vector4> indices = new List <Vector4>(); List <Vector4> weights = new List <Vector4>(); Vector3[] vertices = new Vector3[vertexCount]; Vector3[] normals = new Vector3[vertexCount]; Matrix4x4 meshMatrix = skeletonPoses[bonesMap[transforms[0].name]] * sharedMesh.bindposes[0]; BoneWeight[] boneWeights = sharedMesh.boneWeights; for (int v = 0; v < vertexCount; v++) { BoneWeight weight = boneWeights[v]; float weight0 = weight.weight0; float weight1 = weight.weight1; float weight2 = weight.weight2; float weight3 = weight.weight3; int boneIndex0 = bonesMap[transforms[weight.boneIndex0].name]; int boneIndex1 = bonesMap[transforms[weight.boneIndex1].name]; int boneIndex2 = bonesMap[transforms[weight.boneIndex2].name]; int boneIndex3 = bonesMap[transforms[weight.boneIndex3].name]; indices.Add(new Vector4(boneIndex0, boneIndex1, boneIndex2, boneIndex3)); weights.Add(new Vector4(weight0, weight1, weight2, weight3)); vertices[v] = meshMatrix * sharedMesh.vertices[v]; normals[v] = meshMatrix * sharedMesh.normals[v]; weight.boneIndex0 = boneIndex0; weight.boneIndex1 = boneIndex1; weight.boneIndex2 = boneIndex2; weight.boneIndex3 = boneIndex3; boneWeights[v] = weight; } Mesh newMesh = new Mesh(); newMesh.vertices = vertices; newMesh.normals = normals; newMesh.triangles = sharedMesh.triangles; newMesh.uv = sharedMesh.uv; newMesh.SetUVs(1, indices); newMesh.SetUVs(2, weights); skinnedMeshRenderer.bones = joints; skinnedMeshRenderer.sharedMesh = newMesh; AssetDatabase.CreateAsset(newMesh, assetFolder + "_" + sharedMesh.name + ".asset"); } } GameObject.DestroyImmediate(sampleGO); EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("GPU Animator", string.Format("Baked {0} animation{1} successfully!", clips.Count , clips.Count > 1 ? "s" : string.Empty), "OK"); AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(bakeController)); }
private void CaptureSnapShot(AnimationClip animClip, float bakeFrames, float bakeDelta, GPUAnimation meshAnim, Color[] meshTexturePixels, ref int pixelIndex) { float animationTime = bakeDelta * animClip.length; foreach (string path in positionPathHash) { string boneName = path.Substring(path.LastIndexOf("/") + 1); if (bonesMap.ContainsKey(boneName)) { Transform child = joints[bonesMap[boneName]]; float postionX = GetAnimationClipCurve(animClip, path, positionPath + ".x", bakeDelta); float postionY = GetAnimationClipCurve(animClip, path, positionPath + ".y", bakeDelta); float postionZ = GetAnimationClipCurve(animClip, path, positionPath + ".z", bakeDelta); child.localPosition = new Vector3(postionX, postionY, postionZ); } } foreach (string path in rotationPathHash) { string boneName = path.Substring(path.LastIndexOf("/") + 1); if (bonesMap.ContainsKey(boneName)) { Transform child = joints[bonesMap[boneName]]; float rotationX = GetAnimationClipCurve(animClip, path, rotationPath + ".x", bakeDelta); float rotationY = GetAnimationClipCurve(animClip, path, rotationPath + ".y", bakeDelta); float rotationZ = GetAnimationClipCurve(animClip, path, rotationPath + ".z", bakeDelta); float rotationW = GetAnimationClipCurve(animClip, path, rotationPath + ".w", bakeDelta); Quaternion rotation = new Quaternion(rotationX, rotationY, rotationZ, rotationW); float r = rotationX * rotationX + rotationY * rotationY + rotationZ * rotationZ + rotationW * rotationW; if (r >= .1f) { r = 1.0f / Mathf.Sqrt(r); rotation.x *= r; rotation.y *= r; rotation.z *= r; rotation.w *= r; } child.localRotation = rotation; } } for (int k = 0; k < bonesMap.Count; k++) { Transform child = joints[k]; Matrix4x4 matrix = child.transform.localToWorldMatrix; meshAnim.clipJoints[k].jontFrameMatrixs[k] = matrix; matrix = matrix * bindSkeletonPoses[k]; meshTexturePixels[pixelIndex] = new Color(matrix.m00, matrix.m01, matrix.m02, matrix.m03); pixelIndex++; meshTexturePixels[pixelIndex] = new Color(matrix.m10, matrix.m11, matrix.m12, matrix.m13); pixelIndex++; meshTexturePixels[pixelIndex] = new Color(matrix.m20, matrix.m21, matrix.m22, matrix.m23); pixelIndex++; } }