Full height for manual configuration (#1329)

Co-authored-by: lucas lelievre <loucass003@gmail.com>
This commit is contained in:
Butterscotch!
2025-03-16 10:24:22 -04:00
committed by GitHub
parent a0cedde4b7
commit 3f1a794148
8 changed files with 59 additions and 37 deletions

View File

@@ -130,14 +130,13 @@ skeleton_bone-ELBOW_OFFSET = Elbow Offset
## Tracker reset buttons
reset-reset_all = Reset all proportions
reset-reset_all_warning =
<b>Warning:</b> This will reset your proportions to being just based on your height.
reset-reset_all_warning-v2 =
<b>Warning:</b> Your proportions will be reset to defaults scaled to your configured height.
Are you sure you want to do this?
reset-reset_all_warning-reset = Reset proportions
reset-reset_all_warning-cancel = Cancel
reset-reset_all_warning_default =
<b>Warning:</b> You currently don't have your height defined, which
will make the proportions be based on a default height.
reset-reset_all_warning_default-v2 =
<b>Warning:</b> Your height has not been configured, your proportions will be reset to defaults with the default height.
Are you sure you want to do this?
reset-full = Full Reset
@@ -1078,9 +1077,10 @@ onboarding-automatic_proportions-smol_warning-cancel = Go back
onboarding-scaled_proportions-title = Scaled proportions
onboarding-scaled_proportions-description = For SlimeVR trackers to work, we need to know the length of your bones. This will use an average proportion and scale it based on your height.
onboarding-scaled_proportions-manual_height-title = Configure your height
onboarding-scaled_proportions-manual_height-description = Your headset (HMD) height should be slightly less than your full height, as headsets measure your eye height. This height will be used as a baseline for your body proportions.
onboarding-scaled_proportions-manual_height-description-v2 = This height will be used as a baseline for your body proportions.
onboarding-scaled_proportions-manual_height-missing_steamvr = SteamVR is not currently connected to SlimeVR, so measurements can't be based on your headset. <b>Proceed at your own risk or check the docs!</b>
onboarding-scaled_proportions-manual_height-height = Your headset height is
onboarding-scaled_proportions-manual_height-height-v2 = Your full height is
onboarding-scaled_proportions-manual_height-estimated_height = Your estimated headset height is:
onboarding-scaled_proportions-manual_height-next_step = Continue and save
## Tracker scaled proportions reset

View File

@@ -55,8 +55,8 @@ export function ProportionsResetModal({
<Localized
id={
usingDefaultHeight
? 'reset-reset_all_warning_default'
: 'reset-reset_all_warning'
? 'reset-reset_all_warning_default-v2'
: 'reset-reset_all_warning-v2'
}
elems={{ b: <b></b> }}
>

View File

@@ -12,7 +12,7 @@ import { Typography } from '@/components/commons/Typography';
import { Localized, useLocalization } from '@fluent/react';
import { useEffect, useMemo, useState } from 'react';
import { useLocaleConfig } from '@/i18n/config';
import { useHeightContext } from '@/hooks/height';
import { EYE_HEIGHT_TO_HEIGHT_RATIO, useHeightContext } from '@/hooks/height';
import { useInterval } from '@/hooks/timeout';
import { TooSmolModal } from './TooSmolModal';
@@ -137,7 +137,8 @@ export function CheckFloorHeightStep({
</Typography>
<Typography>
{mFormat.format(
((hmdHeight ?? 0) - (floorHeight ?? 0)) / 0.936
((hmdHeight ?? 0) - (floorHeight ?? 0)) /
EYE_HEIGHT_TO_HEIGHT_RATIO
)}
</Typography>
</div>

View File

@@ -4,7 +4,7 @@ import { Typography } from '@/components/commons/Typography';
import { Localized, useLocalization } from '@fluent/react';
import { useMemo } from 'react';
import { useLocaleConfig } from '@/i18n/config';
import { useHeightContext } from '@/hooks/height';
import { EYE_HEIGHT_TO_HEIGHT_RATIO, useHeightContext } from '@/hooks/height';
import { useForm } from 'react-hook-form';
import {
ChangeSettingsRequestT,
@@ -36,12 +36,13 @@ export function ManualHeightStep({
const { state } = useOnboarding();
const { l10n } = useLocalization();
const { setHmdHeight } = useHeightContext();
const { control, handleSubmit, formState } = useForm<HeightForm>({
const { control, handleSubmit, formState, watch } = useForm<HeightForm>({
defaultValues: { height: 1.5 },
});
const { sendRPCPacket } = useWebsocketAPI();
const { currentLocales } = useLocaleConfig();
const { statuses } = useStatusContext();
const height = watch('height');
const missingSteamConnection = useMemo(
() =>
@@ -65,13 +66,14 @@ export function ManualHeightStep({
);
const submitHmdHeight = (values: HeightForm) => {
setHmdHeight(values.height);
const newHeight = values.height * EYE_HEIGHT_TO_HEIGHT_RATIO;
setHmdHeight(newHeight);
const settingsRequest = new ChangeSettingsRequestT();
settingsRequest.modelSettings = new ModelSettingsT(
null,
null,
null,
new SkeletonHeightT(values.height, 0)
new SkeletonHeightT(newHeight, 0)
);
sendRPCPacket(RpcMessage.ChangeSettingsRequest, settingsRequest);
nextStep();
@@ -92,7 +94,7 @@ export function ManualHeightStep({
<div>
<Typography color="secondary">
{l10n.getString(
'onboarding-scaled_proportions-manual_height-description'
'onboarding-scaled_proportions-manual_height-description-v2'
)}
</Typography>
{missingSteamConnection && (
@@ -112,7 +114,7 @@ export function ManualHeightStep({
control={control}
name="height"
label={l10n.getString(
'onboarding-scaled_proportions-manual_height-height'
'onboarding-scaled_proportions-manual_height-height-v2'
)}
valueLabelFormat={(value) =>
isNaN(value)
@@ -128,6 +130,16 @@ export function ManualHeightStep({
doubleStep={0.1}
/>
</div>
<div className="flex flex-col self-center items-center justify-center">
<Typography>
{l10n.getString(
'onboarding-scaled_proportions-manual_height-estimated_height'
)}
</Typography>
<Typography>
{mFormat.format(height * EYE_HEIGHT_TO_HEIGHT_RATIO)}
</Typography>
</div>
</div>
</div>

View File

@@ -56,3 +56,8 @@ export function useHeightContext() {
}
return context;
}
// The headset height is not the full height! This value compensates for the
// offset from the headset height to the user full height
// From Drillis and Contini (1966)
export const EYE_HEIGHT_TO_HEIGHT_RATIO = 0.936;

View File

@@ -27,10 +27,9 @@ class BodyProportionError : IAutoBoneError {
}
companion object {
// TODO hip tracker stuff... Hip tracker should be around 3 to 5
// centimeters.
// The headset height is not the full height! This value compensates for the
// offset from the headset height to the user height
// offset from the headset height to the user full height
// From Drillis and Contini (1966)
@JvmField
var eyeHeightToHeightRatio = 0.936f

View File

@@ -18,6 +18,7 @@ import dev.slimevr.protocol.rpc.setup.RPCUtil.getLocalIp
import dev.slimevr.protocol.rpc.status.RPCStatusHandler
import dev.slimevr.protocol.rpc.trackingpause.RPCTrackingPause
import dev.slimevr.tracking.processor.config.SkeletonConfigOffsets
import dev.slimevr.tracking.trackers.TrackerPosition
import dev.slimevr.tracking.trackers.TrackerPosition.Companion.getByBodyPart
import dev.slimevr.tracking.trackers.TrackerStatus
import dev.slimevr.tracking.trackers.TrackerUtils.getTrackerForSkeleton
@@ -490,7 +491,8 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler<RpcMessageHeade
.createHeightResponse(
fbb,
posTrackers.minOf { it.position.y },
posTrackers.maxOf { it.position.y },
posTrackers.find { it.trackerPosition == TrackerPosition.HEAD }?.position?.y
?: posTrackers.maxOf { it.position.y },
)
} else {
HeightResponse

View File

@@ -1,6 +1,7 @@
package dev.slimevr.tracking.processor.config
import dev.slimevr.VRServer.Companion.instance
import dev.slimevr.VRServer.Companion.instanceInitialized
import dev.slimevr.autobone.AutoBone
import dev.slimevr.autobone.errors.BodyProportionError.Companion.proportionLimitMap
import dev.slimevr.config.ConfigManager
@@ -409,14 +410,14 @@ class SkeletonConfigManager(
// Remove from config to use default if they change in the future.
Arrays.fill(changedToggles, false)
for (value in SkeletonConfigToggles.values) {
instance.configManager
.vrConfig
.skeleton
.getToggles()
.remove(value.configKey)
// Set default in skeleton
setToggle(value, value.defaultValue)
if (instanceInitialized) {
for (value in SkeletonConfigToggles.values) {
instance.configManager
.vrConfig
.skeleton
.getToggles()
.remove(value.configKey)
}
}
}
@@ -432,14 +433,14 @@ class SkeletonConfigManager(
// Remove from config to use default if they change in the future.
Arrays.fill(changedValues, false)
for (value in SkeletonConfigValues.values) {
instance.configManager
.vrConfig
.skeleton
.getValues()
.remove(value.configKey)
// Set default in skeleton
setValue(value, value.defaultValue)
if (instanceInitialized) {
for (value in SkeletonConfigValues.values) {
instance.configManager
.vrConfig
.skeleton
.getValues()
.remove(value.configKey)
}
}
}
@@ -515,6 +516,8 @@ class SkeletonConfigManager(
}
fun save() {
require(instanceInitialized) { "VRServer instance is not initialized, config cannot be saved." }
val skeletonConfig = instance.configManager
.vrConfig
.skeleton