Преглед изворни кода

Adding IKConstraint support, but it is not not yet usable

TheComet пре 8 година
родитељ
комит
f73b1d16ab

+ 3 - 0
Source/Urho3D/IK/IK.h

@@ -27,6 +27,9 @@
  *  - Optimise.
  *  - Profile.
  *  - Documentation.
+ *  - Move log callback into context init function.
+ *  - Bug when enabling continuous mode and IKSolver is placed somewhere
+ *    on part of the model's bones.
  *
  * FUTURE
  *  - Support for "stretchiness" with min/max lengths.

+ 72 - 3
Source/Urho3D/IK/IKConstraint.cpp

@@ -20,11 +20,12 @@
 // THE SOFTWARE.
 //
 
-#include "IK.h"
-#include "IKConstraint.h"
+#include "../IK/IK.h"
+#include "../IK/IKConstraint.h"
 #include "../Core/Context.h"
 #include "../Scene/Node.h"
 #include "../Scene/SceneEvents.h"
+#include <ik/node.h>
 
 namespace Urho3D
 {
@@ -33,7 +34,9 @@ extern const char* IK_CATEGORY;
 
 // ----------------------------------------------------------------------------
 IKConstraint::IKConstraint(Context* context) :
-    Component(context)
+    Component(context),
+    stiffness_(0.0f),
+    stretchiness_(0.0f)
 {
 }
 
@@ -46,6 +49,72 @@ IKConstraint::~IKConstraint()
 void IKConstraint::RegisterObject(Context* context)
 {
     context->RegisterFactory<IKConstraint>(IK_CATEGORY);
+
+    URHO3D_ACCESSOR_ATTRIBUTE("Stiffness", GetStiffness, SetStiffness, float, 0.0f, AM_DEFAULT);
+    URHO3D_ACCESSOR_ATTRIBUTE("Stretchiness", GetStretchiness, SetStretchiness, float, 0.0f, AM_DEFAULT);
+    URHO3D_ACCESSOR_ATTRIBUTE("Length Constraints", GetLengthConstraints, SetLengthConstraints, Vector2, Vector2::ZERO, AM_DEFAULT);
+}
+
+// ----------------------------------------------------------------------------
+float IKConstraint::GetStiffness() const
+{
+    return stiffness_;
+}
+
+// ----------------------------------------------------------------------------
+void IKConstraint::SetStiffness(float stiffness)
+{
+    stiffness_ = Clamp(stiffness, 0.0f, 1.0f);
+    if (ikNode_ != NULL)
+        /* TODO ikNode_->stiffness = stiffness_; */
+        ;
+}
+
+// ----------------------------------------------------------------------------
+float IKConstraint::GetStretchiness() const
+{
+    return stretchiness_;
+}
+
+// ----------------------------------------------------------------------------
+void IKConstraint::SetStretchiness(float stretchiness)
+{
+    stretchiness_ = Clamp(stretchiness, 0.0f, 1.0f);
+    if (ikNode_)
+        /* TODO ikNode_->stretchiness = stretchiness_;*/
+        ;
+}
+
+// ----------------------------------------------------------------------------
+const Vector2& IKConstraint::GetLengthConstraints() const
+{
+    return lengthConstraints_;
+}
+
+// ----------------------------------------------------------------------------
+void IKConstraint::SetLengthConstraints(const Vector2& lengthConstraints)
+{
+    lengthConstraints_ = lengthConstraints;
+    if (ikNode_ != NULL)
+    {
+        /* TODO
+        ikNode_->min_length = lengthConstraints_.x_;
+        ikNode_->max_length = lengthConstraints_.y_;*/
+    }
+}
+
+// ----------------------------------------------------------------------------
+void IKConstraint::SetIKNode(ik_node_t* node)
+{
+    ikNode_ = node;
+    if (node)
+    {
+        /* TODO
+        node->stiffness = stiffness_;
+        node->stretchiness = stretchiness_;
+        node->min_length = lengthConstraints_.x_;
+        node->max_length = lengthConstraints_.y_;*/
+    }
 }
 
 } // namespace Urho3D

+ 21 - 0
Source/Urho3D/IK/IKConstraint.h

@@ -24,6 +24,8 @@
 
 #include "../Scene/Component.h"
 
+struct ik_node_t;
+
 namespace Urho3D
 {
 
@@ -51,7 +53,26 @@ public:
      */
     static void RegisterObject(Context* context);
 
+    float GetStiffness() const;
+    void SetStiffness(float stiffness);
+
+    float GetStretchiness() const;
+    void SetStretchiness(float stretchiness);
+
+    const Vector2& GetLengthConstraints() const;
+    void SetLengthConstraints(const Vector2& lengthConstraints);
+
 private:
+    friend class IKSolver;
+
+    /// Intended to be used only by IKSolver
+    void SetIKNode(ik_node_t* effector);
+
+    ik_node_t* ikNode_;
+
+    float stiffness_;
+    float stretchiness_;
+    Vector2 lengthConstraints_;
 };
 
 } // namespace Urho3D

+ 2 - 2
Source/Urho3D/IK/IKEffector.cpp

@@ -318,7 +318,7 @@ void IKEffector::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 }
 
 // ----------------------------------------------------------------------------
-void IKEffector::SetEffector(ik_effector_t* effector)
+void IKEffector::SetIKEffector(ik_effector_t* effector)
 {
     ikEffector_ = effector;
     if (effector)
@@ -334,7 +334,7 @@ void IKEffector::SetEffector(ik_effector_t* effector)
 }
 
 // ----------------------------------------------------------------------------
-void IKEffector::SetSolver(IKSolver* solver)
+void IKEffector::SetIKSolver(IKSolver* solver)
 {
     solver_ = solver;
 }

+ 7 - 3
Source/Urho3D/IK/IKEffector.h

@@ -112,10 +112,14 @@ public:
     void DrawDebugGeometry(bool depthTest);
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
 
-    void SetSolver(IKSolver* solver);
-    void SetEffector(ik_effector_t* effector);
-
 private:
+    friend class IKSolver;
+
+    /// Intended to be used only by IKSolver
+    void SetIKSolver(IKSolver* solver);
+    /// Intended to be used only by IKSolver
+    void SetIKEffector(ik_effector_t* effector);
+
     WeakPtr<Node> targetNode_;
     WeakPtr<IKSolver> solver_;
     ik_effector_t* ikEffector_;

+ 71 - 40
Source/Urho3D/IK/IKSolver.cpp

@@ -21,7 +21,9 @@
 //
 
 #include "../IK/IKSolver.h"
+#include "../IK/IKConstraint.h"
 #include "../IK/IKEvents.h"
+#include "../IK/IKEffector.h"
 #include "../IK/IKConverters.h"
 
 #include "../Core/Context.h"
@@ -48,14 +50,6 @@ static void HandleIKLog(const char* msg)
 {
     URHO3D_LOGINFOF("[IK] %s", msg);
 }
-static ik_node_t* CreateIKNode(const Node* node)
-{
-    ik_node_t* ikNode = ik_node_create(node->GetID());
-    ikNode->position = Vec3Urho2IK(node->GetWorldPosition());
-    ikNode->rotation = QuatUrho2IK(node->GetWorldRotation());
-    ikNode->user_data = (void*)node;
-    return ikNode;
-}
 static bool ChildrenHaveEffector(const Node* node)
 {
     if (node->HasComponent<IKEffector>())
@@ -81,10 +75,10 @@ IKSolver::IKSolver(Context* context) :
 
     SetAlgorithm(FABRIK);
 
-    SubscribeToEvent(GetScene(), E_COMPONENTADDED,              URHO3D_HANDLER(IKSolver, HandleComponentAdded));
-    SubscribeToEvent(GetScene(), E_COMPONENTREMOVED,            URHO3D_HANDLER(IKSolver, HandleComponentRemoved));
-    SubscribeToEvent(GetScene(), E_NODEADDED,                   URHO3D_HANDLER(IKSolver, HandleNodeAdded));
-    SubscribeToEvent(GetScene(), E_NODEREMOVED,                 URHO3D_HANDLER(IKSolver, HandleNodeRemoved));
+    SubscribeToEvent(E_COMPONENTADDED,   URHO3D_HANDLER(IKSolver, HandleComponentAdded));
+    SubscribeToEvent(E_COMPONENTREMOVED, URHO3D_HANDLER(IKSolver, HandleComponentRemoved));
+    SubscribeToEvent(E_NODEADDED,        URHO3D_HANDLER(IKSolver, HandleNodeAdded));
+    SubscribeToEvent(E_NODEREMOVED,      URHO3D_HANDLER(IKSolver, HandleNodeRemoved));
 }
 
 // ----------------------------------------------------------------------------
@@ -93,7 +87,7 @@ IKSolver::~IKSolver()
     // Destroying the solver tree will destroy the effector objects, so remove
     // any references any of the IKEffector objects could be holding
     for(PODVector<IKEffector*>::ConstIterator it = effectorList_.Begin(); it != effectorList_.End(); ++it)
-        (*it)->SetEffector(NULL);
+        (*it)->SetIKEffector(NULL);
 
     ik_log_unregister_listener(HandleIKLog);
     ik_solver_destroy(solver_);
@@ -329,14 +323,40 @@ void IKSolver::OnSceneSet(Scene* scene)
 // ----------------------------------------------------------------------------
 void IKSolver::OnNodeSet(Node* node)
 {
-    if (node == NULL)
-        ik_solver_destroy_tree(solver_);
-    else
-        RebuildTree();
+    ResetToInitialPose();
+    DestroyTree();
+
+    if (node != NULL)
+        BuildTree();
 }
 
 // ----------------------------------------------------------------------------
-void IKSolver::RebuildTree()
+ik_node_t* IKSolver::CreateIKNode(const Node* node)
+{
+    ik_node_t* ikNode = ik_node_create(node->GetID());
+
+    // Set initial position/rotation and pass in Node* as user data for later
+    ikNode->position = Vec3Urho2IK(node->GetWorldPosition());
+    ikNode->rotation = QuatUrho2IK(node->GetWorldRotation());
+    ikNode->user_data = (void*)node;
+
+    // If the node has a constraint, it needs access to the ikNode
+    IKConstraint* constraint = node->GetComponent<IKConstraint>();
+    if (constraint != NULL)
+        constraint->SetIKNode(ikNode);
+
+    return ikNode;
+}
+
+// ----------------------------------------------------------------------------
+void IKSolver::DestroyTree()
+{
+    ik_solver_destroy_tree(solver_);
+    effectorList_.Clear();
+}
+
+// ----------------------------------------------------------------------------
+void IKSolver::BuildTree()
 {
     assert(node_ != NULL);
 
@@ -387,8 +407,8 @@ void IKSolver::BuildTreeToEffector(const Node* node)
     // it.
     ik_effector_t* ikEffector = ik_effector_create();
     ik_node_attach_effector(ikNode, ikEffector); // ownership of effector
-    effector->SetEffector(ikEffector);           // "weak" reference to effector
-    effector->SetSolver(this);
+    effector->SetIKEffector(ikEffector);           // "weak" reference to effector
+    effector->SetIKSolver(this);
     effectorList_.Push(effector);
 
     MarkSolverTreeDirty();
@@ -416,20 +436,27 @@ void IKSolver::HandleComponentRemoved(StringHash eventType, VariantMap& eventDat
     if(solver_->tree == NULL)
         return;
 
-    // Check if the component that was removed was an IK effector. If not,
-    // then it does not concern us.
-    IKEffector* effector = static_cast<IKEffector*>(eventData[P_COMPONENT].GetPtr());
-    if(effector->GetType() != IKEffector::GetTypeStatic())
-        return;
-
-    Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr());
-    ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID());
-    ik_node_destroy_effector(ikNode);
-    effector->SetEffector(NULL);
-    effectorList_.RemoveSwap(effector);
+    // If an effector was removed, the tree will have to be rebuilt.
+    Component* component = static_cast<Component*>(eventData[P_COMPONENT].GetPtr());
+    if (component->GetType() == IKEffector::GetTypeStatic())
+    {
+        IKEffector* effector = static_cast<IKEffector*>(component);
+        Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr());
+        ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID());
+        ik_node_destroy_effector(ikNode);
+        effector->SetIKEffector(NULL);
+        effectorList_.RemoveSwap(effector);
+
+        ResetToInitialPose();
+        MarkSolverTreeDirty();
+    }
 
-    ResetToInitialPose();
-    MarkSolverTreeDirty();
+    // Remove the ikNode* reference the IKConstraint was holding
+    if (component->GetType() == IKConstraint::GetTypeStatic())
+    {
+        IKConstraint* constraint = static_cast<IKConstraint*>(component);
+        constraint->SetIKNode(NULL);  // NOTE: Should restore default settings to the node
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -438,14 +465,14 @@ void IKSolver::HandleNodeAdded(StringHash eventType, VariantMap& eventData)
     using namespace NodeAdded;
     (void)eventType;
 
-    if(solver_->tree == NULL)
+    if (solver_->tree == NULL)
         return;
 
     Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr());
 
-    PODVector<Node*> effectorNodes;
-    node->GetChildrenWithComponent<IKEffector>(effectorNodes, true);
-    for(PODVector<Node*>::ConstIterator it = effectorNodes.Begin(); it != effectorNodes.End(); ++it)
+    PODVector<Node*> nodes;
+    node->GetChildrenWithComponent<IKEffector>(nodes, true);
+    for (PODVector<Node*>::ConstIterator it = nodes.Begin(); it != nodes.End(); ++it)
     {
         BuildTreeToEffector(*it);
         effectorList_.Push((*it)->GetComponent<IKEffector>());
@@ -463,13 +490,17 @@ void IKSolver::HandleNodeRemoved(StringHash eventType, VariantMap& eventData)
 
     Node* node = static_cast<Node*>(eventData[P_NODE].GetPtr());
 
-    PODVector<Node*> effectorNodes;
-    node->GetChildrenWithComponent<IKEffector>(effectorNodes, true);
-    for(PODVector<Node*>::ConstIterator it = effectorNodes.Begin(); it != effectorNodes.End(); ++it)
+    // Remove cached IKEffectors from our list
+    PODVector<Node*> nodes;
+    node->GetChildrenWithComponent<IKEffector>(nodes, true);
+    for(PODVector<Node*>::ConstIterator it = nodes.Begin(); it != nodes.End(); ++it)
     {
         effectorList_.Remove((*it)->GetComponent<IKEffector>());
     }
 
+    // Special case, if the node being destroyed is the root node, destroy the
+    // solver's tree instead of destroying the single node. Calling
+    // ik_node_destroy() on the solver's root node will cause segfaults.
     ik_node_t* ikNode = ik_node_find_child(solver_->tree, node->GetID());
     if(ikNode != NULL)
     {

+ 7 - 3
Source/Urho3D/IK/IKSolver.h

@@ -22,7 +22,6 @@
 
 #pragma once
 
-#include "../IK/IKEffector.h"
 #include "../Scene/Component.h"
 
 struct ik_solver_t;
@@ -31,6 +30,8 @@ struct ik_node_t;
 namespace Urho3D
 {
 class AnimationState;
+class IKConstraint;
+class IKEffector;
 
 /*!
  * @brief Marks the root or "beginning" of an IK chain or multiple IK chains.
@@ -138,8 +139,11 @@ public:
 private:
     virtual void OnSceneSet(Scene* scene);
     virtual void OnNodeSet(Node* scene);
-    /// Causes the entire tree to be rebuilt
-    void RebuildTree();
+
+    ik_node_t* CreateIKNode(const Node* node);
+
+    void DestroyTree();
+    void BuildTree();
     void BuildTreeToEffector(const Node* node);
 
     void HandleComponentAdded(StringHash eventType, VariantMap& eventData);