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

Merged
merged 81 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
6ac1947
commit starting code
Stermere Sep 19, 2023
1fa6210
more bug fixes
Stermere Sep 25, 2023
6c6d4b8
it works!
Stermere Sep 26, 2023
6226bf1
simplify forward pass
Stermere Sep 26, 2023
1af548c
remove pointless class
Stermere Oct 19, 2023
cf85157
add Constraint
Stermere Oct 19, 2023
79c70e3
Make Constraint abstract to allow multiple constraint types to be added
Stermere Dec 23, 2023
14f4e10
bug fixes and move classes to own file
Stermere Dec 23, 2023
472a99c
add constraints to each bone
Stermere Dec 23, 2023
39e2a8a
bug fixes + use quat lib projection
Stermere Dec 24, 2023
2387766
add apply Constraint Inverse
Stermere Dec 27, 2023
742f299
bug fixes + make vars private
Stermere Dec 27, 2023
a0ded31
fix centroid deadlocking
Stermere Dec 28, 2023
ed95110
modify applyConstraint + add CompleteConstraint
Stermere Dec 28, 2023
5360535
spotless
Stermere Dec 28, 2023
a2fa6a7
add allowModification to Constraint
Stermere Dec 31, 2023
10f47e2
add locking of rotation on bones where a rotation tracker is present
Stermere Dec 31, 2023
a0ac237
account for bone.rotationOffset + change input to constrainRotation
Stermere Jan 2, 2024
01c4a32
fix constrain function
Stermere Jan 5, 2024
65f61b5
formatting + add position offset at time of reset
Stermere Jan 5, 2024
cb267c1
update skeletal constraints
Stermere Jan 5, 2024
da097ac
spotless
Stermere Jan 6, 2024
83de9a3
add base constraint offset cause its actually needed
Stermere Jan 6, 2024
9a493ec
fix bug where a constrained sub-base being unable to solve would affe…
Stermere Jan 13, 2024
8e6b21c
fix bug where a chain would jitter if in reach of the target but unab…
Stermere Jan 14, 2024
c876c76
small things
Stermere Feb 19, 2024
2981731
Add IKConstraint
Stermere Feb 20, 2024
e7ca590
Reduce IKSolver control in the spine area
Stermere Feb 20, 2024
1918a1c
Allow deviation from rotational constraints if the chains cannot solve
Stermere Mar 18, 2024
7faec49
Update loosening to be more selective and fix chain builder bug
Stermere Mar 26, 2024
529ff8a
Fix bugs, remove unused code
Stermere Mar 29, 2024
51a2782
change imports
Stermere Mar 29, 2024
73878e3
make spotless happy
Stermere Mar 29, 2024
f3937cb
Fix bug causing NULL Quaternion
Stermere Mar 30, 2024
fde7408
pause ikSolver
Stermere Mar 30, 2024
3486250
small formatting things
Stermere Apr 4, 2024
314df29
change math
Stermere Apr 4, 2024
caf10e7
Add toggle for using position information
Stermere Apr 24, 2024
a674962
Fix lint
Stermere May 6, 2024
ce25844
Refactor and simplify constraints
Stermere Jun 18, 2024
0900d45
simplify loosening logic
Stermere Jun 18, 2024
0d0edef
Fix trackers being assigned a bone when they are unassigned
Stermere Jun 24, 2024
436e53b
save state before switching it CCDIK
Stermere Jul 7, 2024
818fb0f
switch from FABRIK to CCDIK
Stermere Jul 11, 2024
1f0d62a
reduce jitter further
Stermere Jul 12, 2024
9351dfb
Tuning and better chain control
Stermere Jul 13, 2024
f2b0175
fix bugs
Stermere Jul 14, 2024
dfc6837
Fix hinge constraint bugs and add annealing
Stermere Jul 25, 2024
55a5b34
Update server/core/src/main/java/dev/slimevr/tracking/processor/Const…
Stermere Jul 26, 2024
fca306d
Format fixes
Stermere Jul 29, 2024
e02b806
Enforce constraints bidirectionally
Stermere Aug 18, 2024
6ba3d4d
Add upper elbow
Stermere Aug 23, 2024
4af4a10
small fixes + optimization
Stermere Aug 31, 2024
4379dd7
Enforce constraints within the skeleton
Stermere Aug 31, 2024
73ff011
formmating
Stermere Aug 31, 2024
67f9946
Correct for constrain violation
Stermere Sep 9, 2024
79c9bfb
fix bugs, add loose hinge constraint
Stermere Sep 16, 2024
19a9fd8
Formatting
Stermere Sep 16, 2024
0a8de91
Increase hinge constraint loose-ness
Stermere Sep 17, 2024
be9a1be
fix decomposition
Stermere Sep 23, 2024
cab3a89
Add toggles for enabling skeleton constraints
Stermere Sep 23, 2024
d639dc2
lint
Stermere Sep 23, 2024
f85112a
fix IK breaking at 180 degree rotations relative to the parent
Stermere Sep 27, 2024
7f6fdca
Adjust hand constraints and fix constraint corrections interaction wi…
Stermere Oct 15, 2024
4438c0a
Add target and end effector offset to improve solver stability
Stermere Oct 15, 2024
b5b230b
spotless
Stermere Oct 15, 2024
e860e50
Always use constraints in iksolver
Stermere Oct 30, 2024
cde91d7
Rip out IKsolver besides skeleton toggles
Stermere Oct 30, 2024
c475446
Address feedback
Stermere Nov 29, 2024
52d64ac
Remove and adjust magic numbers
Stermere Nov 30, 2024
df842a1
Resolve rebase conflict
Stermere Nov 30, 2024
aa0e39b
Resolve rebase conflict
Stermere Nov 30, 2024
39980fd
fix comment
Stermere Dec 4, 2024
561aa38
Update server/core/src/main/java/dev/slimevr/tracking/processor/Const…
Stermere Dec 4, 2024
122423a
Update solarxr-protocol
Stermere Dec 5, 2024
aafc902
Merge branch 'main' into Constraints-only
Stermere Dec 8, 2024
20d9fd0
Disable corrections on upper chest tracker
Stermere Dec 8, 2024
65711d7
Merge branch 'main' into Constraints-only
Stermere Dec 20, 2024
cb1212a
Merge branch 'main' into Constraints-only
Stermere Dec 21, 2024
e877a72
Merge branch 'main' into Constraints-only
Stermere Jan 11, 2025
60b9c5b
Merge branch 'main' into Constraints-only
Stermere Jan 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,11 @@ settings-general-fk_settings-leg_tweak-foot_plant-description = Foot-plant rotat
settings-general-fk_settings-leg_fk = Leg tracking
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = Enable feet Mounting Reset by tiptoeing.
settings-general-fk_settings-leg_fk-reset_mounting_feet = Feet Mounting Reset
settings-general-fk_settings-enforce_joint_constraints = Skeletal Limits
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = Enforce constraints
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = Prevents joints from rotating past their limit
settings-general-fk_settings-enforce_joint_constraints-correct_constraints = Correct with constraints
settings-general-fk_settings-enforce_joint_constraints-correct_constraints-description = Correct joint rotations when they push past their limit
settings-general-fk_settings-arm_fk = Arm tracking
settings-general-fk_settings-arm_fk-description = Force arms to be tracked from the headset (HMD) even if positional hand data is available.
settings-general-fk_settings-arm_fk-force_arms = Force arms from HMD
Expand Down
52 changes: 52 additions & 0 deletions gui/src/components/settings/pages/GeneralSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ interface SettingsForm {
toeSnap: boolean;
footPlant: boolean;
selfLocalization: boolean;
usePosition: boolean;
enforceConstraints: boolean;
correctConstraints: boolean;
};
ratios: {
imputeWaistFromChestHip: number;
Expand Down Expand Up @@ -128,6 +131,9 @@ const defaultValues: SettingsForm = {
toeSnap: false,
footPlant: true,
selfLocalization: false,
usePosition: true,
enforceConstraints: true,
correctConstraints: true,
},
ratios: {
imputeWaistFromChestHip: 0.3,
Expand Down Expand Up @@ -235,6 +241,9 @@ export function GeneralSettings() {
toggles.toeSnap = values.toggles.toeSnap;
toggles.footPlant = values.toggles.footPlant;
toggles.selfLocalization = values.toggles.selfLocalization;
toggles.usePosition = values.toggles.usePosition;
toggles.enforceConstraints = values.toggles.enforceConstraints;
toggles.correctConstraints = values.toggles.correctConstraints;
modelSettings.toggles = toggles;
}

Expand Down Expand Up @@ -981,6 +990,7 @@ export function GeneralSettings() {
)}
/>
</div>

<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-arm_fk-reset_mode-description'
Expand Down Expand Up @@ -1033,6 +1043,48 @@ export function GeneralSettings() {
></Radio>
</div>

<div className="flex flex-col pt-2 pb-3">
<Typography bold>
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints'
)}
</Typography>
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="toggles.enforceConstraints"
label={l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-enforce_constraints'
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-correct_constraints-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="toggles.correctConstraints"
label={l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-correct_constraints'
)}
/>
</div>

{config?.debug && (
<>
<div className="flex flex-col pt-2 pb-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class AutoBoneStep(
// Load server configs into the skeleton
skeleton1.loadFromConfig(serverConfig)
skeleton2.loadFromConfig(serverConfig)
// Disable leg tweaks, this will mess with the resulting positions
// Disable leg tweaks and IK solver, these will mess with the resulting positions
skeleton1.setLegTweaksEnabled(false)
skeleton2.setLegTweaksEnabled(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class QuaternionMovingAverage(
var amount: Float = 0f,
initialRotation: Quaternion = IDENTITY,
) {
var filteredQuaternion = IDENTITY
var filteringImpact = 0f
private var smoothFactor = 0f
private var predictFactor = 0f
private var rotBuffer: CircularArrayList<Quaternion>? = null
Expand All @@ -29,7 +31,6 @@ class QuaternionMovingAverage(
private val fpsTimer = if (VRServer.instanceInitialized) VRServer.instance.fpsTimer else NanoTimer()
private var frameCounter = 0
private var lastAmt = 0f
var filteredQuaternion = IDENTITY

init {
// amount should range from 0 to 1.
Expand Down Expand Up @@ -93,6 +94,8 @@ class QuaternionMovingAverage(
// No filtering; just keep track of rotations (for going over 180 degrees)
filteredQuaternion = latestQuaternion.twinNearest(smoothingQuaternion)
}

filteringImpact = latestQuaternion.angleToR(filteredQuaternion)
}

@Synchronized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ public static int createModelSettings(
humanPoseManager.getToggle(SkeletonConfigToggles.FOOT_PLANT),
humanPoseManager.getToggle(SkeletonConfigToggles.SELF_LOCALIZATION),
false,
true,
true
humanPoseManager.getToggle(SkeletonConfigToggles.ENFORCE_CONSTRAINTS),
humanPoseManager.getToggle(SkeletonConfigToggles.CORRECT_CONSTRAINTS)
);
int ratiosOffset = ModelRatios
.createModelRatios(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) {
hpm.setToggle(SkeletonConfigToggles.TOE_SNAP, toggles.toeSnap())
hpm.setToggle(SkeletonConfigToggles.FOOT_PLANT, toggles.footPlant())
hpm.setToggle(SkeletonConfigToggles.SELF_LOCALIZATION, toggles.selfLocalization())
hpm.setToggle(SkeletonConfigToggles.ENFORCE_CONSTRAINTS, toggles.enforceConstraints())
hpm.setToggle(SkeletonConfigToggles.CORRECT_CONSTRAINTS, toggles.correctConstraints())
}

if (ratios != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package dev.slimevr.tracking.processor

import dev.slimevr.tracking.processor.Constraint.Companion.ConstraintType
import dev.slimevr.tracking.trackers.Tracker
import io.github.axisangles.ktmath.Quaternion
import io.github.axisangles.ktmath.Vector3
import solarxr_protocol.datatypes.BodyPart
import java.util.concurrent.CopyOnWriteArrayList

/**
* Represents a bone composed of 2 joints: headNode and tailNode.
*/
class Bone(val boneType: BoneType) {
class Bone(val boneType: BoneType, val rotationConstraint: Constraint) {
private val headNode = TransformNode(true)
private val tailNode = TransformNode(false)
var parent: Bone? = null
private set
val children: MutableList<Bone> = CopyOnWriteArrayList()
var rotationOffset = Quaternion.IDENTITY
var attachedTracker: Tracker? = null

init {
headNode.attachChild(tailNode)
Expand Down Expand Up @@ -58,6 +62,49 @@ class Bone(val boneType: BoneType) {
headNode.update()
}

/**
* Computes the rotations and positions of
* this bone and all of its children while
* enforcing rotation constraints.
*/
fun updateWithConstraints() {
val initialRot = getGlobalRotation()
val newRot = rotationConstraint.applyConstraint(initialRot, this)
setRotationRaw(newRot)
updateThisNode()

// Correct tracker if applicable. Do not adjust correction for hinge constraints
// or the upper chest tracker.
if (rotationConstraint.constraintType != ConstraintType.HINGE &&
rotationConstraint.constraintType != ConstraintType.LOOSE_HINGE &&
boneType.bodyPart != BodyPart.UPPER_CHEST
) {
val deltaRot = newRot * initialRot.inv()
val angle = deltaRot.angleR()

if (angle > Constraint.ANGLE_THRESHOLD &&
(attachedTracker?.filteringHandler?.getFilteringImpact() ?: 1f) < Constraint.FILTER_IMPACT_THRESHOLD &&
(parent?.attachedTracker?.filteringHandler?.getFilteringImpact() ?: 0f) < Constraint.FILTER_IMPACT_THRESHOLD
) {
attachedTracker?.resetsHandler?.updateConstraintFix(deltaRot)
}
}

// Recursively apply constraints and update children.
for (child in children) {
child.updateWithConstraints()
}
}

/**
* Computes the rotations and positions of this bone.
* Only to be used while traversing bones from top to bottom.
*/
private fun updateThisNode() {
headNode.updateThisNode()
tailNode.updateThisNode()
}

/**
* Returns the world-aligned rotation of the bone
*/
Expand All @@ -75,6 +122,13 @@ class Bone(val boneType: BoneType) {
headNode.localTransform.rotation = rotation * rotationOffset
}

/**
* Sets the global rotation of the bone directly
*/
fun setRotationRaw(rotation: Quaternion) {
headNode.localTransform.rotation = rotation
}

/**
* Returns the global position of the head of the bone
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public enum BoneType {
RIGHT_UPPER_ARM(BodyPart.RIGHT_UPPER_ARM),
LEFT_SHOULDER(BodyPart.LEFT_SHOULDER),
RIGHT_SHOULDER(BodyPart.RIGHT_SHOULDER),
LEFT_UPPER_SHOULDER,
RIGHT_UPPER_SHOULDER,
ImUrX marked this conversation as resolved.
Show resolved Hide resolved
LEFT_HAND(BodyPart.LEFT_HAND),
RIGHT_HAND(BodyPart.RIGHT_HAND),
LEFT_HAND_TRACKER,
Expand Down
Loading
Loading