Skip to content

Commit

Permalink
Enforce constraints bidirectionally
Browse files Browse the repository at this point in the history
  • Loading branch information
Stermere committed Sep 1, 2024
1 parent 518c0c9 commit c193a2d
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class Constraint(
private val constraintFunction = constraintTypeToFunc(constraintType)
private val twistRad = Math.toRadians(twist.toDouble()).toFloat()
private val swingRad = Math.toRadians(swing.toDouble()).toFloat()
var hasTrackerRotation = false

/**
* If false don't allow the rotation of the bone
* to be modified except to satisfy a constraint
* If false solve with minimal movement applied to this link
*/
var allowModifications = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class IKChain(
*/
private fun prepBones() {
for (i in 0..<bones.size) {
if (bones[i].rotationConstraint.allowModifications && bones[i].rotationConstraint.constraintType != ConstraintType.COMPLETE) {
if (!bones[i].rotationConstraint.hasTrackerRotation && bones[i].rotationConstraint.constraintType != ConstraintType.COMPLETE) {
bones[i].setRotationRaw(rotations[i])
}
}
Expand All @@ -51,6 +51,7 @@ class IKChain(

for (i in bones.size - 1 downTo 0) {
val currentBone = bones[i]
val childBone = if (bones.size - 1 < i) bones[i + 1] else null

// Get the local position of the end effector and the target relative to the current node
val endEffectorLocal = (getEndEffectorsAvg() - currentBone.getPosition()).unit()
Expand All @@ -67,7 +68,7 @@ class IKChain(
val adjustment = Quaternion(cos(angle / 2), cross * sinHalfAngle)
val correctedRot = (adjustment * currentBone.getGlobalRotation()).unit()

rotations[i] = setBoneRotation(currentBone, correctedRot, useConstraints)
rotations[i] = setBoneRotation(currentBone, childBone, correctedRot, useConstraints)
}
}

Expand Down Expand Up @@ -130,15 +131,25 @@ class IKChain(
* vector with the bone's rotational constraint
* returns the constrained rotation
*/
private fun setBoneRotation(bone: Bone, rotation: Quaternion, useConstraints: Boolean): Quaternion {
val newRotation = if (useConstraints || bone.rotationConstraint.constraintType == ConstraintType.COMPLETE) {
private fun setBoneRotation(bone: Bone, childBone: Bone?, rotation: Quaternion, useConstraints: Boolean): Quaternion {
// Constrain relative to the parent
val newRotation = if ((useConstraints || bone.rotationConstraint.constraintType == ConstraintType.COMPLETE) && !bone.rotationConstraint.hasTrackerRotation) {
bone.rotationConstraint.applyConstraint(rotation, bone)
} else {
rotation
}

bone.setRotationRaw(newRotation)
bone.update()

return newRotation
// Constrain relative to the child
if (childBone != null && useConstraints && !bone.rotationConstraint.hasTrackerRotation) {
val newChildRot = childBone.rotationConstraint.applyConstraint(childBone.getGlobalRotation(), childBone)
val correctionInv = (newChildRot * rotation.inv()).inv()
bone.setRotationRaw(newRotation * correctionInv)
bone.update()
}

return bone.getGlobalRotation()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.slimevr.tracking.processor.skeleton
import dev.slimevr.tracking.trackers.Tracker
import io.github.axisangles.ktmath.Quaternion
import io.github.axisangles.ktmath.Vector3
import solarxr_protocol.datatypes.BodyPart

class IKConstraint(val tracker: Tracker) {
private var offset = Vector3.NULL
Expand All @@ -12,7 +13,10 @@ class IKConstraint(val tracker: Tracker) {
tracker.position + (tracker.getRotation() * rotationOffset).sandwich(offset)

fun reset(nodePosition: Vector3) {
offset = nodePosition - tracker.position
val bodyPartsToSkip = setOf(BodyPart.LEFT_HAND, BodyPart.RIGHT_HAND)

rotationOffset = tracker.getRotation().inv()
if (tracker.trackerPosition?.bodyPart in bodyPartsToSkip) return
offset = nodePosition - tracker.position
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class IKSolver(private val root: Bone) {
const val ANNEALING_ITERATIONS = 5
const val ANNEALING_MAX = 60
const val DAMPENING_FACTOR = 0.5f
const val STATIC_DAMPENING = 0.25f
const val STATIC_DAMPENING = 0.1f
}

var enabled = true
Expand Down Expand Up @@ -66,8 +66,9 @@ class IKSolver(private val root: Bone) {
): IKChain {
val boneList = mutableListOf<Bone>()
var currentBone = root
currentBone.rotationConstraint.allowModifications =
getConstraint(currentBone, rotationalConstraints) == null
var constraint = getConstraint(currentBone, rotationalConstraints)
currentBone.rotationConstraint.allowModifications = constraint == null
currentBone.rotationConstraint.hasTrackerRotation = constraint != null
boneList.add(currentBone)

// Get constraints
Expand All @@ -81,8 +82,9 @@ class IKSolver(private val root: Bone) {
// Add bones until there is a reason to make a new chain
while (currentBone.children.size == 1 && tailConstraint == null) {
currentBone = currentBone.children.first()
currentBone.rotationConstraint.allowModifications =
getConstraint(currentBone, rotationalConstraints) == null
constraint = getConstraint(currentBone, rotationalConstraints)
currentBone.rotationConstraint.allowModifications = constraint == null
currentBone.rotationConstraint.hasTrackerRotation = constraint != null
boneList.add(currentBone)
tailConstraint = getConstraint(currentBone, positionalConstraints)
}
Expand Down

0 comments on commit c193a2d

Please sign in to comment.