(十一)Flax Engine游戏引擎物理引擎 joints (关节)

2021SC@SDUSC

        本次我们继续针对flax Engine 游戏引擎中物理引擎的joints 包进行源代码的分析。上次我们分析了距离铰链和固定铰链,本次我们将针对flax Engine 中最后一个铰链 D6铰链进行源代码的分析。由于本次将会是joints 最后一个class,所以本次之后我们将针对flax Engine 游戏引擎物理引擎中其他内容进行源代码的分析。按照之前一样,由于D6joints 拥有.h 和.c文件,所以我们将分别对其进行源代码的分析工作。

        在很久之前,我分析过一次flax engine游戏引擎的物理引擎的大致框架,提到过相关的内容和joints ,在那个时候我们也查阅了一些网上的资料,但我们当时无法解释D6 joints到底是干什么的,答案将在这章中揭晓。

        在查看源代码后,我了解到D6 铰链是一种在轴上运行的铰链。

(一):D6Joint.h 头文件:

API_ENUM() enum class D6JointAxis
{
    /// <summary>
    /// Movement on the X axis.
    /// </summary>
    X = 0,

    /// <summary>
    /// Movement on the Y axis.
    /// </summary>
    Y = 1,

    /// <summary>
    /// Movement on the Z axis.
    /// </summary>
    Z = 2,

    /// <summary>
    /// Rotation around the X axis.
    /// </summary>
    Twist = 3,

    /// <summary>
    /// Rotation around the Y axis.
    /// </summary>
    SwingY = 4,

    /// <summary>
    /// Rotation around the Z axis.
    /// </summary>
    SwingZ = 5,

    MAX
};

上述代码定义了D6 joints 的功能的参数:0:x 轴移动,1:y轴移动,2:z轴移动 3:x轴旋转 4:y轴选择 5:z轴的旋转。

API_ENUM() enum class D6JointMotion
{
    /// <summary>
    /// Axis is immovable.
    /// </summary>
    Locked,

    /// <summary>
    /// Axis will be constrained by the specified limits.
    /// </summary>
    Limited,

    /// <summary>
    /// Axis will not be constrained.
    /// </summary>
    Free,

    MAX
};

上述代码表示:指定放置在特定轴上的约束类型 

Locked:轴心是不动的类型

Limited:轴将受到指定限制的约束的类型

Free:轴将不受约束的类型

可用于移动或旋转连接到关节的实体的驱动器类型:

每个驱动器都是一个隐式限力阻尼弹簧:

物理公式:力=弹簧*(目标位置-位置)+阻尼*(目标速度-速度)并且仅当设置了相应的驱动标志时,线性轴才会受到驱动的影响。有两种可能的模型。

API_ENUM() enum class D6JointDriveType
{
    /// <summary>
    /// Linear movement on the X axis using the linear drive model.
    /// </summary>
    X = 0,

    /// <summary>
    /// Linear movement on the Y axis using the linear drive model.
    /// </summary>
    Y = 1,

    /// <summary>
    /// Linear movement on the Z axis using the linear drive model.
    /// </summary>
    Z = 2,

    /// <summary>
    /// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with Slerp mode.
    /// </summary>
    Swing = 3,

    /// <summary>
    /// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with Slerp mode.
    /// </summary>
    Twist = 4,

    /// <summary>
    /// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation
    /// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which
    /// they all must be unlocked).
    /// </summary>
    Slerp = 5,

    MAX
};

上述是线性驱动,使用线性驱动模型在X,Y,Z轴上进行线性移动。

swing:使用扭曲/摆动角度驱动模型绕Y轴旋转

Twist:使用扭曲/摆动角度驱动模型绕Z轴旋转

API_STRUCT() struct D6JointDrive
{
DECLARE_SCRIPTING_TYPE_MINIMAL(D6JointDrive);

    /// <summary>
    /// The spring strength. Force proportional to the position error.
    /// </summary>
    API_FIELD() float Stiffness = 0.0f;

    /// <summary>
    /// Damping strength. Force proportional to the velocity error.
    /// </summary>
    API_FIELD() float Damping = 0.0f;

    /// <summary>
    /// The maximum force the drive can apply.
    /// </summary>
    API_FIELD() float ForceLimit = MAX_float;

    /// <summary>
    /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as they account for the masses of the actors to which the joint is attached.
    /// </summary>
    API_FIELD() bool Acceleration = false;

上述代码是:指定将尝试将关节实体移动到指定驱动位置和速度的驱动的参数

stiffness:弹簧的强度。与位置误差成比例的力

Damping:阻尼强度。与速度误差成比例的力。

 ForceLimit:驱动器可以施加的最大力

Acceleration:如果为真,驱动器将产生加速度而不是力。加速驱动更容易调整,因为它们考虑了连接关节的参与者的质量

    bool operator==(const D6JointDrive& other) const
    {
        return Stiffness == other.Stiffness
                && Damping == other.Damping
                && ForceLimit == other.ForceLimit
                && Acceleration == other.Acceleration;
    }
};

比较两个对象。

API_CLASS() class FLAXENGINE_API D6Joint : public Joint
{
DECLARE_SCENE_OBJECT(D6Joint);
private:

    D6JointMotion _motion[static_cast<int32>(D6JointAxis::MAX)];
    D6JointDrive _drive[static_cast<int32>(D6JointDriveType::MAX)];
    LimitLinear _limitLinear;
    LimitAngularRange _limitTwist;
    LimitConeRange _limitSwing;

D6 Joint D6铰链的构造函数

物理关节是最可自定义的关节类型。此关节类型可用于创建所有其他内置关节

类型,并设计您自己的自定义类型,但使用起来不那么直观。允许指定线性

约束(例如滑块)、扭曲约束(绕X旋转)和摆动约束(绕Y和Z旋转)。

它还允许您仅将限制约束到特定轴或完全锁定特定轴。

    API_FUNCTION() FORCE_INLINE D6JointMotion GetMotion(const D6JointAxis axis) const
    {
        return _motion[static_cast<int32>(axis)];
    }

获取围绕指定轴的运动类型每个轴可独立指定自由度被锁定(阻止沿该轴或围绕该轴的相对运动)、受相应限制或自由。

 API_FUNCTION() void SetMotion(const D6JointAxis axis, const D6JointMotion value);

设置围绕指定轴的运动类型。每个轴可独立指定自由度被锁定(阻止沿该轴或围绕该轴的相对运动)、受相应限制或自由。

    API_FUNCTION() FORCE_INLINE D6JointDrive GetDrive(const D6JointDriveType index) const
    {
        return _drive[static_cast<int32>(index)];
    }

获取指定驱动器类型的驱动器参数。

    API_FUNCTION() void SetDrive(const D6JointDriveType index, const D6JointDrive& value);

设置指定驱动器类型的驱动器参数。

    API_PROPERTY(Attributes="EditorOrder(200), EditorDisplay(\"Joint\")")
    FORCE_INLINE LimitLinear GetLimitLinear() const
    {
        return _limitLinear;
    }

确定用于约束平移自由度的线性限制。

    /// <summary>
    /// Gets the twist angle of the joint.
    /// </summary>
    API_PROPERTY() float GetCurrentTwist() const;

    /// <summary>
    /// Gets the current swing angle of the joint from the Y axis.
    /// </summary>
    API_PROPERTY() float GetCurrentSwingYAngle() const;

    /// <summary>
    /// Gets the current swing angle of the joint from the Z axis.
    /// </summary>
    API_PROPERTY() float GetCurrentSwingZAngle() const;

获取关节相对于X轴的当前摆动角度

获取关节相对于Z轴的当前摆动角度

获取关节相对于Y轴的当前摆动角度

(二):D6Joint.c 头文件:

D6Joint::D6Joint(const SpawnParams& params)
    : Joint(params)
{
    for (int32 i = 0; i < static_cast<int32>(D6JointAxis::MAX); i++)
        _motion[i] = D6JointMotion::Free;
    _limitLinear.Extent = 100.0f;
}

D6 joint 构造函数,初始化参数。赋值线性长度限制。

下面是D6 joint 几个set 和get方法由于很多,我挑选了几个有代表性的。

void D6Joint::SetMotion(const D6JointAxis axis, const D6JointMotion value)
{
    if (value == GetMotion(axis))
        return;

    _motion[static_cast<int32>(axis)] = value;

    if (_joint)
    {
        auto joint = static_cast<PxD6Joint*>(_joint);
        joint->setMotion(static_cast<PxD6Axis::Enum>(axis), static_cast<PxD6Motion::Enum>(value));
    }
}

添加铰链运动。 判断新值和旧值是否相等,相等返回,不相等则初始化。

void D6Joint::SetLimitLinear(const LimitLinear& value)
{
    if (value == _limitLinear)
        return;

    _limitLinear = value;

    if (_joint)
    {
        auto joint = static_cast<PxD6Joint*>(_joint);
        PxJointLinearLimit pxLimit(*Physics::GetTolerancesScale(), value.Extent, value.ContactDist);
        pxLimit.stiffness = value.Spring.Stiffness;
        pxLimit.damping = value.Spring.Damping;
        pxLimit.restitution = value.Restitution;
        joint->setLinearLimit(pxLimit);
    }
}

setLimitLinear: 方法 。判断新值和旧值是否相等,如果不相等, 初始化参数内容。


PxJoint* D6Joint::CreateJoint(JointData& data)
{
    const PxTransform trans0(C2P(data.Pos0), C2P(data.Rot0));
    const PxTransform trans1(C2P(data.Pos1), C2P(data.Rot1));
    auto joint = PxD6JointCreate(*data.Physics, data.Actor0, trans0, data.Actor1, trans1);

    for (int32 i = 0; i < static_cast<int32>(D6JointAxis::MAX); i++)
    {
        joint->setMotion(static_cast<PxD6Axis::Enum>(i), static_cast<PxD6Motion::Enum>(_motion[i]));
    }

    for (int32 i = 0; i < static_cast<int32>(D6JointAxis::MAX); i++)
    {
        const auto& value = _drive[i];
        PxD6JointDrive drive;
        if (value.Acceleration)
            drive.flags = PxD6JointDriveFlag::eACCELERATION;
        drive.stiffness = value.Stiffness;
        drive.damping = value.Damping;
        drive.forceLimit = value.ForceLimit;
        joint->setDrive(static_cast<PxD6Drive::Enum>(i), drive);
    }

    {
        const auto& value = _limitLinear;
        PxJointLinearLimit pxLimit(*Physics::GetTolerancesScale(), Math::Max(value.Extent, 0.01f), value.ContactDist);
        pxLimit.stiffness = value.Spring.Stiffness;
        pxLimit.damping = value.Spring.Damping;
        pxLimit.restitution = value.Restitution;
        joint->setDistanceLimit(pxLimit);
    }

    {
        const auto& value = _limitTwist;
        PxJointAngularLimitPair pxLimit(value.Lower * DegreesToRadians, value.Upper * DegreesToRadians, value.ContactDist);
        pxLimit.stiffness = value.Spring.Stiffness;
        pxLimit.damping = value.Spring.Damping;
        pxLimit.restitution = value.Restitution;
        joint->setTwistLimit(pxLimit);
    }

    {
        const auto& value = _limitSwing;
        PxJointLimitCone pxLimit(value.YLimitAngle * DegreesToRadians, value.ZLimitAngle * DegreesToRadians, value.ContactDist);
        pxLimit.stiffness = value.Spring.Stiffness;
        pxLimit.damping = value.Spring.Damping;
        pxLimit.restitution = value.Restitution;
        joint->setSwingLimit(pxLimit);
    }

创建D6 铰链:首先分配内存空间和相关参数。调用setMotion初始化铰链运动轨迹,和相应的驱动器。初始化线性限制,扭转限制和摆动限制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值