Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skeleton Constraints #1222

Open
wants to merge 70 commits into
base: main
Choose a base branch
from
Open

Skeleton Constraints #1222

wants to merge 70 commits into from

Conversation

Stermere
Copy link
Contributor

Adds constraints to the joints of the skeleton allowing for unrealistic joint angles to be clamped to more reasonable values and for extreme drift to be compensated for. Needs SlimeVR/SolarXR-Protocol#152 to get merged

@github-actions github-actions bot added Area: Skeletal Model Deals with the model of the skeleton and its pose Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: AutoBone The AutoBone feature Area: Translation Improvements or additions to translations Area: Server Related to the server labels Oct 30, 2024
@Stermere Stermere added Priority: Normal The default priority Type: Enhancement Adds or improves a feature Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: AutoBone The AutoBone feature Area: Translation Improvements or additions to translations and removed Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: AutoBone The AutoBone feature Area: Translation Improvements or additions to translations labels Oct 31, 2024
@ButterscotchV ButterscotchV added the Status: Blocked by other issue Progress cannot be made until linked issue is resolved label Nov 21, 2024
Copy link
Member

@ButterscotchV ButterscotchV left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking really good, overall good quality code. I think my suggestions could help to keep things maintainable for the future.

Comment on lines +57 to +58
val leftUpperShoulderBone = Bone(BoneType.LEFT_SHOULDER, Constraint(ConstraintType.COMPLETE))
val rightUpperShoulderBone = Bone(BoneType.RIGHT_SHOULDER, Constraint(ConstraintType.COMPLETE))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be upper shoulder BoneTypes?

Suggested change
val leftUpperShoulderBone = Bone(BoneType.LEFT_SHOULDER, Constraint(ConstraintType.COMPLETE))
val rightUpperShoulderBone = Bone(BoneType.RIGHT_SHOULDER, Constraint(ConstraintType.COMPLETE))
val leftUpperShoulderBone = Bone(BoneType.LEFT_UPPER_SHOULDER, Constraint(ConstraintType.COMPLETE))
val rightUpperShoulderBone = Bone(BoneType.RIGHT_UPPER_SHOULDER, Constraint(ConstraintType.COMPLETE))

@@ -62,6 +62,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
var mountRotFix = Quaternion.IDENTITY
private set
private var yawFix = Quaternion.IDENTITY
private var dynamicFix = Quaternion.IDENTITY
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this name could be more descriptive, like constraintFix? The current name is vague and could refer to a variety of features.

Comment on lines +405 to +410
tracker?.filteringHandler?.getFilteringImpact()
?: 1f
) < 0.01f && (
parentTracker?.filteringHandler?.getFilteringImpact()
?: 1f
) < 0.01f
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels a bit restrictive? I'm not sure what values we can regularly expect to see for filtering impact. I would like to have some feedback about what values should be expected here if possible.

Comment on lines +408 to +409
parentTracker?.filteringHandler?.getFilteringImpact()
?: 1f
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parent tracker may be null in cases like having a hip tracker with no waist tracker, this condition would prevent any correction in that case despite being the most common set-up. imo the parent tracker should be considered 0f (or -1f to be safe?) if not present.

Suggested change
parentTracker?.filteringHandler?.getFilteringImpact()
?: 1f
parentTracker?.filteringHandler?.getFilteringImpact()
?: 0f

Comment on lines +394 to +395
bone.setRotationRaw(newRot)
bone.updateThisNode()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to apply each transform here in this way, this needs to be run top-down through the hierarchy, otherwise the child bones to the current bone will not inherit the position computed by the current bone.

Perhaps this method of constraints should be reconsidered to be applied within the bones (or nodes?) themselves rather than in the skeleton. Correction could then be handled as an output of the bone, as it shouldn't matter when we apply the correction, as whenever we apply it, it should return to a value of 0 if done correctly.

Comment on lines +125 to +128
val parent = thisBone.parent!!
val localRotationOffset = parent.rotationOffset.inv() * thisBone.rotationOffset
val rotationLocal =
(parent.getGlobalRotation() * localRotationOffset).inv() * rotation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code doesn't make sense being here and it is duplicated between constraint functions, perhaps this would do better in the Bone class. I could see this being used in getLocalRotation() if the TransformNode is TransformNode.localRotation == false? I would like an opinion on this.

}

private fun constrain(rotation: Quaternion, angle: Float): Quaternion {
val magnitude = sin(angle * 0.5f)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like a comment explaining this if possible, I do not understand why sine is used here or why we multiply by 0.5f. What is the magnitude of?


// Constraint function for CompleteConstraint
private val completeConstraint: ConstraintFunction = { _: Quaternion, thisBone: Bone, _: Float, _: Float, _: Float ->
thisBone.getGlobalRotation()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not return the initial rotation provided? I think using the bone is beyond the necessary scope.

* Apply rotational constraints and if applicable force the rotation
* to be unchanged unless it violates the constraints
*/
fun applyConstraint(rotation: Quaternion, thisBone: Bone): Quaternion = constraintFunction(rotation, thisBone, swingRad, twistRad, allowedDeviationRad).unit()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could remove Bone from the scope of these constraints entirely and replace rotation with localRotation: Quaternion as the current bone's local rotation and thisBone could be replaced with parentRotation: Quaternion as the parent bone's global rotation? I don't think any of the constraints use anything else besides COMPLETE, but that could be handled in another way (or maybe we just take current global rotation instead? it could also be handled earlier in the helper functions, see below).

We could instead use helper functions to accept a global current rotation and a Bone, that way we have minimal input for constraints. This would be beneficial for unit testing and reduce complexity and duplication.

Comment on lines +64 to +67
fun updateThisNode() {
headNode.updateThisNode()
tailNode.updateThisNode()
}
Copy link
Member

@ButterscotchV ButterscotchV Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unsafe in regards to the bone hierarchy. Please see my earlier comment in HumanSkeleton regarding a refactor of how constraints are applied (#1222 (comment)).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Application Protocol Related to communication with apps like the GUI, overlay, games Area: AutoBone The AutoBone feature Area: Server Related to the server Area: Skeletal Model Deals with the model of the skeleton and its pose Area: Translation Improvements or additions to translations Priority: Normal The default priority Status: Blocked by other issue Progress cannot be made until linked issue is resolved Type: Enhancement Adds or improves a feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants