Browse Source

Adding detailed docstrings in IK headers

TheComet 8 years ago
parent
commit
e6208ab85f
3 changed files with 140 additions and 5 deletions
  1. 2 1
      Source/Urho3D/IK/IK.h
  2. 46 2
      Source/Urho3D/IK/IKEffector.h
  3. 92 2
      Source/Urho3D/IK/IKSolver.h

+ 2 - 1
Source/Urho3D/IK/IK.h

@@ -23,7 +23,8 @@
 /*
 /*
  * TODO
  * TODO
  *  - Add support for manually updating initial pose.
  *  - Add support for manually updating initial pose.
- *  - Script bindings.
+ *  - Lua script bindings crash.
+ *  - Implement inherit parent rotations in IKEffector.
  *  - Optimise.
  *  - Optimise.
  *  - Profile.
  *  - Profile.
  *  - Documentation.
  *  - Documentation.

+ 46 - 2
Source/Urho3D/IK/IKEffector.h

@@ -80,35 +80,77 @@ public:
      */
      */
     void SetTargetName(const String& nodeName);
     void SetTargetName(const String& nodeName);
 
 
+    /// Returns the current target position in world space.
     const Vector3& GetTargetPosition() const;
     const Vector3& GetTargetPosition() const;
+    /// Sets the current target position. If the effector has a target node then this will have no effect.
     void SetTargetPosition(const Vector3& targetPosition);
     void SetTargetPosition(const Vector3& targetPosition);
 
 
+    /// Gets the current target rotation in world space.
     const Quaternion& GetTargetRotation() const;
     const Quaternion& GetTargetRotation() const;
+    /// Sets the current target rotation. If the effector has a target node then this will have no effect.
     void SetTargetRotation(const Quaternion& targetRotation);
     void SetTargetRotation(const Quaternion& targetRotation);
 
 
+    /// Required for the editor, get the target rotation in euler angles
     Vector3 GetTargetRotationEuler() const;
     Vector3 GetTargetRotationEuler() const;
+    /// Required for the editor, sets the target rotation in euler angles
     void SetTargetRotationEuler(const Vector3& targetRotation);
     void SetTargetRotationEuler(const Vector3& targetRotation);
 
 
+    /// Returns the number of segments that will be affected by this effector. 0 Means all nodes between this effector and the next IKSolver.
     unsigned GetChainLength() const;
     unsigned GetChainLength() const;
+    /// Sets the number of segments that will be affected. 0 Means all nodes between this effector and the next IKSolver.
     void SetChainLength(unsigned chainLength);
     void SetChainLength(unsigned chainLength);
 
 
+    /// How strongly the effector affects the solution.
     float GetWeight() const;
     float GetWeight() const;
+    /*!
+     * @brief Sets how much influence the effector has on the solution. You can
+     * use this value to smoothly transition between a solved pose and an
+     * initial pose  For instance, lifting a foot off of the ground or letting
+     * go of an object.
+     */
     void SetWeight(float weight);
     void SetWeight(float weight);
 
 
+    /// How strongly the target node's rotation influences the solution
     float GetRotationWeight() const;
     float GetRotationWeight() const;
+    /*!
+     * @brief Sets how much influence the target rotation should have on the
+     * solution. A value of 1 means to match the target rotation exactly, if
+     * possible. A value of 0 means to not match it at all.
+     * @note The solver must have target rotation enabled for this to have
+     * any effect. See IKSolver::EnableTargetRotation().
+     */
     void SetRotationWeight(float weight);
     void SetRotationWeight(float weight);
 
 
+    /// Retrieves the rotation decay factor. See SetRotationDecay() for info.
     float GetRotationDecay() const;
     float GetRotationDecay() const;
+
+    /*!
+     * @brief A factor with which to control the target rotation influence of
+     * the next segments down the chain. For example, if this is set to 0.5
+     * and the rotation weight is set to 1.0, then the first segment will
+     * match the target rotation exactly, the next segment will match it only
+     * 50%, the next segment 25%, the next 12.5%, etc. This parameter makes
+     * long chains look more natural when matching a target rotation.
+     */
     void SetRotationDecay(float decay);
     void SetRotationDecay(float decay);
 
 
+    /// Whether or not to nlerp instead of lerp when transitioning with the weight parameter
     bool WeightedNlerpEnabled() const;
     bool WeightedNlerpEnabled() const;
+
+    /*!
+     * @brief If you set the effector weight (see SetWeight()) to a value in
+     * between 0 and 1, the default behaviour is to linearly interpolate the
+     * effector's target position. If the solved tree and the initial tree
+     * are far apart, this can look very strange, especially if you are
+     * controlling limbs on a character that are designed to rotation. Enabling
+     * this causes a rotational based interpolation (nlerp) around the chain's
+     * base node and makes transitions look much more natural.
+     */
     void EnableWeightedNlerp(bool enable);
     void EnableWeightedNlerp(bool enable);
 
 
     bool InheritParentRotationEnabled() const;
     bool InheritParentRotationEnabled() const;
     void EnableInheritParentRotation(bool enable);
     void EnableInheritParentRotation(bool enable);
 
 
-    void UpdateTargetNodePosition();
-
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
 
 
@@ -119,6 +161,8 @@ private:
     void SetIKSolver(IKSolver* solver);
     void SetIKSolver(IKSolver* solver);
     /// Intended to be used only by IKSolver
     /// Intended to be used only by IKSolver
     void SetIKEffector(ik_effector_t* effector);
     void SetIKEffector(ik_effector_t* effector);
+    /// Intended to be used by IKSolver. Copies the positions/rotations of the target node into the effector
+    void UpdateTargetNodePosition();
 
 
     WeakPtr<Node> targetNode_;
     WeakPtr<Node> targetNode_;
     WeakPtr<IKSolver> solver_;
     WeakPtr<IKSolver> solver_;

+ 92 - 2
Source/Urho3D/IK/IKSolver.h

@@ -85,13 +85,13 @@ public:
      * FABRIK looks decent after only 10 iterations, whereas Jacobian based
      * FABRIK looks decent after only 10 iterations, whereas Jacobian based
      * methods often require more than a 100.
      * methods often require more than a 100.
      *
      *
-     * The default value is 50.
+     * The default value is 20.
      *
      *
      * @note Most algorithms have a convergence criteria at which the solver
      * @note Most algorithms have a convergence criteria at which the solver
      * will stop iterating, so most of the time the maximum number of
      * will stop iterating, so most of the time the maximum number of
      * iterations isn't even reached.
      * iterations isn't even reached.
      *
      *
-     * @param iterations Number of iterations. Must be greater than 0. Higher
+     * @param[in] iterations Number of iterations. Must be greater than 0. Higher
      * values yield more accurate results, but at the cost of performance.
      * values yield more accurate results, but at the cost of performance.
      */
      */
     void SetMaximumIterations(unsigned iterations);
     void SetMaximumIterations(unsigned iterations);
@@ -111,23 +111,107 @@ public:
      */
      */
     void SetTolerance(float tolerance);
     void SetTolerance(float tolerance);
 
 
+    /// Whether or not rotations should be calculated.
     bool BoneRotationsEnabled() const;
     bool BoneRotationsEnabled() const;
+
+    /*!
+     * @brief When enabled, final joint rotations are calculated as a post
+     * processing step. If you are using IK on a model with skinning, you will
+     * want to enable this or it will look wrong. If you disable this, then
+     * you will get a slight performance boost (less calculations are required)
+     * but only the node positions are updated. This can be useful for scene
+     * IK (perhaps a chain of platforms, where each platform should retain its
+     * initial world rotation?)
+     */
     void EnableBoneRotations(bool enable);
     void EnableBoneRotations(bool enable);
 
 
+    /// Whether or not target rotation is enabled
     bool TargetRotationEnabled() const;
     bool TargetRotationEnabled() const;
+
+    /*!
+     * @brief When enabled, the effector will try to match the target's
+     * rotation as well as the effectors position. When disabled, the target
+     * node will reach the effector with any rotation necessary.
+     *
+     * If the target position goes out of range of the effector then the
+     * rotation will no longer be matched. The chain will try to reach out to
+     * reach the target position, even if it means rotating towards it.
+     */
     void EnableTargetRotation(bool enable);
     void EnableTargetRotation(bool enable);
 
 
+    /// Whether or not continuous solving is enabled or not.
     bool ContinuousSolvingEnabled() const;
     bool ContinuousSolvingEnabled() const;
+
+    /*!
+     * @brief When enabled, the solver will refrain from applying the initial
+     * pose before solving. The result is that it will use the previously
+     * solved tree as a basis for the new calculation instead of using the
+     * initial tree. This can be useful if you want to simulate chains or
+     * something similar. When disabled, the solver will use the initial
+     * positions/rotations which where set when the solver was first created.
+     *
+     * If you call UpdateInitialPose() then the initial tree will be matched to
+     * the current nodes in the scene graph.
+     *
+     * If you call ResetToInitialPose() then you will do the opposite of
+     * UpdateInitialPose() -- the initial pose is applied back to the scene
+     * graph.
+     *
+     * If you enable pose updating with EnableUpdatePose(), then the initial
+     * tree will automatically be matched to the current nodes in the scene
+     * graph.
+     */
     void EnableContinuousSolving(bool enable);
     void EnableContinuousSolving(bool enable);
 
 
+    /// Whether or not the initial pose is updated for every solution
     bool UpdatePoseEnabled() const;
     bool UpdatePoseEnabled() const;
+
+    /*!
+     * @brief When enabled, the current Urho3D node positions and rotations in
+     * the scene graph will be copied into the solver's initial tree right
+     * before solving. This should generally be enabled for animated models
+     * so the solver refers to the current frame of animation rather than to
+     * the animation's initial pose.
+     *
+     * When disabled, the initial pose will remain unmodified. The initial pose
+     * is set when the solver is first created. You can manually update the
+     * initial pose at any time by calling UpdateInitialPose().
+     */
     void EnableUpdatePose(bool enable);
     void EnableUpdatePose(bool enable);
 
 
+    /// Whether or not the solver should be invoked automatically
     bool AutoSolveEnabled() const;
     bool AutoSolveEnabled() const;
+
+    /*!
+     * @brief Mostly exists because of the editor. When enabled, the solver
+     * will be invoked automatically for you. If you need to do additional
+     * calculations before being able to set the effector target data, you will
+     * want to disable this and call Solve() manually.
+     */
     void EnableAutoSolve(bool enable);
     void EnableAutoSolve(bool enable);
 
 
+    /*!
+     * @brief Invokes the solver. The solution is applied back to the scene
+     * graph automatically.
+     * @note You will want to register to E_SCENEDRAWABLEUPDATEFINISHED and
+     * call this method there. This is right after the animations have been
+     * applied.
+     */
     void Solve();
     void Solve();
+
+    /*!
+     * @brief Causes the initial tree to be applied back to Urho3D's scene
+     * graph. This is what gets called when continuous solving is disabled.
+     */
     void ResetToInitialPose();
     void ResetToInitialPose();
+
+    /*!
+     * @brief Causes the current scene graph data to be copied into the solvers
+     * initial pose. This should generally be called before solving if you
+     * are using IK on an animated model. If you don't update the initial pose,
+     * then the result will be a "continuous solution", where the solver will
+     * use the previously calculated tree as a basis for the new solution.
+     */
     void UpdateInitialPose();
     void UpdateInitialPose();
 
 
     /// Causes the solver tree to be rebuilt before solving the next time.
     /// Causes the solver tree to be rebuilt before solving the next time.
@@ -137,13 +221,19 @@ public:
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
     virtual void DrawDebugGeometry(DebugRenderer* debug, bool depthTest);
 
 
 private:
 private:
+    /// Subscribe to drawable update finished event here
     virtual void OnSceneSet(Scene* scene);
     virtual void OnSceneSet(Scene* scene);
+    /// Destroys and creates the tree
     virtual void OnNodeSet(Node* scene);
     virtual void OnNodeSet(Node* scene);
 
 
+    /// Creates the ik library node and sets the current rotation/position and user data correctly.
     ik_node_t* CreateIKNode(const Node* node);
     ik_node_t* CreateIKNode(const Node* node);
 
 
+    /// Destroys the solver's tree
     void DestroyTree();
     void DestroyTree();
+    /// Builds the solver's tree to match the scene graph's tree
     void BuildTree();
     void BuildTree();
+    /// Builds a chain of nodes up to the specified node and adds an effector. Thus, the specified node must have an IKEffector attached.
     void BuildTreeToEffector(const Node* node);
     void BuildTreeToEffector(const Node* node);
 
 
     void HandleComponentAdded(StringHash eventType, VariantMap& eventData);
     void HandleComponentAdded(StringHash eventType, VariantMap& eventData);