///////////////////////////////////////// //Component_Skeleton.SkinningModeEnum GetSkinningMode( Component_Skeleton skeleton ) //{ // var _override = OverrideSkinningMode.Value; // if( _override != Component_Skeleton.SkinningModeEnum.Auto ) // return _override; // var selected = skeleton.SkinningMode.Value; // if( selected != Component_Skeleton.SkinningModeEnum.Auto ) // return selected; // if( !hasScale ) // return Component_Skeleton.SkinningModeEnum.DualQuaternion; // else // return Component_Skeleton.SkinningModeEnum.Linear; //} protected virtual void CalculateCPU(Component_Skeleton skeleton, Component_Mesh originalMesh, Component_Mesh modifiableMesh) { bool dualQuaternion = false; // GetSkinningMode( skeleton ) == Component_Skeleton.SkinningModeEnum.DualQuaternion; for (int nOper = 0; nOper < modifiableMesh.Result.MeshData.RenderOperations.Count; nOper++) { var sourceOper = originalMesh.Result.MeshData.RenderOperations[nOper]; var destOper = modifiableMesh.Result.MeshData.RenderOperations[nOper]; var position = new ChannelFloat3(sourceOper, destOper, VertexElementSemantic.Position); if (position.Exists) { var normal = new ChannelFloat3(sourceOper, destOper, VertexElementSemantic.Normal); var tangent = new ChannelFloat4(sourceOper, destOper, VertexElementSemantic.Tangent); var blendIndices = new SourceChannel <Vector4I>(sourceOper, VertexElementSemantic.BlendIndices, VertexElementType.Integer4); var blendWeights = new SourceChannel <Vector4F>(sourceOper, VertexElementSemantic.BlendWeights, VertexElementType.Float4); if (!blendIndices.Exists || !blendWeights.Exists) { continue; } if (normal.Exists) { if (tangent.Exists) { TransformVertices( dualQuaternion, position.SourceData, normal.SourceData, tangent.SourceData, blendIndices.SourceData, blendWeights.SourceData, position.DestData, normal.DestData, tangent.DestData ); } else { TransformVertices( dualQuaternion, position.SourceData, normal.SourceData, blendIndices.SourceData, blendWeights.SourceData, position.DestData, normal.DestData ); } } else { TransformVertices( dualQuaternion, position.SourceData, blendIndices.SourceData, blendWeights.SourceData, position.DestData ); } position.WriteChannel(); normal.WriteChannel(); tangent.WriteChannel(); } } }
///////////////////////////////////////// public int GetCachedBoneIndex(Component_Skeleton skeleton) { //!!!!threading if (getCachedBoneIndex_Skeleton != skeleton) { getCachedBoneIndex_Skeleton = skeleton; getCachedBoneIndex_Index = Array.IndexOf(skeleton.GetBones(), this); } return(getCachedBoneIndex_Index); }
void Update(Component_Skeleton skeleton, Component_SkeletonAnimationTrack animationTrack, double time) { if (time != calculatedForTime) { //update general data calculatedForTime = time; bones = skeleton.GetBones(); //calculate bone transforms if (boneTransforms == null || boneTransforms.Length != bones.Length) { boneTransforms = new Component_SkeletonAnimationTrack.CalculateBoneTransformsItem[bones.Length]; } animationTrack?.CalculateBoneTransforms(time, boneTransforms); CalculateBoneTransforms?.Invoke(this, boneTransforms); //calculate transformMatrixRelativeToSkin, transformRelativeToSkin, boneGlobalTransforms, hasScale if (transformMatrixRelativeToSkin == null || transformMatrixRelativeToSkin.Length != bones.Length) { transformMatrixRelativeToSkin = new Matrix4F[bones.Length]; } if (transformRelativeToSkin == null || transformRelativeToSkin.Length != bones.Length) { transformRelativeToSkin = new Component_SkeletonAnimationTrack.CalculateBoneTransformsItem[bones.Length]; } if (boneGlobalTransforms == null || boneGlobalTransforms.Length != bones.Length) { boneGlobalTransforms = new BoneGlobalTransformItem[bones.Length]; } var matrixZero = Matrix4F.Zero; for (int i = 0; i < bones.Length; i++) { boneGlobalTransforms[i] = new BoneGlobalTransformItem(false, ref matrixZero); } foreach (var b in bones) { GetBoneGlobalTransformRecursive(skeleton, b); } hasScale = false; for (int i = 0; i < bones.Length; i++) { var bone = bones[i]; Matrix4F m; if (bone != null) { Matrix4F.Multiply(ref GetBoneGlobalTransformRecursive(skeleton, bone), ref bone.GetTransformMatrixInverse(), out m); } else { m = Matrix4F.Identity; } transformMatrixRelativeToSkin[i] = m; m.Decompose(out Vector3F t, out QuaternionF r, out Vector3F s); transformRelativeToSkin[i] = new Component_SkeletonAnimationTrack.CalculateBoneTransformsItem { Position = t, Rotation = r, Scale = s }; //if the scale differs from 1.0 more than this value, then the scaling is present and DualQuaternionSkinning can not be used. const float EpsilonForScale = 1e-3f; if (Math.Abs(1.0f - s.X) > EpsilonForScale || Math.Abs(1.0f - s.Y) > EpsilonForScale || Math.Abs(1.0f - s.Y) > EpsilonForScale) { hasScale = true; } } } }
private void ParentMeshInSpace_GetRenderSceneDataAddToFrameData(Component_MeshInSpace sender, ViewportRenderingContext context, GetRenderSceneDataMode mode, ref Component_RenderingPipeline.RenderSceneData.MeshItem item) { if (!CalculateOnCPU) { Component_Skeleton skeleton = ReplaceSkeleton; if (skeleton == null) { skeleton = ParentMeshInSpace?.Mesh.Value?.Skeleton; } if (skeleton != null) { var animation = PlayAnimation.Value; if (animation != null) { UpdateAnimationTime(); //settings.animationStates = new AnimationStateItem[ 1 ]; //settings.animationStates[ 0 ] = new AnimationStateItem( animation, currentLocalTime, 1 ); var skeletonAnimation = animation as Component_SkeletonAnimation; var track = skeletonAnimation?.Track.Value; if (track != null || CalculateBoneTransforms != null) { Update(skeleton, track, currentAnimationTime); if (transformMatrixRelativeToSkin != null && transformMatrixRelativeToSkin.Length != 0) { item.AnimationData = new Component_RenderingPipeline.RenderSceneData.MeshItem.AnimationDataClass(); bool dualQuaternion = false; // GetSkinningMode( skeleton ) == Component_Skeleton.SkinningModeEnum.DualQuaternion; if (dualQuaternion) { item.AnimationData.Mode = 2; } else { item.AnimationData.Mode = 1; } //create dynamic texture var size = new Vector2I(4, MathEx.NextPowerOfTwo(transformMatrixRelativeToSkin.Length)); var bonesTexture = context.DynamicTexture_Alloc(ViewportRenderingContext.DynamicTextureType.DynamicTexture, Component_Image.TypeEnum._2D, size, PixelFormat.Float32RGBA, 0, false); //try get array from texture to minimize memory allocations var surfaces = bonesTexture.Result.GetData(); if (surfaces == null) { surfaces = new GpuTexture.SurfaceData[] { new GpuTexture.SurfaceData(0, 0, new byte[size.X * size.Y * 16]) } } ; var data = surfaces[0].data; //copy data to the texture unsafe { fixed(byte *pData2 = data) { Matrix4F *pData = (Matrix4F *)pData2; for (int n = 0; n < transformMatrixRelativeToSkin.Length; n++) { pData[n] = transformMatrixRelativeToSkin[n]; } } } bonesTexture.Result.SetData(new GpuTexture.SurfaceData[] { new GpuTexture.SurfaceData(0, 0, data) }); item.AnimationData.BonesTexture = bonesTexture; } } } } } } void RenderSkeleton(Viewport viewport) { // ParentMeshInSpace.Transform is automaticaly applyed to ParentMeshInSpace.Mesh, skeleton must be transformed manually var transformMatrix = ParentMeshInSpace?.Transform.Value?.ToMatrix4() ?? Matrix4.Identity; var skeletonArrows = GetCurrentAnimatedSkeletonArrows(); if (skeletonArrows != null) { var color = new ColorValue(0, 0.5, 1, 0.7); //ToDo : Вынести в другое место. viewport.Simple3DRenderer.SetColor(color, color * ProjectSettings.Get.HiddenByOtherObjectsColorMultiplier); foreach (var arrow in skeletonArrows) { viewport.Simple3DRenderer.AddArrow(transformMatrix * arrow.Start, transformMatrix * arrow.End); } } } bool CheckNeedModifiableMesh() { if (CalculateOnCPU) { if (ReplaceSkeleton.ReferenceSpecified) { return(true); } var mesh = ParentMeshInSpace?.Mesh.Value; if (mesh != null && mesh.Skeleton.ReferenceSpecified) { return(true); } if (PlayAnimation.ReferenceSpecified) { return(true); } } return(false); } void UpdateModifiableMesh(ViewportRenderingContext context) { var originalMesh = ParentMeshInSpace.Mesh.Value; var modifiableMesh = ParentMeshInSpace.ModifiableMesh; Component_Skeleton skeleton = ReplaceSkeleton; if (skeleton == null) { skeleton = originalMesh.Skeleton; } if (skeleton != null) { //!!!!сериализовывать var animation = PlayAnimation.Value; if (animation != null) { UpdateAnimationTime(); //settings.animationStates = new AnimationStateItem[ 1 ]; //settings.animationStates[ 0 ] = new AnimationStateItem( animation, currentLocalTime, 1 ); var skeletonAnimation = animation as Component_SkeletonAnimation; var track = skeletonAnimation?.Track.Value; if (track != null || CalculateBoneTransforms != null) { Update(skeleton, track, currentAnimationTime); CalculateCPU(skeleton, originalMesh, modifiableMesh); } } if (needResetToOriginalMesh) { needResetToOriginalMesh = false; if (CalculateOnCPU) { ResetToOriginalMesh(originalMesh, modifiableMesh); } } } } ///////////////////////////////////////// void ResetTime(bool needResetToOriginalMesh) { if (needResetToOriginalMesh) { this.needResetToOriginalMesh = true; } currentEngineTime = EngineApp.EngineTime; currentAnimationTime = (PlayAnimation.Value as Component_SkeletonAnimation)?.TrackStartTime ?? 0; } void UpdateAnimationTime() { double t = EngineApp.EngineTime; double increment = t - currentEngineTime; currentEngineTime = t; currentAnimationTime += increment * Speed; var animation = PlayAnimation.Value as Component_SkeletonAnimation; if (animation != null) { double animationStartTime = animation.TrackStartTime; double animationLength = animation.Length; if (animationLength > 0) { if (AutoRewind) { while (currentAnimationTime > animationStartTime + animationLength) { currentAnimationTime -= animationLength; } while (currentAnimationTime < animationStartTime) { currentAnimationTime += animationLength; } } else { MathEx.Clamp(ref currentAnimationTime, animationStartTime, animationStartTime + animationLength); } } else { currentAnimationTime = animationStartTime; } } else { currentAnimationTime = 0; } }