private void UpdateJoints(GPUSkinningFrame frame) { if (joints == null) { return; } Matrix4x4[] matrices = frame.matrices; GPUSkinningBone[] bones = res.anim.bones; int numJoints = joints.Count; for (int i = 0; i < numJoints; ++i) { GPUSkinningPlayerJoint joint = joints[i]; Transform jointTransform = Application.isPlaying ? joint.Transform : joint.transform; if (jointTransform != null) { jointTransform.localPosition = (frame.matrices[joint.BoneIndex] * bones[joint.BoneIndex].BindposeInv).MultiplyPoint(Vector3.zero); } else { joints.RemoveAt(i); --i; --numJoints; } } }
private void CreateTextureMatrix(string dir, GPUSkinningAnimation gpuSkinningAnim) { Texture2D texture = new Texture2D(gpuSkinningAnim.textureWidth, gpuSkinningAnim.textureHeight, TextureFormat.RGBAHalf, false, true); Color[] pixels = texture.GetPixels(); int pixelIndex = 0; for (int clipIndex = 0; clipIndex < gpuSkinningAnim.clips.Length; ++clipIndex) { GPUSkinningClip clip = gpuSkinningAnim.clips[clipIndex]; GPUSkinningFrame[] frames = clip.frames; int numFrames = frames.Length; for (int frameIndex = 0; frameIndex < numFrames; ++frameIndex) { GPUSkinningFrame frame = frames[frameIndex]; Matrix4x4[] matrices = frame.matrices; int numMatrices = matrices.Length; for (int matrixIndex = 0; matrixIndex < numMatrices; ++matrixIndex) { Matrix4x4 matrix = matrices[matrixIndex]; pixels[pixelIndex++] = new Color(matrix.m00, matrix.m01, matrix.m02, matrix.m03); pixels[pixelIndex++] = new Color(matrix.m10, matrix.m11, matrix.m12, matrix.m13); pixels[pixelIndex++] = new Color(matrix.m20, matrix.m21, matrix.m22, matrix.m23); } } } texture.SetPixels(pixels); texture.Apply(); string savedPath = dir + "/GPUSKinning_Texture_" + animName + ".bytes"; File.WriteAllBytes(savedPath, texture.GetRawTextureData()); WriteTempData(TEMP_SAVED_TEXTURE_PATH, savedPath); }
/// <summary> /// 设置动画片段的Material->Shader属性,使用GPU计算动画片段数据 /// </summary> /// <param name="mpb"> 需要设置的MaterialPropertyBlock </param> /// <param name="playingClip"> 当前播放的动画片段 </param> /// <param name="frameIndex"> 帧索引 </param> /// <param name="frame"> 帧数据 </param> /// <param name="rootMotionEnabled"> 是否应用RootMotion </param> /// <param name="lastPlayedClip"> 上一次播放的动画片段 </param> /// <param name="frameIndex_crossFade"> 需要CrossFade的上一个动画片段帧索引(上一次播放到的动画片段) </param> /// <param name="crossFadeTime"> CrossFade所花的时间 </param> /// <param name="crossFadeProgress"> CrossFade已经处理的时间 </param> public void UpdatePlayingData( MaterialPropertyBlock mpb, GPUSkinningClip playingClip, int frameIndex, GPUSkinningFrame frame, bool rootMotionEnabled, GPUSkinningClip lastPlayedClip, int frameIndex_crossFade, float crossFadeTime, float crossFadeProgress) { //Profiler.BeginSample("Res.UpdatePlayingData"); //设置mpb的Vector属性 mpb.SetVector(shaderPorpID_GPUSkinning_FrameIndex_PixelSegmentation, new Vector4(frameIndex, playingClip.pixelSegmentation, 0, 0)); //如果开启RootMotion if (rootMotionEnabled) { Matrix4x4 rootMotionInv = frame.RootMotionInv(anim.rootBoneIndex); mpb.SetMatrix(shaderPropID_GPUSkinning_RootMotion, rootMotionInv); } //如果开启CrossFade if (IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { if (lastPlayedClip.rootMotionEnabled) { mpb.SetMatrix(shaderPropID_GPUSkinning_RootMotion_CrossFade, lastPlayedClip.frames[frameIndex_crossFade].RootMotionInv(anim.rootBoneIndex)); } mpb.SetVector(shaderPorpID_GPUSkinning_FrameIndex_PixelSegmentation_Blend_CrossFade, new Vector4(frameIndex_crossFade, lastPlayedClip.pixelSegmentation, CrossFadeBlendFactor(crossFadeProgress, crossFadeTime))); } //Profiler.EndSample(); }
private IEnumerator SamplingCoroutine(GPUSkinningFrame frame, int totalFrames) { yield return(new WaitForEndOfFrame()); GPUSkinningBone[] bones = gpuSkinningAnimation.bones; int numBones = bones.Length; for (int i = 0; i < numBones; ++i) { Transform boneTransform = bones[i].transform; GPUSkinningBone currentBone = GetBoneByTransform(boneTransform); frame.matrices[i] = currentBone.bindpose; do { Matrix4x4 mat = Matrix4x4.TRS(currentBone.transform.localPosition, currentBone.transform.localRotation, currentBone.transform.localScale); frame.matrices[i] = mat * frame.matrices[i]; if (currentBone.parentBoneIndex == -1) { break; } else { currentBone = bones[currentBone.parentBoneIndex]; } }while (true); } if (samplingFrameIndex == 0) { rootMotionPosition = bones[gpuSkinningAnimation.rootBoneIndex].transform.localPosition; rootMotionRotation = bones[gpuSkinningAnimation.rootBoneIndex].transform.localRotation; } else { Vector3 newPosition = bones[gpuSkinningAnimation.rootBoneIndex].transform.localPosition; Quaternion newRotation = bones[gpuSkinningAnimation.rootBoneIndex].transform.localRotation; Vector3 deltaPosition = newPosition - rootMotionPosition; frame.rootMotionDeltaPositionQ = Quaternion.Inverse(Quaternion.Euler(transform.forward.normalized)) * Quaternion.Euler(deltaPosition.normalized); frame.rootMotionDeltaPositionL = deltaPosition.magnitude; frame.rootMotionDeltaRotation = Quaternion.Inverse(rootMotionRotation) * newRotation; rootMotionPosition = newPosition; rootMotionRotation = newRotation; if (samplingFrameIndex == 1) { gpuSkinningClip.frames[0].rootMotionDeltaPositionQ = gpuSkinningClip.frames[1].rootMotionDeltaPositionQ; gpuSkinningClip.frames[0].rootMotionDeltaPositionL = gpuSkinningClip.frames[1].rootMotionDeltaPositionL; gpuSkinningClip.frames[0].rootMotionDeltaRotation = gpuSkinningClip.frames[1].rootMotionDeltaRotation; } } ++samplingFrameIndex; }
public void UpdatePlayingData( GPUSkinningClip playingClip, int frameIndex, GPUSkinningFrame frame, bool rootMotionEnabled, GPUSkinningClip lastPlayedClip, int frameIndex_crossFade, float crossFadeTime, float crossFadeProgress) { //Profiler.BeginSample("PlayerMono.UpdatePlayingData"); myRes.UpdatePlayingData(mpb, playingClip, frameIndex, frame, rootMotionEnabled, lastPlayedClip, frameIndex_crossFade, crossFadeTime, crossFadeProgress); //Profiler.EndSample(); //Profiler.BeginSample("PlayerMono.SetPropertyBlock"); mr.SetPropertyBlock(mpb); //Profiler.EndSample(); }
private void UpdateMaterial_Thread(float deltaTime) { int frameIndex = GetFrameIndex(); //动画片段(WrapMode.Once)播放完毕 if (lastPlayingClip == playingClip && lastPlayingFrameIndex == frameIndex) { resTime += deltaTime; //for (int i = 0; i < playerMonosCount; i++) // playerMonos[i].UpdateMaterial(deltaTime); return; } //记录上一帧播放的动画片段 lastPlayingClip = playingClip; //记录上一次播放的动画片段帧数(有可能跳帧) lastPlayingFrameIndex = frameIndex; blend_crossFade = 1; frameIndex_crossFade = -1; // 新建动画帧,用于crossFade GPUSkinningFrame frame_crossFade = null; if (IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { frameIndex_crossFade = GetCrossFadeFrameIndex(); frame_crossFade = lastPlayedClip.frames[frameIndex_crossFade]; blend_crossFade = CrossFadeBlendFactor(crossFadeProgress, crossFadeTime); } GPUSkinningFrame frame = playingClip.frames[frameIndex]; if (Visible || CullingMode == GPUSKinningCullingMode.AlwaysAnimate) { resTime += deltaTime; //计算临时变量 isRootMotionEnabled = playingClip.rootMotionEnabled && rootMotionEnabled; framePixelSegmentation = new Vector4(frameIndex, playingClip.pixelSegmentation, 0, 0); if (lastPlayedClip != null && frameIndex_crossFade >= 0) { framePixelSegmentation_Blend_CrossFade = new Vector4(frameIndex_crossFade, lastPlayedClip.pixelSegmentation, CrossFadeBlendFactor(crossFadeProgress, crossFadeTime)); rootMotionInv_Last = lastPlayedClip.frames[frameIndex_crossFade].RootMotionInv(anim.rootBoneIndex); } //Unity API无法在线程内调用 //UpdatePlayingData(framePixelSegmentation, rootMotionInv, isRootMotionEnabled, rootMotionInv_Last, framePixelSegmentation_Blend_CrossFade); } }
private void UpdateMaterial(float deltaTime, GPUSkinningMaterial currMtrl) { int frameIndex = GetFrameIndex(); if (lastPlayingClip == playingClip && lastPlayingFrameIndex == frameIndex) { res.Update(deltaTime, currMtrl); return; } lastPlayingClip = playingClip; lastPlayingFrameIndex = frameIndex; float blend_crossFade = 1; int frameIndex_crossFade = -1; GPUSkinningFrame frame_crossFade = null; if (res.IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { frameIndex_crossFade = GetCrossFadeFrameIndex(); frame_crossFade = lastPlayedClip.frames[frameIndex_crossFade]; blend_crossFade = res.CrossFadeBlendFactor(crossFadeProgress, crossFadeTime); } GPUSkinningFrame frame = playingClip.frames[frameIndex]; if (Visible || CullingMode == GPUSKinningCullingMode.AlwaysAnimate) { res.Update(deltaTime, currMtrl); res.UpdatePlayingData( mpb, playingClip, frameIndex, frame, playingClip.rootMotionEnabled && rootMotionEnabled, lastPlayedClip, GetCrossFadeFrameIndex(), crossFadeTime, crossFadeProgress ); mr.SetPropertyBlock(mpb); UpdateJoints(frame); } if (playingClip.rootMotionEnabled && rootMotionEnabled && frameIndex != rootMotionFrameIndex) { if (CullingMode != GPUSKinningCullingMode.CullCompletely) { rootMotionFrameIndex = frameIndex; DoRootMotion(frame_crossFade, 1 - blend_crossFade, false); DoRootMotion(frame, blend_crossFade, true); } } UpdateEvents(playingClip, frameIndex, frame_crossFade == null ? null : lastPlayedClip, frameIndex_crossFade); }
private void CreateTextureMatrix(string dir, GPUSkinningAnimation gpuSkinningAnim) { Texture2D texture = new Texture2D(gpuSkinningAnim.textureWidth, gpuSkinningAnim.textureHeight, TextureFormat.RGBAHalf, false, true); texture.filterMode = FilterMode.Point; texture.wrapMode = TextureWrapMode.Clamp; texture.anisoLevel = 0; Color[] pixels = texture.GetPixels(); int pixelIndex = 0; for (int clipIndex = 0; clipIndex < gpuSkinningAnim.clips.Length; ++clipIndex) { GPUSkinningClip clip = gpuSkinningAnim.clips[clipIndex]; GPUSkinningFrame[] frames = clip.frames; int numFrames = frames.Length; for (int frameIndex = 0; frameIndex < numFrames; ++frameIndex) { GPUSkinningFrame frame = frames[frameIndex]; Matrix4x4[] matrices = frame.matrices; int numMatrices = matrices.Length; for (int matrixIndex = 0; matrixIndex < numMatrices; ++matrixIndex) { Matrix4x4 matrix = matrices[matrixIndex]; pixels[pixelIndex++] = new Color(matrix.m00, matrix.m01, matrix.m02, matrix.m03); pixels[pixelIndex++] = new Color(matrix.m10, matrix.m11, matrix.m12, matrix.m13); pixels[pixelIndex++] = new Color(matrix.m20, matrix.m21, matrix.m22, matrix.m23); } } } texture.SetPixels(pixels); texture.Apply(); string savedPath = dir + "/GPUSKinning_Texture_" + animName + ".asset"; AssetDatabase.CreateAsset(texture, savedPath); WriteTempData(TEMP_SAVED_TEXTURE_PATH, savedPath); //string savedPath = dir + "/GPUSKinning_Texture_" + animName + ".bytes"; //using (FileStream fileStream = new FileStream(savedPath, FileMode.Create)) //{ // byte[] bytes = texture.GetRawTextureData(); // fileStream.Write(bytes, 0, bytes.Length); // fileStream.Flush(); // fileStream.Close(); // fileStream.Dispose(); //} //WriteTempData(TEMP_SAVED_TEXTURE_PATH, savedPath); }
private void DoRootMotion(GPUSkinningFrame frame, float blend, bool doRotate) { if (frame == null) { return; } Quaternion deltaRotation = frame.rootMotionDeltaPositionQ; Vector3 newForward = deltaRotation * transform.forward; Vector3 deltaPosition = newForward * frame.rootMotionDeltaPositionL * blend; transform.Translate(deltaPosition, Space.World); if (doRotate) { transform.rotation *= frame.rootMotionDeltaRotation; } }
private void UpdateJoints(GPUSkinningFrame frame) { if (joints == null) { return; } //fzy delete:never used //Matrix4x4[] matrices = frame.matrices; GPUSkinningBone[] bones = res.anim.bones; int numJoints = joints.Count; for (int i = 0; i < numJoints; ++i) { GPUSkinningPlayerJoint joint = joints[i]; Transform jointTransform = Application.isPlaying ? joint.Transform : joint.transform; if (jointTransform != null) { // TODO: Update Joint when Animation Blend Matrix4x4 jointMatrix = frame.matrices[joint.BoneIndex] * bones[joint.BoneIndex].BindposeInv; if (playingClip.rootMotionEnabled && rootMotionEnabled) { jointMatrix = frame.RootMotionInv(res.anim.rootBoneIndex) * jointMatrix; } jointTransform.localPosition = jointMatrix.MultiplyPoint(Vector3.zero); Vector3 jointDir = jointMatrix.MultiplyVector(Vector3.right); Quaternion jointRotation = Quaternion.FromToRotation(Vector3.right, jointDir); jointTransform.localRotation = jointRotation; } else { joints.RemoveAt(i); --i; --numJoints; } } }
public void UpdatePlayingData( MaterialPropertyBlock mpb, GPUSkinningClip playingClip, int frameIndex, GPUSkinningFrame frame, bool rootMotionEnabled, GPUSkinningClip lastPlayedClip, int frameIndex_crossFade, float crossFadeTime, float crossFadeProgress) { mpb.SetVector(shaderPorpID_GPUSkinning_FrameIndex_PixelSegmentation, new Vector4(frameIndex, playingClip.pixelSegmentation, 0, 0)); if (rootMotionEnabled) { Matrix4x4 rootMotionInv = frame.rootMotionInv; mpb.SetMatrix(shaderPropID_GPUSkinning_RootMotion, rootMotionInv); } if (IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { if (lastPlayedClip.rootMotionEnabled) { mpb.SetMatrix(shaderPropID_GPUSkinning_RootMotion_CrossFade, lastPlayedClip.frames[frameIndex_crossFade].rootMotionInv); } mpb.SetVector(shaderPorpID_GPUSkinning_FrameIndex_PixelSegmentation_Blend_CrossFade, new Vector4(frameIndex_crossFade, lastPlayedClip.pixelSegmentation, CrossFadeBlendFactor(crossFadeProgress, crossFadeTime))); } }
private void UpdateMaterial(float deltaTime) { int frameIndex = GetFrameIndex(); GPUSkinningFrame frame = playingClip.frames[frameIndex]; res.Update(deltaTime); res.UpdatePlayingData(mpb, playingClip, frameIndex, frame, playingClip.rootMotionEnabled && rootMotionEnabled); mr.SetPropertyBlock(mpb); UpdateJoints(frame); if (playingClip.rootMotionEnabled && rootMotionEnabled && frameIndex != rootMotionFrameIndex) { rootMotionFrameIndex = frameIndex; Quaternion rotation = transform.rotation; Quaternion deltaRotation = frame.rootMotionDeltaPositionQ; transform.rotation *= deltaRotation; Vector3 deltaPosition = transform.forward * frame.rootMotionDeltaPositionL; transform.Translate(deltaPosition, Space.World); transform.rotation = rotation; transform.rotation *= frame.rootMotionDeltaRotation; } }
public void UpdatePlayingData(MaterialPropertyBlock mpb, GPUSkinningClip playingClip, int frameIndex, GPUSkinningFrame frame, bool rootMotionEnabled) { mpb.SetFloat(shaderPorpID_GPUSkinning_FrameIndex, frameIndex); mpb.SetFloat(shaderPropID_GPUSkinning_PixelSegmentation, playingClip.pixelSegmentation); mpb.SetFloat(shaderPropID_GPUSkinning_RootMotionEnabled, rootMotionEnabled ? 1 : -1); if (rootMotionEnabled) { Matrix4x4 rootMotionInv = frame.RootMotionInv(anim.rootBoneIndex); mpb.SetMatrix(shaderPropID_GPUSkinning_RootMotion, rootMotionInv); } }
private void Update() { if (!isSampling) { return; } int totalFrams = (int)(gpuSkinningClip.length * gpuSkinningClip.fps); samplingTotalFrams = totalFrams; if (samplingFrameIndex >= totalFrams) { if (animator != null) { animator.StopPlayback(); } string savePath = null; if (anim == null) { savePath = EditorUtility.SaveFolderPanel("GPUSkinning Sampler Save", GetUserPreferDir(), animName); } else { string animPath = AssetDatabase.GetAssetPath(anim); savePath = new FileInfo(animPath).Directory.FullName.Replace('\\', '/'); } if (!string.IsNullOrEmpty(savePath)) { if (!savePath.Contains(Application.dataPath.Replace('\\', '/'))) { ShowDialog("Must select a directory in the project's Asset folder."); } else { SaveUserPreferDir(savePath); string dir = "Assets" + savePath.Substring(Application.dataPath.Length); string savedAnimPath = dir + "/GPUSKinning_Anim_" + animName + ".asset"; SetSthAboutTexture(gpuSkinningAnimation); EditorUtility.SetDirty(gpuSkinningAnimation); if (anim != gpuSkinningAnimation) { AssetDatabase.CreateAsset(gpuSkinningAnimation, savedAnimPath); } WriteTempData(TEMP_SAVED_ANIM_PATH, savedAnimPath); anim = gpuSkinningAnimation; CreateTextureMatrix(dir, anim); if (samplingClipIndex == 0) { Mesh newMesh = CreateNewMesh(smr.sharedMesh, "GPUSkinning_Mesh"); if (savedMesh != null) { newMesh.bounds = savedMesh.bounds; } string savedMeshPath = dir + "/GPUSKinning_Mesh_" + animName + ".asset"; AssetDatabase.CreateAsset(newMesh, savedMeshPath); WriteTempData(TEMP_SAVED_MESH_PATH, savedMeshPath); savedMesh = newMesh; CreateShaderAndMaterial(dir); CreateLODMeshes(newMesh.bounds, dir); } AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); } } isSampling = false; return; } float time = gpuSkinningClip.length * ((float)samplingFrameIndex / totalFrams); GPUSkinningFrame frame = new GPUSkinningFrame(); gpuSkinningClip.frames[samplingFrameIndex] = frame; frame.matrices = new Matrix4x4[gpuSkinningAnimation.bones.Length]; if (animation == null) { animator.playbackTime = time; animator.Update(0); } else { animation.Stop(); AnimationState animState = animation[animClip.name]; if (animState != null) { animState.time = time; animation.Sample(); animation.Play(); } } StartCoroutine(SamplingCoroutine(frame, totalFrams)); }
/// <summary> /// 根据当前动画片段播放状态设置Material /// fzy remak:CPU资源消耗过多 /// </summary> /// <param name="deltaTime">本帧Update消耗的时间</param> private void UpdateMaterial(float deltaTime) { //Profiler.BeginSample("UpdateMaterial.Other"); int frameIndex = GetFrameIndex(); //动画片段(WrapMode.Once)播放完毕 if (lastPlayingClip == playingClip && lastPlayingFrameIndex == frameIndex) { //res.Update(deltaTime); resTime += deltaTime; //for (int i = 0; i < playerMonosCount; i++) // playerMonos[i].UpdateMaterial(deltaTime); return; } //记录上一帧播放的动画片段 lastPlayingClip = playingClip; //记录上一次播放的动画片段帧数(有可能跳帧) lastPlayingFrameIndex = frameIndex; blend_crossFade = 1; frameIndex_crossFade = -1; // 新建动画帧,用于crossFade GPUSkinningFrame frame_crossFade = null; if (IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { frameIndex_crossFade = GetCrossFadeFrameIndex(); frame_crossFade = lastPlayedClip.frames[frameIndex_crossFade]; blend_crossFade = CrossFadeBlendFactor(crossFadeProgress, crossFadeTime); } GPUSkinningFrame frame = playingClip.frames[frameIndex]; //Profiler.EndSample(); //模型可以被看见(Culling)或者CullingMode为AlwaysAnimate if (Visible || CullingMode == GPUSKinningCullingMode.AlwaysAnimate) { //author version //res.Update(deltaTime); resTime += deltaTime; //fzy remark:不需要每帧调用,已在初始化时设置属性 //for (int i = 0; i < playerMonosCount; i++) //{ // playerMonos[i].UpdateMaterial(deltaTime); //} /*author version * res.UpdatePlayingData( * mpb, playingClip, frameIndex, frame, playingClip.rootMotionEnabled && rootMotionEnabled, * lastPlayedClip, GetCrossFadeFrameIndex(), crossFadeTime, crossFadeProgress * ); * mr.SetPropertyBlock(mpb);*/ //if (Time.frameCount % updatePreFrame != updateRemark) return; //Profiler.BeginSample("UpdatePlayingData"); //计算临时变量 isRootMotionEnabled = playingClip.rootMotionEnabled && rootMotionEnabled; framePixelSegmentation = new Vector4(frameIndex, playingClip.pixelSegmentation, 0, 0); rootMotionInv = frame.RootMotionInv(anim.rootBoneIndex); if (lastPlayedClip != null && frameIndex_crossFade >= 0) { framePixelSegmentation_Blend_CrossFade = new Vector4(frameIndex_crossFade, lastPlayedClip.pixelSegmentation, CrossFadeBlendFactor(crossFadeProgress, crossFadeTime)); rootMotionInv_Last = lastPlayedClip.frames[frameIndex_crossFade].RootMotionInv(anim.rootBoneIndex); } //设置动画播放的Material数据 //UpdatePlayingData(framePixelSegmentation, rootMotionInv, isRootMotionEnabled, rootMotionInv_Last, framePixelSegmentation_Blend_CrossFade); UpdatePlayingData(); //Profiler.EndSample(); //bone.isExposed //UpdateJoints(frame); } //Profiler.BeginSample("RootMotion"); /* * if (playingClip.rootMotionEnabled && rootMotionEnabled && frameIndex != rootMotionFrameIndex) * { * if (CullingMode != GPUSKinningCullingMode.CullCompletely) * { * rootMotionFrameIndex = frameIndex; * DoRootMotion(frame_crossFade, 1 - blend_crossFade, false); * DoRootMotion(frame, blend_crossFade, true); * } * }*/ //Profiler.EndSample(); //UpdateEvents(playingClip, frameIndex, frame_crossFade == null ? null : lastPlayedClip, frameIndex_crossFade); }
/// <summary> /// 根据当前动画片段播放状态设置Material /// fzy remak:CPU资源消耗过多 /// </summary> /// <param name="deltaTime">本帧Update消耗的时间</param> /// <param name="currMtrl">当前使用的Material</param> private void UpdateMaterial(float deltaTime, GPUSkinningMaterial currMtrl) { int frameIndex = GetFrameIndex(); //Profiler.BeginSample("PlayerResources.Update"); //动画片段(WrapMode.Once)播放完毕 if (lastPlayingClip == playingClip && lastPlayingFrameIndex == frameIndex) { res.Update(deltaTime, currMtrl); return; } //Profiler.EndSample(); //记录上一帧播放的动画片段 lastPlayingClip = playingClip; //记录上一次播放的动画片段帧数(有可能跳帧) lastPlayingFrameIndex = frameIndex; float blend_crossFade = 1; int frameIndex_crossFade = -1; // 新建动画帧,用于crossFade GPUSkinningFrame frame_crossFade = null; //Profiler.BeginSample("PlayerResources.CrossFadeBlending"); if (res.IsCrossFadeBlending(lastPlayedClip, crossFadeTime, crossFadeProgress)) { frameIndex_crossFade = GetCrossFadeFrameIndex(); frame_crossFade = lastPlayedClip.frames[frameIndex_crossFade]; blend_crossFade = res.CrossFadeBlendFactor(crossFadeProgress, crossFadeTime); } //Profiler.EndSample(); //Profiler.BeginSample("PlayerResources.Update"); GPUSkinningFrame frame = playingClip.frames[frameIndex]; //模型可以被看见(Culling)或者CullingMode为AlwaysAnimate if (Visible || CullingMode == GPUSKinningCullingMode.AlwaysAnimate) { res.Update(deltaTime, currMtrl); res.UpdatePlayingData( mpb, playingClip, frameIndex, frame, playingClip.rootMotionEnabled && rootMotionEnabled, lastPlayedClip, GetCrossFadeFrameIndex(), crossFadeTime, crossFadeProgress ); mr.SetPropertyBlock(mpb); //bone.isExposed UpdateJoints(frame); } //Profiler.EndSample(); //Profiler.BeginSample("RootMotion"); if (playingClip.rootMotionEnabled && rootMotionEnabled && frameIndex != rootMotionFrameIndex) { if (CullingMode != GPUSKinningCullingMode.CullCompletely) { rootMotionFrameIndex = frameIndex; DoRootMotion(frame_crossFade, 1 - blend_crossFade, false); DoRootMotion(frame, blend_crossFade, true); } } //Profiler.EndSample(); UpdateEvents(playingClip, frameIndex, frame_crossFade == null ? null : lastPlayedClip, frameIndex_crossFade); }