public static void ExtractBoneAnimMatrix(GPUSkinning gpuSkinning, GPUSkinning_BoneAnimation boneAnimation, System.Action <Matrix4x4, Matrix4x4> boneAnimMatrixCB, System.Action <int> frameCB) { for (int frameIndex = 0; frameIndex < boneAnimation.frames.Length; ++frameIndex) { float second = (float)(frameIndex) / (float)boneAnimation.fps; gpuSkinning.matrixArray.UpdateBoneAnimationMatrix(null, second); int numBones = gpuSkinning.model.bones.Length; for (int i = 0; i < numBones; ++i) { boneAnimMatrixCB(gpuSkinning.model.bones[i].animationMatrix, gpuSkinning.model.bones[i].hierarchyMatrix); } frameCB(frameIndex); } }
private void UpdateBoneAnimationMatrix(string animName, float time) { GPUSkinning_BoneAnimation boneAnimation = boneAnimations[0];//GetBoneAnimation(animName); int frameIndex = (int)((time * boneAnimation.fps) % (boneAnimation.length * boneAnimation.fps)); if (currFrameIndex != frameIndex) { currFrameIndex = frameIndex; isCurrFrameIndexChanged = true; GPUSkinning_BoneAnimationFrame frame = boneAnimation.frames[frameIndex]; UpdateBoneTransformMatrix(bones[rootBoneIndex], Matrix4x4.identity, frame); } }
private void ExtractBoneAnimMatrix(System.Action <Matrix4x4> boneAnimMatrixCB, System.Action <int> frameCB) { GPUSkinning_BoneAnimation boneAnimation = boneAnimations[0]; for (int frameIndex = 0; frameIndex < boneAnimation.frames.Length; ++frameIndex) { float second = (float)(frameIndex) / (float)boneAnimation.fps; UpdateBoneAnimationMatrix(null, second); int numBones = bones.Length; for (int i = 0; i < numBones; ++i) { Matrix4x4 animMat = bones[i].animationMatrix; boneAnimMatrixCB(animMat); } frameCB(frameIndex); } }
public override void Init(GPUSkinning gpuSkinning) { base.Init(gpuSkinning); shaderPropID_Time = Shader.PropertyToID("_GameTime"); smr = gpuSkinning.GetComponentInChildren <SkinnedMeshRenderer>(); mesh = smr.sharedMesh; // Init Bones int numBones = smr.bones.Length; bones = new GPUSkinning_Bone[numBones]; for (int i = 0; i < numBones; ++i) { GPUSkinning_Bone bone = new GPUSkinning_Bone(); bones[i] = bone; bone.transform = smr.bones[i]; bone.name = bone.transform.gameObject.name; bone.bindpose = mesh.bindposes[i] /*smr to bone*/; } // Construct Hierarchy for (int i = 0; i < numBones; ++i) { if (bones[i].transform == smr.rootBone) { rootBoneIndex = i; break; } } System.Action <GPUSkinning_Bone> CollectChildren = null; CollectChildren = (currentBone) => { List <GPUSkinning_Bone> children = new List <GPUSkinning_Bone>(); for (int j = 0; j < currentBone.transform.childCount; ++j) { Transform childTransform = currentBone.transform.GetChild(j); GPUSkinning_Bone childBone = GetBoneByTransform(childTransform); if (childBone != null) { childBone.parent = currentBone; children.Add(childBone); CollectChildren(childBone); } } currentBone.children = children.ToArray(); }; CollectChildren(bones[rootBoneIndex]); // New MeshFilter MeshRenderer mf = gpuSkinning.gameObject.AddComponent <MeshFilter>(); mr = gpuSkinning.gameObject.AddComponent <MeshRenderer>(); newMtrl = new Material(Shader.Find("Unlit/GPUSkinning")); newMtrl.CopyPropertiesFromMaterial(smr.sharedMaterial); mr.sharedMaterial = newMtrl; // New Mesh newMesh = new Mesh(); newMesh.vertices = mesh.vertices; newMesh.tangents = GPUSkinningUtil.ExtractBoneWeights(mesh); newMesh.uv = mesh.uv; newMesh.triangles = mesh.triangles; mf.sharedMesh = newMesh; #if UNITY_EDITOR // Extract bone animation data int boneAnimationsCount = 0; boneAnimations = new GPUSkinning_BoneAnimation[gpuSkinning.GetComponent <Animator>().runtimeAnimatorController.animationClips.Length]; foreach (AnimationClip animClip in gpuSkinning.GetComponent <Animator>().runtimeAnimatorController.animationClips) { GPUSkinning_BoneAnimation boneAnimation = ScriptableObject.CreateInstance <GPUSkinning_BoneAnimation>(); boneAnimation.fps = 60; boneAnimation.animName = animClip.name; boneAnimation.frames = new GPUSkinning_BoneAnimationFrame[(int)(animClip.length * boneAnimation.fps)]; boneAnimation.length = animClip.length; boneAnimations[boneAnimationsCount++] = boneAnimation; for (int frameIndex = 0; frameIndex < boneAnimation.frames.Length; ++frameIndex) { GPUSkinning_BoneAnimationFrame frame = new GPUSkinning_BoneAnimationFrame(); boneAnimation.frames[frameIndex] = frame; float second = (float)(frameIndex) / (float)boneAnimation.fps; List <GPUSkinning_Bone> bones2 = new List <GPUSkinning_Bone>(); List <Matrix4x4> matrices = new List <Matrix4x4>(); List <string> bonesHierarchyNames = null; if (boneAnimation.bonesHierarchyNames == null) { bonesHierarchyNames = new List <string>(); } EditorCurveBinding[] curvesBinding = AnimationUtility.GetCurveBindings(animClip); foreach (var curveBinding in curvesBinding) { GPUSkinning_Bone bone = GetBoneByHierarchyName(curveBinding.path); if (bones2.Contains(bone)) { continue; } bones2.Add(bone); if (bonesHierarchyNames != null) { bonesHierarchyNames.Add(GetBoneHierarchyName(bone)); } AnimationCurve curveRX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.x"); AnimationCurve curveRY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.y"); AnimationCurve curveRZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.z"); AnimationCurve curveRW = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.w"); AnimationCurve curvePX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.x"); AnimationCurve curvePY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.y"); AnimationCurve curvePZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.z"); float curveRX_v = curveRX.Evaluate(second); float curveRY_v = curveRY.Evaluate(second); float curveRZ_v = curveRZ.Evaluate(second); float curveRW_v = curveRW.Evaluate(second); float curvePX_v = curvePX.Evaluate(second); float curvePY_v = curvePY.Evaluate(second); float curvePZ_v = curvePZ.Evaluate(second); Vector3 translation = new Vector3(curvePX_v, curvePY_v, curvePZ_v); Quaternion rotation = new Quaternion(curveRX_v, curveRY_v, curveRZ_v, curveRW_v); NormalizeQuaternion(ref rotation); matrices.Add( Matrix4x4.TRS(translation, rotation, Vector3.one) ); } frame.bones = bones2.ToArray(); frame.matrices = matrices.ToArray(); if (boneAnimation.bonesHierarchyNames == null) { boneAnimation.bonesHierarchyNames = bonesHierarchyNames.ToArray(); } } } // Save as ScriptableObject AssetDatabase.CreateAsset(boneAnimations[0], "Assets/GPUSkinning/Resources/anim0.asset"); AssetDatabase.Refresh(); #else // Read from ScriptableObject directly boneAnimations = new GPUSkinning_BoneAnimation[] { Resources.Load("anim0") as GPUSkinning_BoneAnimation }; foreach (var boneAnimation in boneAnimations) { foreach (var frame in boneAnimation.frames) { int numBones2 = boneAnimation.bonesHierarchyNames.Length; frame.bones = new GPUSkinning_Bone[numBones2]; for (int i = 0; i < numBones2; ++i) { frame.bones[i] = GetBoneByHierarchyName(boneAnimation.bonesHierarchyNames[i]); } } } #endif // Spawn many models if (spawnPoints != null) { List <GPUSkinning_SpawnObject> list = new List <GPUSkinning_SpawnObject>(); for (int i = 0; i < spawnPoints.Length; ++i) { for (int j = 0; j < spawnPoints[i].childCount; ++j) { GPUSkinning_SpawnObject spawnObject = new GPUSkinning_SpawnObject(); list.Add(spawnObject); spawnObject.transform = spawnPoints[i].GetChild(j); spawnObject.mf = spawnObject.transform.gameObject.AddComponent <MeshFilter>(); spawnObject.mr = spawnObject.transform.gameObject.AddComponent <MeshRenderer>(); spawnObject.mr.sharedMaterial = newMtrl; spawnObject.mf.sharedMesh = newMesh; } } spawnObjects = list.ToArray(); } }
private void Start() { shaderPropID_Matrices = Shader.PropertyToID("_Matrices"); shaderPropID_MatricesTex = Shader.PropertyToID("_MatricesTex"); shaderPropID_MatricesTexSize = Shader.PropertyToID("_MatricesTexSize"); shaderPropID_AnimLength = Shader.PropertyToID("_AnimLength"); shaderPropID_AnimFPS = Shader.PropertyToID("_AnimFPS"); shaderPropID_TerrainTex = Shader.PropertyToID("_TerrainTex"); shaderPropID_TerrainSize = Shader.PropertyToID("_TerrainSize"); shaderPropID_TerrainPos = Shader.PropertyToID("_TerrainPos"); shaderPropID_mpb_time = Shader.PropertyToID("_mpb_time"); smr = GetComponentInChildren <SkinnedMeshRenderer>(); mesh = smr.sharedMesh; // 初始化骨骼对象 int numBones = smr.bones.Length; bones = new GPUSkinning_Bone[numBones]; for (int i = 0; i < numBones; ++i) { GPUSkinning_Bone bone = new GPUSkinning_Bone(); bones[i] = bone; bone.transform = smr.bones[i]; bone.bindpose = mesh.bindposes[i] /*smr to bone*/; } matricesUniformBlock = new Matrix4x4[numBones]; // 构建骨骼的层级结构 for (int i = 0; i < numBones; ++i) { if (bones[i].transform == smr.rootBone) { rootBoneIndex = i; break; } } System.Action <GPUSkinning_Bone> CollectChildren = null; CollectChildren = (currentBone) => { List <GPUSkinning_Bone> children = new List <GPUSkinning_Bone>(); for (int j = 0; j < currentBone.transform.childCount; ++j) { Transform childTransform = currentBone.transform.GetChild(j); GPUSkinning_Bone childBone = GetBoneByTransform(childTransform); if (childBone != null) { childBone.parent = currentBone; children.Add(childBone); CollectChildren(childBone); } } currentBone.children = children.ToArray(); }; CollectChildren(bones[rootBoneIndex]); // New MeshFilter MeshRenderer mf = gameObject.AddComponent <MeshFilter>(); mr = gameObject.AddComponent <MeshRenderer>(); newMtrl = new Material(Shader.Find("Unlit/GPUSkinning")); newMtrl.CopyPropertiesFromMaterial(smr.sharedMaterial); mr.sharedMaterial = newMtrl; // 保存骨骼动画权重 Vector4[] tangents = new Vector4[mesh.vertexCount]; for (int i = 0; i < mesh.vertexCount; ++i) { BoneWeight boneWeight = mesh.boneWeights[i]; tangents[i].x = boneWeight.boneIndex0; tangents[i].y = boneWeight.weight0; tangents[i].z = boneWeight.boneIndex1; tangents[i].w = boneWeight.weight1; } // New Mesh newMesh = new Mesh(); newMesh.vertices = mesh.vertices; newMesh.tangents = tangents; newMesh.uv = mesh.uv; newMesh.triangles = mesh.triangles; mf.sharedMesh = newMesh; // 为每个角色生成差异化数据 if (IsMatricesTextureSupported()) { additionalVertexStreames = new Mesh[50]; for (int i = 0; i < additionalVertexStreames.Length; ++i) { Mesh m = new Mesh(); float rnd = Random.Range(0.0f, 10.0f); Vector2[] uv2 = new Vector2[mesh.vertexCount]; for (int j = 0; j < mesh.vertexCount; ++j) { Vector2 uv = Vector2.zero; uv.x = rnd; uv2[j] = uv; } m.vertices = newMesh.vertices; m.uv2 = uv2; m.UploadMeshData(true); additionalVertexStreames[i] = m; } mr.additionalVertexStreams = additionalVertexStreames[0]; } #if UNITY_EDITOR // 从 Unity 的 Animation 中提取骨骼动画所需要的数据 int boneAnimationsCount = 0; boneAnimations = new GPUSkinning_BoneAnimation[GetComponent <Animator>().runtimeAnimatorController.animationClips.Length]; foreach (AnimationClip animClip in GetComponent <Animator>().runtimeAnimatorController.animationClips) { GPUSkinning_BoneAnimation boneAnimation = ScriptableObject.CreateInstance <GPUSkinning_BoneAnimation>(); boneAnimation.fps = 60; boneAnimation.animName = animClip.name; boneAnimation.frames = new GPUSkinning_BoneAnimationFrame[(int)(animClip.length * boneAnimation.fps)]; boneAnimation.length = animClip.length; boneAnimations[boneAnimationsCount++] = boneAnimation; for (int frameIndex = 0; frameIndex < boneAnimation.frames.Length; ++frameIndex) { GPUSkinning_BoneAnimationFrame frame = new GPUSkinning_BoneAnimationFrame(); boneAnimation.frames[frameIndex] = frame; float second = (float)(frameIndex) / (float)boneAnimation.fps; List <GPUSkinning_Bone> bones2 = new List <GPUSkinning_Bone>(); List <Matrix4x4> matrices = new List <Matrix4x4>(); List <string> bonesHierarchyNames = null; if (boneAnimation.bonesHierarchyNames == null) { bonesHierarchyNames = new List <string>(); } EditorCurveBinding[] curvesBinding = AnimationUtility.GetCurveBindings(animClip); foreach (var curveBinding in curvesBinding) { GPUSkinning_Bone bone = GetBoneByHierarchyName(curveBinding.path); if (bones2.Contains(bone)) { continue; } bones2.Add(bone); if (bonesHierarchyNames != null) { bonesHierarchyNames.Add(GetBoneHierarchyName(bone)); } AnimationCurve curveRX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.x"); AnimationCurve curveRY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.y"); AnimationCurve curveRZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.z"); AnimationCurve curveRW = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalRotation.w"); AnimationCurve curvePX = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.x"); AnimationCurve curvePY = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.y"); AnimationCurve curvePZ = AnimationUtility.GetEditorCurve(animClip, curveBinding.path, curveBinding.type, "m_LocalPosition.z"); float curveRX_v = curveRX.Evaluate(second); float curveRY_v = curveRY.Evaluate(second); float curveRZ_v = curveRZ.Evaluate(second); float curveRW_v = curveRW.Evaluate(second); float curvePX_v = curvePX.Evaluate(second); float curvePY_v = curvePY.Evaluate(second); float curvePZ_v = curvePZ.Evaluate(second); Vector3 translation = new Vector3(curvePX_v, curvePY_v, curvePZ_v); Quaternion rotation = new Quaternion(curveRX_v, curveRY_v, curveRZ_v, curveRW_v); NormalizeQuaternion(ref rotation); matrices.Add( Matrix4x4.TRS(translation, rotation, Vector3.one) ); } frame.bones = bones2.ToArray(); frame.matrices = matrices.ToArray(); if (boneAnimation.bonesHierarchyNames == null) { boneAnimation.bonesHierarchyNames = bonesHierarchyNames.ToArray(); } } } AssetDatabase.CreateAsset(boneAnimations[0], "Assets/GPUSkinning/Resources/anim0.asset"); AssetDatabase.Refresh(); #else // 直接读取序列化的骨骼动画数据 boneAnimations = new GPUSkinning_BoneAnimation[] { Resources.Load("anim0") as GPUSkinning_BoneAnimation }; foreach (var boneAnimation in boneAnimations) { foreach (var frame in boneAnimation.frames) { int numBones2 = boneAnimation.bonesHierarchyNames.Length; frame.bones = new GPUSkinning_Bone[numBones2]; for (int i = 0; i < numBones2; ++i) { frame.bones[i] = GetBoneByHierarchyName(boneAnimation.bonesHierarchyNames[i]); } } } #endif // 创建出更多的角色模型 if (spawnPoints != null) { List <GPUSkinning_SpawnObject> list = new List <GPUSkinning_SpawnObject>(); for (int i = 0; i < spawnPoints.Length; ++i) { for (int j = 0; j < spawnPoints[i].childCount; ++j) { GPUSkinning_SpawnObject spawnObject = new GPUSkinning_SpawnObject(); list.Add(spawnObject); spawnObject.transform = spawnPoints[i].GetChild(j); spawnObject.mf = spawnObject.transform.gameObject.AddComponent <MeshFilter>(); spawnObject.mr = spawnObject.transform.gameObject.AddComponent <MeshRenderer>(); spawnObject.mr.sharedMaterial = newMtrl; spawnObject.mf.sharedMesh = newMesh; if (additionalVertexStreames != null) { // 当开启 GPUInstancing 时,这个是不需要的,偷懒就直接设置了 spawnObject.mr.additionalVertexStreams = additionalVertexStreames[Random.Range(0, additionalVertexStreames.Length)]; } } } spawnObjects = list.ToArray(); } // 销毁并暂停 Unity 的 Animator GameObject.Destroy(transform.FindChild("pelvis").gameObject); GameObject.Destroy(transform.FindChild("mutant_mesh").gameObject); Object.Destroy(gameObject.GetComponent <Animator>()); smr.enabled = false; //PrintBones(); CreateMatricesTexture(); BakeAnimationsToTexture(); SetPlayMode0(); InitTerrain(); SetTerrainHeightSwitch(); InitGPUInstancing(); InitComputeBuffer(newMesh); newMesh.UploadMeshData(true); }