Created
March 10, 2025 21:32
-
-
Save JSandusky/8bdb2466a76819ca329ccd4627054621 to your computer and use it in GitHub Desktop.
Urho3D JiggleBone
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "../Precompiled.h" | |
#include "../Physics/JiggleBone.h" | |
#include "../Core/Context.h" | |
#include "../Graphics/DebugRenderer.h" | |
#include "../Scene/Node.h" | |
/* | |
Port of http://wiki.unity3d.com/index.php?title=JiggleBone | |
to Urho3D | |
*/ | |
namespace Urho3D | |
{ | |
extern const char* PHYSICS_CATEGORY; | |
JiggleBone::JiggleBone(Context* context) : | |
LogicComponent(context) | |
{ | |
SetUpdateEventMask(USE_POSTUPDATE); | |
// Bone settings | |
boneAxis_ = Vector3(0, 0, 1); | |
targetDistance_ = 2.0f; | |
// Dynamics settings | |
stiffness_ = 0.1f; | |
mass_ = 0.9f; | |
damping_ = 0.75f; | |
gravity_ = 0.75f; | |
// Squash and stretch variables | |
squashAndStretch_ = true; | |
sideStretch_ = 0.15f; | |
frontStretch_ = 0.2f; | |
} | |
JiggleBone::~JiggleBone() | |
{ | |
} | |
void JiggleBone::RegisterObject(Context* context) | |
{ | |
context->RegisterFactory<JiggleBone>(PHYSICS_CATEGORY); | |
URHO3D_COPY_BASE_ATTRIBUTES(LogicComponent); | |
URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Bone Axis", Vector3, boneAxis_, Vector3(0, 0, 1), AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Stiffness", float, stiffness_, 0.1f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Mass", float, mass_, 0.9f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Damping", float, damping_, 0.75f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Gravity", float, gravity_, 0.75f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Target Distance", float, targetDistance_, 2.0f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Allow Stretch", bool, squashAndStretch_, true, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Side Stretch", float, sideStretch_, 0.15f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Front Stretch", float, frontStretch_, 0.15f, AM_DEFAULT); | |
URHO3D_ATTRIBUTE("Target Pos", Vector3, targetPos_, Vector3::ZERO, AM_DEFAULT | AM_NOEDIT); | |
URHO3D_ATTRIBUTE("Dynamic Pos", Vector3, dynamicPos_, Vector3::ZERO, AM_DEFAULT | AM_NOEDIT); | |
} | |
void JiggleBone::DelayedStart() | |
{ | |
targetPos_ = GetNode()->GetWorldPosition() + GetNode()->GetWorldDirection() * targetDistance_; | |
dynamicPos_ = targetPos_; | |
} | |
void JiggleBone::PostUpdate(float timeStep) | |
{ | |
if (!IsEnabledEffective()) | |
return; | |
// Update forwardVector and upVector | |
Vector3 forwardVector = GetNode()->GetWorldDirection() * targetDistance_; | |
Vector3 upVector = GetNode()->GetWorldUp(); | |
// Calculate target position | |
Vector3 targetPos = GetNode()->GetWorldPosition() + forwardVector; | |
// Calculate force, acceleration, and velocity per X, Y and Z | |
force_.x_ = (targetPos.x_ - dynamicPos_.x_) * stiffness_; | |
acc_.x_ = force_.x_ / mass_; | |
vel_.x_ += acc_.x_ * (1 - damping_); | |
force_.y_ = (targetPos.y_ - dynamicPos_.y_) * stiffness_; | |
force_.y_ -= gravity_ / 10; // Add some gravity | |
acc_.y_ = force_.y_ / mass_; | |
vel_.y_ += acc_.y_ * (1 - damping_); | |
force_.z_ = (targetPos.z_ - dynamicPos_.z_) * stiffness_; | |
acc_.z_ = force_.z_ / mass_; | |
vel_.z_ += acc_.z_ * (1 - damping_); | |
// Update dynamic postion | |
dynamicPos_ += vel_ + force_; | |
// Set bone rotation to look at dynamicPos | |
GetNode()->LookAt(dynamicPos_, upVector); | |
// ================================================== | |
// Squash and Stretch section | |
// ================================================== | |
if (squashAndStretch_) { | |
// Create a vector from target position to dynamic position | |
// We will measure the magnitude of the vector to determine | |
// how much squash and stretch we will apply | |
Vector3 dynamicVec = dynamicPos_ - targetPos; | |
// Get the magnitude of the vector | |
float stretchMag = dynamicVec.Length(); | |
// Here we determine the amount of squash and stretch based on stretchMag | |
// and the direction the Bone Axis is pointed in. Ideally there should be | |
// a vector with two values at 0 and one at 1. Like Vector3(0,0,1) | |
// for the 0 values, we assume those are the sides, and 1 is the direction | |
// the bone is facing | |
float xStretch; | |
if (boneAxis_.x_ == 0) | |
xStretch = 1 + (-stretchMag * sideStretch_); | |
else | |
xStretch = 1 + (stretchMag * frontStretch_); | |
float yStretch; | |
if (boneAxis_.y_ == 0) | |
yStretch = 1 + (-stretchMag * sideStretch_); | |
else | |
yStretch = 1 + (stretchMag * frontStretch_); | |
float zStretch; | |
if (boneAxis_.z_ == 0) | |
zStretch = 1 + (-stretchMag * sideStretch_); | |
else | |
zStretch = 1 + (stretchMag * frontStretch_); | |
// Set the bone scale | |
GetNode()->SetScale(Vector3(xStretch, yStretch, zStretch)); | |
} | |
} | |
void JiggleBone::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) | |
{ | |
if (IsEnabledEffective()) | |
{ | |
// draw forward line | |
debug->AddLine(GetNode()->GetWorldPosition(), | |
GetNode()->GetWorldPosition() + GetNode()->GetWorldDirection() * targetDistance_, | |
Color(0, 0, 1), false); | |
// draw the up vector | |
debug->AddLine(GetNode()->GetWorldPosition(), | |
GetNode()->GetWorldPosition() + GetNode()->GetWorldUp() * (targetDistance_ * 0.5f), | |
Color(0, 1, 0), false); | |
// draw the target position | |
debug->AddLine(targetPos_, | |
Vector3::UP * (targetDistance_ * 0.2f), | |
Color(1, 1, 0), false); | |
// draw the dynamic position | |
debug->AddLine(dynamicPos_, | |
Vector3::UP * (targetDistance_ * 0.2f), | |
Color(1, 0, 0), false); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <Urho3D/Scene/LogicComponent.h> | |
#include <Urho3D/Math/Vector3.h> | |
namespace Urho3D | |
{ | |
class Context; | |
class URHO3D_API JiggleBone : public LogicComponent | |
{ | |
URHO3D_OBJECT(JiggleBone, LogicComponent) | |
public: | |
JiggleBone(Context*); | |
virtual ~JiggleBone(); | |
static void RegisterObject(Context*); | |
virtual void DelayedStart() override; | |
virtual void PostUpdate(float timeStep) override; | |
virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest) override; | |
float GetStiffness() const { return stiffness_; } | |
float GetMass() const { return mass_; } | |
float GetDamping() const { return damping_; } | |
float GetGravity() const { return gravity_; } | |
void SetStiffness(float aValue) { stiffness_ = aValue; } | |
void SetMass(float aValue) { mass_ = aValue; } | |
void SetDamping(float aValue) { damping_ = aValue; } | |
void SetGravity(float aValue) { gravity_ = aValue; } | |
bool GetSquashAndStretch() const { return squashAndStretch_; } | |
float GetSideStretch() const { return sideStretch_; } | |
float GetFrontStretch() const { return frontStretch_; } | |
void SetSquashAndStretch(bool aValue) { squashAndStretch_ = aValue; } | |
void SetSideStretch(float aValue) { sideStretch_ = aValue; } | |
void SetFrontStretch(float aValue) { frontStretch_ = aValue; } | |
private: | |
Vector3 targetPos_; | |
Vector3 dynamicPos_; | |
Vector3 boneAxis_; | |
float targetDistance_; | |
// dynamics settings | |
float stiffness_; | |
float mass_; | |
float damping_; | |
float gravity_; | |
// dynamics values | |
Vector3 force_; | |
Vector3 acc_; | |
Vector3 vel_; | |
// squashing | |
bool squashAndStretch_; | |
float sideStretch_; | |
float frontStretch_; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment