Beispiel #1
0
        /////////////////////////////////////////

        //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);
        }
Beispiel #3
0
        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;
                    }
                }
            }
        }
Beispiel #4
0
        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;
            }
        }