zoukankan      html  css  js  c++  java
  • 17011701(UE4AnimDynamic的移植)

    【目标】

    UE4AnimDynamic的移植

    【思路】

    1 UE3

    • 骨骼控制器是固定开启,而不能在动画中控制是否开启
    • 如,播放某个动画时开启,或者某个状态下开启这个节点
    • UE4中的图就可以灵活控制节点走向
    • UE3中,每个SkeletalMeshComponent有个控制器列表(按照骨骼顺序来存储

    • 计算骨骼控制器时,也是按照骨骼顺序来计算的,从父骨骼到子骨骼



    2 方案:

    • 新建一个骨骼控制器类SkelControlAnimDynamic











    【步骤】

    1 添加一个EngineClassesSkelControlAnimDynamic.uc

    /**
     *    Controller that simulate physic Animation.
     *
     * Copyright 2017 Kingsoft Games, Inc. All Rights Reserved.
     */
    class SkelControlAnimDynamic extends SkelControlBase
        native(Anim);
     
    cpptext
    {
        // USkelControlBase interface
        virtual void TickSkelControl(FLOAT DeltaSeconds, USkeletalMeshComponent* SkelComp);
        virtual void GetAffectedBones(INT BoneIndex, USkeletalMeshComponent* SkelComp, TArray<INT>& OutBoneIndices);
        virtual void CalculateNewBoneTransforms(INT BoneIndex, USkeletalMeshComponent* SkelComp, TArray<FBoneAtom>& OutBoneTransforms);    
    }
    enum AnimPhysLinearConstraintType
    {
        Free,
        Limited,
    };
    enum AnimPhysAngularConstraintType
    {
        Angular,
        Cone
    };
    enum AnimPhysTwistAxis
    {
        PT_AxisX,
        PT_AxisY,
        PT_AxisZ
    };
    struct native AnimPhysConstraintSetup
    {
        /** Whether to limit the linear X axis */
        var AnimPhysLinearConstraintType LinearXLimitType;
        /** Whether to limit the linear Y axis */
        var AnimPhysLinearConstraintType LinearYLimitType;
        /** Whether to limit the linear Z axis */
        var AnimPhysLinearConstraintType LinearZLimitType;
        /** Minimum linear movement per-axis (Set zero here and in the max limit to lock) */
        var vector LinearAxesMin;
        /** Maximum linear movement per-axis (Set zero here and in the min limit to lock) */
        var vector LinearAxesMax;
        /** Method to use when constraining angular motion */
        var AnimPhysAngularConstraintType AngularConstraintType;
        /** Axis to consider for twist when constraining angular motion (forward axis) */
        var AnimPhysTwistAxis TwistAxis;
        /** Angle to use when constraining using a cone */
        var float ConeAngle;
        /** X-axis limit for angular motion when using the "Angular" constraint type (Set to 0 to lock, or 180 to remain free) */
        var float AngularXAngle_DEPRECATED;
        /** Y-axis limit for angular motion when using the "Angular" constraint type (Set to 0 to lock, or 180 to remain free) */
        var float AngularYAngle_DEPRECATED;
        /** Z-axis limit for angular motion when using the "Angular" constraint type (Set to 0 to lock, or 180 to remain free) */
        var float AngularZAngle_DEPRECATED;
        var vector AngularLimitsMin;
        var vector AngularLimitsMax;
        /** Axis on body1 to match to the angular target direction. */
        var AnimPhysTwistAxis AngularTargetAxis;
        /** Target direction to face for body1 (in body0 local space) */
        var vector AngularTarget;
        /** The values below are calculated on initialisation and used when building the limits */
        /** If all axes are locked we can use 3 linear limits instead of the 6 needed for limited axes */
        var bool bLinearFullyLocked;
    };
    struct native AnimPhysPlanarLimit
    {
        /** When using a driving bone, the plane transform will be relative to the bone transform */
        //var FBoneReference DrivingBone;
        var name DrivingBone;
        /** Transform of the plane, this is either in component-space if no DrivinBone is specified
         *  or in bone-space if a driving bone is present.
         */
        //FTransform PlaneTransform;
        var BoneAtom PlaneTransform;
    };
    enum ESphericalLimitType
    {
        Inner,
        Outer
    };
    enum AnimPhysSimSpaceType
    {
        Component <ToolTip = "Sim origin is the location/orientation of the skeletal mesh component.">,
        Actor <ToolTip = "Sim origin is the location/orientation of the actor containing the skeletal mesh component.">,
        World <ToolTip = "Sim origin is the world origin. Teleporting characters is not recommended in this mode.">,
        RootRelative <ToolTip = "Sim origin is the location/orientation of the root bone.">,
        BoneRelative <ToolTip = "Sim origin is the location/orientation of the bone specified in RelativeSpaceBone">,
    };
    enum AnimPhysCollisionType
    {
        CoM <DisplayName="CoM", DisplayValue="CoM", ToolTip="Only limit the center of mass from crossing planes.">,
        CustomSphere <ToolTip="Use the specified sphere radius to collide with planes.">,
        InnerSphere <ToolTip="Use the largest sphere that fits entirely within the body extents to collide with planes.">,
        OuterSphere <ToolTip="Use the smallest sphere that wholely contains the body extents to collide with planes.">
    };
    struct native AnimPhysSphericalLimit
    {
        structcpptext
        {
        FAnimPhysSphericalLimit()
            : SphereLocalOffset(FVector::ZeroVector)
            , LimitRadius(0.0f)
            , LimitType(ESphericalLimitType::Outer)
        {}
        }
        /** Bone to attach the sphere to */
        //FBoneReference DrivingBone;
        var name  DrivingBone;
        /** Local offset for the sphere, if no driving bone is set this is in node space, otherwise bone space */
        var vector SphereLocalOffset;
        /** Radius of the sphere */
        var float LimitRadius;
        /** Whether to lock bodies inside or outside of the sphere */
        var ESphericalLimitType LimitType;
    };
    /** The space used to run the simulation */
    var(AnimDynamic)        AnimPhysSimSpaceType SimulationSpace;
    /** When in BoneRelative sim space, the simulation will use this bone as the origin */
    //var(AnimDynamic)        FBoneReference RelativeSpaceBone;
    var(AnimDynamic)        name RelativeSpaceBone;
    /** Set to true to use the solver to simulate a connected chain */
    var(AnimDynamic)        bool bChain;
    /** The bone to attach the physics body to, if bChain is true this is the top of the chain */
    //var(AnimDynamic)        FBoneReference BoundBone;
    var(AnimDynamic)        name BoundBone;
        
    /** If bChain is true this is the bottom of the chain, otherwise ignored */
    //FBoneReference ChainEnd;
    var(AnimDynamic)        name ChainEnd;
    /** Extents of the box to use for simulation */
    var(AnimDynamic)        vector     BoxExtents;
    /** Vector relative to the body being simulated to attach the constraint to */
    var(AnimDynamic)        vector     LocalJointOffset;
    /** Scale for gravity, higher values increase forces due to gravity */
    var(AnimDynamic)        float GravityScale;
    /** If true the body will attempt to spring back to its initial position */
    var(AnimDynamic)        bool bLinearSpring;
    /** If true the body will attempt to align itself with the specified angular target */
    var(AnimDynamic)        bool bAngularSpring;
    /** Spring constant to use when calculating linear springs, higher values mean a stronger spring.*/
    var(AnimDynamic)        float LinearSpringConstant;
    /** Spring constant to use when calculating angular springs, higher values mean a stronger spring */
    var(AnimDynamic)        float AngularSpringConstant;
    /** Whether or not wind is enabled for the bodies in this simulation */
    var(AnimDynamic)        bool bEnableWind;
    /** Scale to apply to calculated wind velocities in the solver */
    var(AnimDynamic)        float WindScale;
    /** If true, the override value will be used for linear damping */
    var(AnimDynamic)        bool bOverrideLinearDamping;
    /** Overridden linear damping value */
    var(AnimDynamic)        float LinearDampingOverride;
    /** If true, the override value will be used for angular damping */
    var(AnimDynamic)        bool bOverrideAngularDamping;
    /** Overridden angular damping value */
    var(AnimDynamic)        float AngularDampingOverride;
    /** If true, the override value will be used for the angular bias for bodies in this node. 
        *  Angular bias is essentially a twist reduction for chain forces and defaults to a value to keep chains stability
        *  in check. When using single-body systems sometimes angular forces will look like they are "catching-up" with
        *  the mesh, if that's the case override this and push it towards 1.0f until it settles correctly
        */
    var(AnimDynamic)        bool bOverrideAngularBias;
    /** Overridden angular bias value
        *  Angular bias is essentially a twist reduction for chain forces and defaults to a value to keep chains stability
        *  in check. When using single-body systems sometimes angular forces will look like they are "catching-up" with
        *  the mesh, if that's the case override this and push it towards 1.0f until it settles correctly
        */
    var(AnimDynamic)        float AngularBiasOverride;
    /** If true we will perform physics update, otherwise skip - allows visualisation of the initial state of the bodies */
    var(AnimDynamic)        bool bDoUpdate;
    /** If true we will perform bone transform evaluation, otherwise skip - allows visualisation of the initial anim state compared to the physics sim */
    var(AnimDynamic)        bool bDoEval;
    /** Number of update passes on the linear and angular limits before we solve the position of the bodies recommended to be four times the value of NumSolverIterationsPostUpdate */
    var(AnimDynamic)        int NumSolverIterationsPreUpdate;
    /** Number of update passes on the linear and angular limits after we solve the position of the bodies, recommended to be around a quarter of NumSolverIterationsPreUpdate */
    var(AnimDynamic)        int NumSolverIterationsPostUpdate;
    /** Data describing the constraints we will apply to the body */
    var(AnimDynamic)        AnimPhysConstraintSetup ConstraintSetup;
    /** Whether to evaluate planar limits */
    var(AnimDynamic)        bool bUsePlanarLimit;
    /** List of available planar limits for this node */
    var(AnimDynamic)        array<AnimPhysPlanarLimit> PlanarLimits;
    /** Whether to evaluate spherical limits */
    var(AnimDynamic)        bool bUseSphericalLimits;
    /** List of available spherical limits for this node */
    var(AnimDynamic)        array<AnimPhysSphericalLimit> SphericalLimits;
    /** Resolution method for planar limits */
    var(AnimDynamic)        AnimPhysCollisionType CollisionType;
    /** Radius to use if CollisionType is set to CustomSphere */
    var(AnimDynamic)        float SphereCollisionRadius;
    /** An external force to apply to all bodies in the simulation when ticked, specified in world space */
    var(AnimDynamic)        vector ExternalForce;
    defaultproperties
    {
    }


    make一下




    UE4的




    现在填入函数


    2添加初始化Physics函数

    uc

        void InitPhysics(USkeletalMeshComponent* Component);
        void TermPhysics();


    添加一些私有的变量,不需要编辑的,应该是临时变量


    问题:

    在uc中如何使用C++的F类


    只能用Struct来


    【实验】

    1.

    在uc中写一遍struct,和C++中匹配,不导出到h文件?

    但是h文件会找不到申明


    2.

    除非不导出到h文件,自己写一个h文件来

    如果不导出,需要自己派生Serialize函数,自己序列化


    3.

    在uc中写结构体,导出到h文件,



    3 添加结构体

    /**
      * Defines a transform (Position/Orientation) for an anim phys object without scaling
      */
    struct native AnimPhysPose
    {
        var vector Position;
        var quat Orientation;
        
        structcpptext
        {
        FAnimPhysPose(const FVector& InPosition, const FQuat& InOrient)
            : Position(InPosition)
            , Orientation(InOrient)
        {}
        FAnimPhysPose()
            : Position(FVector::ZeroVector)
            , Orientation(FQuat::Identity)
        {
        }
        FAnimPhysPose Inverse() const
        {
            FQuat InverseOrient = Orientation.Inverse();
            FVector InversePosition = InverseOrient * Position;
            return FAnimPhysPose(InversePosition, InverseOrient);
        }
        FMatrix Matrix() const
        {
            return FBoneAtom(Orientation, Position).ToMatrixNoScale();
        }
        FVector operator*(const FVector& InPoint) const
        {
            return Position + (Orientation * InPoint);
        }
        FAnimPhysPose operator*(const FAnimPhysPose& InPose) const
        {
            return FAnimPhysPose(*this *InPose.Position, Orientation * InPose.Orientation);
        }
        FPlane TransformPlane(const FPlane& InPlane)
        {
            FVector NewNormal(InPlane.X, InPlane.Y, InPlane.Z);
            NewNormal = Orientation * NewNormal;
            return FPlane(NewNormal, InPlane.W - FVector::DotProduct(Position, NewNormal));
        }
        }
    };



    FVector需要添加

        FORCEINLINE static FVector CrossProduct(const FVector& A, const FVector& B)
        {
            return A ^ B;
        }
        FORCEINLINE static float DotProduct(const FVector& A, const FVector& B)
        {
            return A | B;
        }


    UnMathFpu.h 

    /**
     * Swizzles the 4 components of a vector and returns the result.
     *
     * @param Vec        Source vector
     * @param X            Index for which component to use for X (literal 0-3)
     * @param Y            Index for which component to use for Y (literal 0-3)
     * @param Z            Index for which component to use for Z (literal 0-3)
     * @param W            Index for which component to use for W (literal 0-3)
     * @return            The swizzled vector
     */
    #define VectorSwizzle( Vec, X, Y, Z, W )    MakeVectorRegister( (Vec).V[X], (Vec).V[Y], (Vec).V[Z], (Vec).V[W] )


    同理UnMathSSE.h 

    /**
     * Creates a vector through selecting two components from each vector via a shuffle mask. 
     *
     * @param Vec1        Source vector1
     * @param Vec2        Source vector2
     * @param X            Index for which component of Vector1 to use for X (literal 0-3)
     * @param Y            Index for which component to Vector1 to use for Y (literal 0-3)
     * @param Z            Index for which component to Vector2 to use for Z (literal 0-3)
     * @param W            Index for which component to Vector2 to use for W (literal 0-3)
     * @return            The swizzled vector
     */
    #define VectorShuffle( Vec1, Vec2, X, Y, Z, W )    _mm_shuffle_ps( Vec1, Vec2, SHUFFLEMASK(X,Y,Z,W) )



    FBoneAtomVectorized.h 

        FORCEINLINE void ToMatrixInternalNoScale( VectorRegister& OutDiagonals, VectorRegister& OutAdds, VectorRegister& OutSubtracts ) const
        {
    #if !FINAL_RELEASE && !CONSOLE
            // Make sure Rotation is normalized when we turn it into a matrix.
            check( IsRotationNormalized() );
    #endif        
            const VectorRegister RotationX2Y2Z2 = VectorAdd(Rotation, Rotation);    // x2, y2, z2
            const VectorRegister RotationXX2YY2ZZ2 = VectorMultiply(RotationX2Y2Z2, Rotation);    // xx2, yy2, zz2        
            // The diagonal terms of the rotation matrix are:
            //   (1 - (yy2 + zz2))
            //   (1 - (xx2 + zz2))
            //   (1 - (xx2 + yy2))
            const VectorRegister yy2_xx2_xx2 = VectorSwizzle(RotationXX2YY2ZZ2, 1, 0, 0, 0);
            const VectorRegister zz2_zz2_yy2 = VectorSwizzle(RotationXX2YY2ZZ2, 2, 2, 1, 0);
            const VectorRegister DiagonalSum = VectorAdd(yy2_xx2_xx2, zz2_zz2_yy2);
            OutDiagonals = VectorSubtract(VectorOne(), DiagonalSum);
            // Grouping the non-diagonal elements in the rotation block by operations:
            //    ((x*y2,y*z2,x*z2) + (w*z2,w*x2,w*y2)) and
            //    ((x*y2,y*z2,x*z2) - (w*z2,w*x2,w*y2))
            // Rearranging so the LHS and RHS are in the same order as for +
            //    ((x*y2,y*z2,x*z2) - (w*z2,w*x2,w*y2))
            // RotBase = x*y2, y*z2, x*z2
            // RotOffset = w*z2, w*x2, w*y2
            const VectorRegister x_y_x = VectorSwizzle(Rotation, 0, 1, 0, 0);
            const VectorRegister y2_z2_z2 = VectorSwizzle(RotationX2Y2Z2, 1, 2, 2, 0);
            const VectorRegister RotBase = VectorMultiply(x_y_x, y2_z2_z2);
            const VectorRegister w_w_w = VectorReplicate(Rotation, 3);
            const VectorRegister z2_x2_y2 = VectorSwizzle(RotationX2Y2Z2, 2, 0, 1, 0);
            const VectorRegister RotOffset = VectorMultiply(w_w_w, z2_x2_y2);
            // Adds = (RotBase + RotOffset):  (x*y2 + w*z2) , (y*z2 + w*x2), (x*z2 + w*y2)
            // Subtracts = (RotBase - RotOffset) :  (x*y2 - w*z2) , (y*z2 - w*x2), (x*z2 - w*y2)
            OutAdds = VectorAdd(RotBase, RotOffset);        
            OutSubtracts = VectorSubtract(RotBase, RotOffset);
        }
            /**
        * Convert this Transform to a transformation matrix, ignoring its scaling
        */
        FORCEINLINE FMatrix ToMatrixNoScale() const
        {
            FMatrix OutMatrix;
            VectorRegister DiagonalsXYZ;
            VectorRegister Adds;
            VectorRegister Subtracts;
            ToMatrixInternalNoScale( DiagonalsXYZ, Adds, Subtracts );
            const VectorRegister DiagonalsXYZ_W0 = VectorSet_W0(DiagonalsXYZ);
            // OutMatrix.M[0][0] = (1.0f - (yy2 + zz2));            // Diagonal.X
            // OutMatrix.M[0][1] = (xy2 + wz2);                        // Adds.X
            // OutMatrix.M[0][2] = (xz2 - wy2);                        // Subtracts.Z
            // OutMatrix.M[0][3] = 0.0f;                            // DiagonalsXYZ_W0.W
            const VectorRegister AddX_DC_DiagX_DC = VectorShuffle(Adds, DiagonalsXYZ_W0, 0, 0, 0, 0);
            const VectorRegister SubZ_DC_DiagW_DC = VectorShuffle(Subtracts, DiagonalsXYZ_W0, 2, 0, 3, 0);
            const VectorRegister Row0 = VectorShuffle(AddX_DC_DiagX_DC, SubZ_DC_DiagW_DC, 2, 0, 0, 2);
            // OutMatrix.M[1][0] = (xy2 - wz2);                        // Subtracts.X
            // OutMatrix.M[1][1] = (1.0f - (xx2 + zz2));            // Diagonal.Y
            // OutMatrix.M[1][2] = (yz2 + wx2);                        // Adds.Y
            // OutMatrix.M[1][3] = 0.0f;                            // DiagonalsXYZ_W0.W
            const VectorRegister SubX_DC_DiagY_DC = VectorShuffle(Subtracts, DiagonalsXYZ_W0, 0, 0, 1, 0);
            const VectorRegister AddY_DC_DiagW_DC = VectorShuffle(Adds, DiagonalsXYZ_W0, 1, 0, 3, 0);
            const VectorRegister Row1 = VectorShuffle(SubX_DC_DiagY_DC, AddY_DC_DiagW_DC, 0, 2, 0, 2);
            // OutMatrix.M[2][0] = (xz2 + wy2);                        // Adds.Z
            // OutMatrix.M[2][1] = (yz2 - wx2);                        // Subtracts.Y
            // OutMatrix.M[2][2] = (1.0f - (xx2 + yy2));            // Diagonals.Z
            // OutMatrix.M[2][3] = 0.0f;                            // DiagonalsXYZ_W0.W
            const VectorRegister AddZ_DC_SubY_DC = VectorShuffle(Adds, Subtracts, 2, 0, 1, 0);
            const VectorRegister Row2 = VectorShuffle(AddZ_DC_SubY_DC, DiagonalsXYZ_W0, 0, 2, 2, 3);
            VectorStoreAligned(Row0, &(OutMatrix.M[0][0]));
            VectorStoreAligned(Row1, &(OutMatrix.M[1][0]));
            VectorStoreAligned(Row2, &(OutMatrix.M[2][0]));
            // OutMatrix.M[3][0] = Translation.X;
            // OutMatrix.M[3][1] = Translation.Y;
            // OutMatrix.M[3][2] = Translation.Z;
            // OutMatrix.M[3][3] = 1.0f;
            const VectorRegister Row3 = VectorSet_W1(Translation);
            VectorStoreAligned(Row3, &(OutMatrix.M[3][0]));
            return OutMatrix;
        }



    4 继续添加结构体,将class 转成struct

    struct native AnimPhysState
    {
    var AnimPhysPose Pose;

    var vector LinearMomentum;   
    var vector AngularMomentum;

    structcpptext
    {
    FAnimPhysState();
    FAnimPhysState(const FVector& InPosition, const FQuat& InOrient, const FVector& InLinearMomentum, const FVector& InAngularMomentum);



        FAnimPhysPose&           GetPose() { return Pose; }
        const FAnimPhysPose&     GetPose() const { return Pose; }

    FAnimPhysState&          GetState() { return *this; }
    const FAnimPhysState&    GetState() const { return *this; }
    }
    };



    在Object.uc 添加基础类型

    /**
     * An integer vector in 3D space.
     */
    struct immutable IntVector
    {
        var() int X, Y, Z;
    }


    需要填充C++代码DevelopmentSrcCoreIncUnMath.h

    /*-----------------------------------------------------------------------------
        FIntVector.
    -----------------------------------------------------------------------------*/
    /**
     * Structure for integer vectors in 3-d space.
     */
    struct FIntVector
    {
        /** Holds the point's x-coordinate. */
        INT32 X;
        
        /** Holds the point's y-coordinate. */
        INT32 Y;
        /**  Holds the point's z-coordinate. */
        INT32 Z;
    public:
        /** An int point with zeroed values. */
        static const FIntVector ZeroValue;
        /** An int point with INDEX_NONE values. */
        static const FIntVector NoneValue;
    public:
        /**
         * Default constructor (no initialization).
         */
        FIntVector();
        /**
         * Creates and initializes a new instance with the specified coordinates.
         *
         * @param InX The x-coordinate.
         * @param InY The y-coordinate.
         * @param InZ The z-coordinate.
         */
        FIntVector( INT32 InX, INT32 InY, INT32 InZ );
        /**
         * Constructor
         *
         * @param InValue replicated to all components
         */
        explicit FIntVector( INT32 InValue );
        /**
         * Constructor
         *
         * @param EForceInit Force init enum
         */
        explicit FORCEINLINE FIntVector( EForceInit );
    public:
        /**
         * Gets specific component of a point.
         *
         * @param ComponentIndex Index of point component.
         * @return const reference to component.
         */
        const INT32& operator()( INT32 ComponentIndex ) const;
        /**
         * Gets specific component of a point.
         *
         * @param ComponentIndex Index of point component.
         * @return reference to component.
         */
        INT32& operator()( INT32 ComponentIndex );
        /**
         * Gets specific component of a point.
         *
         * @param ComponentIndex Index of point component.
         * @return const reference to component.
         */
        const INT32& operator[]( INT32 ComponentIndex ) const;
        /**
         * Gets specific component of a point.
         *
         * @param ComponentIndex Index of point component.
         * @return reference to component.
         */
        INT32& operator[]( INT32 ComponentIndex );
        /**
         * Compares points for equality.
         *
         * @param Other The other int point being compared.
         * @return true if the points are equal, false otherwise..
         */
        bool operator==( const FIntVector& Other ) const;
        /**
         * Compares points for inequality.
         *
         * @param Other The other int point being compared.
         * @return true if the points are not equal, false otherwise..
         */
        bool operator!=( const FIntVector& Other ) const;
        /**
         * Scales this point.
         *
         * @param Scale What to multiply the point by.
         * @return Reference to this point after multiplication.
         */
        FIntVector& operator*=( INT32 Scale );
        /**
         * Divides this point.
         *
         * @param Divisor What to divide the point by.
         * @return Reference to this point after division.
         */
        FIntVector& operator/=( INT32 Divisor );
        /**
         * Adds to this point.
         *
         * @param Other The point to add to this point.
         * @return Reference to this point after addition.
         */
        FIntVector& operator+=( const FIntVector& Other );
        /**
         * Subtracts from this point.
         *
         * @param Other The point to subtract from this point.
         * @return Reference to this point after subtraction.
         */
        FIntVector& operator-=( const FIntVector& Other );
        /**
         * Assigns another point to this one.
         *
         * @param Other The point to assign this point from.
         * @return Reference to this point after assignment.
         */
        FIntVector& operator=( const FIntVector& Other );
        /**
         * Gets the result of scaling on this point.
         *
         * @param Scale What to multiply the point by.
         * @return A new scaled int point.
         */
        FIntVector operator*( INT32 Scale ) const;
        /**
         * Gets the result of division on this point.
         *
         * @param Divisor What to divide the point by.
         * @return A new divided int point.
         */
        FIntVector operator/( INT32 Divisor ) const;
        /**
         * Gets the result of addition on this point.
         *
         * @param Other The other point to add to this.
         * @return A new combined int point.
         */
        FIntVector operator+( const FIntVector& Other ) const;
        /**
         * Gets the result of subtraction from this point.
         *
         * @param Other The other point to subtract from this.
         * @return A new subtracted int point.
         */
        FIntVector operator-( const FIntVector& Other ) const;
    public:
        /**
         * Gets the maximum value in the point.
         *
         * @return The maximum value in the point.
         */
        float GetMax() const;
        /**
         * Gets the minimum value in the point.
         *
         * @return The minimum value in the point.
         */
        float GetMin() const;
        /**
         * Gets the distance of this point from (0,0,0).
         *
         * @return The distance of this point from (0,0,0).
         */
        INT32 Size() const;
        /**
         * Get a textual representation of this vector.
         *
         * @return A string describing the vector.
         */
        FString ToString() const;
    public:
        /**
         * Divide an int point and round up the result.
         *
         * @param lhs The int point being divided.
         * @param Divisor What to divide the int point by.
         * @return A new divided int point.
         */
        static FIntVector GetDivideAndRoundUp( FIntVector lhs, INT32 Divisor );
        /**
         * Gets the number of components a point has.
         *
         * @return Number of components point has.
         */
        static INT32 Num();
    public:
        /**
         * Serializes the Rectangle.
         *
         * @param Ar The archive to serialize into.
         * @param Vector The vector to serialize.
         * @return Reference to the Archive after serialization.
         */
        friend FArchive& operator<<( FArchive& Ar, FIntVector& Vector )
        {
            return Ar << Vector.X << Vector.Y << Vector.Z;
        }
        bool Serialize( FArchive& Ar )
        {
            Ar << *this;
            return true;
        }
    };
    /* FIntVector inline functions
     *****************************************************************************/
    FORCEINLINE FIntVector::FIntVector()
    { }
    FORCEINLINE FIntVector::FIntVector( INT32 InX, INT32 InY, INT32 InZ )
        : X(InX)
        , Y(InY)
        , Z(InZ)
    { }
    FORCEINLINE FIntVector::FIntVector( INT32 InValue )
        : X(InValue)
        , Y(InValue)
        , Z(InValue)
    { }
    FORCEINLINE FIntVector::FIntVector( EForceInit )
        : X(0)
        , Y(0)
        , Z(0)
    { }
    FORCEINLINE const INT32& FIntVector::operator()( INT32 ComponentIndex ) const
    {
        return (&X)[ComponentIndex];
    }
    FORCEINLINE INT32& FIntVector::operator()( INT32 ComponentIndex )
    {
        return (&X)[ComponentIndex];
    }
    FORCEINLINE const INT32& FIntVector::operator[]( INT32 ComponentIndex ) const
    {
        return (&X)[ComponentIndex];
    }
    FORCEINLINE INT32& FIntVector::operator[]( INT32 ComponentIndex )
    {
        return (&X)[ComponentIndex];
    }
    FORCEINLINE bool FIntVector::operator==( const FIntVector& Other ) const
    {
        return X==Other.X && Y==Other.Y && Z==Other.Z;
    }
    FORCEINLINE bool FIntVector::operator!=( const FIntVector& Other ) const
    {
        return X!=Other.X || Y!=Other.Y || Z!=Other.Z;
    }
    FORCEINLINE FIntVector& FIntVector::operator*=( INT32 Scale )
    {
        X *= Scale;
        Y *= Scale;
        Z *= Scale;
        return *this;
    }
    FORCEINLINE FIntVector& FIntVector::operator/=( INT32 Divisor )
    {
        X /= Divisor;
        Y /= Divisor;
        Z /= Divisor;
        return *this;
    }
    FORCEINLINE FIntVector& FIntVector::operator+=( const FIntVector& Other )
    {
        X += Other.X;
        Y += Other.Y;
        Z += Other.Z;
        return *this;
    }
    FORCEINLINE FIntVector& FIntVector::operator-=( const FIntVector& Other )
    {
        X -= Other.X;
        Y -= Other.Y;
        Z -= Other.Z;
        return *this;
    }
    FORCEINLINE FIntVector& FIntVector::operator=( const FIntVector& Other )
    {
        X = Other.X;
        Y = Other.Y;
        Z = Other.Z;
        return *this;
    }
    FORCEINLINE FIntVector FIntVector::operator*( INT32 Scale ) const
    {
        return FIntVector(*this) *= Scale;
    }
    FORCEINLINE FIntVector FIntVector::operator/( INT32 Divisor ) const
    {
        return FIntVector(*this) /= Divisor;
    }
    FORCEINLINE FIntVector FIntVector::operator+( const FIntVector& Other ) const
    {
        return FIntVector(*this) += Other;
    }
    FORCEINLINE FIntVector FIntVector::operator-( const FIntVector& Other ) const
    {
        return FIntVector(*this) -= Other;
    }
    FORCEINLINE FIntVector FIntVector::GetDivideAndRoundUp( FIntVector lhs, INT32 Divisor )
    {
        return FIntVector(DivideAndRoundUp(lhs.X, Divisor), DivideAndRoundUp(lhs.Y, Divisor), DivideAndRoundUp(lhs.Z, Divisor));
    }
    FORCEINLINE float FIntVector::GetMax() const
    {
        return Max(Max(X, Y), Z);
    }
    FORCEINLINE float FIntVector::GetMin() const
    {
        return Min(Min(X, Y), Z);
    }
    FORCEINLINE INT32 FIntVector::Num()
    {
        return 3;
    }
    FORCEINLINE INT32 FIntVector::Size() const
    {
        INT64 X64 = (INT64)X;
        INT64 Y64 = (INT64)Y;
        INT64 Z64 = (INT64)Z;
        return INT32(appSqrt(float(X64 * X64 + Y64 * Y64 + Z64 * Z64)));
    }
    FORCEINLINE FString FIntVector::ToString() const
    {
        return FString::Printf(TEXT("X=%d Y=%d Z=%d"), X, Y, Z);
    }
    FORCEINLINE UINT32 GetTypeHash(const FIntVector& Vector)
    {
        return appMemCrc(&Vector,sizeof(FIntVector));
    }
    struct FIntVector4
    {
        INT32 X, Y, Z, W;
        FORCEINLINE FIntVector4()
        {
        }
        FORCEINLINE FIntVector4(INT32 InX, INT32 InY, INT32 InZ, INT32 InW)
            : X(InX)
            , Y(InY)
            , Z(InZ)
            , W(InW)
        {
        }
        FORCEINLINE explicit FIntVector4(INT32 InValue)
            : X(InValue)
            , Y(InValue)
            , Z(InValue)
            , W(InValue)
        {
        }
        FORCEINLINE FIntVector4(EForceInit)
            : X(0)
            , Y(0)
            , Z(0)
            , W(0)
        {
        }
        FORCEINLINE const INT32& operator[](INT32 ComponentIndex) const
        {
            return (&X)[ComponentIndex];
        }
        FORCEINLINE INT32& operator[](INT32 ComponentIndex)
        {
            return (&X)[ComponentIndex];
        }
        FORCEINLINE bool operator==(const FIntVector4& Other) const
        {
            return X==Other.X && Y==Other.Y && Z==Other.Z && W==Other.W;
        }
        FORCEINLINE bool operator!=(const FIntVector4& Other) const
        {
            return X!=Other.X || Y!=Other.Y || Z!=Other.Z || W!=Other.W;
        }
    };
    struct FUintVector4
    {
        UINT32 X, Y, Z, W;
        FORCEINLINE FUintVector4()
        {
        }
        FORCEINLINE FUintVector4(UINT32 InX, UINT32 InY, UINT32 InZ, UINT32 InW)
            : X(InX)
            , Y(InY)
            , Z(InZ)
            , W(InW)
        {
        }
        FORCEINLINE explicit FUintVector4(UINT32 InValue)
            : X(InValue)
            , Y(InValue)
            , Z(InValue)
            , W(InValue)
        {
        }
        FORCEINLINE FUintVector4(EForceInit)
            : X(0)
            , Y(0)
            , Z(0)
            , W(0)
        {
        }
        FORCEINLINE const UINT32& operator[](INT32 ComponentIndex) const
        {
            return (&X)[ComponentIndex];
        }
        FORCEINLINE UINT32& operator[](INT32 ComponentIndex)
        {
            return (&X)[ComponentIndex];
        }
        FORCEINLINE bool operator==(const FUintVector4& Other) const
        {
            return X==Other.X && Y==Other.Y && Z==Other.Z && W==Other.W;
        }
        FORCEINLINE bool operator!=(const FUintVector4& Other) const
        {
            return X!=Other.X || Y!=Other.Y || Z!=Other.Z || W!=Other.W;
        }
    };


    UnTemplate.h 

    /** Divides two integers and rounds up */
    template <class T>
    FORCEINLINE T DivideAndRoundUp(T Dividend,T Divisor)
    {
        return (Dividend + Divisor - 1) / Divisor;
    }
    template <class T>
    FORCEINLINE T DivideAndRoundDown(T Dividend,T Divisor)
    {
        return Dividend / Divisor;
    }


    FBoneAtom 需要添加函数

        /** Inverts the matrix and then transforms V - correctly handles scaling in this matrix. */
        FORCEINLINE FVector InverseTransformPosition(const FVector &V) const;
        FORCEINLINE FVector InverseTransformPositionNoScale(const FVector &V) const;
        FORCEINLINE FVector TransformVector(const FVector& V) const;
        FORCEINLINE FVector TransformVectorNoScale(const FVector& V) const;



    FBoneAtom.GetSafeScaleReciprocal 


    TArray.需要添加拷贝构造

        /**
         * Copy constructor. Use the common routine to perform the copy.
         *
         * @param Other The source array to copy.
         */
        FORCEINLINE TArray(const TArray& Other)
            :   ArrayNum( 0 )
            ,    ArrayMax( 0 )
        {
            Copy(Other);
        }




    填充FAnimPhysShape类

    //////////////////////////////////////////////////////////////////////////
    // FAnimPhysShape - Defines a set of vertices that make a shape with volume and CoM
    FAnimPhysShape::FAnimPhysShape() : Volume(0.0f)
        , CenterOfMass(0.0f)
    {
    }
    FAnimPhysShape::FAnimPhysShape(TArray<FVector>& InVertices, TArray<FIntVector>& InTriangles)// : Vertices(InVertices)
    //    , Triangles(InTriangles)
    {
        Vertices = InVertices;
        Triangles = InTriangles;
    //     Volume = FAnimPhys::CalculateVolume(Vertices, Triangles);
    //     CenterOfMass = FAnimPhys::CalculateCenterOfMass(Vertices, Triangles);
    }
    FAnimPhysShape FAnimPhysShape::MakeBox(FVector& Extents)
    {
        // A box of zero size will introduce NaNs into the simulation so we stomp it here and log
        // if we encounter it.
        if(Extents.SizeSquared() <= SMALL_NUMBER)
        {
            //UE_LOG(LogAnimation, Warning, TEXT("AnimDynamics: Attempted to create a simulation box with 0 volume, this introduces NaNs into the simulation. Adjusting box extents to (1.0f,1.0f,1.0f)"));
            warnf(TEXT("AnimDynamics: Attempted to create a simulation box with 0 volume, this introduces NaNs into the simulation. Adjusting box extents to (1.0f,1.0f,1.0f)"));
            Extents = FVector(1.0f);
        }
        TArray<FVector> Verts;
        TArray<FIntVector> Tris;
        Verts.Reserve(8);
        Tris.Reserve(12);
        FVector HalfExtents = Extents / 2.0f;
        // Front Verts
        Verts.AddItem(FVector(-HalfExtents.X, -HalfExtents.Y, HalfExtents.Z));
        Verts.AddItem(FVector(HalfExtents.X, -HalfExtents.Y, HalfExtents.Z));
        Verts.AddItem(FVector(HalfExtents.X, -HalfExtents.Y, -HalfExtents.Z));
        Verts.AddItem(FVector(-HalfExtents.X, -HalfExtents.Y, -HalfExtents.Z));
        // Back Verts
        Verts.AddItem(FVector(HalfExtents.X, HalfExtents.Y, HalfExtents.Z));
        Verts.AddItem(FVector(-HalfExtents.X, HalfExtents.Y, HalfExtents.Z));
        Verts.AddItem(FVector(-HalfExtents.X, HalfExtents.Y, -HalfExtents.Z));
        Verts.AddItem(FVector(HalfExtents.X, HalfExtents.Y, -HalfExtents.Z));
        // Front
        Tris.AddItem(FIntVector(0, 1, 3));
        Tris.AddItem(FIntVector(1, 2, 3));
        // Back
        Tris.AddItem(FIntVector(4, 5, 7));
        Tris.AddItem(FIntVector(5, 6, 7));
        // Top
        Tris.AddItem(FIntVector(0, 5, 1));
        Tris.AddItem(FIntVector(5, 4, 1));
        // Right
        Tris.AddItem(FIntVector(1, 4, 2));
        Tris.AddItem(FIntVector(2, 4, 7));
        // Left
        Tris.AddItem(FIntVector(0, 3, 5));
        Tris.AddItem(FIntVector(5, 3, 6));
        // Bottom
        Tris.AddItem(FIntVector(3, 2, 6));
        Tris.AddItem(FIntVector(2, 7, 6));
        return FAnimPhysShape(Verts, Tris);
    }
    void FAnimPhysShape::TransformVerts(FBoneAtom& InTransform)
    {
        for (INT Idx = 0; Idx < Vertices.Num(); Idx++)
        {
            Vertices(Idx) = InTransform.TransformVector(Vertices(Idx));
        }
    }



    问题:继承类怎么处理?


    可以用extends




    5 添加AnimPhysRigidBody结构体,继承于AnimPhysState

    /** 
      * Simple struct holding wind params passed into simulation
      */
    struct native AnimPhysWindData
    {
        // Scale for the final velocity
        var float BodyWindScale;
        // Current wind speed
        var float WindSpeed;
        // World space wind direction
        var Vector WindDirection;
        // Mirrors APEX adaption, adds some randomness / billow
        var float WindAdaption;
    };
    /**
      * A collection of shapes grouped for simulation as a rigid body
      */
    struct native AnimPhysRigidBody extends AnimPhysState
    {
        // Mass of this body
        var float                Mass;
        // 1.0f / Mass
        var float                InverseMass;
        // Mass free inverse tensor (easier to scale mass)
        var Matrix                InverseTensorWithoutMass;  
        // Full (with mass) inverse tensor in world space
        var Matrix                InverseWorldSpaceTensor;    // Inverse Inertia Tensor rotated into world space 
        // Maintained state, Start/Prev/Next
        var Vector                NextPosition;
        var Quat                NextOrientation;
        var Vector                PreviousPosition;
        var Quat                PreviousOrientation;
        var Vector                StartPosition;
        var Quat                StartOrientation;
        // Whether to use wind forces on this body
        var bool                bWindEnabled;
        // Per-body wind data (speed, direction etc.)
        var AnimPhysWindData    WindData;
        // Override angular damping for this body
        var bool                bAngularDampingOverriden;
        var float                AngularDamping;
        // Override linear damping for this body
        var bool                bLinearDampingOverriden;
        var float                LinearDamping;
        // Override gravity scale for this body
        var float                GravityScale;
        // Previous motion state (linear/angular momentum)
        var AnimPhysState        PreviousState;
        // Body center of mass (CoM of all shapes)
        var Vector                CenterOfMass;
        // Collision Data (Only how we interact with planes currently)
        var AnimPhysCollisionType CollisionType;
        // Radius to use when not using CoM collision mode
        var float SphereCollisionRadius;
        
        // Shapes contained within this body
        var array<AnimPhysShape>        Shapes;
        structcpptext
        {
        FAnimPhysRigidBody(TArray<FAnimPhysShape>& InShapes, const FVector& InPosition);
        // Spin / Omega for the body
        FVector Spin();
        }
    };


    填充C++

    //////////////////////////////////////////////////////////////////////////
    FAnimPhysRigidBody::FAnimPhysRigidBody(TArray<FAnimPhysShape>& InShapes, const FVector& InPosition) : Mass(1.0f)
        , InverseMass(1.0f)
        , InverseTensorWithoutMass(FMatrix::Identity)
        , InverseWorldSpaceTensor(FMatrix::Identity)
        , NextOrientation(FQuat::Identity)
        , PreviousOrientation(FQuat::Identity)
        , StartOrientation(FQuat::Identity)
        , bAngularDampingOverriden(false)
        , AngularDamping(0.0f)
        , bLinearDampingOverriden(false)
        , LinearDamping(0.0f)
        , GravityScale(1.0f)
    //    , Shapes(InShapes)
    {
        Shapes = InShapes;
        StartPosition = InPosition;
        PreviousPosition = InPosition;
        NextPosition = InPosition;
        Pose.Position = InPosition;
    //    CenterOfMass = FAnimPhys::CalculateCenterOfMass(Shapes);
        Pose.Position += CenterOfMass;
        StartPosition = Pose.Position;
        PreviousPosition = Pose.Position;
        NextPosition = Pose.Position;
        for (INT Idx = 0; Idx < Shapes.Num(); Idx++)
        {
            FAnimPhysShape& CurrentShape = Shapes(Idx);
            for (INT VertIdx = 0; VertIdx <  CurrentShape.Vertices.Num(); VertIdx++ )
            {
                FVector& CurrentVert = CurrentShape.Vertices(VertIdx);
                CurrentVert -= CenterOfMass;
            }
        }
    //    FMatrix InertiaTensor = FAnimPhys::CalculateInertia(Shapes, CenterOfMass);
        InverseMass = 1.0f / Mass;
    //    InverseTensorWithoutMass = InertiaTensor.Inverse();
        InverseWorldSpaceTensor = InverseTensorWithoutMass * InverseMass;
    }
    FVector FAnimPhysRigidBody::Spin()
    {
        return InverseWorldSpaceTensor.TransformFVector(AngularMomentum);
    }




    6 FAnimPhys是计算物理相关的类,需要添加到C++中

    ue3DevelopmentSrcEngineIncAnimPhysicsSolver.h

    #include "EngineAnimClasses.h"
    #define MIN_flt            (1.175494351e-38F)            /* min positive value */
    #define MAX_flt            (3.402823466e+38F)
    #define MIN_dbl            (2.2250738585072014e-308)    /* min positive value */
    #define MAX_dbl            (1.7976931348623158e+308)
    /**
      * Base class for constraint limits
      */
    class FAnimPhysLimit
    {
    public:
        FAnimPhysRigidBody* Bodies[2];
        FAnimPhysLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody);
    };
    /**
      * Angular limit, keeps angular torque around an axis within a defined range
      */
    class FAnimPhysAngularLimit : public FAnimPhysLimit
    {
    public:
        // Axis of the limit in world space
        FVector WorldSpaceAxis;
        // Rotational impulse
        float  Torque;
        // The required spin required to align the limit
        float  TargetSpin;
        // Minimum torque this limit can apply
        float  MinimumTorque;
        // Maximum torque this limit can apply
        float  MaximumTorque;
        // Cached spin to torque value that is independant of iterations
        float CachedSpinToTorque;
        FAnimPhysAngularLimit();
        FAnimPhysAngularLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody, const FVector& InWorldSpaceAxis, float InTargetSpin = 0, float InMinimumTorque = -MAX_flt, float InMaximumTorque = MAX_flt);    
        /** Remove bias added to solve the limit
         */
        void RemoveBias();
        /** Solve the limit
         */
        void Iter(float DeltaTime);
        void UpdateCachedData();
    };
    class FAnimPhysLinearLimit : public FAnimPhysLimit
    {
     public:
        // Position of anchor on first object (in first object local space)
        FVector FirstPosition;
        // Position of anchor on second object (in second object local space)
        FVector SecondPosition;
        // Normal along which the limit is applied
        FVector LimitNormal;
        // Target speed needed to solve the limit
        float  TargetSpeed; 
        // Target speed of the limit without bias (force added just to solve limit)
        float  TargetSpeedWithoutBias;
        // Minimum force this limit can apply along the normal
        float  MinimumForce;
        // Maximum force this limit can apply along the normal
        float  Maximumforce;
        // Sum of impulses applied
        float  SumImpulses;
        // Cached denominator of the impulse calculation, doesn't change across iterations
        float InverseInertiaImpulse;
        // Cached world space position on body 0
        FVector WorldSpacePosition0;
        // Cached world space position on body 1
        FVector WorldSpacePosition1;
        FAnimPhysLinearLimit();
        FAnimPhysLinearLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody, const FVector& InFirstPosition, const FVector& InSecondPosition,
            const FVector& InNormal = FVector(0.0f, 0.0f, 1.0f), float InTargetSpeed = 0.0f, float InTargetSpeedWithoutBias = 0.0f, const FVector2D& InForceRange = FVector2D(-MAX_flt, MAX_flt));
        /** Remove bias added to solve the limit
        */
        void RemoveBias();
        /** Solve the limit
        */
        void Iter(float DetlaTime);
        void UpdateCachedData();
    };
    struct FAnimPhysSpring
    {
        // Bodies connected by the spring (Or nullptr for world)
        FAnimPhysRigidBody* Body0;
        FAnimPhysRigidBody* Body1;
        // Extra orientation applied on top of Body0's orientation to the target direction
        FQuat TargetOrientationOffset;
        // Target in body0 space for the target axis on body1 to reach
        FVector AngularTarget;
        
        // The axis of body1's orientation to match to the angular target
        AnimPhysTwistAxis AngularTargetAxis;
        // Local space anchor positions (in space of Body0 and Body1 respectively)
        FVector Anchor0;
        FVector Anchor1;
        // Spring constant for linear springs
        float SpringConstantLinear;
        // Sprint constant for angular springs
        float SpringConstantAngular;
        // Whether to apply linear spring force
        bool bApplyLinear;
        // Whether to apply angular spring force
        bool bApplyAngular;
        /** Applies forces to the bound bodies
         */
        void ApplyForces(float DeltaTime);
    };
    /**
      * Lightweight rigid body motion solver (no collision) used for cosmetic secondary motion in an animation graph
      * without invoking something heavier like using PhysX to simulate constraints which could be cost prohibitive
      */
    class FAnimPhys
    {
    public:
        /** Calculates the volume of a shape
         *  @param InVertices Verts in the shape
         *  @param InTriangles Triangles represented in InVertices
         */
        static float CalculateVolume(const TArray<FVector>& InVertices, const TArray<FIntVector>& InTriangles);
        
        /** Calculates the volume of a collection of shapes
         *  @param InShapes Collection of shapes to use
         */
        static float CalculateVolume(const TArray<FAnimPhysShape>& InShapes);
        /** Calculates the center of mass of a shape
         *  @param InVertices Verts in the shape
         *  @param InTriangles Triangles represented in InVertices
         */
        static FVector CalculateCenterOfMass(const TArray<FVector>& InVertices, const TArray<FIntVector>& InTriangles);
        
        /** Calculates the centre of mass of a collection of shapes
         *  @param InShapes Collection of shapes to use
         */
        static FVector CalculateCenterOfMass(const TArray<FAnimPhysShape>& InShapes);
        /** Calculate the inertia tensor of a shape
         *  @param InVertices Verts in the shape
         *  @param InTriangles Triangles represented in InVertices
         *  @param InCenterOfMass Center of mass of the shape
         */
        static FMatrix CalculateInertia(const TArray<FVector>& InVertices, const TArray<FIntVector>& InTriangles, const FVector& InCenterOfMass);
        /** Calculate the inertia tensor of a collection of shapes
         *  @param InShapes Shapes to use
         *  @param InCenterOfMass Center of mass of the collection
         */
        static FMatrix CalculateInertia(const TArray<FAnimPhysShape>& InShapes, const FVector& InCenterOfMass);
        /** Scale the mass and inertia properties of a rigid body
         *  @param InOutRigidBody Body to modify
         *  @param Scale Scale to use
         */
        static void ScaleRigidBodyMass(FAnimPhysRigidBody* InOutRigidBody, float Scale);  // scales the mass and all relevant inertial properties by multiplier s
        /** Apply an impulse to a body
         *  @param InOutRigidBody Body to apply the impulse to
         *  @param InWorldOrientedImpactPoint Location of the impulse
         *  @param InImpulse Impulse to apply
         */
        static void ApplyImpulse(FAnimPhysRigidBody* InOutRigidBody, const FVector& InWorldOrientedImpactPoint, const FVector& InImpulse);
        
        /** Performs a physics update on the provided state objects
        *  @param DeltaTime Time for the frame / update
        *  @param Bodies Bodies to integrate
        *  @param LinearLimits Linear limits to apply to the bodies
        *  @param AngularLimits Angular limits to apply to the bodies
        *  @param Springs Linear/Angular springs to apply to the bodies prior to solving
        *  @param NumPreIterations Number of times to iterate the limits before performing the integration
        *  @param NumPostIterations Number of times to iterae the limits after performing the integration
        */
        static void PhysicsUpdate(float DeltaTime, TArray<FAnimPhysRigidBody*>& Bodies, TArray<FAnimPhysLinearLimit>& LinearLimits, TArray<FAnimPhysAngularLimit>& AngularLimits, TArray<FAnimPhysSpring>& Springs, const FVector& GravityDirection, const FVector& ExternalForce, INT32 NumPreIterations = 8, INT32 NumPostIterations = 2);
        //////////////////////////////////////////////////////////////////////////
        // Constraint functions
        /** Constrain bodies along a provided axis
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in constraint (or nullptr for world)
         *  @param FirstPosition Local position on first body to apply constraint
         *  @param SecondBody Second body in constraint
         *  @param SecondPosition Local position on second body to apply constraint
         *  @param AxisToConstrain Axis to constrain between bodies
         *  @param Limits Limit on the provided axis so that Limits.X(min) < Final Position < Limits.Y(max)
         *  @param MinimumForce Minimum force that can be applied to satisfy the maximum limit (default -MAX_flt)
         *  @param MaximumForce Maximum force that can be applied to satisfy the minimum limit (default MAX_flt)
         */
        static void ConstrainAlongDirection(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody *FirstBody, const FVector& FirstPosition, FAnimPhysRigidBody *SecondBody, const FVector& SecondPosition, const FVector& AxisToConstrain, const FVector2D Limits, float MinimumForce = -MAX_flt, float MaximumForce = MAX_flt);
        /** Constrain bodies together as if fixed or nailed (linear only, bodies can still rotate)
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in constraint (or nullptr for world)
         *  @param FirstPosition Local position on first body to apply constraint
         *  @param SecondBody Second body in constraint
         *  @param SecondPosition Local position on second body to apply constraint
         */
        static void ConstrainPositionNailed(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody *FirstBody, const FVector& FirstPosition, FAnimPhysRigidBody *SecondBody, const FVector& SecondPosition);
        /** Constrain bodies together with linear limits forming a box or prism around the constraint
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in the constraint (or nullptr for world)
         *  @param FirstPosition Local position on first body to apply constraint
         *  @param SecondBody Second body in the constraint
         *  @param SecondPosition Local position on the second body to apply constraint
         *  @param PrismRotation Rotation to apply to the prism axes, only necessary when constraining to world, otherwise the rotation of the first body is used
         *  @param LimitsMin Minimum limits along axes
         *  @param LimitsMax Maximum limits along axes
         */
        static void ConstrainPositionPrismatic(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody* FirstBody, const FVector& FirstPosition, FAnimPhysRigidBody* SecondBody, const FVector& SecondPosition, const FQuat& PrismRotation, const FVector& LimitsMin, const FVector& LimitsMax);
        /** Constraint two bodies together with angular limits, limiting the relative rotation between them.
         *  Note that this allows TWO axes to rotate, the twist axis will always be locked
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in the constraint (or nullptr for world)
         *  @param SecondBody Second body in constraint
         *  @param JointFrame Frame/Rotation of the joint
         *  @param TwistAxis The axis to regard as the twist axis
         *  @param JointLimitMin Minimum limits along each axis (twist axis ignored)
         *  @param JointLimitMax Maximum limits along each axis (twist axis ignored)
         *  @param InJointBias Bias towards second body's forces (1.0f = 100%)
         */
        static void ConstrainAngularRange(float DeltaTime, TArray<FAnimPhysAngularLimit>& LimitContainer, FAnimPhysRigidBody *FirstBody, FAnimPhysRigidBody *SecondBody, const FQuat& JointFrame, AnimPhysTwistAxis TwistAxis, const FVector& JointLimitMin, const FVector& JointLimitMax, float InJointBias);
        /** Constraints the rotation between two bodies into a cone
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in the constraint (or nullptr for world)
         *  @param Normal0 Normal for the first side of the constraint
         *  @param SecondBody Second body in the constraint
         *  @param Normal1 Normal for the second side of the constraint
         *  @param LimitAngle Angle to limit the cone to
         *  @param InJointBias Bias towards second body's forces (1.0f = 100%)
         */
        static void ConstrainConeAngle(float DeltaTime, TArray<FAnimPhysAngularLimit>& LimitContainer, FAnimPhysRigidBody* FirstBody, const FVector& Normal0, FAnimPhysRigidBody* SecondBody, const FVector& Normal1, float LimitAngle, float InJointBias);  // a hinge is a cone with 0 limitangle
        /** Constrains the position of a body to one side of a plane placed at PlaneTransform (plane normal is Z axis)
        *  @param LimitContainer Container to add limits to
        *  @param Body The body to constrain to the plane
        *  @param PlaneTransform Transform of the plane, with the normal facing along the Z axis of the orientation
        */
        static void ConstrainPlanar(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody* Body, const FBoneAtom& PlaneTransform);
        /** Constrains the position of a body within the requested sphere */
        static void ConstrainSphericalInner(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody* Body, const FBoneAtom& SphereTransform, float SphereRadius);
        /** Constrains the position of a body outside of the requested sphere */
        static void ConstrainSphericalOuter(float DeltaTime, TArray<FAnimPhysLinearLimit>& LimitContainer, FAnimPhysRigidBody* Body, const FBoneAtom& SphereTransform, float SphereRadius);
        //////////////////////////////////////////////////////////////////////////
        // Spring creation methods
        static void CreateSpring(TArray<FAnimPhysSpring>& SpringContainer, FAnimPhysRigidBody* Body0, FVector Position0, FAnimPhysRigidBody* Body1, FVector Position1);
    private:
        /** Calculate differentiated orientation quaternion
        *  @param InOrientation Orientation of the body
        *  @param InInverseTensor Inverse inertia tensor for the body
        *  @param InAngularMomentum Current angular momentum of the body
        */
        static FQuat DiffQ(const FQuat& InOrientation, const FMatrix &InInverseTensor, const FVector& InAngularMomentum);
        /** Perform an RK update of the provided orientation
        *  @param InOrient Orientation to update
        *  @param InInverseTensor Inverse inertia tensor of the body
        *  @param InAngularMomentum Angular momentum of the body
        *  @param InDeltaTime Delta time to process the update over
        */
        static FQuat UpdateOrientRK(const FQuat& InOrient, const FMatrix& InInverseTensor, const FVector& InAngularMomentum, float InDeltaTime);
        /** Initialize the velocity for a given body
         *  @param InBody Body to initialize
         */
        static void InitializeBodyVelocity(float DeltaTime, FAnimPhysRigidBody *InBody, const FVector& GravityDirection);
        /** Using calculated linear and angular momentum, integrate the position and orientation of a body
         *  @param InBody Body to integrate
         */
        static void CalculateNextPose(float DeltaTime, FAnimPhysRigidBody* InBody);
        /** Update previous and current pose state
         *  @param InBody Body to update
         */
        static void UpdatePose(FAnimPhysRigidBody* InBody);
        /** Internal version of constrain angular. ConstrainAngularRange can work out some of these params so wraps this
         *  @param LimitContainer Container to add limits to
         *  @param FirstBody First body in the constraint (or nullptr for world)
         *  @param JointFrame0 Frame/Rotation of the first side of the joint
         *  @param SecondBody Second body in the constraint
         *  @param JointFrame1 Frame/Rotation of the second side of the joint
         *  @param TwistAxis Axis to consider as the twist axis
         *  @param InJointLimitMin Minimum limits for the joint (twist axis ignored, always locked)
         *  @param InJointLimitMax Maximum limits for the joint (twist axis ignored, always locked)
         */
        static void ConstrainAngularRangeInternal(float DeltaTime, TArray<FAnimPhysAngularLimit>& LimitContainer, FAnimPhysRigidBody *FirstBody, const FQuat& JointFrame0, FAnimPhysRigidBody *SecondBody, const FQuat& JointFrame1, AnimPhysTwistAxis TwistAxis, const FVector& InJointLimitMin, const FVector& InJointLimitMax, float InJointBias);
    };




    7 继续添加EngineClassesSkelControlAnimDynamic.uc的成员

    问题:函数声明中的宏定义

        structcpptext
        {
        FAnimPhysAngularLimit();
        //FAnimPhysAngularLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody, const FVector& InWorldSpaceAxis, float InTargetSpin = 0, float InMinimumTorque = -MAX_flt, float InMaximumTorque = MAX_flt);    
        /** Remove bias added to solve the limit
         */
        void RemoveBias();
        /** Solve the limit
         */
        void Iter(float DeltaTime);
        void UpdateCachedData();
        }


    生成到h文件会编译不通过,因为没有定义


    用 const?

    const MAX_AIGROUP_NUMBER = 10;


    有个例子ue3DevelopmentSrcEngineClassesLandscapeInfo.uc

    cpptext
    {
    ...
        FVector GetLandscapeCenterPos(FLOAT& LengthZ, INT MinX = MAXINT, INT MinY = MAXINT, INT MaxX = MININT, INT MaxY = MININT);


    EngineTerrainClasses.h文件中


    宏定义在core.h



    是枚举


    解决:在core.h中定义即可





    8 继续添加EngineClassesSkelControlAnimDynamic.uc的成员

    /**
      * Base class for constraint limits
      */
    struct native AnimPhysLimit
    {
        var native pointer  Bodies[2] {FAnimPhysRigidBody};
        structcpptext
        {
        FAnimPhysLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody);
        }
    };
    /**
      * Angular limit, keeps angular torque around an axis within a defined range
      */
    struct native AnimPhysAngularLimit extends AnimPhysLimit
    {
        // Axis of the limit in world space
        var Vector WorldSpaceAxis;
        // Rotational impulse
        var float  Torque;
        // The required spin required to align the limit
        var float  TargetSpin;
        // Minimum torque this limit can apply
        var float  MinimumTorque;
        // Maximum torque this limit can apply
        var float  MaximumTorque;
        // Cached spin to torque value that is independant of iterations
        var float CachedSpinToTorque;
        structcpptext
        {
        FAnimPhysAngularLimit();
        FAnimPhysAngularLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody, const FVector& InWorldSpaceAxis, float InTargetSpin = 0, float InMinimumTorque = -MAX_flt, float InMaximumTorque = MAX_flt);    
        /** Remove bias added to solve the limit
         */
        void RemoveBias();
        /** Solve the limit
         */
        void Iter(float DeltaTime);
        void UpdateCachedData();
        }
    };
    struct native AnimPhysLinearLimit extends AnimPhysLimit
    {
        // Position of anchor on first object (in first object local space)
        var Vector FirstPosition;
        // Position of anchor on second object (in second object local space)
        var Vector SecondPosition;
        // Normal along which the limit is applied
        var Vector LimitNormal;
        // Target speed needed to solve the limit
        var float  TargetSpeed; 
        // Target speed of the limit without bias (force added just to solve limit)
        var float  TargetSpeedWithoutBias;
        // Minimum force this limit can apply along the normal
        var float  MinimumForce;
        // Maximum force this limit can apply along the normal
        var float  Maximumforce;
        // Sum of impulses applied
        var float  SumImpulses;
        // Cached denominator of the impulse calculation, doesn't change across iterations
        var float InverseInertiaImpulse;
        // Cached world space position on body 0
        var Vector WorldSpacePosition0;
        // Cached world space position on body 1
        var Vector WorldSpacePosition1;
        structcpptext
        {
        FAnimPhysLinearLimit();
        FAnimPhysLinearLimit(FAnimPhysRigidBody* InFirstBody, FAnimPhysRigidBody* InSecondBody, const FVector& InFirstPosition, const FVector& InSecondPosition,
            const FVector& InNormal = FVector(0.0f, 0.0f, 1.0f), float InTargetSpeed = 0.0f, float InTargetSpeedWithoutBias = 0.0f, const FVector2D& InForceRange = FVector2D(-MAX_flt, MAX_flt));
        /** Remove bias added to solve the limit
        */
        void RemoveBias();
        /** Solve the limit
        */
        void Iter(float DetlaTime);
        void UpdateCachedData();
        }
    };
    struct native AnimPhysSpring
    {
        // Bodies connected by the spring (Or nullptr for world)
        var native pointer Body0 {FAnimPhysRigidBody};
        var native pointer Body1 {FAnimPhysRigidBody};
        // Extra orientation applied on top of Body0's orientation to the target direction
        var Quat TargetOrientationOffset;
        // Target in body0 space for the target axis on body1 to reach
        var Vector AngularTarget;
        
        // The axis of body1's orientation to match to the angular target
        var AnimPhysTwistAxis AngularTargetAxis;
        // Local space anchor positions (in space of Body0 and Body1 respectively)
        var Vector Anchor0;
        var Vector Anchor1;
        // Spring constant for linear springs
        var float SpringConstantLinear;
        // Sprint constant for angular springs
        var float SpringConstantAngular;
        // Whether to apply linear spring force
        var bool bApplyLinear;
        // Whether to apply angular spring force
        var bool bApplyAngular;
        structcpptext
        {
        /** Applies forces to the bound bodies
         */
        void ApplyForces(float DeltaTime);
        }
    };
    ...
    // Cached timestep from the update phase (needed in evaluate phase)
    var transient float NextTimeStep;
    // Current amount of time debt
    var transient float TimeDebt;
    // Current time dilation
    var transient float CurrentTimeDilation;
    // Cached physics settings. We cache these on initialise to avoid the cost of accessing UPhysicsSettings a lot each frame
    var transient float MaxPhysicsDeltaTime;
    var transient float MaxSubstepDeltaTime;
    //var transient int MaxSubsteps;
    //////////////////////////////////////////////////////////////////////////
    // Cached sim space that we last used
    var transient AnimPhysSimSpaceType LastSimSpace;
    // Active body list
    var transient array<AnimPhysLinkedBody> Bodies;
    // Pointers to bodies that need to be reset to their bound bone.
    // This happens on LOD change so we don't make the simulation unstable
    //var transient array<FAnimPhysLinkedBody*> BodiesToReset;
    var native transient array<pointer> BodiesToReset{FAnimPhysLinkedBody};
    // Pointers back to the base bodies to pass to the simulation
    //var transient array<FAnimPhysRigidBody*> BaseBodyPtrs;
    var native transient array<pointer> BaseBodyPtrs{FAnimPhysRigidBody};
    // List of current linear limits built for the current frame
    var transient array<AnimPhysLinearLimit> LinearLimits;
    // List of current angular limits built for the current frame
    var transient array<AnimPhysAngularLimit> AngularLimits;
    // List of spring force generators created for this frame
    var transient array<AnimPhysSpring> Springs;
    // Local space offsets for each body
    var transient array<Vector> JointOffsets;
    // List of bone references for all bodies in this node
    //var transient array<FBoneReference> BoundBoneReferences;
    // Depending on the LOD we might not be runnning all of the bound bodies (for chains)
    // this tracks the active bodies.
    var transient array<int> ActiveBoneIndices;
    // Gravity direction in sim space
    var transient vector SimSpaceGravityDirection;


    9 填充USkelControlAnimDynamic.InitPhysics 

    ChainEnd 用于 连接骨骼控制器的骨骼节点时赋值,不手动编辑


    FAnimNode_AnimDynamics.GetBoneTransformInSimSpace 


    FAnimNode_SkeletalControlBase.EvaluateComponentSpace中






    UE3的USkeletalMeshComponent.ApplyControllersForBoneIndex




    10 骨骼基础函数FBoneAtom.SetToRelativeTransform 

    /**
     * Set current transform and the relative to ParentTransform.
     * Equates to This = This->GetRelativeTransform(Parent), but saves the intermediate FTransform storage and copy.
     */
    FORCEINLINE void FBoneAtom::SetToRelativeTransform(const FBoneAtom& ParentTransform)
    {
        // A * B(-1) = VQS(B)(-1) (VQS (A))
        // 
        // Scale = S(A)/S(B)
        // Rotation = Q(B)(-1) * Q(A)
        // Translation = 1/S(B) *[Q(B)(-1)*(T(A)-T(B))*Q(B)]
        // where A = this, B = Other
    #if DEBUG_INVERSE_TRANSFORM
        FMatrix AM = ToMatrix();
        FMatrix BM = ParentTransform.ToMatrix();
    #endif
        const FVector SafeRecipScale3D = GetSafeScaleReciprocal(ParentTransform.Scale3D, SMALL_NUMBER);
        const FQuat InverseRot = ParentTransform.Rotation.Inverse();
        Scale3D *= SafeRecipScale3D;    
        Translation = (InverseRot * (Translation - ParentTransform.Translation)) * SafeRecipScale3D;
        Rotation = InverseRot * Rotation;
    #if DEBUG_INVERSE_TRANSFORM
        DebugEqualMatrix(AM *  BM.InverseFast());
    #endif
    }


    DevelopmentSrcCoreIncFBoneAtomVectorized.h

    /**
    * Set current transform and the relative to ParentTransform.
    * Equates to This = This->GetRelativeTransform(Parent), but saves the intermediate FTransform storage and copy.
    */
    FORCEINLINE void FBoneAtom::SetToRelativeTransform(const FBoneAtom& ParentTransform)
    {
        // A * B(-1) = VQS(B)(-1) (VQS (A))
        // 
        // Scale = S(A)/S(B)
        // Rotation = Q(B)(-1) * Q(A)
        // Translation = 1/S(B) *[Q(B)(-1)*(T(A)-T(B))*Q(B)]
        // where A = this, B = Other
    #if DEBUG_INVERSE_TRANSFORM
        FMatrix AM = ToMatrix();
        FMatrix BM = ParentTransform.ToMatrix();
    #endif
        checkSlow(ParentTransform.IsRotationNormalized());
        // Scale = S(A)/S(B)    
        VectorRegister VSafeScale3D    = VectorSet_W0(GetSafeScaleReciprocal(ParentTransform.Scale3D, ScalarRegister(SMALL_NUMBER)));
        Scale3D = VectorMultiply(Scale3D, VSafeScale3D);
        //VQTranslation = (  ( T(A).X - T(B).X ),  ( T(A).Y - T(B).Y ), ( T(A).Z - T(B).Z), 0.f );
        VectorRegister VQTranslation = VectorSet_W0(VectorSubtract(Translation, ParentTransform.Translation));
        // Inverse RotatedTranslation
        VectorRegister VInverseParentRot = VectorQuaternionInverse(ParentTransform.Rotation);
        VectorRegister VR = VectorQuaternionRotateVector(VInverseParentRot, VQTranslation);
        // Translation = 1/S(B)
        Translation = VectorMultiply(VR, VSafeScale3D);
        // Rotation = Q(B)(-1) * Q(A)    
        Rotation = VectorQuaternionMultiply2(VInverseParentRot, Rotation );
        DiagnosticCheckNaN_All(); 
    #if DEBUG_INVERSE_TRANSFORM
        DebugEqualMatrix(AM *  BM.Inverse());
    #endif
    }



    FBoneAtomVectorized.h

        /**
        * Create a new transform: OutTransform = A * B using the matrix while keeping the scale that's given by A and B
        * Please note that this operation is a lot more expensive than normal Multiply
        *
        * Order matters when composing transforms : A * B will yield a transform that logically first applies A then B to any subsequent transformation.
        *
        * @param  OutTransform pointer to transform that will store the result of A * B.
        * @param  A Transform A.
        * @param  B Transform B.
        */
        FORCEINLINE static void MultiplyUsingMatrixWithScale(FBoneAtom* OutTransform, const FBoneAtom* A, const FBoneAtom* B);
        /**
        * Create a new transform from multiplications of given to matrices (AMatrix*BMatrix) using desired scale
        * This is used by MultiplyUsingMatrixWithScale and GetRelativeTransformUsingMatrixWithScale
        * This is only used to handle negative scale
        *
        * @param    AMatrix first Matrix of operation
        * @param    BMatrix second Matrix of operation
        * @param    DesiredScale - there is no check on if the magnitude is correct here. It assumes that is correct.
        * @param    OutTransform the constructed transform
        */
        FORCEINLINE static void ConstructTransformFromMatrixWithDesiredScale(const FMatrix& AMatrix, const FMatrix& BMatrix, const VectorRegister& DesiredScale, FBoneAtom& OutTransform);
        /**
        * Create a new transform: OutTransform = Base * Relative(-1) using the matrix while keeping the scale that's given by Base and Relative
        * Please note that this operation is a lot more expensive than normal GetRelativeTrnasform
        *
        * @param  OutTransform pointer to transform that will store the result of Base * Relative(-1).
        * @param  BAse Transform Base.
        * @param  Relative Transform Relative.
        */
        FORCEINLINE static void GetRelativeTransformUsingMatrixWithScale(FBoneAtom* OutTransform, const FBoneAtom* Base, const FBoneAtom* Relative);




    11 USkelControlAnimDynamic.UpdateLimits

    void USkelControlAnimDynamic::UpdateLimits(USkeletalMeshComponent* SkelComp)
    {
        SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsLimitUpdate);
        // We're always going to use the same number so don't realloc
        LinearLimits.Empty(LinearLimits.Num());
        AngularLimits.Empty(AngularLimits.Num());
        Springs.Empty(Springs.Num());
        //const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();
        //for(int32 ActiveIndex : ActiveBoneIndices)
        for (INT Idx = 0; Idx < ActiveBoneIndices.Num(); Idx++)
        {
            INT32 ActiveIndex = ActiveBoneIndices(Idx);
            //const FBoneReference& CurrentBoneRef = BoundBoneReferences[ActiveIndex];
            FName CurrentBoneName = BoundBoneReferences(ActiveIndex);
            // If our bone isn't valid, move on
            //if(!CurrentBoneRef.IsValid(BoneContainer))
            if (SkelComp->MatchRefBone(CurrentBoneName) == INDEX_NONE)
            {
                continue;
            }
            FAnimPhysLinkedBody& ChainBody = Bodies(ActiveIndex);
            FAnimPhysRigidBody& RigidBody = Bodies(ActiveIndex).RigidBody.PhysBody;
            FAnimPhysRigidBody* PrevBody = NULL;
            if (ChainBody.ParentBody)
            {
                PrevBody = &ChainBody.ParentBody->PhysBody;
            }
            // Get joint transform
    //         FCompactPoseBoneIndex BoneIndex = CurrentBoneRef.GetCompactPoseIndex(BoneContainer);
    //         FTransform BoundBoneTransform = GetBoneTransformInSimSpace(SkelComp, MeshBases, BoneIndex);
    // 
    //         FTransform ShapeTransform = BoundBoneTransform;
            INT BoneIndex = SkelComp->MatchRefBone(CurrentBoneName);
            FBoneAtom BoundBoneTransform = GetBoneTransformInSimSpace(SkelComp, BoneIndex);
            FBoneAtom ShapeTransform = BoundBoneTransform;
            // Local offset to joint for Body1
            FVector Body1JointOffset = LocalJointOffset;
            if (PrevBody)
            {
                // Get the correct offset
                Body1JointOffset = JointOffsets(ActiveIndex);
                // Modify the shape transform to be correct in Body0 frame
                ShapeTransform = FBoneAtom(FQuat::Identity, -Body1JointOffset);
            }
            if (ConstraintSetup.bLinearFullyLocked)
            {
                // Rather than calculate prismatic limits, just lock the transform (1 limit instead of 6)
                FAnimPhys::ConstrainPositionNailed(NextTimeStep, LinearLimits, PrevBody, ShapeTransform.GetTranslation(), &RigidBody, Body1JointOffset);
            }
            else
            {
                if (ConstraintSetup.LinearXLimitType != AnimPhysLinearConstraintType::Free)
                {
                    FAnimPhys::ConstrainAlongDirection(NextTimeStep, LinearLimits, PrevBody, ShapeTransform.GetTranslation(), &RigidBody, Body1JointOffset, ShapeTransform.GetRotation().GetAxisX(), FVector2D(ConstraintSetup.LinearAxesMin.X, ConstraintSetup.LinearAxesMax.X));
                }
                if (ConstraintSetup.LinearYLimitType != AnimPhysLinearConstraintType::Free)
                {
                    FAnimPhys::ConstrainAlongDirection(NextTimeStep, LinearLimits, PrevBody, ShapeTransform.GetTranslation(), &RigidBody, Body1JointOffset, ShapeTransform.GetRotation().GetAxisY(), FVector2D(ConstraintSetup.LinearAxesMin.Y, ConstraintSetup.LinearAxesMax.Y));
                }
                if (ConstraintSetup.LinearZLimitType != AnimPhysLinearConstraintType::Free)
                {
                    FAnimPhys::ConstrainAlongDirection(NextTimeStep, LinearLimits, PrevBody, ShapeTransform.GetTranslation(), &RigidBody, Body1JointOffset, ShapeTransform.GetRotation().GetAxisZ(), FVector2D(ConstraintSetup.LinearAxesMin.Z, ConstraintSetup.LinearAxesMax.Z));
                }
            }
            if (ConstraintSetup.AngularConstraintType == AnimPhysAngularConstraintType::Angular)
            {
    #if WITH_EDITOR
                // Check the ranges are valid when running in the editor, log if something is wrong
                if(ConstraintSetup.AngularLimitsMin.X > ConstraintSetup.AngularLimitsMax.X ||
                    ConstraintSetup.AngularLimitsMin.Y > ConstraintSetup.AngularLimitsMax.Y ||
                    ConstraintSetup.AngularLimitsMin.Z > ConstraintSetup.AngularLimitsMax.Z)
                {
                    //UE_LOG(LogAnimation, Warning, TEXT("AnimDynamics: Min/Max angular limits for bone %s incorrect, at least one min axis value is greater than the corresponding max."), *BoundBone.BoneName.ToString());
                    warnf(TEXT("AnimDynamics: Min/Max angular limits for bone %s incorrect, at least one min axis value is greater than the corresponding max."), *BoundBone.ToString());
                }
    #endif
                // Add angular limits. any limit with 360+ degree range is ignored and left free.
                FAnimPhys::ConstrainAngularRange(NextTimeStep, AngularLimits, PrevBody, &RigidBody, ShapeTransform.GetRotation(), (AnimPhysTwistAxis)ConstraintSetup.TwistAxis, ConstraintSetup.AngularLimitsMin, ConstraintSetup.AngularLimitsMax, bOverrideAngularBias ? AngularBiasOverride : AnimPhysicsConstants::JointBiasFactor);
            }
            else
            {
                FAnimPhys::ConstrainConeAngle(NextTimeStep, AngularLimits, PrevBody, BoundBoneTransform.GetRotation().GetAxisX(), &RigidBody, FVector(1.0f, 0.0f, 0.0f), ConstraintSetup.ConeAngle, bOverrideAngularBias ? AngularBiasOverride : AnimPhysicsConstants::JointBiasFactor);
            }
            if(PlanarLimits.Num() > 0 && bUsePlanarLimit)
            {
                //for(FAnimPhysPlanarLimit& PlanarLimit : PlanarLimits)
                for (INT Idx = 0; Idx < PlanarLimits.Num(); Idx++)
                {
                    FAnimPhysPlanarLimit& PlanarLimit = PlanarLimits(Idx);
                    FBoneAtom LimitPlaneTransform = PlanarLimit.PlaneTransform;
                    INT DrivingBoneIndex = SkelComp->MatchRefBone(PlanarLimit.DrivingBone);
                    //if(PlanarLimit.DrivingBone.IsValid(BoneContainer))
                    if ( DrivingBoneIndex != INDEX_NONE)
                    {
    //                     FCompactPoseBoneIndex DrivingBoneIndex = PlanarLimit.DrivingBone.GetCompactPoseIndex(BoneContainer);
    // 
    //                     FTransform DrivingBoneTransform = GetBoneTransformInSimSpace(SkelComp, MeshBases, DrivingBoneIndex);
                        
                        FBoneAtom DrivingBoneTransform = GetBoneTransformInSimSpace(SkelComp, DrivingBoneIndex);
                        LimitPlaneTransform *= DrivingBoneTransform;
                    }
                    FAnimPhys::ConstrainPlanar(NextTimeStep, LinearLimits, &RigidBody, LimitPlaneTransform);
                }
            }
            if(SphericalLimits.Num() > 0 && bUseSphericalLimits)
            {
                //for(FAnimPhysSphericalLimit& SphericalLimit : SphericalLimits)
                for (INT Idx = 0; Idx < SphericalLimits.Num(); Idx++)
                {
                    FAnimPhysSphericalLimit& SphericalLimit = SphericalLimits(Idx);
                    FBoneAtom SphereTransform = FBoneAtom::Identity;
                    SphereTransform.SetTranslation(SphericalLimit.SphereLocalOffset);
                    INT DrivingBoneIndex = SkelComp->MatchRefBone(SphericalLimit.DrivingBone);
                    //if(SphericalLimit.DrivingBone.IsValid(BoneContainer))
                    if ( DrivingBoneIndex != INDEX_NONE)
                    {
                        //FCompactPoseBoneIndex DrivingBoneIndex = SphericalLimit.DrivingBone.GetCompactPoseIndex(BoneContainer);
                        //FTransform DrivingBoneTransform = GetBoneTransformInSimSpace(SkelComp, MeshBases, DrivingBoneIndex);
                        FBoneAtom DrivingBoneTransform = GetBoneTransformInSimSpace(SkelComp, DrivingBoneIndex);
                        SphereTransform *= DrivingBoneTransform;
                    }
                    switch(SphericalLimit.LimitType)
                    {
                    case ESphericalLimitType::Inner:
                        FAnimPhys::ConstrainSphericalInner(NextTimeStep, LinearLimits, &RigidBody, SphereTransform, SphericalLimit.LimitRadius);
                        break;
                    case ESphericalLimitType::Outer:
                        FAnimPhys::ConstrainSphericalOuter(NextTimeStep, LinearLimits, &RigidBody, SphereTransform, SphericalLimit.LimitRadius);
                        break;
                    default:
                        break;
                    }
                }
            }
            // Add spring if we need spring forces
            if (bAngularSpring || bLinearSpring)
            {
                FAnimPhys::CreateSpring(Springs, PrevBody, ShapeTransform.GetTranslation(), &RigidBody, FVector::ZeroVector);
                FAnimPhysSpring& NewSpring = Springs.Last();
                NewSpring.SpringConstantLinear = LinearSpringConstant;
                NewSpring.SpringConstantAngular = AngularSpringConstant;
                NewSpring.AngularTarget = ConstraintSetup.AngularTarget.SafeNormal();
                NewSpring.AngularTargetAxis = ConstraintSetup.AngularTargetAxis;
                NewSpring.TargetOrientationOffset = ShapeTransform.GetRotation();
                NewSpring.bApplyAngular = bAngularSpring;
                NewSpring.bApplyLinear = bLinearSpring;
            }
        }
    }



    12  USkelControlAnimDynamic.CalculateNewBoneTransforms.

    void USkelControlAnimDynamic::CalculateNewBoneTransforms(INT BoneIndex, USkeletalMeshComponent* SkelComp, TArray<FBoneAtom>& OutBoneTransforms)
    {
        check(OutBoneTransforms.Num() == 0);
        SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsOverall);
    //     int32 RestrictToLOD = CVarRestrictLod.GetValueOnAnyThread();
    //     bool bEnabledForLod = RestrictToLOD >= 0 ? SkelComp->PredictedLODLevel == RestrictToLOD : true;
    //    if (CVarEnableDynamics.GetValueOnAnyThread() == 1 && bEnabledForLod)
        {
            if(LastSimSpace != SimulationSpace)
            {
                // Our sim space has been changed since our last update, we need to convert all of our
                // body transforms into the new space.
                ConvertSimulationSpace(SkelComp, (AnimPhysSimSpaceType)LastSimSpace, (AnimPhysSimSpaceType)SimulationSpace);
            }
            // Pretty nasty - but there isn't really a good way to get clean bone transforms (without the modification from
            // previous runs) so we have to initialize here, checking often so we can restart a simulation in the editor.
            if (bRequiresInit)
            {
                InitPhysics(SkelComp);
                bRequiresInit = false;
            }
            //const FBoneContainer& RequiredBones = MeshBases.GetPose().GetBoneContainer();
            while(BodiesToReset.Num() > 0)
            {
                FAnimPhysLinkedBody* BodyToReset = BodiesToReset.Pop();
                
                if(BodyToReset /*&& BodyToReset->RigidBody.BoundBone.IsValid(RequiredBones)*/)
                {
                    INT BoundBoneIndex = SkelComp->MatchRefBone(BodyToReset->RigidBody.BoundBone);
                    if (BoundBoneIndex != INDEX_NONE)
                    {
                        //FTransform BoneTransform = GetBoneTransformInSimSpace(SkelComp, MeshBases, BodyToReset->RigidBody.BoundBone.GetCompactPoseIndex(RequiredBones));
                        FBoneAtom BoneTransform = GetBoneTransformInSimSpace(SkelComp, BoundBoneIndex);
                        FAnimPhysRigidBody& PhysBody = BodyToReset->RigidBody.PhysBody;
                        PhysBody.Pose.Position = BoneTransform.GetTranslation();
                        PhysBody.Pose.Orientation = BoneTransform.GetRotation();
                        PhysBody.LinearMomentum = FVector::ZeroVector;
                        PhysBody.AngularMomentum = FVector::ZeroVector;                
                    }
                }
            }
            if (bDoUpdate && NextTimeStep > 0.0f)
            {
                // Wind / Force update
                if(/*CVarEnableWind.GetValueOnAnyThread() == 1 &&*/ bEnableWind)
                {
                    SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsWindData);
                    //for(FAnimPhysRigidBody* Body : BaseBodyPtrs)
                    for (INT Idx = 0; Idx < BaseBodyPtrs.Num(); Idx++)
                    {
                        FAnimPhysRigidBody* Body = BaseBodyPtrs(Idx);
                        if(SkelComp && GWorld/*SkelComp->GetWorld()*/)
                        {
                            Body->bWindEnabled = bEnableWind;
                            if(Body->bWindEnabled)
                            {
                                //UWorld* World = SkelComp->GetWorld();
                                FSceneInterface* Scene = GWorld->Scene;
                                // Unused by our simulation but needed for the call to GetWindParameters below
                                float WindMinGust;
                                float WindMaxGust;
                                // Setup wind data
                                Body->bWindEnabled = true;
                                //Scene->GetWindParameters(SkelComp->ComponentToWorld.TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust);
                                Scene->GetWindParameters(SkelComp->LocalToWorldBoneAtom.TransformPosition(Body->Pose.Position), Body->WindData.WindDirection, Body->WindData.WindSpeed, WindMinGust, WindMaxGust);
                                Body->WindData.WindDirection = SkelComp->LocalToWorldBoneAtom.Inverse().TransformVector(Body->WindData.WindDirection);
                                Body->WindData.WindAdaption = RandRange(0.0f, 2.0f);
                                Body->WindData.BodyWindScale = WindScale;
                            }
                        }
                    }
                }
                else
                {
                    SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsWindData);
                    // Disable wind.
                    //for(FAnimPhysRigidBody* Body : BaseBodyPtrs)
                    for (INT Idx = 0; Idx < BaseBodyPtrs.Num(); Idx++)
                    {
                        FAnimPhysRigidBody* Body = BaseBodyPtrs(Idx);
                        Body->bWindEnabled = false;
                    }
                }
                FVector OrientedExternalForce = ExternalForce;
                if(!OrientedExternalForce.IsNearlyZero())
                {
                    OrientedExternalForce = TransformWorldVectorToSimSpace(SkelComp, OrientedExternalForce);
                }
                // We don't send any bodies that don't have valid bones to the simulation
    //            TArray<FAnimPhysRigidBody*>& SimBodies = FSimBodiesScratch::Get().SimBodies;
                static TArray<FAnimPhysRigidBody*> SimBodies;
                SimBodies.Empty(SimBodies.Num());
                //for(int32& ActiveIndex : ActiveBoneIndices)
                for (INT Idx = 0; Idx < BaseBodyPtrs.Num(); Idx++)
                {
                    INT32& ActiveIndex = ActiveBoneIndices(Idx);
                    if(BaseBodyPtrs.IsValidIndex(ActiveIndex))
                    {
                        SimBodies.AddItem(BaseBodyPtrs(ActiveIndex));
                    }
                }
                //if (CVarEnableAdaptiveSubstep.GetValueOnAnyThread() == 1)
                if (0)
                {
                    float FixedTimeStep = MaxSubstepDeltaTime * CurrentTimeDilation;
                    // Clamp the fixed timestep down to max physics tick time.
                    // at high speeds the simulation will not converge as the delta time is too high, this will
                    // help to keep constraints together at a cost of physical accuracy
                    FixedTimeStep = Clamp(FixedTimeStep, 0.0f, MaxPhysicsDeltaTime);
                    // Calculate number of substeps we should do.
                    INT32 NumIters = appTrunc((NextTimeStep + (TimeDebt * CurrentTimeDilation)) / FixedTimeStep);
                    NumIters = Clamp(NumIters, 0, MaxSubstep);
                    SET_DWORD_STAT(STAT_AnimDynamicsSubSteps, NumIters);
                    // Store the remaining time as debt for later frames
                    TimeDebt = (NextTimeStep + TimeDebt) - (NumIters * FixedTimeStep);
                    TimeDebt = Clamp(TimeDebt, 0.0f, MaxTimeDebt);
                    NextTimeStep = FixedTimeStep;
                    for (INT32 Iter = 0; Iter < NumIters; ++Iter)
                    {
                        UpdateLimits(SkelComp);
                        FAnimPhys::PhysicsUpdate(FixedTimeStep, SimBodies, LinearLimits, AngularLimits, Springs, SimSpaceGravityDirection, OrientedExternalForce, NumSolverIterationsPreUpdate, NumSolverIterationsPostUpdate);
                    }
                }
                else
                {
                    // Do variable frame-time update
                    const float MaxDeltaTime = MaxPhysicsDeltaTime;
                    NextTimeStep = Min(NextTimeStep, MaxDeltaTime);
                    UpdateLimits(SkelComp);
                    FAnimPhys::PhysicsUpdate(NextTimeStep, SimBodies, LinearLimits, AngularLimits, Springs, SimSpaceGravityDirection, OrientedExternalForce, NumSolverIterationsPreUpdate, NumSolverIterationsPostUpdate);
                }
            }
            if (bDoEval)
            {
                SCOPE_CYCLE_COUNTER(STAT_AnimDynamicsBoneEval);
                //const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();
                for (INT32 Idx = 0; Idx < BoundBoneReferences.Num(); ++Idx)
                {
                    //FBoneReference& CurrentChainBone = BoundBoneReferences[Idx];
                    INT BoneIndex = SkelComp->MatchRefBone(BoundBoneReferences(Idx));
                    FAnimPhysRigidBody& CurrentBody = Bodies(Idx).RigidBody.PhysBody;
                    // Skip invalid bones
                    //if(!CurrentChainBone.IsValid(BoneContainer))
                    if (BoneIndex == INDEX_NONE)
                    {
                        continue;
                    }
                    //FCompactPoseBoneIndex BoneIndex = CurrentChainBone.GetCompactPoseIndex(BoneContainer);
                    FBoneAtom NewBoneTransform(CurrentBody.Pose.Orientation, CurrentBody.Pose.Position + CurrentBody.Pose.Orientation.RotateVector(JointOffsets(Idx)));
                    NewBoneTransform = GetComponentSpaceTransformFromSimSpace((AnimPhysSimSpaceType)SimulationSpace, SkelComp, NewBoneTransform);
                    OutBoneTransforms.AddItem(NewBoneTransform);
                }
            }
            // Store our sim space incase it changes
            LastSimSpace = SimulationSpace;
        }
    }





    13 节点AnimDynamicSkeletalControl需要初始化物理

    • 每次只执行一次
    • 在USkeletalMeshComponent.InitSkelControls.中调用
    • 需要添加Init虚函数
    • 修改属性(ChainEnd、BoundBone)时需要初始化一次


    ue3DevelopmentSrcEngineClassesSkelControlBase.uc

        virtual void Initialize(FName BoneName) {}



    添加USkelControlAnimDynamic.Initialize 

    void USkelControlAnimDynamic::Initialize(FName BoneName)
    {
        BoundBone = BoneName;
        RequestInitialise();
    }


    在USkeletalMeshComponent.InitSkelControls中调用Initialize


    修改时 USkelControlAnimDynamic.PostEditChangeProperty 

    // Editor modification
    void USkelControlAnimDynamic::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
    {
        UProperty* PropertyThatChanged = PropertyChangedEvent.Property;
        if( GIsEditor && PropertyThatChanged && 
            (PropertyThatChanged->GetFName() == FName(TEXT("ChainEnd"))||PropertyThatChanged->GetFName() == FName(TEXT("BoundBone")) )
        )
        {
            RequestInitialise();
        }
        Super::PostEditChangeProperty(PropertyChangedEvent);
    }




    测试运行



    两个骨骼







    【运行】


     

    3






  • 相关阅读:
    Codeforces 1316B String Modification
    Codeforces 1305C Kuroni and Impossible Calculation
    Codeforces 1305B Kuroni and Simple Strings
    Codeforces 1321D Navigation System
    Codeforces 1321C Remove Adjacent
    Codeforces 1321B Journey Planning
    Operating systems Chapter 6
    Operating systems Chapter 5
    Abandoned country HDU
    Computer HDU
  • 原文地址:https://www.cnblogs.com/username/p/6410069.html
Copyright © 2011-2022 走看看