added support for ragdoll scaling

This commit is contained in:
Turánszki János
2023-10-31 18:17:43 +01:00
parent adab77de55
commit c1d5ba7b32
5 changed files with 48 additions and 16 deletions
+9 -4
View File
@@ -56,7 +56,7 @@ void HumanoidWindow::Create(EditorComponent* _editor)
lookatMouseCheckBox.SetCheck(true);
ragdollCheckBox.Create("Ragdoll: ");
ragdollCheckBox.SetTooltip("Activate dynamic ragdoll physics. Note that kinematic ragdoll physics is always active (ragdoll is animation-driven/kinematic by default).");
ragdollCheckBox.SetTooltip("Activate dynamic ragdoll physics.\nNote that kinematic ragdoll physics is always active (ragdoll is animation-driven/kinematic by default).\nNote that scaling humanoid will disable ragdoll physics and you need to re-enable if you want to.");
ragdollCheckBox.SetSize(XMFLOAT2(hei, hei));
ragdollCheckBox.OnClick([=](wi::gui::EventArgs args) {
wi::scene::Scene& scene = editor->GetCurrentScene();
@@ -214,13 +214,18 @@ void HumanoidWindow::Create(EditorComponent* _editor)
void HumanoidWindow::SetEntity(Entity entity)
{
if (this->entity == entity)
return;
Scene& scene = editor->GetCurrentScene();
const HumanoidComponent* humanoid = scene.humanoids.GetComponent(entity);
if (humanoid != nullptr)
{
ragdollCheckBox.SetCheck(humanoid->IsRagdollPhysicsEnabled()); // this is always force updated
}
if (this->entity == entity)
return;
if (humanoid != nullptr || IsCollapsed())
{
this->entity = entity;
+1
View File
@@ -34,6 +34,7 @@ namespace wi::lua
{
bool result = wi::audio::CreateSound(wi::lua::SGetString(L, 1), &sound->sound);
wi::lua::SSetBool(L, result);
return 1;
}
else
{
+4
View File
@@ -32,6 +32,10 @@ namespace wi::math
static constexpr XMFLOAT4X4 IDENTITY_MATRIX = XMFLOAT4X4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
static constexpr float PI = XM_PI;
inline bool float_equal(float f1, float f2) {
return (std::abs(f1 - f2) <= std::numeric_limits<float>::epsilon() * std::max(std::abs(f1), std::abs(f2)));
}
constexpr float saturate(float x) { return std::min(std::max(x, 0.0f), 1.0f); }
inline float Length(const XMFLOAT2& v)
+33 -11
View File
@@ -556,8 +556,9 @@ namespace wi::physics
btTypedConstraint* m_joints[JOINT_COUNT];
bool state_active = false;
Entity saved_parents[BODYPART_COUNT] = {};
float scale = 1;
Ragdoll(Scene& scene, HumanoidComponent& humanoid, Entity humanoidEntity)
Ragdoll(Scene& scene, HumanoidComponent& humanoid, Entity humanoidEntity, float scale)
{
physics_scene = scene.physics_scene;
btSoftRigidDynamicsWorld& dynamicsWorld = ((PhysicsScene*)physics_scene.get())->dynamicsWorld;
@@ -584,6 +585,10 @@ namespace wi::physics
facing = -1;
}
// Whole ragdoll will take a uniform scaling:
const XMMATRIX scaleMatrix = XMMatrixScaling(scale, scale, scale);
this->scale = scale;
// Calculate the bone lengths and radiuses in armature local space and create rigid bodies for bones:
for (int c = 0; c < BODYPART_COUNT; ++c)
{
@@ -660,8 +665,9 @@ namespace wi::physics
// Calculations here will be done in armature local space.
// Unfortunately since humanoid can be separate from armature, we use a "find" utility to find bone rest matrix in armature
XMMATRIX restA = scene.FindBoneRestPose(entityA);
XMMATRIX restB = scene.FindBoneRestPose(entityB);
// Note that current scaling of character is applied here separately from rest pose
XMMATRIX restA = scene.FindBoneRestPose(entityA) * scaleMatrix;
XMMATRIX restB = scene.FindBoneRestPose(entityB) * scaleMatrix;
XMVECTOR rootA = restA.r[3];
XMVECTOR rootB = restB.r[3];
@@ -670,15 +676,15 @@ namespace wi::physics
RigidBody& physicsobject = *rigidbodies[c];
physicsobject.entity = entityA;
float mass = 1;
float capsule_height = 1;
float capsule_radius = 1;
float mass = scale;
float capsule_height = scale;
float capsule_radius = scale;
if (c == BODYPART_HEAD)
{
// Head doesn't necessarily have a child, so make up something reasonable:
capsule_height = 0.05f;
capsule_radius = 0.1f;
capsule_height = 0.05f * scale;
capsule_radius = 0.1f * scale;
}
else
{
@@ -690,10 +696,10 @@ namespace wi::physics
switch (c)
{
case BODYPART_PELVIS:
capsule_radius = 0.1f;
capsule_radius = 0.1f * scale;
break;
case BODYPART_SPINE:
capsule_radius = 0.1f;
capsule_radius = 0.1f * scale;
capsule_height -= capsule_radius * 2;
break;
case BODYPART_LEFT_LOWER_ARM:
@@ -1164,13 +1170,29 @@ namespace wi::physics
btVector3 wind = btVector3(scene.weather.windDirection.x, scene.weather.windDirection.y, scene.weather.windDirection.z);
// Ragdoll management:
for (size_t i = 0; i < scene.humanoids.GetCount(); ++i)
{
HumanoidComponent& humanoid = scene.humanoids[i];
Entity humanoidEntity = scene.humanoids.GetEntity(i);
float scale = 1;
if (scene.transforms.Contains(humanoidEntity))
{
scale = scene.transforms.GetComponent(humanoidEntity)->GetScale().x;
}
if (humanoid.ragdoll != nullptr)
{
Ragdoll& ragdoll = *(Ragdoll*)humanoid.ragdoll.get();
if (!wi::math::float_equal(ragdoll.scale, scale))
{
humanoid.SetRagdollPhysicsEnabled(false); // while scaling ragdoll, it will be kinematic
ragdoll.Deactivate(scene); // recreate attached skeleton hierarchy structure
humanoid.ragdoll = {}; // delete ragdoll if scale changed, it will be recreated
}
}
if (humanoid.ragdoll == nullptr)
{
humanoid.ragdoll = std::make_shared<Ragdoll>(scene, humanoid, humanoidEntity);
humanoid.ragdoll = std::make_shared<Ragdoll>(scene, humanoid, humanoidEntity, scale);
}
Ragdoll& ragdoll = *(Ragdoll*)humanoid.ragdoll.get();
if (humanoid.IsRagdollPhysicsEnabled())
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 333;
const int revision = 334;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);