mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Compare commits
49 Commits
feat_flash
...
oldflex
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f30ee3bcce | ||
|
|
e3a99cdcf5 | ||
|
|
704f2157ee | ||
|
|
95acdaf8c2 | ||
|
|
09c51fb5df | ||
|
|
d69399d471 | ||
|
|
eac4341201 | ||
|
|
8c0c49f57a | ||
|
|
79fcdb3cd9 | ||
|
|
96651ddeb7 | ||
|
|
ee0161575b | ||
|
|
82df10be7c | ||
|
|
5489abd754 | ||
|
|
9c0463cc86 | ||
|
|
25bcb84ade | ||
|
|
c3b76ab242 | ||
|
|
7ea2767227 | ||
|
|
5264e3908d | ||
|
|
d4fb3847a9 | ||
|
|
a0afa4ca94 | ||
|
|
c2ee25e9d1 | ||
|
|
d5997ffb99 | ||
|
|
6dca92387b | ||
|
|
0a18a1d8e6 | ||
|
|
0b890c197b | ||
|
|
81157f3c18 | ||
|
|
beaf83f097 | ||
|
|
4e02562e05 | ||
|
|
708cab9ea8 | ||
|
|
d29109887b | ||
|
|
bbd63923dc | ||
|
|
14293f4842 | ||
|
|
0d4921e099 | ||
|
|
c7aa6451f2 | ||
|
|
a80ce41079 | ||
|
|
6c289c91f4 | ||
|
|
79e7b19a12 | ||
|
|
2f095aeb73 | ||
|
|
7909a1b312 | ||
|
|
d404fb5a88 | ||
|
|
938f708c89 | ||
|
|
e1d9a2cd5b | ||
|
|
98c7db658f | ||
|
|
75cd829a5d | ||
|
|
c4a4016d45 | ||
|
|
0191b421bb | ||
|
|
1ec642f3b5 | ||
|
|
99a2cee182 | ||
|
|
063a686efa |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -43,3 +43,6 @@ build/
|
||||
|
||||
# Ignore Android local properties
|
||||
local.properties
|
||||
|
||||
# Ignore temporary config
|
||||
vrconfig.yml.tmp
|
||||
|
||||
@@ -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
|
||||
@@ -184,6 +214,7 @@ tracker-infos-url = Tracker URL
|
||||
tracker-infos-version = Firmware Version
|
||||
tracker-infos-hardware_rev = Hardware Revision
|
||||
tracker-infos-hardware_identifier = Hardware ID
|
||||
tracker-infos-data_support = Data support
|
||||
tracker-infos-imu = IMU Sensor
|
||||
tracker-infos-board_type = Main board
|
||||
tracker-infos-network_version = Protocol Version
|
||||
|
||||
@@ -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({
|
||||
|
||||
15
gui/src/components/commons/icon/FingersIcon.tsx
Normal file
15
gui/src/components/commons/icon/FingersIcon.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -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({
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ImuType,
|
||||
MagnetometerStatus,
|
||||
RpcMessage,
|
||||
TrackerDataType,
|
||||
} from 'solarxr-protocol';
|
||||
import { useDebouncedEffect } from '@/hooks/timeout';
|
||||
import { useTrackerFromId } from '@/hooks/tracker';
|
||||
@@ -260,6 +261,16 @@ export function TrackerSettingsPage() {
|
||||
{tracker?.device?.hardwareInfo?.hardwareIdentifier || '--'}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<Typography color="secondary">
|
||||
{l10n.getString('tracker-infos-data_support')}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{tracker?.tracker.info?.dataSupport
|
||||
? TrackerDataType[tracker?.tracker.info?.dataSupport]
|
||||
: '--'}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<Typography color="secondary">
|
||||
{l10n.getString('tracker-infos-imu')}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DataFeedBuilder {
|
||||
)
|
||||
);
|
||||
|
||||
HardwareInfo.addNetworkProtocolVersion(fbb, udpDevice.firmwareBuild);
|
||||
HardwareInfo.addNetworkProtocolVersion(fbb, udpDevice.protocolVersion);
|
||||
}
|
||||
|
||||
// BRUH MOMENT
|
||||
@@ -142,6 +142,8 @@ public class DataFeedBuilder {
|
||||
TrackerInfo.addMagnetometer(fbb, tracker.getMagStatus().getSolarType());
|
||||
TrackerInfo.addIsHmd(fbb, tracker.isHmd());
|
||||
|
||||
TrackerInfo.addDataSupport(fbb, tracker.getTrackerDataType().getSolarType());
|
||||
|
||||
return TrackerInfo.endTrackerInfo(fbb);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import dev.slimevr.tracking.trackers.TrackerPosition
|
||||
import dev.slimevr.tracking.trackers.TrackerRole
|
||||
import dev.slimevr.tracking.trackers.TrackerUtils.getFirstAvailableTracker
|
||||
import dev.slimevr.tracking.trackers.TrackerUtils.getTrackerForSkeleton
|
||||
import dev.slimevr.tracking.trackers.udp.TrackerDataType
|
||||
import dev.slimevr.util.ann.VRServerThread
|
||||
import io.eiren.util.ann.ThreadSafe
|
||||
import io.eiren.util.collections.FastList
|
||||
@@ -61,6 +62,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 +110,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 +141,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 +320,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 +386,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 +532,7 @@ class HumanSkeleton(
|
||||
|
||||
// Spine
|
||||
updateSpineTransforms()
|
||||
|
||||
// Left leg
|
||||
updateLegTransforms(
|
||||
leftUpperLegBone,
|
||||
@@ -405,6 +544,7 @@ class HumanSkeleton(
|
||||
leftLowerLegTracker,
|
||||
leftFootTracker,
|
||||
)
|
||||
|
||||
// Right leg
|
||||
updateLegTransforms(
|
||||
rightUpperLegBone,
|
||||
@@ -416,6 +556,7 @@ class HumanSkeleton(
|
||||
rightLowerLegTracker,
|
||||
rightFootTracker,
|
||||
)
|
||||
|
||||
// Left arm
|
||||
updateArmTransforms(
|
||||
isTrackingLeftArmFromController,
|
||||
@@ -430,6 +571,7 @@ class HumanSkeleton(
|
||||
leftLowerArmTracker,
|
||||
leftHandTracker,
|
||||
)
|
||||
|
||||
// Right arm
|
||||
updateArmTransforms(
|
||||
isTrackingRightArmFromController,
|
||||
@@ -444,6 +586,116 @@ class HumanSkeleton(
|
||||
rightLowerArmTracker,
|
||||
rightHandTracker,
|
||||
)
|
||||
|
||||
// Left thumb
|
||||
updateFingerTransforms(
|
||||
leftHandTrackerBone.getGlobalRotation(),
|
||||
leftThumbProximalBone,
|
||||
leftThumbIntermediateBone,
|
||||
leftThumbDistalBone,
|
||||
leftThumbProximalTracker,
|
||||
leftThumbIntermediateTracker,
|
||||
leftThumbDistalTracker,
|
||||
)
|
||||
|
||||
// Left index
|
||||
updateFingerTransforms(
|
||||
leftHandTrackerBone.getGlobalRotation(),
|
||||
leftIndexProximalBone,
|
||||
leftIndexIntermediateBone,
|
||||
leftIndexDistalBone,
|
||||
leftIndexProximalTracker,
|
||||
leftIndexIntermediateTracker,
|
||||
leftIndexDistalTracker,
|
||||
)
|
||||
|
||||
// Left middle
|
||||
updateFingerTransforms(
|
||||
leftHandTrackerBone.getGlobalRotation(),
|
||||
leftMiddleProximalBone,
|
||||
leftMiddleIntermediateBone,
|
||||
leftMiddleDistalBone,
|
||||
leftMiddleProximalTracker,
|
||||
leftMiddleIntermediateTracker,
|
||||
leftMiddleDistalTracker,
|
||||
)
|
||||
|
||||
// Left ring
|
||||
updateFingerTransforms(
|
||||
leftHandTrackerBone.getGlobalRotation(),
|
||||
leftRingProximalBone,
|
||||
leftRingIntermediateBone,
|
||||
leftRingDistalBone,
|
||||
leftRingProximalTracker,
|
||||
leftRingIntermediateTracker,
|
||||
leftRingDistalTracker,
|
||||
)
|
||||
|
||||
// Left little
|
||||
updateFingerTransforms(
|
||||
leftHandTrackerBone.getGlobalRotation(),
|
||||
leftLittleProximalBone,
|
||||
leftLittleIntermediateBone,
|
||||
leftLittleDistalBone,
|
||||
leftLittleProximalTracker,
|
||||
leftLittleIntermediateTracker,
|
||||
leftLittleDistalTracker,
|
||||
)
|
||||
|
||||
// Right thumb
|
||||
updateFingerTransforms(
|
||||
rightHandTrackerBone.getGlobalRotation(),
|
||||
rightThumbProximalBone,
|
||||
rightThumbIntermediateBone,
|
||||
rightThumbDistalBone,
|
||||
rightThumbProximalTracker,
|
||||
rightThumbIntermediateTracker,
|
||||
rightThumbDistalTracker,
|
||||
)
|
||||
|
||||
// Right index
|
||||
updateFingerTransforms(
|
||||
rightHandTrackerBone.getGlobalRotation(),
|
||||
rightIndexProximalBone,
|
||||
rightIndexIntermediateBone,
|
||||
rightIndexDistalBone,
|
||||
rightIndexProximalTracker,
|
||||
rightIndexIntermediateTracker,
|
||||
rightIndexDistalTracker,
|
||||
)
|
||||
|
||||
// Right middle
|
||||
updateFingerTransforms(
|
||||
rightHandTrackerBone.getGlobalRotation(),
|
||||
rightMiddleProximalBone,
|
||||
rightMiddleIntermediateBone,
|
||||
rightMiddleDistalBone,
|
||||
rightMiddleProximalTracker,
|
||||
rightMiddleIntermediateTracker,
|
||||
rightMiddleDistalTracker,
|
||||
)
|
||||
|
||||
// Right ring
|
||||
updateFingerTransforms(
|
||||
rightHandTrackerBone.getGlobalRotation(),
|
||||
rightRingProximalBone,
|
||||
rightRingIntermediateBone,
|
||||
rightRingDistalBone,
|
||||
rightRingProximalTracker,
|
||||
rightRingIntermediateTracker,
|
||||
rightRingDistalTracker,
|
||||
)
|
||||
|
||||
// Right little
|
||||
updateFingerTransforms(
|
||||
rightHandTrackerBone.getGlobalRotation(),
|
||||
rightLittleProximalBone,
|
||||
rightLittleIntermediateBone,
|
||||
rightLittleDistalBone,
|
||||
rightLittleProximalTracker,
|
||||
rightLittleIntermediateTracker,
|
||||
rightLittleDistalTracker,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -767,6 +1019,70 @@ 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 {
|
||||
val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE ||
|
||||
it.trackerDataType == TrackerDataType.FLEX_ANGLE
|
||||
) {
|
||||
handRotation * it.getRotation()
|
||||
} else {
|
||||
it.getRotation()
|
||||
}
|
||||
|
||||
proximalBone.setRotation(fingerRot)
|
||||
if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(fingerRot, 2.12f))
|
||||
if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(fingerRot, 3.03f))
|
||||
}
|
||||
// Middle of finger
|
||||
intermediateTracker?.let {
|
||||
val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE ||
|
||||
it.trackerDataType == TrackerDataType.FLEX_ANGLE
|
||||
) {
|
||||
handRotation * it.getRotation()
|
||||
} else {
|
||||
it.getRotation()
|
||||
}
|
||||
|
||||
if (proximalTracker == null) proximalBone.setRotation(handRotation.interpQ(fingerRot, 0.47f))
|
||||
intermediateBone.setRotation(fingerRot)
|
||||
if (distalTracker == null) distalBone.setRotation(handRotation.interpQ(fingerRot, 1.43f))
|
||||
}
|
||||
// Tip of finger
|
||||
distalTracker?.let {
|
||||
val fingerRot = if (it.trackerDataType == TrackerDataType.FLEX_RESISTANCE ||
|
||||
it.trackerDataType == TrackerDataType.FLEX_ANGLE
|
||||
) {
|
||||
handRotation * it.getRotation()
|
||||
} else {
|
||||
it.getRotation()
|
||||
}
|
||||
|
||||
if (proximalTracker == null && intermediateTracker == null) proximalBone.setRotation(handRotation.interpQ(fingerRot, 0.33f))
|
||||
if (intermediateTracker == null) intermediateBone.setRotation(handRotation.interpQ(fingerRot, 0.7f))
|
||||
distalBone.setRotation(fingerRot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the first Quaternion to match its yaw and roll to the rotation of
|
||||
* the second Quaternion
|
||||
@@ -959,6 +1275,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 +1334,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 +1383,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 +1459,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?) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import dev.slimevr.config.TrackerConfig
|
||||
import dev.slimevr.tracking.trackers.TrackerPosition.Companion.getByDesignation
|
||||
import dev.slimevr.tracking.trackers.udp.IMUType
|
||||
import dev.slimevr.tracking.trackers.udp.MagnetometerStatus
|
||||
import dev.slimevr.tracking.trackers.udp.TrackerDataType
|
||||
import io.eiren.util.BufferedTimer
|
||||
import io.github.axisangles.ktmath.Quaternion
|
||||
import io.github.axisangles.ktmath.Vector3
|
||||
@@ -67,6 +68,11 @@ class Tracker @JvmOverloads constructor(
|
||||
val needsMounting: Boolean = false,
|
||||
val isHmd: Boolean = false,
|
||||
magStatus: MagnetometerStatus = MagnetometerStatus.NOT_SUPPORTED,
|
||||
/**
|
||||
* Rotation by default.
|
||||
* NOT the same as hasRotation (other data types emulate rotation)
|
||||
*/
|
||||
val trackerDataType: TrackerDataType = TrackerDataType.ROTATION,
|
||||
) {
|
||||
private val timer = BufferedTimer(1f)
|
||||
private var timeAtLastUpdate: Long = System.currentTimeMillis()
|
||||
@@ -75,6 +81,7 @@ class Tracker @JvmOverloads constructor(
|
||||
var position = Vector3.NULL
|
||||
val resetsHandler: TrackerResetsHandler = TrackerResetsHandler(this)
|
||||
val filteringHandler: TrackerFilteringHandler = TrackerFilteringHandler()
|
||||
val trackerFlexHandler: TrackerFlexHandler = TrackerFlexHandler(this)
|
||||
var batteryVoltage: Float? = null
|
||||
var batteryLevel: Float? = null
|
||||
var ping: Int? = null
|
||||
@@ -150,7 +157,7 @@ class Tracker @JvmOverloads constructor(
|
||||
|
||||
fun checkReportRequireReset() {
|
||||
if (needsReset && trackerPosition != null && lastResetStatus == 0u &&
|
||||
!status.reset && (isImu() || !statusResetRecently)
|
||||
!status.reset && (isImu() || !statusResetRecently && trackerDataType != TrackerDataType.FLEX_ANGLE)
|
||||
) {
|
||||
reportRequireReset()
|
||||
} else if (lastResetStatus != 0u && (trackerPosition == null || status.reset)) {
|
||||
@@ -319,16 +326,16 @@ 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
|
||||
if (needsReset && !(isComputed && isInternal)) {
|
||||
if (needsReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) {
|
||||
// Adjust to reset, mounting and drift compensation
|
||||
rot = resetsHandler.getReferenceAdjustedDriftRotationFrom(rot)
|
||||
}
|
||||
@@ -351,16 +358,16 @@ 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
|
||||
if (needsReset && !(isComputed && trackerPosition != TrackerPosition.HEAD)) {
|
||||
if (needsReset && !(isComputed && trackerPosition != TrackerPosition.HEAD) && trackerDataType == TrackerDataType.ROTATION) {
|
||||
// Adjust to reset and mounting
|
||||
rot = resetsHandler.getIdentityAdjustedDriftRotationFrom(rot)
|
||||
}
|
||||
@@ -372,7 +379,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.
|
||||
@@ -388,7 +395,11 @@ class Tracker @JvmOverloads constructor(
|
||||
this._acceleration = vec
|
||||
}
|
||||
|
||||
fun isImu(): Boolean = imuType != null
|
||||
/**
|
||||
* True if the raw rotation is coming directly from an IMU (no cameras or lighthouses)
|
||||
* For example, flex sensor trackers are not considered as IMU trackers (see TrackerDataType)
|
||||
*/
|
||||
fun isImu(): Boolean = imuType != null && trackerDataType == TrackerDataType.ROTATION
|
||||
|
||||
/**
|
||||
* Please don't use this and instead set it via [Device.setMag]
|
||||
@@ -406,4 +417,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
package dev.slimevr.tracking.trackers
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import io.github.axisangles.ktmath.EulerAngles
|
||||
import io.github.axisangles.ktmath.EulerOrder
|
||||
import kotlin.math.*
|
||||
|
||||
/**
|
||||
* Class handling flex sensor data (angle and resistance)
|
||||
* Resistance is expected to go up with bend by default, but a mounting reset allows the contrary
|
||||
*/
|
||||
class TrackerFlexHandler(val tracker: Tracker) {
|
||||
private var minResistance = Float.MIN_VALUE
|
||||
private var maxResistance = Float.MAX_VALUE
|
||||
|
||||
// Used to support resistance going both ways.
|
||||
// Default is higher = more bend, but can change after a full and mounting reset.
|
||||
private var lastMinResetResistance = Float.MIN_VALUE
|
||||
private var resistanceReversed = false
|
||||
private var lastResistance = 0f
|
||||
private val thumbInitialOffset = FastMath.PI / 8 // 22.5 deg
|
||||
|
||||
/**
|
||||
* Resets the min resistance from the last resistance value received.
|
||||
* Triggered from full reset
|
||||
*/
|
||||
fun resetMin() {
|
||||
minResistance = lastResistance
|
||||
lastMinResetResistance = lastResistance
|
||||
|
||||
setFlexResistance(lastResistance)
|
||||
tracker.dataTick()
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the max resistance from the last resistance value received.
|
||||
* Triggered from mounting reset
|
||||
*/
|
||||
fun resetMax() {
|
||||
// Account for the resistance being able to be reversed
|
||||
if (resistanceReversed != lastResistance < lastMinResetResistance) {
|
||||
// Switching
|
||||
resistanceReversed = lastResistance < lastMinResetResistance
|
||||
minResistance = maxResistance
|
||||
maxResistance = lastMinResetResistance
|
||||
} else {
|
||||
// Not switching
|
||||
maxResistance = lastResistance
|
||||
}
|
||||
|
||||
setFlexResistance(lastResistance)
|
||||
tracker.dataTick()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flex resistance which is then calculated into an angle
|
||||
*/
|
||||
fun setFlexResistance(resistance: Float) {
|
||||
// Dynamically calibrate the minimum resistance
|
||||
minResistance = if (minResistance == Float.MIN_VALUE) {
|
||||
resistance
|
||||
} else if (!resistanceReversed) {
|
||||
min(minResistance, resistance)
|
||||
} else {
|
||||
max(minResistance, resistance)
|
||||
}
|
||||
|
||||
// Dynamically calibrate the maximum resistance
|
||||
maxResistance = if (maxResistance == Float.MAX_VALUE) {
|
||||
resistance
|
||||
} else if (!resistanceReversed) {
|
||||
max(maxResistance, resistance)
|
||||
} else {
|
||||
min(maxResistance, resistance)
|
||||
}
|
||||
|
||||
// Get max angle
|
||||
val maxBend = getMaxAngleForTrackerPosition(tracker.trackerPosition)
|
||||
|
||||
// Get angle and set it
|
||||
val angle = if (minResistance == maxResistance) {
|
||||
// Avoid division by 0
|
||||
0f
|
||||
} else {
|
||||
maxBend * (resistance - minResistance) / (maxResistance - minResistance)
|
||||
}
|
||||
setFlexAngle(angle)
|
||||
|
||||
lastResistance = resistance
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an angle (rad) about the X axis
|
||||
*/
|
||||
fun setFlexAngle(angle: Float) {
|
||||
// Sets the rotation of the tracker by the angle about a given axis depending on
|
||||
// the tracker's TrackerPosition
|
||||
when (tracker.trackerPosition) {
|
||||
TrackerPosition.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_INDEX_INTERMEDIATE,
|
||||
TrackerPosition.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL,
|
||||
TrackerPosition.LEFT_MIDDLE_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_DISTAL,
|
||||
TrackerPosition.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_RING_INTERMEDIATE,
|
||||
TrackerPosition.LEFT_RING_DISTAL, TrackerPosition.LEFT_LITTLE_PROXIMAL,
|
||||
TrackerPosition.LEFT_LITTLE_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_DISTAL,
|
||||
TrackerPosition.RIGHT_SHOULDER,
|
||||
-> tracker.setRotation(EulerAngles(EulerOrder.YZX, 0f, 0f, angle).toQuaternion())
|
||||
|
||||
TrackerPosition.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_INDEX_INTERMEDIATE,
|
||||
TrackerPosition.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL,
|
||||
TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_DISTAL,
|
||||
TrackerPosition.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_RING_INTERMEDIATE,
|
||||
TrackerPosition.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL,
|
||||
TrackerPosition.RIGHT_LITTLE_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_DISTAL,
|
||||
TrackerPosition.LEFT_SHOULDER,
|
||||
-> tracker.setRotation(EulerAngles(EulerOrder.YZX, 0f, 0f, -angle).toQuaternion())
|
||||
|
||||
TrackerPosition.LEFT_THUMB_PROXIMAL, TrackerPosition.LEFT_THUMB_INTERMEDIATE, TrackerPosition.LEFT_THUMB_DISTAL,
|
||||
-> tracker.setRotation(EulerAngles(EulerOrder.YZX, thumbInitialOffset - angle, -angle * 0.05f, angle * 0.1f).toQuaternion())
|
||||
|
||||
TrackerPosition.RIGHT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_INTERMEDIATE, TrackerPosition.RIGHT_THUMB_DISTAL,
|
||||
-> tracker.setRotation(EulerAngles(EulerOrder.YZX, thumbInitialOffset - angle, angle * 0.05f, -angle * 0.1f).toQuaternion())
|
||||
|
||||
// Default to X axis (pitch)
|
||||
else -> tracker.setRotation(EulerAngles(EulerOrder.YZX, angle, 0f, 0f).toQuaternion())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the max angle for a TrackerPosition
|
||||
*/
|
||||
private fun getMaxAngleForTrackerPosition(trackerPosition: TrackerPosition?): Float {
|
||||
if (trackerPosition == null) return FastMath.PI // 180 degrees
|
||||
|
||||
return when (trackerPosition) {
|
||||
// 270 degrees
|
||||
TrackerPosition.LEFT_INDEX_DISTAL, TrackerPosition.LEFT_MIDDLE_DISTAL,
|
||||
TrackerPosition.LEFT_RING_DISTAL, TrackerPosition.LEFT_LITTLE_DISTAL,
|
||||
TrackerPosition.RIGHT_INDEX_DISTAL, TrackerPosition.RIGHT_MIDDLE_DISTAL,
|
||||
TrackerPosition.RIGHT_RING_DISTAL, TrackerPosition.RIGHT_LITTLE_DISTAL,
|
||||
-> FastMath.PI + FastMath.HALF_PI
|
||||
|
||||
// 202.5 degrees
|
||||
TrackerPosition.LEFT_THUMB_DISTAL, TrackerPosition.RIGHT_THUMB_DISTAL,
|
||||
-> FastMath.PI + thumbInitialOffset
|
||||
|
||||
// 180 degrees
|
||||
TrackerPosition.LEFT_INDEX_INTERMEDIATE, TrackerPosition.LEFT_MIDDLE_INTERMEDIATE,
|
||||
TrackerPosition.LEFT_RING_INTERMEDIATE, TrackerPosition.LEFT_LITTLE_INTERMEDIATE,
|
||||
TrackerPosition.RIGHT_INDEX_INTERMEDIATE, TrackerPosition.RIGHT_MIDDLE_INTERMEDIATE,
|
||||
TrackerPosition.RIGHT_RING_INTERMEDIATE, TrackerPosition.RIGHT_LITTLE_INTERMEDIATE,
|
||||
-> FastMath.PI
|
||||
|
||||
// 112.5 degrees
|
||||
TrackerPosition.LEFT_THUMB_INTERMEDIATE, TrackerPosition.RIGHT_THUMB_INTERMEDIATE,
|
||||
-> FastMath.HALF_PI + thumbInitialOffset
|
||||
|
||||
// 90 degrees
|
||||
TrackerPosition.LEFT_INDEX_PROXIMAL, TrackerPosition.LEFT_MIDDLE_PROXIMAL,
|
||||
TrackerPosition.LEFT_RING_PROXIMAL, TrackerPosition.LEFT_LITTLE_PROXIMAL,
|
||||
TrackerPosition.RIGHT_INDEX_PROXIMAL, TrackerPosition.RIGHT_MIDDLE_PROXIMAL,
|
||||
TrackerPosition.RIGHT_RING_PROXIMAL, TrackerPosition.RIGHT_LITTLE_PROXIMAL,
|
||||
-> FastMath.HALF_PI
|
||||
|
||||
// 67.5 degrees
|
||||
TrackerPosition.LEFT_THUMB_PROXIMAL, TrackerPosition.RIGHT_THUMB_PROXIMAL,
|
||||
-> FastMath.QUARTER_PI + thumbInitialOffset
|
||||
|
||||
// 45 degrees
|
||||
TrackerPosition.LEFT_SHOULDER, TrackerPosition.RIGHT_SHOULDER,
|
||||
-> FastMath.QUARTER_PI
|
||||
|
||||
// 135 degrees
|
||||
else -> FastMath.HALF_PI + FastMath.QUARTER_PI
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,39 +13,88 @@ enum class TrackerPosition(
|
||||
val designation: String,
|
||||
val trackerRole: TrackerRole?,
|
||||
val bodyPart: Int,
|
||||
val id: Int,
|
||||
) {
|
||||
// If updating BodyPart of a TrackerRole,
|
||||
// please also update SteamVRBridge#updateShareSettingsAutomatically()
|
||||
HEAD("body:head", TrackerRole.HMD, BodyPart.HEAD),
|
||||
NECK("body:neck", TrackerRole.NECK, BodyPart.NECK),
|
||||
UPPER_CHEST("body:upper_chest", TrackerRole.CHEST, BodyPart.UPPER_CHEST),
|
||||
CHEST("body:chest", null, BodyPart.CHEST),
|
||||
WAIST("body:waist", null, BodyPart.WAIST),
|
||||
HIP("body:hip", TrackerRole.WAIST, BodyPart.HIP),
|
||||
LEFT_UPPER_LEG("body:left_upper_leg", TrackerRole.LEFT_KNEE, BodyPart.LEFT_UPPER_LEG),
|
||||
RIGHT_UPPER_LEG("body:right_upper_leg", TrackerRole.RIGHT_KNEE, BodyPart.RIGHT_UPPER_LEG),
|
||||
LEFT_LOWER_LEG("body:left_lower_leg", null, BodyPart.LEFT_LOWER_LEG),
|
||||
RIGHT_LOWER_LEG("body:right_lower_leg", null, BodyPart.RIGHT_LOWER_LEG),
|
||||
LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT, BodyPart.LEFT_FOOT),
|
||||
RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT, BodyPart.RIGHT_FOOT),
|
||||
LEFT_LOWER_ARM("body:left_lower_arm", null, BodyPart.LEFT_LOWER_ARM),
|
||||
RIGHT_LOWER_ARM("body:right_lower_arm", null, BodyPart.RIGHT_LOWER_ARM),
|
||||
LEFT_UPPER_ARM("body:left_upper_arm", TrackerRole.LEFT_ELBOW, BodyPart.LEFT_UPPER_ARM),
|
||||
RIGHT_UPPER_ARM("body:right_upper_arm", TrackerRole.RIGHT_ELBOW, BodyPart.RIGHT_UPPER_ARM),
|
||||
LEFT_HAND("body:left_hand", TrackerRole.LEFT_HAND, BodyPart.LEFT_HAND),
|
||||
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),
|
||||
HEAD("body:head", TrackerRole.HMD, BodyPart.HEAD, 1),
|
||||
NECK("body:neck", TrackerRole.NECK, BodyPart.NECK, 2),
|
||||
UPPER_CHEST("body:upper_chest", TrackerRole.CHEST, BodyPart.UPPER_CHEST, 3),
|
||||
CHEST("body:chest", null, BodyPart.CHEST, 4),
|
||||
WAIST("body:waist", null, BodyPart.WAIST, 5),
|
||||
HIP("body:hip", TrackerRole.WAIST, BodyPart.HIP, 6),
|
||||
LEFT_UPPER_LEG("body:left_upper_leg", TrackerRole.LEFT_KNEE, BodyPart.LEFT_UPPER_LEG, 7),
|
||||
RIGHT_UPPER_LEG("body:right_upper_leg", TrackerRole.RIGHT_KNEE, BodyPart.RIGHT_UPPER_LEG, 8),
|
||||
LEFT_LOWER_LEG("body:left_lower_leg", null, BodyPart.LEFT_LOWER_LEG, 9),
|
||||
RIGHT_LOWER_LEG("body:right_lower_leg", null, BodyPart.RIGHT_LOWER_LEG, 10),
|
||||
LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT, BodyPart.LEFT_FOOT, 11),
|
||||
RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT, BodyPart.RIGHT_FOOT, 12),
|
||||
LEFT_LOWER_ARM("body:left_lower_arm", null, BodyPart.LEFT_LOWER_ARM, 13),
|
||||
RIGHT_LOWER_ARM("body:right_lower_arm", null, BodyPart.RIGHT_LOWER_ARM, 14),
|
||||
LEFT_UPPER_ARM("body:left_upper_arm", TrackerRole.LEFT_ELBOW, BodyPart.LEFT_UPPER_ARM, 15),
|
||||
RIGHT_UPPER_ARM("body:right_upper_arm", TrackerRole.RIGHT_ELBOW, BodyPart.RIGHT_UPPER_ARM, 16),
|
||||
LEFT_HAND("body:left_hand", TrackerRole.LEFT_HAND, BodyPart.LEFT_HAND, 17),
|
||||
RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_HAND, BodyPart.RIGHT_HAND, 18),
|
||||
LEFT_SHOULDER("body:left_shoulder", TrackerRole.LEFT_SHOULDER, BodyPart.LEFT_SHOULDER, 19),
|
||||
RIGHT_SHOULDER("body:right_shoulder", TrackerRole.RIGHT_SHOULDER, BodyPart.RIGHT_SHOULDER, 20),
|
||||
LEFT_THUMB_PROXIMAL("body:left_thumb_proximal", null, BodyPart.LEFT_THUMB_PROXIMAL, 21),
|
||||
LEFT_THUMB_INTERMEDIATE("body:left_thumb_intermediate", null, BodyPart.LEFT_THUMB_INTERMEDIATE, 22),
|
||||
LEFT_THUMB_DISTAL("body:left_thumb_distal", null, BodyPart.LEFT_THUMB_DISTAL, 23),
|
||||
LEFT_INDEX_PROXIMAL("body:left_index_proximal", null, BodyPart.LEFT_INDEX_PROXIMAL, 24),
|
||||
LEFT_INDEX_INTERMEDIATE("body:left_index_intermediate", null, BodyPart.LEFT_INDEX_INTERMEDIATE, 25),
|
||||
LEFT_INDEX_DISTAL("body:left_index_distal", null, BodyPart.LEFT_INDEX_DISTAL, 26),
|
||||
LEFT_MIDDLE_PROXIMAL("body:left_middle_proximal", null, BodyPart.LEFT_MIDDLE_PROXIMAL, 27),
|
||||
LEFT_MIDDLE_INTERMEDIATE("body:left_middle_intermediate", null, BodyPart.LEFT_MIDDLE_INTERMEDIATE, 28),
|
||||
LEFT_MIDDLE_DISTAL("body:left_middle_distal", null, BodyPart.LEFT_MIDDLE_DISTAL, 29),
|
||||
LEFT_RING_PROXIMAL("body:left_ring_proximal", null, BodyPart.LEFT_RING_PROXIMAL, 30),
|
||||
LEFT_RING_INTERMEDIATE("body:left_ring_intermediate", null, BodyPart.LEFT_RING_INTERMEDIATE, 31),
|
||||
LEFT_RING_DISTAL("body:left_ring_distal", null, BodyPart.LEFT_RING_DISTAL, 32),
|
||||
LEFT_LITTLE_PROXIMAL("body:left_little_proximal", null, BodyPart.LEFT_LITTLE_PROXIMAL, 33),
|
||||
LEFT_LITTLE_INTERMEDIATE("body:left_little_intermediate", null, BodyPart.LEFT_LITTLE_INTERMEDIATE, 34),
|
||||
LEFT_LITTLE_DISTAL("body:left_little_distal", null, BodyPart.LEFT_LITTLE_DISTAL, 35),
|
||||
RIGHT_THUMB_PROXIMAL("body:right_thumb_proximal", null, BodyPart.RIGHT_THUMB_PROXIMAL, 36),
|
||||
RIGHT_THUMB_INTERMEDIATE("body:right_thumb_intermediate", null, BodyPart.RIGHT_THUMB_INTERMEDIATE, 37),
|
||||
RIGHT_THUMB_DISTAL("body:right_thumb_distal", null, BodyPart.RIGHT_THUMB_DISTAL, 38),
|
||||
RIGHT_INDEX_PROXIMAL("body:right_index_proximal", null, BodyPart.RIGHT_INDEX_PROXIMAL, 39),
|
||||
RIGHT_INDEX_INTERMEDIATE("body:right_index_intermediate", null, BodyPart.RIGHT_INDEX_INTERMEDIATE, 40),
|
||||
RIGHT_INDEX_DISTAL("body:right_index_distal", null, BodyPart.RIGHT_INDEX_DISTAL, 41),
|
||||
RIGHT_MIDDLE_PROXIMAL("body:right_middle_proximal", null, BodyPart.RIGHT_MIDDLE_PROXIMAL, 42),
|
||||
RIGHT_MIDDLE_INTERMEDIATE("body:right_middle_intermediate", null, BodyPart.RIGHT_MIDDLE_INTERMEDIATE, 43),
|
||||
RIGHT_MIDDLE_DISTAL("body:right_middle_distal", null, BodyPart.RIGHT_MIDDLE_DISTAL, 44),
|
||||
RIGHT_RING_PROXIMAL("body:right_ring_proximal", null, BodyPart.RIGHT_RING_PROXIMAL, 45),
|
||||
RIGHT_RING_INTERMEDIATE("body:right_ring_intermediate", null, BodyPart.RIGHT_RING_INTERMEDIATE, 46),
|
||||
RIGHT_RING_DISTAL("body:right_ring_distal", null, BodyPart.RIGHT_RING_DISTAL, 47),
|
||||
RIGHT_LITTLE_PROXIMAL("body:right_little_proximal", null, BodyPart.RIGHT_LITTLE_PROXIMAL, 48),
|
||||
RIGHT_LITTLE_INTERMEDIATE("body:right_little_intermediate", null, BodyPart.RIGHT_LITTLE_INTERMEDIATE, 49),
|
||||
RIGHT_LITTLE_DISTAL("body:right_little_distal", null, BodyPart.RIGHT_LITTLE_DISTAL, 50),
|
||||
;
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
@@ -56,6 +105,7 @@ enum class TrackerPosition(
|
||||
this[position.bodyPart] = position
|
||||
}
|
||||
}
|
||||
private val byId = entries.associateBy { it.id }
|
||||
private val byDesignation = entries.associateBy { it.designation.lowercase() }
|
||||
private val byTrackerRole = entries.filter { it.trackerRole != null }.associateBy { it.trackerRole!! }
|
||||
|
||||
@@ -82,5 +132,8 @@ enum class TrackerPosition(
|
||||
|
||||
@JvmStatic
|
||||
fun getByBodyPart(bodyPart: Int): TrackerPosition? = byBodyPart[bodyPart]
|
||||
|
||||
@JvmStatic
|
||||
fun getById(id: Int): TrackerPosition? = byId[id]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.slimevr.config.ArmsResetModes
|
||||
import dev.slimevr.config.DriftCompensationConfig
|
||||
import dev.slimevr.config.ResetsConfig
|
||||
import dev.slimevr.filtering.CircularArrayList
|
||||
import dev.slimevr.tracking.trackers.udp.TrackerDataType
|
||||
import io.eiren.math.FloatMath.animateEase
|
||||
import io.github.axisangles.ktmath.EulerAngles
|
||||
import io.github.axisangles.ktmath.EulerOrder
|
||||
@@ -213,10 +214,19 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
* 0). This allows the tracker to be strapped to body at any pitch and roll.
|
||||
*/
|
||||
fun resetFull(reference: Quaternion) {
|
||||
if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) {
|
||||
tracker.trackerFlexHandler.resetMin()
|
||||
postProcessResetFull()
|
||||
return
|
||||
} else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) {
|
||||
postProcessResetFull()
|
||||
return
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -276,10 +286,16 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
|
||||
calculateDrift(oldRot)
|
||||
|
||||
postProcessResetFull()
|
||||
}
|
||||
|
||||
private fun postProcessResetFull() {
|
||||
if (this.tracker.lastResetStatus != 0u) {
|
||||
VRServer.instance.statusSystem.removeStatus(this.tracker.lastResetStatus)
|
||||
this.tracker.lastResetStatus = 0u
|
||||
}
|
||||
|
||||
tracker.resetFilteringQuats()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,6 +305,12 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
* position should be corrected in the source.
|
||||
*/
|
||||
fun resetYaw(reference: Quaternion) {
|
||||
if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE ||
|
||||
tracker.trackerDataType == TrackerDataType.FLEX_ANGLE
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Old rot for drift compensation
|
||||
val oldRot = adjustToReference(tracker.getRawRotation())
|
||||
lastResetQuaternion = oldRot
|
||||
@@ -314,6 +336,8 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
this.tracker.statusResetRecently = false
|
||||
this.tracker.lastResetStatus = 0u
|
||||
}
|
||||
|
||||
tracker.resetFilteringQuats()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +345,15 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
* and stores it in mountRotFix, and adjusts yawFix
|
||||
*/
|
||||
fun resetMounting(reference: Quaternion) {
|
||||
if (!resetMountingFeet && isFootTracker()) return
|
||||
if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) {
|
||||
tracker.trackerFlexHandler.resetMax()
|
||||
tracker.resetFilteringQuats()
|
||||
return
|
||||
} else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) {
|
||||
return
|
||||
} else if (!resetMountingFeet && isFootTracker()) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the current calibrated rotation
|
||||
var rotBuf = adjustToDrift(tracker.getRawRotation() * mountingOrientation)
|
||||
@@ -338,15 +370,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 +399,8 @@ class TrackerResetsHandler(val tracker: Tracker) {
|
||||
|
||||
// save mounting reset
|
||||
if (saveMountingReset) tracker.saveMountingResetOrientation(mountRotFix)
|
||||
|
||||
tracker.resetFilteringQuats()
|
||||
}
|
||||
|
||||
fun clearMounting() {
|
||||
@@ -573,4 +609,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,22 @@ enum class MCUType(val id: UInt) {
|
||||
}
|
||||
}
|
||||
|
||||
enum class TrackerDataType(val id: UInt) {
|
||||
ROTATION(0u),
|
||||
FLEX_RESISTANCE(1u),
|
||||
FLEX_ANGLE(2u),
|
||||
;
|
||||
|
||||
fun getSolarType(): Int = this.id.toInt()
|
||||
|
||||
companion object {
|
||||
private val byId = entries.associateBy { it.id }
|
||||
|
||||
@JvmStatic
|
||||
fun getById(id: UInt): TrackerDataType? = byId[id]
|
||||
}
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class ConfigTypeId(val v: UShort)
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ import dev.slimevr.NetworkProtocol
|
||||
import dev.slimevr.VRServer
|
||||
import dev.slimevr.config.config
|
||||
import dev.slimevr.protocol.rpc.MAG_TIMEOUT
|
||||
import dev.slimevr.tracking.trackers.Tracker
|
||||
import dev.slimevr.tracking.trackers.TrackerStatus
|
||||
import dev.slimevr.tracking.trackers.*
|
||||
import io.eiren.util.Util
|
||||
import io.eiren.util.collections.FastList
|
||||
import io.eiren.util.logging.LogManager
|
||||
@@ -87,7 +86,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
ipAddress = addr
|
||||
name = handshake.macString?.let { "udp://$it" }
|
||||
descriptiveName = "udp:/$addr"
|
||||
firmwareBuild = handshake.firmwareBuild
|
||||
protocolVersion = handshake.protocolVersion
|
||||
firmwareVersion = handshake.firmware
|
||||
connectionsByAddress[address] = this
|
||||
|
||||
@@ -97,8 +96,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
"""
|
||||
[TrackerServer] Tracker $i handed over to address $socketAddr.
|
||||
Board type: ${handshake.boardType},
|
||||
imu type: ${handshake.imuType},
|
||||
firmware: ${handshake.firmware} ($firmwareBuild),
|
||||
firmware name: ${handshake.firmware},
|
||||
protocol version: $protocolVersion,
|
||||
mac: ${handshake.macString},
|
||||
name: $name
|
||||
""".trimIndent(),
|
||||
@@ -111,7 +110,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
name = handshake.macString?.let { "udp://$it" }
|
||||
?: "udp:/$addr"
|
||||
descriptiveName = "udp:/$addr"
|
||||
firmwareBuild = handshake.firmwareBuild
|
||||
protocolVersion = handshake.protocolVersion
|
||||
firmwareVersion = handshake.firmware
|
||||
val i = connections.indexOf(this)
|
||||
LogManager
|
||||
@@ -119,8 +118,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
"""
|
||||
[TrackerServer] Tracker $i reconnected from address $socketAddr.
|
||||
Board type: ${handshake.boardType},
|
||||
imu type: ${handshake.imuType},
|
||||
firmware: ${handshake.firmware} ($firmwareBuild),
|
||||
firmware name: ${handshake.firmware},
|
||||
protocol version: $protocolVersion,
|
||||
mac: ${handshake.macString},
|
||||
name: $name
|
||||
""".trimIndent(),
|
||||
@@ -137,7 +136,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
handshake.mcuType,
|
||||
)
|
||||
VRServer.instance.deviceManager.addDevice(connection)
|
||||
connection.firmwareBuild = handshake.firmwareBuild
|
||||
connection.protocolVersion = handshake.protocolVersion
|
||||
connection.protocol = if (handshake.firmware?.isEmpty() == true) {
|
||||
// Only old owoTrack doesn't report firmware and have different packet IDs with SlimeVR
|
||||
NetworkProtocol.OWO_LEGACY
|
||||
@@ -165,18 +164,18 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
"""
|
||||
[TrackerServer] Tracker $i connected from address $socketAddr.
|
||||
Board type: ${handshake.boardType},
|
||||
imu type: ${handshake.imuType},
|
||||
firmware: ${handshake.firmware} (${connection.firmwareBuild}),
|
||||
firmware name: ${handshake.firmware},
|
||||
protocol version: ${connection.protocolVersion},
|
||||
mac: ${handshake.macString},
|
||||
name: ${connection.name}
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) {
|
||||
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.protocolVersion < 9) {
|
||||
// Set up new sensor for older firmware.
|
||||
// Firmware after 7 should send sensor status packet and sensor
|
||||
// will be created when it's received
|
||||
setUpSensor(connection, 0, handshake.imuType, 1, MagnetometerStatus.NOT_SUPPORTED)
|
||||
setUpSensor(connection, 0, handshake.imuType, 1, MagnetometerStatus.NOT_SUPPORTED, null, TrackerDataType.ROTATION)
|
||||
}
|
||||
connection
|
||||
}
|
||||
@@ -188,7 +187,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
}
|
||||
|
||||
private val mainScope = CoroutineScope(SupervisorJob())
|
||||
private fun setUpSensor(connection: UDPDevice, trackerId: Int, sensorType: IMUType, sensorStatus: Int, magStatus: MagnetometerStatus) {
|
||||
private fun setUpSensor(connection: UDPDevice, trackerId: Int, sensorType: IMUType, sensorStatus: Int, magStatus: MagnetometerStatus, trackerPosition: TrackerPosition?, trackerDataType: TrackerDataType) {
|
||||
LogManager.info("[TrackerServer] Sensor $trackerId for ${connection.name} status: $sensorStatus")
|
||||
var imuTracker = connection.getTracker(trackerId)
|
||||
if (imuTracker == null) {
|
||||
@@ -202,21 +201,22 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
VRServer.getNextLocalTrackerId(),
|
||||
connection.name + "/" + trackerId,
|
||||
"IMU Tracker $formattedHWID",
|
||||
null,
|
||||
trackerPosition,
|
||||
trackerNum = trackerId,
|
||||
hasRotation = true,
|
||||
hasAcceleration = true,
|
||||
userEditable = true,
|
||||
imuType = sensorType,
|
||||
imuType = if (trackerDataType == TrackerDataType.ROTATION) sensorType else null,
|
||||
allowFiltering = true,
|
||||
needsReset = true,
|
||||
needsMounting = true,
|
||||
usesTimeout = true,
|
||||
magStatus = magStatus,
|
||||
trackerDataType = trackerDataType,
|
||||
)
|
||||
connection.trackers[trackerId] = imuTracker
|
||||
trackersConsumer.accept(imuTracker)
|
||||
LogManager.info("[TrackerServer] Added sensor $trackerId for ${connection.name}, type $sensorType")
|
||||
LogManager.info("[TrackerServer] Added sensor $trackerId for ${connection.name}, ImuType $sensorType, DataType $trackerDataType, default TrackerPosition $trackerPosition")
|
||||
}
|
||||
val status = UDPPacket15SensorInfo.getStatus(sensorStatus)
|
||||
if (status != null) imuTracker.status = status
|
||||
@@ -479,6 +479,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
packet.sensorType,
|
||||
packet.sensorStatus,
|
||||
magStatus,
|
||||
packet.trackerPosition,
|
||||
packet.trackerDataType,
|
||||
)
|
||||
// Send ack
|
||||
bb.limit(bb.capacity())
|
||||
@@ -561,6 +563,17 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
|
||||
LogManager.info("[TrackerServer] Acknowledged config change on ${connection.descriptiveName} (${trackers.map { it.trackerNum }.joinToString()}). Config changed on ${packet.configType}")
|
||||
}
|
||||
|
||||
is UDPPacket26FlexData -> {
|
||||
tracker = connection?.getTracker(packet.sensorId)
|
||||
if (tracker == null) return
|
||||
if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) {
|
||||
tracker.trackerFlexHandler.setFlexResistance(packet.flexData)
|
||||
} else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) {
|
||||
tracker.trackerFlexHandler.setFlexAngle(packet.flexData)
|
||||
}
|
||||
tracker.dataTick()
|
||||
}
|
||||
|
||||
is UDPPacket200ProtocolChange -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class UDPDevice(
|
||||
var protocol: NetworkProtocol? = null
|
||||
|
||||
@JvmField
|
||||
var firmwareBuild = 0
|
||||
var protocolVersion = 0
|
||||
|
||||
@JvmField
|
||||
var timedOut = false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.slimevr.tracking.trackers.udp
|
||||
|
||||
import dev.slimevr.tracking.trackers.TrackerPosition
|
||||
import dev.slimevr.tracking.trackers.TrackerStatus
|
||||
import io.github.axisangles.ktmath.Quaternion
|
||||
import io.github.axisangles.ktmath.Vector3
|
||||
@@ -95,7 +96,7 @@ data class UDPPacket3Handshake(
|
||||
var boardType: BoardType = BoardType.UNKNOWN,
|
||||
var imuType: IMUType = IMUType.UNKNOWN,
|
||||
var mcuType: MCUType = MCUType.UNKNOWN,
|
||||
var firmwareBuild: Int = 0,
|
||||
var protocolVersion: Int = 0,
|
||||
var firmware: String? = null,
|
||||
var macString: String? = null,
|
||||
) : UDPPacket(3) {
|
||||
@@ -115,7 +116,7 @@ data class UDPPacket3Handshake(
|
||||
buf.int
|
||||
buf.int // IMU info
|
||||
}
|
||||
if (buf.remaining() > 3) firmwareBuild = buf.int
|
||||
if (buf.remaining() > 3) protocolVersion = buf.int
|
||||
var length = 0
|
||||
if (buf.remaining() > 0) length = buf.get().toInt()
|
||||
// firmware version length is 1 longer than
|
||||
@@ -224,6 +225,8 @@ data class UDPPacket15SensorInfo(
|
||||
var sensorStatus: Int = 0,
|
||||
var sensorType: IMUType = IMUType.UNKNOWN,
|
||||
var sensorConfig: SensorConfig? = null,
|
||||
var trackerDataType: TrackerDataType = TrackerDataType.ROTATION,
|
||||
var trackerPosition: TrackerPosition? = null,
|
||||
) : UDPPacket(15),
|
||||
SensorSpecificPacket {
|
||||
override var sensorId = 0
|
||||
@@ -231,12 +234,13 @@ data class UDPPacket15SensorInfo(
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
sensorStatus = buf.get().toInt() and 0xFF
|
||||
if (buf.remaining() > 0) {
|
||||
sensorType =
|
||||
IMUType.getById(buf.get().toUInt() and 0xFFu) ?: IMUType.UNKNOWN
|
||||
sensorType = IMUType.getById(buf.get().toUInt() and 0xFFu) ?: IMUType.UNKNOWN
|
||||
}
|
||||
if (buf.remaining() > 1) {
|
||||
sensorConfig = SensorConfig(buf.getShort().toUShort())
|
||||
}
|
||||
if (buf.remaining() > 0) trackerPosition = TrackerPosition.getById(buf.get().toInt() and 0xFF)
|
||||
if (buf.remaining() > 0) trackerDataType = TrackerDataType.getById(buf.get().toUInt() and 0xFFu) ?: TrackerDataType.ROTATION
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -378,6 +382,18 @@ data class UDPPacket25SetConfigFlag(
|
||||
}
|
||||
}
|
||||
|
||||
data class UDPPacket26FlexData(
|
||||
var flexData: Float = 0f,
|
||||
) : UDPPacket(26),
|
||||
SensorSpecificPacket {
|
||||
|
||||
override var sensorId = 0
|
||||
override fun readData(buf: ByteBuffer) {
|
||||
sensorId = buf.get().toInt() and 0xFF
|
||||
flexData = UDPUtils.getSafeBufferFloat(buf)
|
||||
}
|
||||
}
|
||||
|
||||
data class UDPPacket200ProtocolChange(
|
||||
var targetProtocol: Int = 0,
|
||||
var targetProtocolVersion: Int = 0,
|
||||
|
||||
@@ -115,6 +115,7 @@ class UDPProtocolParser {
|
||||
PACKET_USER_ACTION -> UDPPacket21UserAction()
|
||||
PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags()
|
||||
PACKET_ACK_CONFIG_CHANGE -> UDPPacket24AckConfigChange()
|
||||
PACKET_FLEX_DATA -> UDPPacket26FlexData()
|
||||
PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange()
|
||||
else -> null
|
||||
}
|
||||
@@ -150,6 +151,7 @@ class UDPProtocolParser {
|
||||
const val PACKET_ROTATION_AND_ACCELERATION = 23
|
||||
const val PACKET_ACK_CONFIG_CHANGE = 24
|
||||
const val PACKET_SET_CONFIG_FLAG = 25
|
||||
const val PACKET_FLEX_DATA = 26
|
||||
const val PACKET_BUNDLE = 100
|
||||
const val PACKET_BUNDLE_COMPACT = 101
|
||||
const val PACKET_PROTOCOL_CHANGE = 200
|
||||
|
||||
Submodule solarxr-protocol updated: 73fca6300d...f581cd5003
Reference in New Issue
Block a user