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初始化铰链运动轨迹,和相应的驱动器。初始化线性限制,扭转限制和摆动限制。