Finger tracking skeleton and VMC support (#1091)

This commit is contained in:
Erimel
2024-11-15 12:10:17 -05:00
committed by GitHub
parent 67df399f14
commit 18f291345d
19 changed files with 1344 additions and 124 deletions

3
.gitignore vendored
View File

@@ -43,3 +43,6 @@ build/
# Ignore Android local properties
local.properties
# Ignore temporary config
vrconfig.yml.tmp

View File

@@ -44,6 +44,36 @@ body_part-LEFT_HAND = Left hand
body_part-LEFT_UPPER_LEG = Left thigh
body_part-LEFT_LOWER_LEG = Left ankle
body_part-LEFT_FOOT = Left foot
body_part-LEFT_THUMB_PROXIMAL = Left thumb proximal
body_part-LEFT_THUMB_INTERMEDIATE = Left thumb intermediate
body_part-LEFT_THUMB_DISTAL = Left thumb distal
body_part-LEFT_INDEX_PROXIMAL = Left index proximal
body_part-LEFT_INDEX_INTERMEDIATE = Left index intermediate
body_part-LEFT_INDEX_DISTAL = Left index distal
body_part-LEFT_MIDDLE_PROXIMAL = Left middle proximal
body_part-LEFT_MIDDLE_INTERMEDIATE = Left middle intermediate
body_part-LEFT_MIDDLE_DISTAL = Left middle distal
body_part-LEFT_RING_PROXIMAL = Left ring proximal
body_part-LEFT_RING_INTERMEDIATE = Left ring intermediate
body_part-LEFT_RING_DISTAL = Left ring distal
body_part-LEFT_LITTLE_PROXIMAL = Left little proximal
body_part-LEFT_LITTLE_INTERMEDIATE = Left little intermediate
body_part-LEFT_LITTLE_DISTAL = Left little distal
body_part-RIGHT_THUMB_PROXIMAL = Right thumb proximal
body_part-RIGHT_THUMB_INTERMEDIATE = Right thumb intermediate
body_part-RIGHT_THUMB_DISTAL = Right thumb distal
body_part-RIGHT_INDEX_PROXIMAL = Right index proximal
body_part-RIGHT_INDEX_INTERMEDIATE = Right index intermediate
body_part-RIGHT_INDEX_DISTAL = Right index distal
body_part-RIGHT_MIDDLE_PROXIMAL = Right middle proximal
body_part-RIGHT_MIDDLE_INTERMEDIATE = Right middle intermediate
body_part-RIGHT_MIDDLE_DISTAL = Right middle distal
body_part-RIGHT_RING_PROXIMAL = Right ring proximal
body_part-RIGHT_RING_INTERMEDIATE = Right ring intermediate
body_part-RIGHT_RING_DISTAL = Right ring distal
body_part-RIGHT_LITTLE_PROXIMAL = Right little proximal
body_part-RIGHT_LITTLE_INTERMEDIATE = Right little intermediate
body_part-RIGHT_LITTLE_DISTAL = Right little distal
## Proportions
skeleton_bone-NONE = None

View File

@@ -15,6 +15,7 @@ import { UpperArmIcon } from './icon/UpperArmIcon';
import { UpperLegIcon } from './icon/UpperLegIcon';
import { WaistIcon } from './icon/WaistIcon';
import { UpperChestIcon } from './icon/UpperChestIcon';
import { FingersIcon } from './icon/FingersIcon';
// All body parts that are right or left, are by default left!
export const mapPart: Record<
@@ -86,6 +87,96 @@ export const mapPart: Record<
<UpperLegIcon width={width} flipped></UpperLegIcon>
),
[BodyPart.WAIST]: ({ width }) => <WaistIcon width={width}></WaistIcon>,
[BodyPart.LEFT_THUMB_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_THUMB_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_THUMB_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
};
export function BodyPartIcon({

View File

@@ -0,0 +1,15 @@
export function FingersIcon({ width = 28 }: { width?: number }) {
return (
<svg
version="1.1"
id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
width={width}
viewBox="0 0 93.49 130"
>
<g>
<path d="M2.34,62.52l-0.26,0.27l-2.08-0.83V31.27c0-1.42,0.42-2.76,1.14-3.89l0,0c0.14-0.22,0.29-0.44,0.46-0.64 c0.17-0.22,0.35-0.42,0.53-0.6l0.02-0.02c0.54-0.54,1.18-1.01,1.89-1.36l0.03-0.01l0.35-0.17l0.04-0.02 c0.86-0.37,1.82-0.58,2.81-0.58l0,0h0.04v0c2.01,0,3.84,0.82,5.16,2.14c0.54,0.54,1.01,1.18,1.36,1.88l0.02,0.04l0.16,0.35 l0.01,0.03c0.37,0.86,0.58,1.82,0.58,2.81l0,0.01v0.04v24.96v1.13l-1.13,0.07c-3.08,0.19-5.92,1.18-8.32,2.77 c-0.48,0.32-0.94,0.66-1.38,1.02c-0.41,0.34-0.84,0.72-1.26,1.15L2.34,62.52L2.34,62.52L2.34,62.52z M65.62,83.35l1.23,0.46 l0.53,0.39c0.09,0.12,0.2,0.22,0.33,0.31l0,0l0.16,0.09l0,0.01c0.17,0.08,0.35,0.12,0.54,0.12v0h0.03c0.18,0,0.34-0.03,0.49-0.09 l0.12-0.06l0.12-0.07l0.04-0.02l0.04-0.02c0.54-0.31,1.26-0.85,2.05-1.5c0.8-0.67,1.71-1.49,2.61-2.33 c1.76-1.66,3.76-3.66,4.56-4.45l0.04-0.04c2.53-2.53,5.11-3.7,7.38-3.85c0.46-0.03,0.92-0.02,1.35,0.03 c0.44,0.05,0.87,0.14,1.28,0.27h0.01l0.05,0.02l0.01,0c0.81,0.26,1.56,0.67,2.22,1.2l0.03,0.03l0.31,0.27l0.06,0.05l0.29,0.29 l0.05,0.06l0.01,0.01l0,0l0.01,0.02l0,0c0.56,0.62,1.01,1.35,1.34,2.16l0.02,0.03l0.15,0.42l0.02,0.09l0.12,0.43l0.01,0.05 l0.01,0.06h0c0.57,2.38,0.1,5.27-1.88,8.17c-0.37,0.55-0.81,1.11-1.29,1.65c-0.48,0.54-1.02,1.09-1.62,1.62l0,0l-0.08,0.07 l-0.1,0.09l-0.07,0.07l-0.04,0.04L63.64,114.3l-0.85,0.93l-0.06-0.06c-1.35,1.23-2.67,2.29-4.01,3.2c-1.6,1.08-3.22,1.95-4.9,2.61 c-1.69,0.67-3.46,1.15-5.33,1.46c-1.87,0.3-3.84,0.45-5.94,0.45h-15.9c-5.3,0-10.23-1.56-14.36-4.23l0,0 c-0.79-0.51-1.57-1.08-2.32-1.69c-0.76-0.62-1.47-1.26-2.12-1.92l-0.02-0.02l0,0c-2.01-2.04-3.71-4.42-5-7.03 c-0.25-0.52-0.49-1.04-0.71-1.56C0.76,103.2,0.01,99.65,0,95.93h0V95.9V74.93c0-1.93,0.36-3.79,1-5.49l0-0.01 c0.12-0.31,0.26-0.64,0.41-0.97h0c0.15-0.32,0.31-0.64,0.48-0.95l0.01-0.02l0.03-0.05l0.02-0.04c0.62-0.97,1.36-1.88,2.19-2.69 l0.02-0.02l0.46-0.43l0.04-0.03l0.48-0.41l0.04-0.04l0.02-0.02l0,0c1.06-0.85,2.24-1.57,3.51-2.11h0c0.29-0.12,0.57-0.24,0.76-0.3 v0c1.56-0.57,3.25-0.88,5.01-0.88v0h0.04h0.64l0.29,0.04l0.27,0.07l0.21,0.02v0h17.27v0l0.11,0h0.08l0.11,0v0h17.27v0l0.05,0h0.07 l0.05,0v0h1.28c2.54,0,4.94,0.65,7.05,1.79l0,0c0.42,0.23,0.82,0.47,1.19,0.72v0l0.01,0c0.36,0.24,0.74,0.52,1.11,0.82l0.01,0.01 l0.02,0.02l0,0c1.82,1.49,3.3,3.41,4.25,5.6c0.2,0.45,0.37,0.89,0.5,1.31v0c0.15,0.45,0.27,0.91,0.38,1.37v0.01l0.01,0.07 l0.02,0.11c0.01,0.08,0.02,0.16,0.04,0.22h0l0.01,0.03h0l0.04,0.11h0l0.02,0.06L67,73.21l0.06,0.65l0,0.04l0.02,0.26v0.04 l0.02,0.46v0.03l0,0.25l0,0.01v4.43v1.66l-1.58-0.52c-2.46-0.81-4.81-1.36-7.03-1.66h0c-0.5-0.07-0.98-0.12-1.42-0.17 c-0.45-0.04-0.92-0.08-1.39-0.1l-1.02-0.03c-2.85-0.04-5.48,0.37-7.81,1.17c-0.51,0.18-0.99,0.36-1.42,0.55 c-0.45,0.2-0.9,0.41-1.32,0.64l-0.71,0.41c-2.23,1.34-4.08,3.14-5.49,5.34c-0.29,0.46-0.56,0.9-0.78,1.33 c-0.24,0.45-0.46,0.94-0.68,1.44v0l-0.01,0.03h0c-0.68,1.62-1.17,3.4-1.45,5.33c-0.06,0.44-0.12,0.87-0.15,1.28 c-0.03,0.34-0.07,0.7-0.08,1.06l2.66,0.03c0.08-1.35,0.28-2.64,0.57-3.84h0c0.09-0.37,0.18-0.72,0.27-1.03h0 c0.09-0.3,0.2-0.64,0.33-0.98v0l0.32-0.82l0,0c0.89-2.13,2.18-3.94,3.8-5.38c0.32-0.28,0.66-0.55,0.99-0.8 c0.37-0.27,0.72-0.51,1.06-0.71l0.02-0.01l0.03-0.02v0c1.7-1.02,3.68-1.73,5.9-2.09c0.45-0.07,0.94-0.14,1.44-0.18 c0.49-0.05,1-0.07,1.49-0.09h0.03l0.98,0h0.02c2.3,0.03,4.79,0.39,7.44,1.07v0c0.61,0.15,1.18,0.32,1.72,0.49 c0.62,0.19,1.21,0.39,1.77,0.58L65.62,83.35L65.62,83.35z M15.74,60.59L15.74,60.59L15.74,60.59L15.74,60.59L15.74,60.59z M48.24,57.4H36.05h-1.2v-1.2V7.3h0c0-2.01,0.82-3.84,2.14-5.16c0.54-0.54,1.18-1.01,1.88-1.36l0.03-0.01l0.35-0.17l0.04-0.02 c0.86-0.37,1.81-0.58,2.81-0.58l0-0.01h0.04v0.01c2.01,0,3.84,0.82,5.16,2.14c0.54,0.54,1,1.18,1.36,1.88l0.02,0.03l0.16,0.35 l0.02,0.04c0.37,0.86,0.58,1.81,0.58,2.81l0,0.01V7.3v48.89v1.2H48.24L48.24,57.4z M53.63,57.45l-0.22-0.02l-1.12-0.09v-1.11V19.01 h0c0-2.01,0.82-3.84,2.14-5.16c0.54-0.54,1.18-1,1.89-1.36l0.04-0.02l0.35-0.16l0.03-0.02c0.86-0.37,1.81-0.58,2.81-0.58l0,0h0.04 c1.42,0,2.76,0.42,3.89,1.14l0,0l0.01,0.01c0.22,0.13,0.43,0.29,0.63,0.45l0,0l0.01,0.01c0.21,0.16,0.41,0.34,0.59,0.52l0.02,0.02 c0.54,0.54,1.01,1.18,1.36,1.88l0.01,0.03l0.17,0.35l0.02,0.04c0.37,0.86,0.58,1.82,0.58,2.81l0,0v0.04v42.9l-2.07,0.84l-0.2-0.2 c-2.06-2.06-4.63-3.62-7.49-4.45c-0.57-0.17-1.16-0.31-1.73-0.41C54.84,57.58,54.24,57.5,53.63,57.45L53.63,57.45z M30.68,57.4 H18.49h-1.21v-1.2V31.27h0V18.89h0c0-1.42,0.42-2.77,1.14-3.9h0c0.14-0.23,0.3-0.45,0.46-0.65c0.17-0.22,0.35-0.42,0.52-0.59 l0.02-0.02c0.54-0.54,1.18-1,1.89-1.36l0.03-0.01l0.35-0.16l0.04-0.02c0.86-0.37,1.81-0.58,2.81-0.58l0,0h0.04v0 c2.01,0,3.84,0.82,5.16,2.14c0.54,0.54,1,1.18,1.36,1.88l0.01,0.03L31.28,16l0.02,0.04c0.37,0.86,0.58,1.82,0.58,2.81l0,0v0.04 v37.3v1.2H30.68L30.68,57.4z" />
</g>
</svg>
);
}

View File

@@ -10,6 +10,7 @@ import { SlimeUpIcon } from '@/components/commons/icon/SlimeUpIcon';
import { BodyPart } from 'solarxr-protocol';
import { PawIcon } from '@/components/commons/icon/PawIcon';
import { useLocaleConfig } from '@/i18n/config';
import { FingersIcon } from '@/components/commons/icon/FingersIcon';
// All body parts that are right or left, are by default left!
export const mapPart: Record<
@@ -97,6 +98,96 @@ export const mapPart: Record<
<FootIcon width={width} flipped></FootIcon>
),
[BodyPart.WAIST]: ({ width }) => <FootIcon width={width}></FootIcon>,
[BodyPart.LEFT_THUMB_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_THUMB_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_THUMB_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_INDEX_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_MIDDLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_RING_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.LEFT_LITTLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_THUMB_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_INDEX_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_MIDDLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_RING_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_PROXIMAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_INTERMEDIATE]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
[BodyPart.RIGHT_LITTLE_DISTAL]: ({ width }) => (
<FingersIcon width={width}></FingersIcon>
),
};
export function MountingBodyPartIcon({

View File

@@ -223,6 +223,37 @@ export class BoneKind extends Bone {
case BodyPart.LEFT_HIP:
case BodyPart.RIGHT_HIP:
return new Color('pink');
case BodyPart.LEFT_THUMB_PROXIMAL:
case BodyPart.LEFT_THUMB_INTERMEDIATE:
case BodyPart.LEFT_THUMB_DISTAL:
case BodyPart.LEFT_INDEX_PROXIMAL:
case BodyPart.LEFT_INDEX_INTERMEDIATE:
case BodyPart.LEFT_INDEX_DISTAL:
case BodyPart.LEFT_MIDDLE_PROXIMAL:
case BodyPart.LEFT_MIDDLE_INTERMEDIATE:
case BodyPart.LEFT_MIDDLE_DISTAL:
case BodyPart.LEFT_RING_PROXIMAL:
case BodyPart.LEFT_RING_INTERMEDIATE:
case BodyPart.LEFT_RING_DISTAL:
case BodyPart.LEFT_LITTLE_PROXIMAL:
case BodyPart.LEFT_LITTLE_INTERMEDIATE:
case BodyPart.LEFT_LITTLE_DISTAL:
case BodyPart.RIGHT_THUMB_PROXIMAL:
case BodyPart.RIGHT_THUMB_INTERMEDIATE:
case BodyPart.RIGHT_THUMB_DISTAL:
case BodyPart.RIGHT_INDEX_PROXIMAL:
case BodyPart.RIGHT_INDEX_INTERMEDIATE:
case BodyPart.RIGHT_INDEX_DISTAL:
case BodyPart.RIGHT_MIDDLE_PROXIMAL:
case BodyPart.RIGHT_MIDDLE_INTERMEDIATE:
case BodyPart.RIGHT_MIDDLE_DISTAL:
case BodyPart.RIGHT_RING_PROXIMAL:
case BodyPart.RIGHT_RING_INTERMEDIATE:
case BodyPart.RIGHT_RING_DISTAL:
case BodyPart.RIGHT_LITTLE_PROXIMAL:
case BodyPart.RIGHT_LITTLE_INTERMEDIATE:
case BodyPart.RIGHT_LITTLE_DISTAL:
return new Color('pink');
}
}
@@ -275,8 +306,81 @@ export class BoneKind extends Bone {
case BodyPart.RIGHT_LOWER_ARM:
return [BodyPart.RIGHT_HAND];
case BodyPart.LEFT_HAND:
return [];
return [
BodyPart.LEFT_THUMB_PROXIMAL,
BodyPart.LEFT_INDEX_PROXIMAL,
BodyPart.LEFT_MIDDLE_PROXIMAL,
BodyPart.LEFT_RING_PROXIMAL,
BodyPart.LEFT_LITTLE_PROXIMAL,
];
case BodyPart.RIGHT_HAND:
return [
BodyPart.RIGHT_THUMB_PROXIMAL,
BodyPart.RIGHT_INDEX_PROXIMAL,
BodyPart.RIGHT_MIDDLE_PROXIMAL,
BodyPart.RIGHT_RING_PROXIMAL,
BodyPart.RIGHT_LITTLE_PROXIMAL,
];
case BodyPart.LEFT_THUMB_PROXIMAL:
return [BodyPart.LEFT_THUMB_INTERMEDIATE];
case BodyPart.LEFT_THUMB_INTERMEDIATE:
return [BodyPart.LEFT_THUMB_DISTAL];
case BodyPart.LEFT_THUMB_DISTAL:
return [];
case BodyPart.LEFT_INDEX_PROXIMAL:
return [BodyPart.LEFT_INDEX_INTERMEDIATE];
case BodyPart.LEFT_INDEX_INTERMEDIATE:
return [BodyPart.LEFT_INDEX_DISTAL];
case BodyPart.LEFT_INDEX_DISTAL:
return [];
case BodyPart.LEFT_MIDDLE_PROXIMAL:
return [BodyPart.LEFT_MIDDLE_INTERMEDIATE];
case BodyPart.LEFT_MIDDLE_INTERMEDIATE:
return [BodyPart.LEFT_MIDDLE_DISTAL];
case BodyPart.LEFT_MIDDLE_DISTAL:
return [];
case BodyPart.LEFT_RING_PROXIMAL:
return [BodyPart.LEFT_RING_INTERMEDIATE];
case BodyPart.LEFT_RING_INTERMEDIATE:
return [BodyPart.LEFT_RING_DISTAL];
case BodyPart.LEFT_RING_DISTAL:
return [];
case BodyPart.LEFT_LITTLE_PROXIMAL:
return [BodyPart.LEFT_LITTLE_INTERMEDIATE];
case BodyPart.LEFT_LITTLE_INTERMEDIATE:
return [BodyPart.LEFT_LITTLE_DISTAL];
case BodyPart.LEFT_LITTLE_DISTAL:
return [];
case BodyPart.RIGHT_THUMB_PROXIMAL:
return [BodyPart.RIGHT_THUMB_INTERMEDIATE];
case BodyPart.RIGHT_THUMB_INTERMEDIATE:
return [BodyPart.RIGHT_THUMB_DISTAL];
case BodyPart.RIGHT_THUMB_DISTAL:
return [];
case BodyPart.RIGHT_INDEX_PROXIMAL:
return [BodyPart.RIGHT_INDEX_INTERMEDIATE];
case BodyPart.RIGHT_INDEX_INTERMEDIATE:
return [BodyPart.RIGHT_INDEX_DISTAL];
case BodyPart.RIGHT_INDEX_DISTAL:
return [];
case BodyPart.RIGHT_MIDDLE_PROXIMAL:
return [BodyPart.RIGHT_MIDDLE_INTERMEDIATE];
case BodyPart.RIGHT_MIDDLE_INTERMEDIATE:
return [BodyPart.RIGHT_MIDDLE_DISTAL];
case BodyPart.RIGHT_MIDDLE_DISTAL:
return [];
case BodyPart.RIGHT_RING_PROXIMAL:
return [BodyPart.RIGHT_RING_INTERMEDIATE];
case BodyPart.RIGHT_RING_INTERMEDIATE:
return [BodyPart.RIGHT_RING_DISTAL];
case BodyPart.RIGHT_RING_DISTAL:
return [];
case BodyPart.RIGHT_LITTLE_PROXIMAL:
return [BodyPart.RIGHT_LITTLE_INTERMEDIATE];
case BodyPart.RIGHT_LITTLE_INTERMEDIATE:
return [BodyPart.RIGHT_LITTLE_DISTAL];
case BodyPart.RIGHT_LITTLE_DISTAL:
return [];
}
}
@@ -329,6 +433,67 @@ export class BoneKind extends Bone {
return BodyPart.LEFT_LOWER_ARM;
case BodyPart.RIGHT_HAND:
return BodyPart.RIGHT_LOWER_ARM;
case BodyPart.LEFT_THUMB_PROXIMAL:
return BodyPart.LEFT_HAND;
case BodyPart.LEFT_THUMB_INTERMEDIATE:
return BodyPart.LEFT_THUMB_PROXIMAL;
case BodyPart.LEFT_THUMB_DISTAL:
return BodyPart.LEFT_THUMB_INTERMEDIATE;
case BodyPart.LEFT_INDEX_PROXIMAL:
return BodyPart.LEFT_HAND;
case BodyPart.LEFT_INDEX_INTERMEDIATE:
return BodyPart.LEFT_INDEX_PROXIMAL;
case BodyPart.LEFT_INDEX_DISTAL:
return BodyPart.LEFT_INDEX_INTERMEDIATE;
case BodyPart.LEFT_MIDDLE_PROXIMAL:
return BodyPart.LEFT_HAND;
case BodyPart.LEFT_MIDDLE_INTERMEDIATE:
return BodyPart.LEFT_MIDDLE_PROXIMAL;
case BodyPart.LEFT_MIDDLE_DISTAL:
return BodyPart.LEFT_MIDDLE_INTERMEDIATE;
case BodyPart.LEFT_RING_PROXIMAL:
return BodyPart.LEFT_HAND;
case BodyPart.LEFT_RING_INTERMEDIATE:
return BodyPart.LEFT_RING_PROXIMAL;
case BodyPart.LEFT_RING_DISTAL:
return BodyPart.LEFT_RING_INTERMEDIATE;
case BodyPart.LEFT_LITTLE_PROXIMAL:
return BodyPart.LEFT_HAND;
case BodyPart.LEFT_LITTLE_INTERMEDIATE:
return BodyPart.LEFT_LITTLE_PROXIMAL;
case BodyPart.LEFT_LITTLE_DISTAL:
return BodyPart.LEFT_LITTLE_INTERMEDIATE;
case BodyPart.RIGHT_THUMB_PROXIMAL:
return BodyPart.RIGHT_HAND;
case BodyPart.RIGHT_THUMB_INTERMEDIATE:
return BodyPart.RIGHT_THUMB_PROXIMAL;
case BodyPart.RIGHT_THUMB_DISTAL:
return BodyPart.RIGHT_THUMB_INTERMEDIATE;
case BodyPart.RIGHT_INDEX_PROXIMAL:
return BodyPart.RIGHT_HAND;
case BodyPart.RIGHT_INDEX_INTERMEDIATE:
return BodyPart.RIGHT_INDEX_PROXIMAL;
case BodyPart.RIGHT_INDEX_DISTAL:
return BodyPart.RIGHT_INDEX_INTERMEDIATE;
case BodyPart.RIGHT_MIDDLE_PROXIMAL:
return BodyPart.RIGHT_HAND;
case BodyPart.RIGHT_MIDDLE_INTERMEDIATE:
return BodyPart.RIGHT_MIDDLE_PROXIMAL;
case BodyPart.RIGHT_MIDDLE_DISTAL:
return BodyPart.RIGHT_MIDDLE_INTERMEDIATE;
case BodyPart.RIGHT_RING_PROXIMAL:
return BodyPart.RIGHT_HAND;
case BodyPart.RIGHT_RING_INTERMEDIATE:
return BodyPart.RIGHT_RING_PROXIMAL;
case BodyPart.RIGHT_RING_DISTAL:
return BodyPart.RIGHT_RING_INTERMEDIATE;
case BodyPart.RIGHT_LITTLE_PROXIMAL:
return BodyPart.RIGHT_HAND;
case BodyPart.RIGHT_LITTLE_INTERMEDIATE:
return BodyPart.RIGHT_LITTLE_PROXIMAL;
case BodyPart.RIGHT_LITTLE_DISTAL:
return BodyPart.RIGHT_LITTLE_INTERMEDIATE;
}
}
}

View File

@@ -102,8 +102,6 @@ class VRServer @JvmOverloads constructor(
init {
// UwU
instance = this
configManager = ConfigManager(configPath)
configManager.loadConfig()
deviceManager = DeviceManager(this)
@@ -163,6 +161,7 @@ class VRServer @JvmOverloads constructor(
for (tracker in computedTrackers) {
registerTracker(tracker)
}
instance = this
}
fun hasBridge(bridgeClass: Class<out Bridge?>): Boolean {

View File

@@ -1,5 +1,6 @@
package dev.slimevr.filtering
import com.jme3.system.NanoTimer
import dev.slimevr.VRServer
import io.github.axisangles.ktmath.Quaternion
import io.github.axisangles.ktmath.Quaternion.Companion.IDENTITY
@@ -17,18 +18,18 @@ private const val PREDICT_BUFFER = 6
class QuaternionMovingAverage(
val type: TrackerFilters,
var amount: Float,
initialRotation: Quaternion,
var amount: Float = 0f,
initialRotation: Quaternion = IDENTITY,
) {
var filteredQuaternion = IDENTITY
private var smoothFactor = 0f
private var predictFactor = 0f
private lateinit var rotBuffer: CircularArrayList<Quaternion>
private var latestQuaternion = IDENTITY
private var smoothingQuaternion = IDENTITY
private val fpsTimer = VRServer.instance.fpsTimer
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.
@@ -48,9 +49,7 @@ class QuaternionMovingAverage(
predictFactor = PREDICT_MULTIPLIER * amount + PREDICT_MIN
rotBuffer = CircularArrayList(PREDICT_BUFFER)
}
filteredQuaternion = initialRotation
latestQuaternion = initialRotation
smoothingQuaternion = initialRotation
resetQuats(initialRotation)
}
// Runs at up to 1000hz. We use a timer to make it framerate-independent
@@ -70,7 +69,7 @@ class QuaternionMovingAverage(
// Slerps the target rotation to that predicted rotation by amt
filteredQuaternion = filteredQuaternion.interpR(quatBuf, amt)
}
} else { // Smoothing
} else if (type == TrackerFilters.SMOOTHING) {
// Increase every update for linear interpolation
frameCounter++
@@ -90,6 +89,9 @@ class QuaternionMovingAverage(
// Smooth towards the target rotation by the slerp factor
filteredQuaternion = smoothingQuaternion.interpR(latestQuaternion, amt)
} else {
// No filtering; just keep track of rotations (for going over 180 degrees)
filteredQuaternion = latestQuaternion.twinNearest(smoothingQuaternion)
}
}
@@ -102,12 +104,20 @@ class QuaternionMovingAverage(
// Gets and stores the rotation between the last 2 quaternions
rotBuffer.add(latestQuaternion.inv().times(q))
} else { // Smoothing
} else if (type == TrackerFilters.SMOOTHING) {
frameCounter = 0
lastAmt = 0f
smoothingQuaternion = filteredQuaternion
} else {
smoothingQuaternion = filteredQuaternion
}
latestQuaternion = q
}
fun resetQuats(q: Quaternion) {
filteredQuaternion = q
latestQuaternion = q
smoothingQuaternion = q
}
}

View File

@@ -12,9 +12,12 @@ import io.github.axisangles.ktmath.Vector3
*/
class UnityArmature(localRot: Boolean) {
// Head
private val headNode = TransformNode(localRotation = localRot)
private val neckTailNode = TransformNode(localRotation = localRot)
private val neckHeadNode = TransformNode(localRotation = localRot)
// Spine
private val upperChestNode = TransformNode(localRotation = localRot)
private val chestNode = TransformNode(localRotation = localRot)
private val spineTailNode = TransformNode(localRotation = localRot)
@@ -22,12 +25,16 @@ class UnityArmature(localRot: Boolean) {
private val hipsNode = TransformNode(localRotation = localRot)
private val leftHipNode = TransformNode(localRotation = localRot)
private val rightHipNode = TransformNode(localRotation = localRot)
// Legs
private val leftKneeNode = TransformNode(localRotation = localRot)
private val leftAnkleNode = TransformNode(localRotation = localRot)
private val leftFootNode = TransformNode(localRotation = localRot)
private val rightKneeNode = TransformNode(localRotation = localRot)
private val rightAnkleNode = TransformNode(localRotation = localRot)
private val rightFootNode = TransformNode(localRotation = localRot)
// Arms
private val leftShoulderHeadNode = TransformNode(localRotation = localRot)
private val rightShoulderHeadNode = TransformNode(localRotation = localRot)
private val leftShoulderTailNode = TransformNode(localRotation = localRot)
@@ -36,8 +43,50 @@ class UnityArmature(localRot: Boolean) {
private val rightElbowNode = TransformNode(localRotation = localRot)
private val leftWristNode = TransformNode(localRotation = localRot)
private val rightWristNode = TransformNode(localRotation = localRot)
private val leftHandNode = TransformNode(localRotation = localRot)
private val rightHandNode = TransformNode(localRotation = localRot)
private val leftHandNode = TransformNode(localRotation = !localRot)
private val rightHandNode = TransformNode(localRotation = !localRot)
// Fingers
val leftThumbProximalHeadNode = TransformNode(localRotation = localRot)
val leftThumbProximalTailNode = TransformNode(localRotation = localRot)
val leftThumbIntermediateNode = TransformNode(localRotation = localRot)
val leftThumbDistalNode = TransformNode(localRotation = localRot)
val leftIndexProximalHeadNode = TransformNode(localRotation = localRot)
val leftIndexProximalTailNode = TransformNode(localRotation = localRot)
val leftIndexIntermediateNode = TransformNode(localRotation = localRot)
val leftIndexDistalNode = TransformNode(localRotation = localRot)
val leftMiddleProximalHeadNode = TransformNode(localRotation = localRot)
val leftMiddleProximalTailNode = TransformNode(localRotation = localRot)
val leftMiddleIntermediateNode = TransformNode(localRotation = localRot)
val leftMiddleDistalNode = TransformNode(localRotation = localRot)
val leftRingProximalHeadNode = TransformNode(localRotation = localRot)
val leftRingProximalTailNode = TransformNode(localRotation = localRot)
val leftRingIntermediateNode = TransformNode(localRotation = localRot)
val leftRingDistalNode = TransformNode(localRotation = localRot)
val leftLittleProximalHeadNode = TransformNode(localRotation = localRot)
val leftLittleProximalTailNode = TransformNode(localRotation = localRot)
val leftLittleIntermediateNode = TransformNode(localRotation = localRot)
val leftLittleDistalNode = TransformNode(localRotation = localRot)
val rightThumbProximalHeadNode = TransformNode(localRotation = localRot)
val rightThumbProximalTailNode = TransformNode(localRotation = localRot)
val rightThumbIntermediateNode = TransformNode(localRotation = localRot)
val rightThumbDistalNode = TransformNode(localRotation = localRot)
val rightIndexProximalHeadNode = TransformNode(localRotation = localRot)
val rightIndexProximalTailNode = TransformNode(localRotation = localRot)
val rightIndexIntermediateNode = TransformNode(localRotation = localRot)
val rightIndexDistalNode = TransformNode(localRotation = localRot)
val rightMiddleProximalHeadNode = TransformNode(localRotation = localRot)
val rightMiddleProximalTailNode = TransformNode(localRotation = localRot)
val rightMiddleIntermediateNode = TransformNode(localRotation = localRot)
val rightMiddleDistalNode = TransformNode(localRotation = localRot)
val rightRingProximalHeadNode = TransformNode(localRotation = localRot)
val rightRingProximalTailNode = TransformNode(localRotation = localRot)
val rightRingIntermediateNode = TransformNode(localRotation = localRot)
val rightRingDistalNode = TransformNode(localRotation = localRot)
val rightLittleProximalHeadNode = TransformNode(localRotation = localRot)
val rightLittleProximalTailNode = TransformNode(localRotation = localRot)
val rightLittleIntermediateNode = TransformNode(localRotation = localRot)
val rightLittleDistalNode = TransformNode(localRotation = localRot)
private var rootPosition = Vector3.NULL
private var rootRotation = Quaternion.IDENTITY
@@ -74,6 +123,48 @@ class UnityArmature(localRot: Boolean) {
rightElbowNode.attachChild(rightWristNode)
leftWristNode.attachChild(leftHandNode)
rightWristNode.attachChild(rightHandNode)
// Fingers
leftHandNode.attachChild(leftThumbProximalHeadNode)
leftThumbProximalHeadNode.attachChild(leftThumbProximalTailNode)
leftThumbProximalTailNode.attachChild(leftThumbIntermediateNode)
leftThumbIntermediateNode.attachChild(leftThumbDistalNode)
leftHandNode.attachChild(leftIndexProximalHeadNode)
leftIndexProximalHeadNode.attachChild(leftIndexProximalTailNode)
leftIndexProximalTailNode.attachChild(leftIndexIntermediateNode)
leftIndexIntermediateNode.attachChild(leftIndexDistalNode)
leftHandNode.attachChild(leftMiddleProximalHeadNode)
leftMiddleProximalHeadNode.attachChild(leftMiddleProximalTailNode)
leftMiddleProximalTailNode.attachChild(leftMiddleIntermediateNode)
leftMiddleIntermediateNode.attachChild(leftMiddleDistalNode)
leftHandNode.attachChild(leftRingProximalHeadNode)
leftRingProximalHeadNode.attachChild(leftRingProximalTailNode)
leftRingProximalTailNode.attachChild(leftRingIntermediateNode)
leftRingIntermediateNode.attachChild(leftRingDistalNode)
leftHandNode.attachChild(leftLittleProximalHeadNode)
leftLittleProximalHeadNode.attachChild(leftLittleProximalTailNode)
leftLittleProximalTailNode.attachChild(leftLittleIntermediateNode)
leftLittleIntermediateNode.attachChild(leftLittleDistalNode)
rightHandNode.attachChild(rightThumbProximalHeadNode)
rightThumbProximalHeadNode.attachChild(rightThumbProximalTailNode)
rightThumbProximalTailNode.attachChild(rightThumbIntermediateNode)
rightThumbIntermediateNode.attachChild(rightThumbDistalNode)
rightHandNode.attachChild(rightIndexProximalHeadNode)
rightIndexProximalHeadNode.attachChild(rightIndexProximalTailNode)
rightIndexProximalTailNode.attachChild(rightIndexIntermediateNode)
rightIndexIntermediateNode.attachChild(rightIndexDistalNode)
rightHandNode.attachChild(rightMiddleProximalHeadNode)
rightMiddleProximalHeadNode.attachChild(rightMiddleProximalTailNode)
rightMiddleProximalTailNode.attachChild(rightMiddleIntermediateNode)
rightMiddleIntermediateNode.attachChild(rightMiddleDistalNode)
rightHandNode.attachChild(rightRingProximalHeadNode)
rightRingProximalHeadNode.attachChild(rightRingProximalTailNode)
rightRingProximalTailNode.attachChild(rightRingIntermediateNode)
rightRingIntermediateNode.attachChild(rightRingDistalNode)
rightHandNode.attachChild(rightLittleProximalHeadNode)
rightLittleProximalHeadNode.attachChild(rightLittleProximalTailNode)
rightLittleProximalTailNode.attachChild(rightLittleIntermediateNode)
rightLittleIntermediateNode.attachChild(rightLittleDistalNode)
}
fun update() {
@@ -91,10 +182,12 @@ class UnityArmature(localRot: Boolean) {
fun setGlobalRotationForBone(unityBone: UnityBone, globalRot: Quaternion) {
val node = getHeadNodeOfBone(unityBone)
if (node != null) {
node.localTransform.rotation = when (unityBone) {
UnityBone.LEFT_UPPER_ARM, UnityBone.LEFT_LOWER_ARM, UnityBone.LEFT_HAND -> globalRot * LEFT_SHOULDER_OFFSET
UnityBone.RIGHT_UPPER_ARM, UnityBone.RIGHT_LOWER_ARM, UnityBone.RIGHT_HAND -> globalRot * RIGHT_SHOULDER_OFFSET
else -> globalRot
node.localTransform.rotation = if (UnityBone.isLeftArmBone(unityBone)) {
globalRot * LEFT_SHOULDER_OFFSET
} else if (UnityBone.isRightArmBone(unityBone)) {
globalRot * RIGHT_SHOULDER_OFFSET
} else {
globalRot
}
}
}
@@ -105,10 +198,12 @@ class UnityArmature(localRot: Boolean) {
if (unityBone == UnityBone.HIPS) {
node.worldTransform.rotation = localRot
} else {
node.localTransform.rotation = when (unityBone) {
UnityBone.LEFT_UPPER_ARM -> localRot * RIGHT_SHOULDER_OFFSET
UnityBone.RIGHT_UPPER_ARM -> localRot * LEFT_SHOULDER_OFFSET
else -> localRot
node.localTransform.rotation = if (UnityBone.isLeftStartOfArmOrFingerBone(unityBone)) {
localRot * RIGHT_SHOULDER_OFFSET
} else if (UnityBone.isRightStartOfArmOrFingerBone(unityBone)) {
localRot * LEFT_SHOULDER_OFFSET
} else {
localRot
}
}
}
@@ -194,6 +289,36 @@ class UnityArmature(localRot: Boolean) {
UnityBone.RIGHT_LOWER_ARM -> rightElbowNode
UnityBone.LEFT_HAND -> leftWristNode
UnityBone.RIGHT_HAND -> rightWristNode
UnityBone.LEFT_THUMB_PROXIMAL -> leftThumbProximalHeadNode
UnityBone.LEFT_THUMB_INTERMEDIATE -> leftThumbProximalTailNode
UnityBone.LEFT_THUMB_DISTAL -> leftThumbIntermediateNode
UnityBone.LEFT_INDEX_PROXIMAL -> leftIndexProximalHeadNode
UnityBone.LEFT_INDEX_INTERMEDIATE -> leftIndexProximalTailNode
UnityBone.LEFT_INDEX_DISTAL -> leftIndexIntermediateNode
UnityBone.LEFT_MIDDLE_PROXIMAL -> leftMiddleProximalHeadNode
UnityBone.LEFT_MIDDLE_INTERMEDIATE -> leftMiddleProximalTailNode
UnityBone.LEFT_MIDDLE_DISTAL -> leftMiddleIntermediateNode
UnityBone.LEFT_RING_PROXIMAL -> leftRingProximalHeadNode
UnityBone.LEFT_RING_INTERMEDIATE -> leftRingProximalTailNode
UnityBone.LEFT_RING_DISTAL -> leftRingIntermediateNode
UnityBone.LEFT_LITTLE_PROXIMAL -> leftLittleProximalHeadNode
UnityBone.LEFT_LITTLE_INTERMEDIATE -> leftLittleProximalTailNode
UnityBone.LEFT_LITTLE_DISTAL -> leftLittleIntermediateNode
UnityBone.RIGHT_THUMB_PROXIMAL -> rightThumbProximalHeadNode
UnityBone.RIGHT_THUMB_INTERMEDIATE -> rightThumbProximalTailNode
UnityBone.RIGHT_THUMB_DISTAL -> rightThumbIntermediateNode
UnityBone.RIGHT_INDEX_PROXIMAL -> rightIndexProximalHeadNode
UnityBone.RIGHT_INDEX_INTERMEDIATE -> rightIndexProximalTailNode
UnityBone.RIGHT_INDEX_DISTAL -> rightIndexIntermediateNode
UnityBone.RIGHT_MIDDLE_PROXIMAL -> rightMiddleProximalHeadNode
UnityBone.RIGHT_MIDDLE_INTERMEDIATE -> rightMiddleProximalTailNode
UnityBone.RIGHT_MIDDLE_DISTAL -> rightMiddleIntermediateNode
UnityBone.RIGHT_RING_PROXIMAL -> rightRingProximalHeadNode
UnityBone.RIGHT_RING_INTERMEDIATE -> rightRingProximalTailNode
UnityBone.RIGHT_RING_DISTAL -> rightRingIntermediateNode
UnityBone.RIGHT_LITTLE_PROXIMAL -> rightLittleProximalHeadNode
UnityBone.RIGHT_LITTLE_INTERMEDIATE -> rightLittleProximalTailNode
UnityBone.RIGHT_LITTLE_DISTAL -> rightLittleIntermediateNode
else -> null
}
}

View File

@@ -38,36 +38,36 @@ enum class UnityBone(
LEFT_EYE("LeftEye", null, null),
RIGHT_EYE("RightEye", null, null),
JAW("Jaw", null, null),
LEFT_THUMB_PROXIMAL("LeftThumbProximal", null, null),
LEFT_THUMB_INTERMEDIATE("LeftThumbIntermediate", null, null),
LEFT_THUMB_DISTAL("LeftThumbDistal", null, null),
LEFT_INDEX_PROXIMAL("LeftIndexProximal", null, null),
LEFT_INDEX_INTERMEDIATE("LeftIndexIntermediate", null, null),
LEFT_INDEX_DISTAL("LeftIndexDistal", null, null),
LEFT_MIDDLE_PROXIMAL("LeftMiddleProximal", null, null),
LEFT_MIDDLE_INTERMEDIATE("LeftMiddleIntermediate", null, null),
LEFT_MIDDLE_DISTAL("LeftMiddleDistal", null, null),
LEFT_RING_PROXIMAL("LeftRingProximal", null, null),
LEFT_RING_INTERMEDIATE("LeftRingIntermediate", null, null),
LEFT_RING_DISTAL("LeftRingDistal", null, null),
LEFT_LITTLE_PROXIMAL("LeftLittleProximal", null, null),
LEFT_LITTLE_INTERMEDIATE("LeftLittleIntermediate", null, null),
LEFT_LITTLE_DISTAL("LeftLittleDistal", null, null),
RIGHT_THUMB_PROXIMAL("RightThumbProximal", null, null),
RIGHT_THUMB_INTERMEDIATE("RightThumbIntermediate", null, null),
RIGHT_THUMB_DISTAL("RightThumbDistal", null, null),
RIGHT_INDEX_PROXIMAL("RightIndexProximal", null, null),
RIGHT_INDEX_INTERMEDIATE("RightIndexIntermediate", null, null),
RIGHT_INDEX_DISTAL("RightIndexDistal", null, null),
RIGHT_MIDDLE_PROXIMAL("RightMiddleProximal", null, null),
RIGHT_MIDDLE_INTERMEDIATE("RightMiddleIntermediate", null, null),
RIGHT_MIDDLE_DISTAL("RightMiddleDistal", null, null),
RIGHT_RING_PROXIMAL("RightRingProximal", null, null),
RIGHT_RING_INTERMEDIATE("RightRingIntermediate", null, null),
RIGHT_RING_DISTAL("RightRingDistal", null, null),
RIGHT_LITTLE_PROXIMAL("RightLittleProximal", null, null),
RIGHT_LITTLE_INTERMEDIATE("RightLittleIntermediate", null, null),
RIGHT_LITTLE_DISTAL("RightLittleDistal", null, null),
LEFT_THUMB_PROXIMAL("LeftThumbProximal", BoneType.LEFT_THUMB_PROXIMAL, TrackerPosition.LEFT_THUMB_PROXIMAL),
LEFT_THUMB_INTERMEDIATE("LeftThumbIntermediate", BoneType.LEFT_THUMB_INTERMEDIATE, TrackerPosition.LEFT_THUMB_INTERMEDIATE),
LEFT_THUMB_DISTAL("LeftThumbDistal", BoneType.LEFT_THUMB_DISTAL, TrackerPosition.LEFT_THUMB_DISTAL),
LEFT_INDEX_PROXIMAL("LeftIndexProximal", BoneType.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_INDEX_PROXIMAL),
LEFT_INDEX_INTERMEDIATE("LeftIndexIntermediate", BoneType.LEFT_INDEX_INTERMEDIATE, TrackerPosition.LEFT_INDEX_INTERMEDIATE),
LEFT_INDEX_DISTAL("LeftIndexDistal", BoneType.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_INDEX_DISTAL),
LEFT_MIDDLE_PROXIMAL("LeftMiddleProximal", BoneType.LEFT_MIDDLE_PROXIMAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL),
LEFT_MIDDLE_INTERMEDIATE("LeftMiddleIntermediate", BoneType.LEFT_MIDDLE_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE),
LEFT_MIDDLE_DISTAL("LeftMiddleDistal", BoneType.LEFT_MIDDLE_DISTAL, TrackerPosition.LEFT_MIDDLE_DISTAL),
LEFT_RING_PROXIMAL("LeftRingProximal", BoneType.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_RING_PROXIMAL),
LEFT_RING_INTERMEDIATE("LeftRingIntermediate", BoneType.LEFT_RING_INTERMEDIATE, TrackerPosition.LEFT_RING_INTERMEDIATE),
LEFT_RING_DISTAL("LeftRingDistal", BoneType.LEFT_RING_DISTAL, TrackerPosition.LEFT_RING_DISTAL),
LEFT_LITTLE_PROXIMAL("LeftLittleProximal", BoneType.LEFT_LITTLE_PROXIMAL, TrackerPosition.LEFT_LITTLE_PROXIMAL),
LEFT_LITTLE_INTERMEDIATE("LeftLittleIntermediate", BoneType.LEFT_LITTLE_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_INTERMEDIATE),
LEFT_LITTLE_DISTAL("LeftLittleDistal", BoneType.LEFT_LITTLE_DISTAL, TrackerPosition.LEFT_LITTLE_DISTAL),
RIGHT_THUMB_PROXIMAL("RightThumbProximal", BoneType.RIGHT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_PROXIMAL),
RIGHT_THUMB_INTERMEDIATE("RightThumbIntermediate", BoneType.RIGHT_THUMB_INTERMEDIATE, TrackerPosition.RIGHT_THUMB_INTERMEDIATE),
RIGHT_THUMB_DISTAL("RightThumbDistal", BoneType.RIGHT_THUMB_DISTAL, TrackerPosition.RIGHT_THUMB_DISTAL),
RIGHT_INDEX_PROXIMAL("RightIndexProximal", BoneType.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_INDEX_PROXIMAL),
RIGHT_INDEX_INTERMEDIATE("RightIndexIntermediate", BoneType.RIGHT_INDEX_INTERMEDIATE, TrackerPosition.RIGHT_INDEX_INTERMEDIATE),
RIGHT_INDEX_DISTAL("RightIndexDistal", BoneType.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_INDEX_DISTAL),
RIGHT_MIDDLE_PROXIMAL("RightMiddleProximal", BoneType.RIGHT_MIDDLE_PROXIMAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL),
RIGHT_MIDDLE_INTERMEDIATE("RightMiddleIntermediate", BoneType.RIGHT_MIDDLE_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE),
RIGHT_MIDDLE_DISTAL("RightMiddleDistal", BoneType.RIGHT_MIDDLE_DISTAL, TrackerPosition.RIGHT_MIDDLE_DISTAL),
RIGHT_RING_PROXIMAL("RightRingProximal", BoneType.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_RING_PROXIMAL),
RIGHT_RING_INTERMEDIATE("RightRingIntermediate", BoneType.RIGHT_RING_INTERMEDIATE, TrackerPosition.RIGHT_RING_INTERMEDIATE),
RIGHT_RING_DISTAL("RightRingDistal", BoneType.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_RING_DISTAL),
RIGHT_LITTLE_PROXIMAL("RightLittleProximal", BoneType.RIGHT_LITTLE_PROXIMAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL),
RIGHT_LITTLE_INTERMEDIATE("RightLittleIntermediate", BoneType.RIGHT_LITTLE_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE),
RIGHT_LITTLE_DISTAL("RightLittleDistal", BoneType.RIGHT_LITTLE_DISTAL, TrackerPosition.RIGHT_LITTLE_DISTAL),
LAST_BONE("LastBone", null, null),
;
@@ -76,5 +76,107 @@ enum class UnityBone(
@JvmStatic
fun getByStringVal(stringVal: String): UnityBone? = byStringVal[stringVal.lowercase()]
/**
* Returns the bone on the opposite limb, or the original bone if
* it not a limb bone.
*/
fun tryGetOppositeArmBone(bone: UnityBone): UnityBone = when (bone) {
LEFT_SHOULDER -> RIGHT_SHOULDER
LEFT_UPPER_ARM -> RIGHT_UPPER_ARM
LEFT_LOWER_ARM -> RIGHT_LOWER_ARM
LEFT_HAND -> RIGHT_HAND
RIGHT_SHOULDER -> LEFT_SHOULDER
RIGHT_UPPER_ARM -> LEFT_UPPER_ARM
RIGHT_LOWER_ARM -> LEFT_LOWER_ARM
RIGHT_HAND -> LEFT_HAND
LEFT_UPPER_LEG -> RIGHT_UPPER_LEG
LEFT_LOWER_LEG -> RIGHT_LOWER_LEG
LEFT_FOOT -> RIGHT_FOOT
RIGHT_UPPER_LEG -> LEFT_UPPER_LEG
RIGHT_LOWER_LEG -> LEFT_LOWER_LEG
RIGHT_FOOT -> LEFT_FOOT
LEFT_THUMB_PROXIMAL -> RIGHT_THUMB_PROXIMAL
LEFT_THUMB_INTERMEDIATE -> RIGHT_THUMB_INTERMEDIATE
LEFT_THUMB_DISTAL -> RIGHT_THUMB_DISTAL
LEFT_INDEX_PROXIMAL -> RIGHT_INDEX_PROXIMAL
LEFT_INDEX_INTERMEDIATE -> RIGHT_INDEX_INTERMEDIATE
LEFT_INDEX_DISTAL -> RIGHT_INDEX_DISTAL
LEFT_MIDDLE_PROXIMAL -> RIGHT_MIDDLE_PROXIMAL
LEFT_MIDDLE_INTERMEDIATE -> RIGHT_MIDDLE_INTERMEDIATE
LEFT_MIDDLE_DISTAL -> RIGHT_MIDDLE_DISTAL
LEFT_RING_PROXIMAL -> RIGHT_RING_PROXIMAL
LEFT_RING_INTERMEDIATE -> RIGHT_RING_INTERMEDIATE
LEFT_RING_DISTAL -> RIGHT_RING_DISTAL
LEFT_LITTLE_PROXIMAL -> RIGHT_LITTLE_PROXIMAL
LEFT_LITTLE_INTERMEDIATE -> RIGHT_LITTLE_INTERMEDIATE
LEFT_LITTLE_DISTAL -> RIGHT_LITTLE_DISTAL
RIGHT_THUMB_PROXIMAL -> LEFT_THUMB_PROXIMAL
RIGHT_THUMB_INTERMEDIATE -> LEFT_THUMB_INTERMEDIATE
RIGHT_THUMB_DISTAL -> LEFT_THUMB_DISTAL
RIGHT_INDEX_PROXIMAL -> LEFT_INDEX_PROXIMAL
RIGHT_INDEX_INTERMEDIATE -> LEFT_INDEX_INTERMEDIATE
RIGHT_INDEX_DISTAL -> LEFT_INDEX_DISTAL
RIGHT_MIDDLE_PROXIMAL -> LEFT_MIDDLE_PROXIMAL
RIGHT_MIDDLE_INTERMEDIATE -> LEFT_MIDDLE_INTERMEDIATE
RIGHT_MIDDLE_DISTAL -> LEFT_MIDDLE_DISTAL
RIGHT_RING_PROXIMAL -> LEFT_RING_PROXIMAL
RIGHT_RING_INTERMEDIATE -> LEFT_RING_INTERMEDIATE
RIGHT_RING_DISTAL -> LEFT_RING_DISTAL
RIGHT_LITTLE_PROXIMAL -> LEFT_LITTLE_PROXIMAL
RIGHT_LITTLE_INTERMEDIATE -> LEFT_LITTLE_INTERMEDIATE
RIGHT_LITTLE_DISTAL -> LEFT_LITTLE_DISTAL
else -> bone
}
/**
* Returns true if the bone is part of the left arm (incl. fingers, excl. shoulder)
*/
fun isLeftArmBone(bone: UnityBone): Boolean = bone == LEFT_UPPER_ARM || bone == LEFT_LOWER_ARM || bone == LEFT_HAND ||
bone == LEFT_THUMB_PROXIMAL || bone == LEFT_THUMB_INTERMEDIATE || bone == LEFT_THUMB_DISTAL ||
bone == LEFT_INDEX_PROXIMAL || bone == LEFT_INDEX_INTERMEDIATE || bone == LEFT_INDEX_DISTAL ||
bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_MIDDLE_INTERMEDIATE || bone == LEFT_MIDDLE_DISTAL ||
bone == LEFT_RING_PROXIMAL || bone == LEFT_RING_INTERMEDIATE || bone == LEFT_RING_DISTAL ||
bone == LEFT_LITTLE_PROXIMAL || bone == LEFT_LITTLE_INTERMEDIATE || bone == LEFT_LITTLE_DISTAL
/**
* Returns true if the bone is part of the right arm (incl. fingers, excl. shoulder)
*/
fun isRightArmBone(bone: UnityBone): Boolean = bone == RIGHT_UPPER_ARM || bone == RIGHT_LOWER_ARM || bone == RIGHT_HAND ||
bone == RIGHT_THUMB_PROXIMAL || bone == RIGHT_THUMB_INTERMEDIATE || bone == RIGHT_THUMB_DISTAL ||
bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_INDEX_INTERMEDIATE || bone == RIGHT_INDEX_DISTAL ||
bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_MIDDLE_INTERMEDIATE || bone == RIGHT_MIDDLE_DISTAL ||
bone == RIGHT_RING_PROXIMAL || bone == RIGHT_RING_INTERMEDIATE || bone == RIGHT_RING_DISTAL ||
bone == RIGHT_LITTLE_PROXIMAL || bone == RIGHT_LITTLE_INTERMEDIATE || bone == RIGHT_LITTLE_DISTAL
/**
* Returns true if the bone is the left upper arm or proximal left finger bone
*/
fun isLeftStartOfArmOrFingerBone(bone: UnityBone): Boolean = bone == LEFT_UPPER_ARM || bone == LEFT_THUMB_PROXIMAL ||
bone == LEFT_INDEX_PROXIMAL || bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_RING_PROXIMAL || bone == LEFT_LITTLE_PROXIMAL
/**
* Returns true if the bone is the right upper arm or proximal right finger bone
*/
fun isRightStartOfArmOrFingerBone(bone: UnityBone): Boolean = bone == RIGHT_UPPER_ARM || bone == RIGHT_THUMB_PROXIMAL ||
bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_RING_PROXIMAL || bone == RIGHT_LITTLE_PROXIMAL
/**
* Returns true if the bone is part of the left fingers
*/
fun isLeftFingerBone(bone: UnityBone): Boolean = bone == LEFT_THUMB_PROXIMAL || bone == LEFT_THUMB_INTERMEDIATE || bone == LEFT_THUMB_DISTAL ||
bone == LEFT_INDEX_PROXIMAL || bone == LEFT_INDEX_INTERMEDIATE || bone == LEFT_INDEX_DISTAL ||
bone == LEFT_MIDDLE_PROXIMAL || bone == LEFT_MIDDLE_INTERMEDIATE || bone == LEFT_MIDDLE_DISTAL ||
bone == LEFT_RING_PROXIMAL || bone == LEFT_RING_INTERMEDIATE || bone == LEFT_RING_DISTAL ||
bone == LEFT_LITTLE_PROXIMAL || bone == LEFT_LITTLE_INTERMEDIATE || bone == LEFT_LITTLE_DISTAL
/**
* Returns true if the bone part of the right fingers
*/
fun isRightFingerBone(bone: UnityBone): Boolean = bone == RIGHT_THUMB_PROXIMAL || bone == RIGHT_THUMB_INTERMEDIATE || bone == RIGHT_THUMB_DISTAL ||
bone == RIGHT_INDEX_PROXIMAL || bone == RIGHT_INDEX_INTERMEDIATE || bone == RIGHT_INDEX_DISTAL ||
bone == RIGHT_MIDDLE_PROXIMAL || bone == RIGHT_MIDDLE_INTERMEDIATE || bone == RIGHT_MIDDLE_DISTAL ||
bone == RIGHT_RING_PROXIMAL || bone == RIGHT_RING_INTERMEDIATE || bone == RIGHT_RING_DISTAL ||
bone == RIGHT_LITTLE_PROXIMAL || bone == RIGHT_LITTLE_INTERMEDIATE || bone == RIGHT_LITTLE_DISTAL
}
}

View File

@@ -345,13 +345,13 @@ class VMCHandler(
oscBundle.addPacket(OSCMessage("/VMC/Ext/Root/Pos", oscArgs.clone()))
for (unityBone in UnityBone.entries) {
if (unityBone.boneType == null) continue
// Get opposite bone if tracking must be mirrored
val boneType = (if (mirrorTracking) tryGetOppositeArmBone(unityBone) else unityBone).boneType
val boneType = (if (mirrorTracking) UnityBone.tryGetOppositeArmBone(unityBone) else unityBone).boneType
if (boneType == null) continue
// Get SlimeVR bone
val bone = humanPoseManager.getBone(boneType!!)
val bone = humanPoseManager.getBone(boneType)
// Update unity hierarchy from bone's global rotation
val boneRotation = if (mirrorTracking) {
@@ -384,20 +384,28 @@ class VMCHandler(
}
// Update Unity skeleton
outputUnityArmature!!.update()
outputUnityArmature?.update()
// Add Unity humanoid bones transforms
for (bone in UnityBone.entries) {
if (bone.boneType != null &&
!(humanPoseManager.isTrackingLeftArmFromController && isLeftArmUnityBone(bone)) &&
!(humanPoseManager.isTrackingRightArmFromController && isRightArmUnityBone(bone))
for (unityBone in UnityBone.entries) {
// Don't send bones for which we don't have an equivalent
// Don't send fingers if we don't have any tracker for them
// Don't send arm bones if we're tracking from the controller
if (unityBone.boneType != null &&
(!UnityBone.isLeftFingerBone(unityBone) || humanPoseManager.skeleton.hasLeftFingerTracker || (mirrorTracking && humanPoseManager.skeleton.hasRightFingerTracker)) &&
(!UnityBone.isRightFingerBone(unityBone) || humanPoseManager.skeleton.hasRightFingerTracker || (mirrorTracking && humanPoseManager.skeleton.hasLeftFingerTracker)) &&
!(humanPoseManager.isTrackingLeftArmFromController && (UnityBone.isLeftArmBone(unityBone) || unityBone == UnityBone.LEFT_SHOULDER)) &&
!(humanPoseManager.isTrackingRightArmFromController && (UnityBone.isRightArmBone(unityBone) || unityBone == UnityBone.RIGHT_SHOULDER))
) {
oscArgs.clear()
oscArgs.add(bone.stringVal)
addTransformToArgs(
outputUnityArmature!!.getLocalTranslationForBone(bone),
outputUnityArmature!!.getLocalRotationForBone(bone),
)
oscArgs.add(unityBone.stringVal)
outputUnityArmature?.let {
addTransformToArgs(
it.getLocalTranslationForBone(unityBone),
it.getLocalRotationForBone(unityBone),
)
}
oscBundle.addPacket(OSCMessage("/VMC/Ext/Bone/Pos", oscArgs.clone()))
}
}
@@ -491,32 +499,6 @@ class VMCHandler(
oscArgs.add(-rot.w)
}
/**
* Returns the bone on the opposite limb, or the original bone if
* it not a limb bone.
*/
private fun tryGetOppositeArmBone(bone: UnityBone): UnityBone = when (bone) {
UnityBone.LEFT_SHOULDER -> UnityBone.RIGHT_SHOULDER
UnityBone.LEFT_UPPER_ARM -> UnityBone.RIGHT_UPPER_ARM
UnityBone.LEFT_LOWER_ARM -> UnityBone.RIGHT_LOWER_ARM
UnityBone.LEFT_HAND -> UnityBone.RIGHT_HAND
UnityBone.RIGHT_SHOULDER -> UnityBone.LEFT_SHOULDER
UnityBone.RIGHT_UPPER_ARM -> UnityBone.LEFT_UPPER_ARM
UnityBone.RIGHT_LOWER_ARM -> UnityBone.LEFT_LOWER_ARM
UnityBone.RIGHT_HAND -> UnityBone.LEFT_HAND
UnityBone.LEFT_UPPER_LEG -> UnityBone.RIGHT_UPPER_LEG
UnityBone.LEFT_LOWER_LEG -> UnityBone.RIGHT_LOWER_LEG
UnityBone.LEFT_FOOT -> UnityBone.RIGHT_FOOT
UnityBone.RIGHT_UPPER_LEG -> UnityBone.LEFT_UPPER_LEG
UnityBone.RIGHT_LOWER_LEG -> UnityBone.LEFT_LOWER_LEG
UnityBone.RIGHT_FOOT -> UnityBone.LEFT_FOOT
else -> bone
}
private fun isLeftArmUnityBone(bone: UnityBone): Boolean = bone == UnityBone.LEFT_SHOULDER || bone == UnityBone.LEFT_UPPER_ARM || bone == UnityBone.LEFT_LOWER_ARM || bone == UnityBone.LEFT_HAND
private fun isRightArmUnityBone(bone: UnityBone): Boolean = bone == UnityBone.RIGHT_SHOULDER || bone == UnityBone.RIGHT_UPPER_ARM || bone == UnityBone.RIGHT_LOWER_ARM || bone == UnityBone.RIGHT_HAND
override fun getOscSender(): OSCPortOut = oscSender!!
override fun getPortOut(): Int = lastPortOut

View File

@@ -39,7 +39,37 @@ public enum BoneType {
LEFT_HAND(BodyPart.LEFT_HAND),
RIGHT_HAND(BodyPart.RIGHT_HAND),
LEFT_HAND_TRACKER,
RIGHT_HAND_TRACKER;
RIGHT_HAND_TRACKER,
LEFT_THUMB_PROXIMAL(BodyPart.LEFT_THUMB_PROXIMAL),
LEFT_THUMB_INTERMEDIATE(BodyPart.LEFT_THUMB_INTERMEDIATE),
LEFT_THUMB_DISTAL(BodyPart.LEFT_THUMB_DISTAL),
LEFT_INDEX_PROXIMAL(BodyPart.LEFT_INDEX_PROXIMAL),
LEFT_INDEX_INTERMEDIATE(BodyPart.LEFT_INDEX_INTERMEDIATE),
LEFT_INDEX_DISTAL(BodyPart.LEFT_INDEX_DISTAL),
LEFT_MIDDLE_PROXIMAL(BodyPart.LEFT_MIDDLE_PROXIMAL),
LEFT_MIDDLE_INTERMEDIATE(BodyPart.LEFT_MIDDLE_INTERMEDIATE),
LEFT_MIDDLE_DISTAL(BodyPart.LEFT_MIDDLE_DISTAL),
LEFT_RING_PROXIMAL(BodyPart.LEFT_RING_PROXIMAL),
LEFT_RING_INTERMEDIATE(BodyPart.LEFT_RING_INTERMEDIATE),
LEFT_RING_DISTAL(BodyPart.LEFT_RING_DISTAL),
LEFT_LITTLE_PROXIMAL(BodyPart.LEFT_LITTLE_PROXIMAL),
LEFT_LITTLE_INTERMEDIATE(BodyPart.LEFT_LITTLE_INTERMEDIATE),
LEFT_LITTLE_DISTAL(BodyPart.LEFT_LITTLE_DISTAL),
RIGHT_THUMB_PROXIMAL(BodyPart.RIGHT_THUMB_PROXIMAL),
RIGHT_THUMB_INTERMEDIATE(BodyPart.RIGHT_THUMB_INTERMEDIATE),
RIGHT_THUMB_DISTAL(BodyPart.RIGHT_THUMB_DISTAL),
RIGHT_INDEX_PROXIMAL(BodyPart.RIGHT_INDEX_PROXIMAL),
RIGHT_INDEX_INTERMEDIATE(BodyPart.RIGHT_INDEX_INTERMEDIATE),
RIGHT_INDEX_DISTAL(BodyPart.RIGHT_INDEX_DISTAL),
RIGHT_MIDDLE_PROXIMAL(BodyPart.RIGHT_MIDDLE_PROXIMAL),
RIGHT_MIDDLE_INTERMEDIATE(BodyPart.RIGHT_MIDDLE_INTERMEDIATE),
RIGHT_MIDDLE_DISTAL(BodyPart.RIGHT_MIDDLE_DISTAL),
RIGHT_RING_PROXIMAL(BodyPart.RIGHT_RING_PROXIMAL),
RIGHT_RING_INTERMEDIATE(BodyPart.RIGHT_RING_INTERMEDIATE),
RIGHT_RING_DISTAL(BodyPart.RIGHT_RING_DISTAL),
RIGHT_LITTLE_PROXIMAL(BodyPart.RIGHT_LITTLE_PROXIMAL),
RIGHT_LITTLE_INTERMEDIATE(BodyPart.RIGHT_LITTLE_INTERMEDIATE),
RIGHT_LITTLE_DISTAL(BodyPart.RIGHT_LITTLE_DISTAL);
public static final BoneType[] values = values();

View File

@@ -287,6 +287,51 @@ class SkeletonConfigManager(
0f,
)
BoneType.LEFT_THUMB_PROXIMAL, BoneType.LEFT_THUMB_INTERMEDIATE, BoneType.LEFT_THUMB_DISTAL,
BoneType.RIGHT_THUMB_PROXIMAL, BoneType.RIGHT_THUMB_INTERMEDIATE, BoneType.RIGHT_THUMB_DISTAL,
-> setNodeOffset(
nodeOffset,
0f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.2f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.1f,
)
BoneType.LEFT_INDEX_PROXIMAL, BoneType.LEFT_INDEX_INTERMEDIATE, BoneType.LEFT_INDEX_DISTAL,
BoneType.RIGHT_INDEX_PROXIMAL, BoneType.RIGHT_INDEX_INTERMEDIATE, BoneType.RIGHT_INDEX_DISTAL,
-> setNodeOffset(
nodeOffset,
0f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.25f,
0f,
)
BoneType.LEFT_MIDDLE_PROXIMAL, BoneType.LEFT_MIDDLE_INTERMEDIATE, BoneType.LEFT_MIDDLE_DISTAL,
BoneType.RIGHT_MIDDLE_PROXIMAL, BoneType.RIGHT_MIDDLE_INTERMEDIATE, BoneType.RIGHT_MIDDLE_DISTAL,
-> setNodeOffset(
nodeOffset,
0f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.3f,
0f,
)
BoneType.LEFT_RING_PROXIMAL, BoneType.LEFT_RING_INTERMEDIATE, BoneType.LEFT_RING_DISTAL,
BoneType.RIGHT_RING_PROXIMAL, BoneType.RIGHT_RING_INTERMEDIATE, BoneType.RIGHT_RING_DISTAL,
-> setNodeOffset(
nodeOffset,
0f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.28f,
0f,
)
BoneType.LEFT_LITTLE_PROXIMAL, BoneType.LEFT_LITTLE_INTERMEDIATE, BoneType.LEFT_LITTLE_DISTAL,
BoneType.RIGHT_LITTLE_PROXIMAL, BoneType.RIGHT_LITTLE_INTERMEDIATE, BoneType.RIGHT_LITTLE_DISTAL,
-> setNodeOffset(
nodeOffset,
0f,
-getOffset(SkeletonConfigOffsets.HAND_Y) * 0.2f,
0f,
)
else -> {}
}
}

View File

@@ -61,6 +61,38 @@ class HumanSkeleton(
val leftHandBone = Bone(BoneType.LEFT_HAND)
val rightHandBone = Bone(BoneType.RIGHT_HAND)
// Finger bones
val leftThumbProximalBone = Bone(BoneType.LEFT_THUMB_PROXIMAL)
val leftThumbIntermediateBone = Bone(BoneType.LEFT_THUMB_INTERMEDIATE)
val leftThumbDistalBone = Bone(BoneType.LEFT_THUMB_DISTAL)
val leftIndexProximalBone = Bone(BoneType.LEFT_INDEX_PROXIMAL)
val leftIndexIntermediateBone = Bone(BoneType.LEFT_INDEX_INTERMEDIATE)
val leftIndexDistalBone = Bone(BoneType.LEFT_INDEX_DISTAL)
val leftMiddleProximalBone = Bone(BoneType.LEFT_MIDDLE_PROXIMAL)
val leftMiddleIntermediateBone = Bone(BoneType.LEFT_MIDDLE_INTERMEDIATE)
val leftMiddleDistalBone = Bone(BoneType.LEFT_MIDDLE_DISTAL)
val leftRingProximalBone = Bone(BoneType.LEFT_RING_PROXIMAL)
val leftRingIntermediateBone = Bone(BoneType.LEFT_RING_INTERMEDIATE)
val leftRingDistalBone = Bone(BoneType.LEFT_RING_DISTAL)
val leftLittleProximalBone = Bone(BoneType.LEFT_LITTLE_PROXIMAL)
val leftLittleIntermediateBone = Bone(BoneType.LEFT_LITTLE_INTERMEDIATE)
val leftLittleDistalBone = Bone(BoneType.LEFT_LITTLE_DISTAL)
val rightThumbProximalBone = Bone(BoneType.RIGHT_THUMB_PROXIMAL)
val rightThumbIntermediateBone = Bone(BoneType.RIGHT_THUMB_INTERMEDIATE)
val rightThumbDistalBone = Bone(BoneType.RIGHT_THUMB_DISTAL)
val rightIndexProximalBone = Bone(BoneType.RIGHT_INDEX_PROXIMAL)
val rightIndexIntermediateBone = Bone(BoneType.RIGHT_INDEX_INTERMEDIATE)
val rightIndexDistalBone = Bone(BoneType.RIGHT_INDEX_DISTAL)
val rightMiddleProximalBone = Bone(BoneType.RIGHT_MIDDLE_PROXIMAL)
val rightMiddleIntermediateBone = Bone(BoneType.RIGHT_MIDDLE_INTERMEDIATE)
val rightMiddleDistalBone = Bone(BoneType.RIGHT_MIDDLE_DISTAL)
val rightRingProximalBone = Bone(BoneType.RIGHT_RING_PROXIMAL)
val rightRingIntermediateBone = Bone(BoneType.RIGHT_RING_INTERMEDIATE)
val rightRingDistalBone = Bone(BoneType.RIGHT_RING_DISTAL)
val rightLittleProximalBone = Bone(BoneType.RIGHT_LITTLE_PROXIMAL)
val rightLittleIntermediateBone = Bone(BoneType.RIGHT_LITTLE_INTERMEDIATE)
val rightLittleDistalBone = Bone(BoneType.RIGHT_LITTLE_DISTAL)
// Tracker bones
val headTrackerBone = Bone(BoneType.HEAD_TRACKER)
val chestTrackerBone = Bone(BoneType.CHEST_TRACKER)
@@ -77,12 +109,10 @@ class HumanSkeleton(
// Buffers
var hasSpineTracker = false
var hasKneeTrackers = false
var hasLeftLegTracker = false
var hasRightLegTracker = false
var hasLeftFootTracker = false
var hasRightFootTracker = false
var hasLeftArmTracker = false
var hasRightArmTracker = false
var hasLeftFingerTracker = false
var hasRightFingerTracker = false
// Input trackers
var headTracker: Tracker? by Delegates.observable(null) { _, old, new ->
@@ -110,6 +140,36 @@ class HumanSkeleton(
var rightHandTracker: Tracker? = null
var leftShoulderTracker: Tracker? = null
var rightShoulderTracker: Tracker? = null
var leftThumbProximalTracker: Tracker? = null
var leftThumbIntermediateTracker: Tracker? = null
var leftThumbDistalTracker: Tracker? = null
var leftIndexProximalTracker: Tracker? = null
var leftIndexIntermediateTracker: Tracker? = null
var leftIndexDistalTracker: Tracker? = null
var leftMiddleProximalTracker: Tracker? = null
var leftMiddleIntermediateTracker: Tracker? = null
var leftMiddleDistalTracker: Tracker? = null
var leftRingProximalTracker: Tracker? = null
var leftRingIntermediateTracker: Tracker? = null
var leftRingDistalTracker: Tracker? = null
var leftLittleProximalTracker: Tracker? = null
var leftLittleIntermediateTracker: Tracker? = null
var leftLittleDistalTracker: Tracker? = null
var rightThumbProximalTracker: Tracker? = null
var rightThumbIntermediateTracker: Tracker? = null
var rightThumbDistalTracker: Tracker? = null
var rightIndexProximalTracker: Tracker? = null
var rightIndexIntermediateTracker: Tracker? = null
var rightIndexDistalTracker: Tracker? = null
var rightMiddleProximalTracker: Tracker? = null
var rightMiddleIntermediateTracker: Tracker? = null
var rightMiddleDistalTracker: Tracker? = null
var rightRingProximalTracker: Tracker? = null
var rightRingIntermediateTracker: Tracker? = null
var rightRingDistalTracker: Tracker? = null
var rightLittleProximalTracker: Tracker? = null
var rightLittleIntermediateTracker: Tracker? = null
var rightLittleDistalTracker: Tracker? = null
// Output trackers
var computedHeadTracker: Tracker? = null
@@ -259,24 +319,63 @@ class HumanSkeleton(
rightLowerArmBone.attachChild(rightHandBone)
rightHandBone.attachChild(rightHandTrackerBone)
}
// Fingers
leftHandBone.attachChild(leftThumbProximalBone)
leftThumbProximalBone.attachChild(leftThumbIntermediateBone)
leftThumbIntermediateBone.attachChild(leftThumbDistalBone)
leftHandBone.attachChild(leftIndexProximalBone)
leftIndexProximalBone.attachChild(leftIndexIntermediateBone)
leftIndexIntermediateBone.attachChild(leftIndexDistalBone)
leftHandBone.attachChild(leftMiddleProximalBone)
leftMiddleProximalBone.attachChild(leftMiddleIntermediateBone)
leftMiddleIntermediateBone.attachChild(leftMiddleDistalBone)
leftHandBone.attachChild(leftRingProximalBone)
leftRingProximalBone.attachChild(leftRingIntermediateBone)
leftRingIntermediateBone.attachChild(leftRingDistalBone)
leftHandBone.attachChild(leftLittleProximalBone)
leftLittleProximalBone.attachChild(leftLittleIntermediateBone)
leftLittleIntermediateBone.attachChild(leftLittleDistalBone)
rightHandBone.attachChild(rightThumbProximalBone)
rightThumbProximalBone.attachChild(rightThumbIntermediateBone)
rightThumbIntermediateBone.attachChild(rightThumbDistalBone)
rightHandBone.attachChild(rightIndexProximalBone)
rightIndexProximalBone.attachChild(rightIndexIntermediateBone)
rightIndexIntermediateBone.attachChild(rightIndexDistalBone)
rightHandBone.attachChild(rightMiddleProximalBone)
rightMiddleProximalBone.attachChild(rightMiddleIntermediateBone)
rightMiddleIntermediateBone.attachChild(rightMiddleDistalBone)
rightHandBone.attachChild(rightRingProximalBone)
rightRingProximalBone.attachChild(rightRingIntermediateBone)
rightRingIntermediateBone.attachChild(rightRingDistalBone)
rightHandBone.attachChild(rightLittleProximalBone)
rightLittleProximalBone.attachChild(rightLittleIntermediateBone)
rightLittleIntermediateBone.attachChild(rightLittleDistalBone)
}
/**
* Set input trackers from a list
*/
fun setTrackersFromList(trackers: List<Tracker>) {
// Head
headTracker = getTrackerForSkeleton(trackers, TrackerPosition.HEAD)
neckTracker = getTrackerForSkeleton(trackers, TrackerPosition.NECK)
// Spine
upperChestTracker = getTrackerForSkeleton(trackers, TrackerPosition.UPPER_CHEST)
chestTracker = getTrackerForSkeleton(trackers, TrackerPosition.CHEST)
waistTracker = getTrackerForSkeleton(trackers, TrackerPosition.WAIST)
hipTracker = getTrackerForSkeleton(trackers, TrackerPosition.HIP)
// Legs
leftUpperLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_UPPER_LEG)
leftLowerLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LOWER_LEG)
leftFootTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_FOOT)
rightUpperLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_UPPER_LEG)
rightLowerLegTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LOWER_LEG)
rightFootTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_FOOT)
// Arms
leftLowerArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LOWER_ARM)
rightLowerArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LOWER_ARM)
leftUpperArmTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_UPPER_ARM)
@@ -286,15 +385,53 @@ class HumanSkeleton(
leftShoulderTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_SHOULDER)
rightShoulderTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_SHOULDER)
// Check for specific conditions and store them in booleans.
// Fingers
leftThumbProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_PROXIMAL)
leftThumbIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_INTERMEDIATE)
leftThumbDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_THUMB_DISTAL)
leftIndexProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_PROXIMAL)
leftIndexIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_INTERMEDIATE)
leftIndexDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_INDEX_DISTAL)
leftMiddleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_PROXIMAL)
leftMiddleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE)
leftMiddleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_MIDDLE_DISTAL)
leftRingProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_PROXIMAL)
leftRingIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_INTERMEDIATE)
leftRingDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_RING_DISTAL)
leftLittleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_PROXIMAL)
leftLittleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_INTERMEDIATE)
leftLittleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.LEFT_LITTLE_DISTAL)
rightThumbProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_PROXIMAL)
rightThumbIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_INTERMEDIATE)
rightThumbDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_THUMB_DISTAL)
rightIndexProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_PROXIMAL)
rightIndexIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_INTERMEDIATE)
rightIndexDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_INDEX_DISTAL)
rightMiddleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_PROXIMAL)
rightMiddleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE)
rightMiddleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_MIDDLE_DISTAL)
rightRingProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_PROXIMAL)
rightRingIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_INTERMEDIATE)
rightRingDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_RING_DISTAL)
rightLittleProximalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_PROXIMAL)
rightLittleIntermediateTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE)
rightLittleDistalTracker = getTrackerForSkeleton(trackers, TrackerPosition.RIGHT_LITTLE_DISTAL)
// Check for specific conditions and cache them
hasSpineTracker = upperChestTracker != null || chestTracker != null || waistTracker != null || hipTracker != null
hasKneeTrackers = leftUpperLegTracker != null && rightUpperLegTracker != null
hasLeftLegTracker = leftUpperLegTracker != null || leftLowerLegTracker != null || leftFootTracker != null
hasRightLegTracker = rightUpperLegTracker != null || rightLowerLegTracker != null || rightFootTracker != null
hasLeftFootTracker = leftFootTracker != null
hasRightFootTracker = rightFootTracker != null
hasLeftArmTracker = leftLowerArmTracker != null || leftUpperArmTracker != null
hasRightArmTracker = rightLowerArmTracker != null || rightUpperArmTracker != null
hasLeftFingerTracker = leftThumbProximalTracker != null || leftThumbIntermediateTracker != null || leftThumbDistalTracker != null ||
leftIndexProximalTracker != null || leftIndexIntermediateTracker != null || leftIndexDistalTracker != null ||
leftMiddleProximalTracker != null || leftMiddleIntermediateTracker != null || leftMiddleDistalTracker != null ||
leftRingProximalTracker != null || leftRingIntermediateTracker != null || leftRingDistalTracker != null ||
leftLittleProximalTracker != null || leftLittleIntermediateTracker != null || leftLittleDistalTracker != null
hasRightFingerTracker = rightThumbProximalTracker != null || rightThumbIntermediateTracker != null || rightThumbDistalTracker != null ||
rightIndexProximalTracker != null || rightIndexIntermediateTracker != null || rightIndexDistalTracker != null ||
rightMiddleProximalTracker != null || rightMiddleIntermediateTracker != null || rightMiddleDistalTracker != null ||
rightRingProximalTracker != null || rightRingIntermediateTracker != null || rightRingDistalTracker != null ||
rightLittleProximalTracker != null || rightLittleIntermediateTracker != null || rightLittleDistalTracker != null
// Rebuilds the arm skeleton nodes attachments
assembleSkeletonArms(true)
@@ -394,6 +531,7 @@ class HumanSkeleton(
// Spine
updateSpineTransforms()
// Left leg
updateLegTransforms(
leftUpperLegBone,
@@ -405,6 +543,7 @@ class HumanSkeleton(
leftLowerLegTracker,
leftFootTracker,
)
// Right leg
updateLegTransforms(
rightUpperLegBone,
@@ -416,6 +555,7 @@ class HumanSkeleton(
rightLowerLegTracker,
rightFootTracker,
)
// Left arm
updateArmTransforms(
isTrackingLeftArmFromController,
@@ -430,6 +570,7 @@ class HumanSkeleton(
leftLowerArmTracker,
leftHandTracker,
)
// Right arm
updateArmTransforms(
isTrackingRightArmFromController,
@@ -444,6 +585,116 @@ class HumanSkeleton(
rightLowerArmTracker,
rightHandTracker,
)
// Left thumb
updateFingerTransforms(
leftHandBone.getGlobalRotation(),
leftThumbProximalBone,
leftThumbIntermediateBone,
leftThumbDistalBone,
leftThumbProximalTracker,
leftThumbIntermediateTracker,
leftThumbDistalTracker,
)
// Left index
updateFingerTransforms(
leftHandBone.getGlobalRotation(),
leftIndexProximalBone,
leftIndexIntermediateBone,
leftIndexDistalBone,
leftIndexProximalTracker,
leftIndexIntermediateTracker,
leftIndexDistalTracker,
)
// Left middle
updateFingerTransforms(
leftHandBone.getGlobalRotation(),
leftMiddleProximalBone,
leftMiddleIntermediateBone,
leftMiddleDistalBone,
leftMiddleProximalTracker,
leftMiddleIntermediateTracker,
leftMiddleDistalTracker,
)
// Left ring
updateFingerTransforms(
leftHandBone.getGlobalRotation(),
leftRingProximalBone,
leftRingIntermediateBone,
leftRingDistalBone,
leftRingProximalTracker,
leftRingIntermediateTracker,
leftRingDistalTracker,
)
// Left little
updateFingerTransforms(
leftHandBone.getGlobalRotation(),
leftLittleProximalBone,
leftLittleIntermediateBone,
leftLittleDistalBone,
leftLittleProximalTracker,
leftLittleIntermediateTracker,
leftLittleDistalTracker,
)
// Right thumb
updateFingerTransforms(
rightHandBone.getGlobalRotation(),
rightThumbProximalBone,
rightThumbIntermediateBone,
rightThumbDistalBone,
rightThumbProximalTracker,
rightThumbIntermediateTracker,
rightThumbDistalTracker,
)
// Right index
updateFingerTransforms(
rightHandBone.getGlobalRotation(),
rightIndexProximalBone,
rightIndexIntermediateBone,
rightIndexDistalBone,
rightIndexProximalTracker,
rightIndexIntermediateTracker,
rightIndexDistalTracker,
)
// Right middle
updateFingerTransforms(
rightHandBone.getGlobalRotation(),
rightMiddleProximalBone,
rightMiddleIntermediateBone,
rightMiddleDistalBone,
rightMiddleProximalTracker,
rightMiddleIntermediateTracker,
rightMiddleDistalTracker,
)
// Right ring
updateFingerTransforms(
rightHandBone.getGlobalRotation(),
rightRingProximalBone,
rightRingIntermediateBone,
rightRingDistalBone,
rightRingProximalTracker,
rightRingIntermediateTracker,
rightRingDistalTracker,
)
// Right little
updateFingerTransforms(
rightHandBone.getGlobalRotation(),
rightLittleProximalBone,
rightLittleIntermediateBone,
rightLittleDistalBone,
rightLittleProximalTracker,
rightLittleIntermediateTracker,
rightLittleDistalTracker,
)
}
/**
@@ -767,6 +1018,46 @@ class HumanSkeleton(
}
}
/**
* Update a finger's 3 bones' transforms
*/
private fun updateFingerTransforms(
handRotation: Quaternion,
proximalBone: Bone,
intermediateBone: Bone,
distalBone: Bone,
proximalTracker: Tracker?,
intermediateTracker: Tracker?,
distalTracker: Tracker?,
) {
if (distalTracker == null && intermediateTracker == null && proximalTracker == null) {
// Set fingers' rotations to the hand's if no finger tracker
proximalBone.setRotation(handRotation)
intermediateBone.setRotation(handRotation)
distalBone.setRotation(handRotation)
}
// Note: we use interpQ instead of interpR in order to slerp over 180 degrees.
// Start of finger
proximalTracker?.let {
proximalBone.setRotation(it.getRotation())
if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(it.getRotation(), 2.12f))
if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(it.getRotation(), 3.03f))
}
// Middle of finger
intermediateTracker?.let {
if (proximalTracker == null) proximalBone.setRotation(handRotation.interpQ(it.getRotation(), 0.47f))
intermediateBone.setRotation(it.getRotation())
if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(it.getRotation(), 1.43f))
}
// Tip of finger
distalTracker?.let {
if (proximalTracker == null && intermediateTracker == null) proximalBone.setRotation(handRotation.interpQ(it.getRotation(), 0.33f))
if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(it.getRotation(), 0.7f))
distalBone.setRotation(it.getRotation())
}
}
/**
* Rotates the first Quaternion to match its yaw and roll to the rotation of
* the second Quaternion
@@ -959,6 +1250,36 @@ class HumanSkeleton(
BoneType.RIGHT_HAND -> rightHandBone
BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone
BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone
BoneType.LEFT_THUMB_PROXIMAL -> leftThumbProximalBone
BoneType.LEFT_THUMB_INTERMEDIATE -> leftThumbIntermediateBone
BoneType.LEFT_THUMB_DISTAL -> leftThumbDistalBone
BoneType.LEFT_INDEX_PROXIMAL -> leftIndexProximalBone
BoneType.LEFT_INDEX_INTERMEDIATE -> leftIndexIntermediateBone
BoneType.LEFT_INDEX_DISTAL -> leftIndexDistalBone
BoneType.LEFT_MIDDLE_PROXIMAL -> leftMiddleProximalBone
BoneType.LEFT_MIDDLE_INTERMEDIATE -> leftMiddleIntermediateBone
BoneType.LEFT_MIDDLE_DISTAL -> leftMiddleDistalBone
BoneType.LEFT_RING_PROXIMAL -> leftRingProximalBone
BoneType.LEFT_RING_INTERMEDIATE -> leftRingIntermediateBone
BoneType.LEFT_RING_DISTAL -> leftRingDistalBone
BoneType.LEFT_LITTLE_PROXIMAL -> leftLittleProximalBone
BoneType.LEFT_LITTLE_INTERMEDIATE -> leftLittleIntermediateBone
BoneType.LEFT_LITTLE_DISTAL -> leftLittleDistalBone
BoneType.RIGHT_THUMB_PROXIMAL -> rightThumbProximalBone
BoneType.RIGHT_THUMB_INTERMEDIATE -> rightThumbIntermediateBone
BoneType.RIGHT_THUMB_DISTAL -> rightThumbDistalBone
BoneType.RIGHT_INDEX_PROXIMAL -> rightIndexProximalBone
BoneType.RIGHT_INDEX_INTERMEDIATE -> rightIndexIntermediateBone
BoneType.RIGHT_INDEX_DISTAL -> rightIndexDistalBone
BoneType.RIGHT_MIDDLE_PROXIMAL -> rightMiddleProximalBone
BoneType.RIGHT_MIDDLE_INTERMEDIATE -> rightMiddleIntermediateBone
BoneType.RIGHT_MIDDLE_DISTAL -> rightMiddleDistalBone
BoneType.RIGHT_RING_PROXIMAL -> rightRingProximalBone
BoneType.RIGHT_RING_INTERMEDIATE -> rightRingIntermediateBone
BoneType.RIGHT_RING_DISTAL -> rightRingDistalBone
BoneType.RIGHT_LITTLE_PROXIMAL -> rightLittleProximalBone
BoneType.RIGHT_LITTLE_INTERMEDIATE -> rightLittleIntermediateBone
BoneType.RIGHT_LITTLE_DISTAL -> rightLittleDistalBone
}
/**
@@ -988,6 +1309,36 @@ class HumanSkeleton(
rightLowerArmBone,
leftHandBone,
rightHandBone,
leftThumbProximalBone,
leftThumbIntermediateBone,
leftThumbDistalBone,
leftIndexProximalBone,
leftIndexIntermediateBone,
leftIndexDistalBone,
leftMiddleProximalBone,
leftMiddleIntermediateBone,
leftMiddleDistalBone,
leftRingProximalBone,
leftRingIntermediateBone,
leftRingDistalBone,
leftLittleProximalBone,
leftLittleIntermediateBone,
leftLittleDistalBone,
rightThumbProximalBone,
rightThumbIntermediateBone,
rightThumbDistalBone,
rightIndexProximalBone,
rightIndexIntermediateBone,
rightIndexDistalBone,
rightMiddleProximalBone,
rightMiddleIntermediateBone,
rightMiddleDistalBone,
rightRingProximalBone,
rightRingIntermediateBone,
rightRingDistalBone,
rightLittleProximalBone,
rightLittleIntermediateBone,
rightLittleDistalBone,
)
/**
@@ -1007,6 +1358,36 @@ class HumanSkeleton(
rightHandBone,
leftHandTrackerBone,
rightHandTrackerBone,
leftThumbProximalBone,
leftThumbIntermediateBone,
leftThumbDistalBone,
leftIndexProximalBone,
leftIndexIntermediateBone,
leftIndexDistalBone,
leftMiddleProximalBone,
leftMiddleIntermediateBone,
leftMiddleDistalBone,
leftRingProximalBone,
leftRingIntermediateBone,
leftRingDistalBone,
leftLittleProximalBone,
leftLittleIntermediateBone,
leftLittleDistalBone,
rightThumbProximalBone,
rightThumbIntermediateBone,
rightThumbDistalBone,
rightIndexProximalBone,
rightIndexIntermediateBone,
rightIndexDistalBone,
rightMiddleProximalBone,
rightMiddleIntermediateBone,
rightMiddleDistalBone,
rightRingProximalBone,
rightRingIntermediateBone,
rightRingDistalBone,
rightLittleProximalBone,
rightLittleIntermediateBone,
rightLittleDistalBone,
)
val hmdHeight: Float
@@ -1053,6 +1434,36 @@ class HumanSkeleton(
rightHandTracker,
leftShoulderTracker,
rightShoulderTracker,
leftThumbProximalTracker,
leftThumbIntermediateTracker,
leftThumbDistalTracker,
leftIndexProximalTracker,
leftIndexIntermediateTracker,
leftIndexDistalTracker,
leftMiddleProximalTracker,
leftMiddleIntermediateTracker,
leftMiddleDistalTracker,
leftRingProximalTracker,
leftRingIntermediateTracker,
leftRingDistalTracker,
leftLittleProximalTracker,
leftLittleIntermediateTracker,
leftLittleDistalTracker,
rightThumbProximalTracker,
rightThumbIntermediateTracker,
rightThumbDistalTracker,
rightIndexProximalTracker,
rightIndexIntermediateTracker,
rightIndexDistalTracker,
rightMiddleProximalTracker,
rightMiddleIntermediateTracker,
rightMiddleDistalTracker,
rightRingProximalTracker,
rightRingIntermediateTracker,
rightRingDistalTracker,
rightLittleProximalTracker,
rightLittleIntermediateTracker,
rightLittleDistalTracker,
)
fun resetTrackersFull(resetSourceName: String?) {

View File

@@ -319,12 +319,12 @@ class Tracker @JvmOverloads constructor(
* it too much should be avoided for performance reasons.
*/
fun getRotation(): Quaternion {
var rot = if (allowFiltering && filteringHandler.enabled) {
var rot = if (allowFiltering && filteringHandler.filteringEnabled) {
// Get filtered rotation
filteringHandler.getFilteredRotation()
} else {
// Get unfiltered rotation
_rotation
filteringHandler.getTrackedRotation()
}
// Reset if needed and is not computed and internal
@@ -351,12 +351,12 @@ class Tracker @JvmOverloads constructor(
* This is used for debugging/visualizing tracker data
*/
fun getIdentityAdjustedRotation(): Quaternion {
var rot = if (filteringHandler.enabled) {
var rot = if (filteringHandler.filteringEnabled) {
// Get filtered rotation
filteringHandler.getFilteredRotation()
} else {
// Get unfiltered rotation
_rotation
filteringHandler.getTrackedRotation()
}
// Reset if needed or is a computed tracker besides head
@@ -372,7 +372,7 @@ class Tracker @JvmOverloads constructor(
* Gets the raw (unadjusted) rotation of the tracker.
* If this is an IMU, this will be the raw sensor rotation.
*/
fun getRawRotation(): Quaternion = _rotation
fun getRawRotation() = _rotation
/**
* Sets the raw (unadjusted) rotation of the tracker.
@@ -406,4 +406,11 @@ class Tracker @JvmOverloads constructor(
*/
val tps: Float
get() = timer.averageFPS
/**
* Call when doing a full reset to reset the tracking of rotations >180 degrees
*/
fun resetFilteringQuats() {
filteringHandler.resetQuats(_rotation)
}
}

View File

@@ -12,8 +12,9 @@ import io.github.axisangles.ktmath.Quaternion
*/
class TrackerFilteringHandler {
private var movingAverage: QuaternionMovingAverage? = null
var enabled = false
private var filteringMovingAverage: QuaternionMovingAverage? = null
private var trackingMovingAverage = QuaternionMovingAverage(TrackerFilters.NONE)
var filteringEnabled = false
/**
* Reads/loads filtering settings from given config
@@ -21,15 +22,15 @@ class TrackerFilteringHandler {
fun readFilteringConfig(config: FiltersConfig, currentRawRotation: Quaternion) {
val type = TrackerFilters.getByConfigkey(config.type)
if (type == TrackerFilters.SMOOTHING || type == TrackerFilters.PREDICTION) {
movingAverage = QuaternionMovingAverage(
filteringMovingAverage = QuaternionMovingAverage(
type,
config.amount,
currentRawRotation,
)
enabled = true
filteringEnabled = true
} else {
movingAverage = null
enabled = false
filteringMovingAverage = null
filteringEnabled = false
}
}
@@ -37,18 +38,33 @@ class TrackerFilteringHandler {
* Update the moving average to make it smooth
*/
fun update() {
movingAverage?.update()
trackingMovingAverage.update()
filteringMovingAverage?.update()
}
/**
* Updates the latest rotation
*/
fun dataTick(currentRawRotation: Quaternion) {
movingAverage?.addQuaternion(currentRawRotation)
trackingMovingAverage.addQuaternion(currentRawRotation)
filteringMovingAverage?.addQuaternion(currentRawRotation)
}
/**
* Call when doing a full reset to reset the tracking of rotations >180 degrees
*/
fun resetQuats(currentRawRotation: Quaternion) {
trackingMovingAverage.resetQuats(currentRawRotation)
filteringMovingAverage?.resetQuats(currentRawRotation)
}
/**
* Gets the tracked rotation from the moving average (allows >180 degrees)
*/
fun getTrackedRotation() = trackingMovingAverage.filteredQuaternion
/**
* Get the filtered rotation from the moving average
*/
fun getFilteredRotation(): Quaternion = movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
fun getFilteredRotation() = filteringMovingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
}

View File

@@ -36,16 +36,64 @@ enum class TrackerPosition(
RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_HAND, BodyPart.RIGHT_HAND),
LEFT_SHOULDER("body:left_shoulder", TrackerRole.LEFT_SHOULDER, BodyPart.LEFT_SHOULDER),
RIGHT_SHOULDER("body:right_shoulder", TrackerRole.RIGHT_SHOULDER, BodyPart.RIGHT_SHOULDER),
LEFT_THUMB_PROXIMAL("body:left_thumb_proximal", null, BodyPart.LEFT_THUMB_PROXIMAL),
LEFT_THUMB_INTERMEDIATE("body:left_thumb_intermediate", null, BodyPart.LEFT_THUMB_INTERMEDIATE),
LEFT_THUMB_DISTAL("body:left_thumb_distal", null, BodyPart.LEFT_THUMB_DISTAL),
LEFT_INDEX_PROXIMAL("body:left_index_proximal", null, BodyPart.LEFT_INDEX_PROXIMAL),
LEFT_INDEX_INTERMEDIATE("body:left_index_intermediate", null, BodyPart.LEFT_INDEX_INTERMEDIATE),
LEFT_INDEX_DISTAL("body:left_index_distal", null, BodyPart.LEFT_INDEX_DISTAL),
LEFT_MIDDLE_PROXIMAL("body:left_middle_proximal", null, BodyPart.LEFT_MIDDLE_PROXIMAL),
LEFT_MIDDLE_INTERMEDIATE("body:left_middle_intermediate", null, BodyPart.LEFT_MIDDLE_INTERMEDIATE),
LEFT_MIDDLE_DISTAL("body:left_middle_distal", null, BodyPart.LEFT_MIDDLE_DISTAL),
LEFT_RING_PROXIMAL("body:left_ring_proximal", null, BodyPart.LEFT_RING_PROXIMAL),
LEFT_RING_INTERMEDIATE("body:left_ring_intermediate", null, BodyPart.LEFT_RING_INTERMEDIATE),
LEFT_RING_DISTAL("body:left_ring_distal", null, BodyPart.LEFT_RING_DISTAL),
LEFT_LITTLE_PROXIMAL("body:left_little_proximal", null, BodyPart.LEFT_LITTLE_PROXIMAL),
LEFT_LITTLE_INTERMEDIATE("body:left_little_intermediate", null, BodyPart.LEFT_LITTLE_INTERMEDIATE),
LEFT_LITTLE_DISTAL("body:left_little_distal", null, BodyPart.LEFT_LITTLE_DISTAL),
RIGHT_THUMB_PROXIMAL("body:right_thumb_proximal", null, BodyPart.RIGHT_THUMB_PROXIMAL),
RIGHT_THUMB_INTERMEDIATE("body:right_thumb_intermediate", null, BodyPart.RIGHT_THUMB_INTERMEDIATE),
RIGHT_THUMB_DISTAL("body:right_thumb_distal", null, BodyPart.RIGHT_THUMB_DISTAL),
RIGHT_INDEX_PROXIMAL("body:right_index_proximal", null, BodyPart.RIGHT_INDEX_PROXIMAL),
RIGHT_INDEX_INTERMEDIATE("body:right_index_intermediate", null, BodyPart.RIGHT_INDEX_INTERMEDIATE),
RIGHT_INDEX_DISTAL("body:right_index_distal", null, BodyPart.RIGHT_INDEX_DISTAL),
RIGHT_MIDDLE_PROXIMAL("body:right_middle_proximal", null, BodyPart.RIGHT_MIDDLE_PROXIMAL),
RIGHT_MIDDLE_INTERMEDIATE("body:right_middle_intermediate", null, BodyPart.RIGHT_MIDDLE_INTERMEDIATE),
RIGHT_MIDDLE_DISTAL("body:right_middle_distal", null, BodyPart.RIGHT_MIDDLE_DISTAL),
RIGHT_RING_PROXIMAL("body:right_ring_proximal", null, BodyPart.RIGHT_RING_PROXIMAL),
RIGHT_RING_INTERMEDIATE("body:right_ring_intermediate", null, BodyPart.RIGHT_RING_INTERMEDIATE),
RIGHT_RING_DISTAL("body:right_ring_distal", null, BodyPart.RIGHT_RING_DISTAL),
RIGHT_LITTLE_PROXIMAL("body:right_little_proximal", null, BodyPart.RIGHT_LITTLE_PROXIMAL),
RIGHT_LITTLE_INTERMEDIATE("body:right_little_intermediate", null, BodyPart.RIGHT_LITTLE_INTERMEDIATE),
RIGHT_LITTLE_DISTAL("body:right_little_distal", null, BodyPart.RIGHT_LITTLE_DISTAL),
;
/**
* Returns the default mounting orientation for the body part
*/
fun defaultMounting(): Quaternion = when (this) {
LEFT_LOWER_ARM, LEFT_HAND -> Quaternion.SLIMEVR.LEFT
RIGHT_LOWER_ARM, RIGHT_HAND -> Quaternion.SLIMEVR.RIGHT
LEFT_LOWER_ARM, LEFT_HAND,
LEFT_INDEX_PROXIMAL, LEFT_INDEX_INTERMEDIATE,
LEFT_INDEX_DISTAL, LEFT_MIDDLE_PROXIMAL,
LEFT_MIDDLE_INTERMEDIATE, LEFT_MIDDLE_DISTAL,
LEFT_RING_PROXIMAL, LEFT_RING_INTERMEDIATE,
LEFT_RING_DISTAL, LEFT_LITTLE_PROXIMAL,
LEFT_LITTLE_INTERMEDIATE, LEFT_LITTLE_DISTAL,
-> Quaternion.SLIMEVR.LEFT
RIGHT_LOWER_ARM, RIGHT_HAND,
RIGHT_INDEX_PROXIMAL, RIGHT_INDEX_INTERMEDIATE,
RIGHT_INDEX_DISTAL, RIGHT_MIDDLE_PROXIMAL,
RIGHT_MIDDLE_INTERMEDIATE, RIGHT_MIDDLE_DISTAL,
RIGHT_RING_PROXIMAL, RIGHT_RING_INTERMEDIATE,
RIGHT_RING_DISTAL, RIGHT_LITTLE_PROXIMAL,
RIGHT_LITTLE_INTERMEDIATE, RIGHT_LITTLE_DISTAL,
-> Quaternion.SLIMEVR.RIGHT
LEFT_UPPER_ARM, LEFT_LOWER_LEG -> Quaternion.SLIMEVR.FRONT_LEFT
RIGHT_UPPER_ARM, RIGHT_LOWER_LEG -> Quaternion.SLIMEVR.FRONT_RIGHT
else -> Quaternion.SLIMEVR.FRONT
}

View File

@@ -214,9 +214,9 @@ class TrackerResetsHandler(val tracker: Tracker) {
*/
fun resetFull(reference: Quaternion) {
// Adjust for T-Pose (down)
tposeDownFix = if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
tposeDownFix = if (((isLeftArmTracker() || isLeftFingerTracker()) && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
EulerAngles(EulerOrder.YZX, 0f, 0f, -FastMath.HALF_PI).toQuaternion()
} else if ((isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
} else if (((isRightArmTracker() || isRightFingerTracker()) && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
EulerAngles(EulerOrder.YZX, 0f, 0f, FastMath.HALF_PI).toQuaternion()
} else {
Quaternion.IDENTITY
@@ -280,6 +280,8 @@ class TrackerResetsHandler(val tracker: Tracker) {
VRServer.instance.statusSystem.removeStatus(this.tracker.lastResetStatus)
this.tracker.lastResetStatus = 0u
}
tracker.resetFilteringQuats()
}
/**
@@ -314,6 +316,8 @@ class TrackerResetsHandler(val tracker: Tracker) {
this.tracker.statusResetRecently = false
this.tracker.lastResetStatus = 0u
}
tracker.resetFilteringQuats()
}
/**
@@ -338,15 +342,17 @@ class TrackerResetsHandler(val tracker: Tracker) {
// Calculate the yaw angle using tan
var yawAngle = atan2(rotVector.x, rotVector.z)
// Adjust for T-Pose
// Adjust for T-Pose and fingers
if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN) ||
(isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP)
(isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP) ||
isLeftFingerTracker()
) {
// Tracker goes right
yawAngle -= FastMath.HALF_PI
}
if ((isLeftArmTracker() && armsResetMode == ArmsResetModes.TPOSE_UP) ||
(isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)
(isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN) ||
isRightFingerTracker()
) {
// Tracker goes left
yawAngle += FastMath.HALF_PI
@@ -365,6 +371,8 @@ class TrackerResetsHandler(val tracker: Tracker) {
// save mounting reset
if (saveMountingReset) tracker.saveMountingResetOrientation(mountRotFix)
tracker.resetFilteringQuats()
}
fun clearMounting() {
@@ -573,4 +581,46 @@ class TrackerResetsHandler(val tracker: Tracker) {
}
return false
}
private fun isLeftFingerTracker(): Boolean {
tracker.trackerPosition?.let {
return it == TrackerPosition.LEFT_THUMB_PROXIMAL ||
it == TrackerPosition.LEFT_THUMB_INTERMEDIATE ||
it == TrackerPosition.LEFT_THUMB_DISTAL ||
it == TrackerPosition.LEFT_INDEX_PROXIMAL ||
it == TrackerPosition.LEFT_INDEX_INTERMEDIATE ||
it == TrackerPosition.LEFT_INDEX_DISTAL ||
it == TrackerPosition.LEFT_MIDDLE_PROXIMAL ||
it == TrackerPosition.LEFT_MIDDLE_INTERMEDIATE ||
it == TrackerPosition.LEFT_MIDDLE_DISTAL ||
it == TrackerPosition.LEFT_RING_PROXIMAL ||
it == TrackerPosition.LEFT_RING_INTERMEDIATE ||
it == TrackerPosition.LEFT_RING_DISTAL ||
it == TrackerPosition.LEFT_LITTLE_PROXIMAL ||
it == TrackerPosition.LEFT_LITTLE_INTERMEDIATE ||
it == TrackerPosition.LEFT_LITTLE_DISTAL
}
return false
}
private fun isRightFingerTracker(): Boolean {
tracker.trackerPosition?.let {
return it == TrackerPosition.RIGHT_THUMB_PROXIMAL ||
it == TrackerPosition.RIGHT_THUMB_INTERMEDIATE ||
it == TrackerPosition.RIGHT_THUMB_DISTAL ||
it == TrackerPosition.RIGHT_INDEX_PROXIMAL ||
it == TrackerPosition.RIGHT_INDEX_INTERMEDIATE ||
it == TrackerPosition.RIGHT_INDEX_DISTAL ||
it == TrackerPosition.RIGHT_MIDDLE_PROXIMAL ||
it == TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE ||
it == TrackerPosition.RIGHT_MIDDLE_DISTAL ||
it == TrackerPosition.RIGHT_RING_PROXIMAL ||
it == TrackerPosition.RIGHT_RING_INTERMEDIATE ||
it == TrackerPosition.RIGHT_RING_DISTAL ||
it == TrackerPosition.RIGHT_LITTLE_PROXIMAL ||
it == TrackerPosition.RIGHT_LITTLE_INTERMEDIATE ||
it == TrackerPosition.RIGHT_LITTLE_DISTAL
}
return false
}
}