diff --git a/package.json b/package.json index 53bddd36c46102c68bf8ca96954a4cb6dc9860ff..c3da9d632587028709c1ebed498798d225611822 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "react-swipeable-views": "^0.14.0", "roslib": "^1.3.0", "three": "^0.144.0", + "troika-3d-text": "^0.48.0-unicode.3", "typescript": "^4.4.2", "url": "^0.11.0", "web-vitals": "^2.1.0", diff --git a/src/features/viewport/TF2.tsx b/src/features/viewport/TF2.tsx index 4942879f62b55600e9748ff1051c231264b816b2..97578142d6fdc12ed8e83d3a8131469be2ea3f52 100644 --- a/src/features/viewport/TF2.tsx +++ b/src/features/viewport/TF2.tsx @@ -1,12 +1,13 @@ -import { Props, useThree } from '@react-three/fiber' +import { Props, useFrame, useThree } from '@react-three/fiber' import { PropsWithChildren, useEffect, useRef } from 'react'; -import { Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, SphereGeometry, Vector3 } from 'three' +import { AxesHelper, Group, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, SphereGeometry, Vector3 } from 'three' import { useConnection, useStore } from '../../common/store'; import { Config as GeneralConfig } from '../../schemas/Config.schema'; import tf2_msgs from '../../common/ROS/tf2_msgs'; import geometry_msgs from '../../common/ROS/geometry_msgs'; import { Topic } from 'roslib'; import { load as load_yaml } from 'js-yaml' +import { Text } from 'troika-three-text' const prefix = "tf2_tree_frame_"; @@ -67,11 +68,13 @@ function TF2(props: TF2Props) { let root = useRef<Object3D>(new Object3D()); let knownObjects = useRef(new Map<string, Object3D>()); let debugGeometry = useRef<Object3D[]>([]); + let debugLabels = useRef<Object3D[]>([]); const debug_geometry = useRef<SphereGeometry>(new SphereGeometry(0.1, 16, 16)); const debug_material = useRef<MeshBasicMaterial>(new MeshBasicMaterial({ color: 0xff0000 })); const config = useStore(state => state.transformTree); const connection = useConnection(config?.rosbridge.uri); let showDebugSpheres = useStore(state => state.appSettings.showTFDebugVis); + let showDebugLabels = useStore(state => state.appSettings.showTFDebugLabels); useEffect(() => { if (!props.yaml) return; @@ -108,11 +111,28 @@ function TF2(props: TF2Props) { Result.name = prefix + name; Result.matrixAutoUpdate = false; - // Debug - const sphere = new Mesh(debug_geometry.current, debug_material.current); - sphere.visible = showDebugSpheres; - debugGeometry.current.push(sphere); - Result.add(sphere); + // Debug geometry + const axesHelper = new AxesHelper(); + axesHelper.visible = showDebugSpheres; + debugGeometry.current.push(axesHelper); + Result.add(axesHelper); + + // const sphere = new Mesh(debug_geometry.current, debug_material.current); + // sphere.visible = showDebugSpheres; + // debugGeometry.current.push(sphere); + // Result.add(sphere); + + // Debug Label + const label = new Text(); + label.visible = true; + label.text = name; + label.fontSize = 0.2; + label.anchorX = "center"; + label.anchorY = "bottom"; + label.color = 0xFF0000; + debugLabels.current.push(label); + + Result.add(label); knownObjects.current.set(name, Result); if (parent) { @@ -182,7 +202,26 @@ function TF2(props: TF2Props) { for (let obj of debugGeometry.current) { obj.visible = showDebugSpheres; } - }, [showDebugSpheres]); + + for (let label of debugLabels.current) { + label.visible = showDebugLabels; + } + }, [showDebugSpheres, showDebugLabels]); + + useFrame(({ camera }) => { + if (!showDebugLabels) return; + + for (let label of debugLabels.current) { + if (!label.parent) continue; + + // always face the camera + let q = new Quaternion(); + let p = new Quaternion(); + camera.getWorldQuaternion(q); + label.parent.getWorldQuaternion(p); + label.setRotationFromQuaternion(p.invert().multiply(q)); + } + }) // Subscribe/Unsubscribe to TF Messages useEffect(() => { diff --git a/yarn.lock b/yarn.lock index b421e5efb80d62f48b5d70668d5b647bcbe5f76e..496e11f6591a8190014880aa8ea59b6017fc12ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10587,6 +10587,36 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +troika-3d-text@^0.48.0-unicode.3: + version "0.48.0-unicode.3" + resolved "https://registry.yarnpkg.com/troika-3d-text/-/troika-3d-text-0.48.0-unicode.3.tgz#0b75f930afe2584abac2a7cfcfdf35b1fd19acc3" + integrity sha512-kNMC3K7S3KsxYrLnsvBA2w4PNN2zD4Zb2gob9sIUoef349n97SOQwpasoYT85JvYWo52AA4FOoKk80qscIJzdQ== + dependencies: + troika-3d "^0.47.2" + troika-three-text "^0.48.0-unicode.3" + troika-three-utils "^0.47.2" + +troika-3d@^0.47.2: + version "0.47.2" + resolved "https://registry.yarnpkg.com/troika-3d/-/troika-3d-0.47.2.tgz#e367a0fa2ee66ba5e7bdc4ebdaac89c897bf067c" + integrity sha512-ZF6fOMOGzWgkOqrTtHlBdBlFx1Po8EEICb+BglCdhCj2JRVm6yRjPj8rW6UxjGoSmvfwjlxhxC9M0Lbo8p3ktg== + dependencies: + troika-core "^0.47.2" + troika-three-utils "^0.47.2" + +troika-animation@^0.47.2: + version "0.47.2" + resolved "https://registry.yarnpkg.com/troika-animation/-/troika-animation-0.47.2.tgz#f808a9670e02d2687d976011925743807ccf56ef" + integrity sha512-Le81hD80vWbQYN0HBSj/7VI8lGcoH1CIXvbAwpUd5l7jZh8bpi1Tur2tsNHRY8HbqK5spM2kfydxmskvV2FArA== + +troika-core@^0.47.2: + version "0.47.2" + resolved "https://registry.yarnpkg.com/troika-core/-/troika-core-0.47.2.tgz#f78597a3be500875139f9745e53b1f41f3c2301b" + integrity sha512-zKMOkal/RnURF7IDysaoZLhOTSAYdee92azbiJxHw6lfsTfPx4kQ+5Ar0oIYg81ba1bfC0BD6ST3dHLwSQ6M+A== + dependencies: + prop-types "^15.6.2" + troika-animation "^0.47.2" + troika-three-text@^0.46.4: version "0.46.4" resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.46.4.tgz#77627ac2ac4765d5248c857a8b42f82c25f2d034" @@ -10597,16 +10627,36 @@ troika-three-text@^0.46.4: troika-worker-utils "^0.46.0" webgl-sdf-generator "1.1.1" +troika-three-text@^0.48.0-unicode.3: + version "0.48.0-unicode.3" + resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.48.0-unicode.3.tgz#a49821d48f4aac60cae2a6a5088041764a7789f5" + integrity sha512-z/5J7qSX+sfJX7/HBJtTZk/MB3fi9xhjfb2MgZLH7j+iGxRqb/gbxkh8Jde9FYuEZOxaJ1gYExkgTqFBupcZPA== + dependencies: + bidi-js "^1.0.2" + troika-three-utils "^0.47.2" + troika-worker-utils "^0.47.2" + webgl-sdf-generator "1.1.1" + troika-three-utils@^0.46.0: version "0.46.0" resolved "https://registry.yarnpkg.com/troika-three-utils/-/troika-three-utils-0.46.0.tgz#6d97a9bf08f2260285edf2bb0be6328dd3d50eec" integrity sha512-llHyrXAcwzr0bpg80GxsIp73N7FuImm4WCrKDJkAqcAsWmE5pfP9+Qzw+oMWK1P/AdHQ79eOrOl9NjyW4aOw0w== +troika-three-utils@^0.47.2: + version "0.47.2" + resolved "https://registry.yarnpkg.com/troika-three-utils/-/troika-three-utils-0.47.2.tgz#af49ca694245dce631963d5fefe4e8e1b8af9044" + integrity sha512-/28plhCxfKtH7MSxEGx8e3b/OXU5A0xlwl+Sbdp0H8FXUHKZDoksduEKmjQayXYtxAyuUiCRunYIv/8Vi7aiyg== + troika-worker-utils@^0.46.0: version "0.46.0" resolved "https://registry.yarnpkg.com/troika-worker-utils/-/troika-worker-utils-0.46.0.tgz#1b698090af78b51a27e03881c90237a2e648d6c4" integrity sha512-bzOx5f2ZBxkFhXtIvDJlLn2AI3bzCkGVbCndl/2dL5QZrwHEKl45OEIilCxYQQWJG1rEbOD9O80tMjoYjw19OA== +troika-worker-utils@^0.47.2: + version "0.47.2" + resolved "https://registry.yarnpkg.com/troika-worker-utils/-/troika-worker-utils-0.47.2.tgz#e7c5de5f37d56c072b13fa8112bb844e048ff46c" + integrity sha512-mzss4MeyzUkYBppn4x5cdAqrhBHFEuVmMMgLMTyFV23x6GvQMyo+/R5E5Lsbrt7WSt5RfvewjcwD1DChRTA9lA== + tryer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"