@viamrobotics/motion-tools 1.24.0 → 1.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FrameConfigUpdater.svelte.js +5 -5
- package/dist/components/BatchedArrows.svelte +4 -4
- package/dist/components/Entities/Arrows/Arrows.svelte +2 -2
- package/dist/components/Entities/Capsule.svelte +137 -0
- package/dist/components/Entities/Capsule.svelte.d.ts +19 -0
- package/dist/components/Entities/Frame.svelte +2 -2
- package/dist/components/Entities/GLTF.svelte +2 -2
- package/dist/components/Entities/Geometry.svelte +2 -2
- package/dist/components/Entities/Line.svelte +2 -2
- package/dist/components/Entities/Mesh.svelte +121 -68
- package/dist/components/Entities/Points.svelte +2 -2
- package/dist/components/Entities/Pose.svelte +2 -2
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Snapshot.svelte +20 -10
- package/dist/components/overlay/Details.svelte +3 -3
- package/dist/components/overlay/__tests__/__fixtures__/entity.js +2 -2
- package/dist/components/overlay/left-pane/buildTree.js +3 -3
- package/dist/draw.js +7 -8
- package/dist/ecs/hierarchy.d.ts +36 -0
- package/dist/ecs/hierarchy.js +80 -0
- package/dist/ecs/index.d.ts +4 -0
- package/dist/ecs/index.js +4 -0
- package/dist/ecs/provideHierarchy.svelte.d.ts +17 -0
- package/dist/ecs/provideHierarchy.svelte.js +31 -0
- package/dist/ecs/relations.d.ts +7 -0
- package/dist/ecs/relations.js +8 -1
- package/dist/ecs/traits.d.ts +9 -4
- package/dist/ecs/traits.js +8 -14
- package/dist/ecs/useParentName.svelte.d.ts +11 -0
- package/dist/ecs/useParentName.svelte.js +21 -0
- package/dist/ecs/useTarget.svelte.d.ts +10 -0
- package/dist/ecs/useTarget.svelte.js +42 -0
- package/dist/editing/FrameEditSession.js +6 -6
- package/dist/hooks/useArmKinematics.svelte.js +12 -8
- package/dist/hooks/useDrawAPI.svelte.js +4 -4
- package/dist/hooks/useFrames.svelte.js +3 -3
- package/dist/hooks/useGeometries.svelte.js +3 -2
- package/dist/hooks/usePointcloudObjects.svelte.js +3 -2
- package/dist/hooks/usePointclouds.svelte.js +3 -2
- package/dist/hooks/usePose.svelte.js +8 -6
- package/dist/snapshot.d.ts +7 -0
- package/dist/snapshot.js +74 -1
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { traits } from './ecs';
|
|
1
|
+
import { hierarchy, traits } from './ecs';
|
|
2
2
|
export class FrameConfigUpdater {
|
|
3
3
|
updateFrame;
|
|
4
4
|
removeFrame;
|
|
@@ -19,7 +19,7 @@ export class FrameConfigUpdater {
|
|
|
19
19
|
change.z = z;
|
|
20
20
|
entity.set(traits.EditedPose, change);
|
|
21
21
|
const name = entity.get(traits.Name);
|
|
22
|
-
const parent =
|
|
22
|
+
const parent = hierarchy.getParentName(entity) ?? 'world';
|
|
23
23
|
const updatedPose = entity.get(traits.EditedPose);
|
|
24
24
|
if (name && updatedPose) {
|
|
25
25
|
this.updateFrame(name, parent, updatedPose);
|
|
@@ -41,7 +41,7 @@ export class FrameConfigUpdater {
|
|
|
41
41
|
change.theta = theta;
|
|
42
42
|
entity.set(traits.EditedPose, change);
|
|
43
43
|
const name = entity.get(traits.Name);
|
|
44
|
-
const parent =
|
|
44
|
+
const parent = hierarchy.getParentName(entity) ?? 'world';
|
|
45
45
|
const updatedPose = entity.get(traits.EditedPose);
|
|
46
46
|
if (name && updatedPose) {
|
|
47
47
|
this.updateFrame(name, parent, updatedPose);
|
|
@@ -49,7 +49,7 @@ export class FrameConfigUpdater {
|
|
|
49
49
|
};
|
|
50
50
|
updateGeometry = (entity, geometry) => {
|
|
51
51
|
const name = entity.get(traits.Name);
|
|
52
|
-
const parent =
|
|
52
|
+
const parent = hierarchy.getParentName(entity) ?? 'world';
|
|
53
53
|
const pose = entity.get(traits.EditedPose);
|
|
54
54
|
if (geometry?.type === 'box') {
|
|
55
55
|
const { x, y, z } = geometry;
|
|
@@ -109,7 +109,7 @@ export class FrameConfigUpdater {
|
|
|
109
109
|
};
|
|
110
110
|
setGeometryType = (entity, type) => {
|
|
111
111
|
const name = entity.get(traits.Name);
|
|
112
|
-
const parent =
|
|
112
|
+
const parent = hierarchy.getParentName(entity) ?? 'world';
|
|
113
113
|
const pose = entity.get(traits.EditedPose);
|
|
114
114
|
if (!name || !pose)
|
|
115
115
|
return;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Portal } from '@threlte/extras'
|
|
6
6
|
import { Color, Vector3 } from 'three'
|
|
7
7
|
|
|
8
|
-
import { traits, useWorld } from '../ecs'
|
|
8
|
+
import { hierarchy, traits, useWorld } from '../ecs'
|
|
9
9
|
import { BatchedArrow } from '../three/BatchedArrow'
|
|
10
10
|
|
|
11
11
|
const arrowBatchMap = $state<Record<string, BatchedArrow>>({
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
const color = new Color()
|
|
21
21
|
|
|
22
22
|
const onAdd = (entity: Entity) => {
|
|
23
|
-
const parent =
|
|
23
|
+
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
24
24
|
|
|
25
25
|
arrowBatchMap[parent] ??= new BatchedArrow()
|
|
26
26
|
const batched = arrowBatchMap[parent]
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
const onPoseChange = (entity: Entity) => {
|
|
41
41
|
if (!entity.has(traits.Arrow)) return
|
|
42
42
|
|
|
43
|
-
const parent =
|
|
43
|
+
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
44
44
|
const batch = arrowBatchMap[parent]
|
|
45
45
|
const instanceID = entity.get(traits.Instance)?.instanceID
|
|
46
46
|
const pose = entity.get(traits.Pose)
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
const onColorChange = (entity: Entity) => {
|
|
58
58
|
if (!entity.has(traits.Arrow)) return
|
|
59
59
|
|
|
60
|
-
const parent =
|
|
60
|
+
const parent = hierarchy.getParentName(entity) ?? 'world'
|
|
61
61
|
const batch = arrowBatchMap[parent]
|
|
62
62
|
const instanceID = entity.get(traits.Instance)?.instanceID
|
|
63
63
|
const colorRGB = entity.get(traits.Color)
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import AxesHelper from '../../AxesHelper.svelte'
|
|
10
10
|
import { useEntityEvents } from '../hooks/useEntityEvents.svelte'
|
|
11
|
-
import { traits, useTrait } from '../../../ecs'
|
|
11
|
+
import { traits, useParentName, useTrait } from '../../../ecs'
|
|
12
12
|
import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte'
|
|
13
13
|
import { meshBoundsRaycast, raycast } from '../../../three/InstancedArrows/raycast'
|
|
14
14
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
let { entity, arrows }: Props = $props()
|
|
21
21
|
|
|
22
|
-
const parent =
|
|
22
|
+
const parent = useParentName(() => entity)
|
|
23
23
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
24
24
|
const showAxesHelper = useTrait(() => entity, traits.ShowAxesHelper)
|
|
25
25
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
|
|
4
|
+
A compound capsule via a shared open-ended unit cylinder and two
|
|
5
|
+
hemispheres, each scaled per `r` and `l`, so dimension changes update
|
|
6
|
+
transforms only and cause no geometry rebuild.
|
|
7
|
+
|
|
8
|
+
Viam's capsule `l` is the *total* length, including the rounded caps, so the
|
|
9
|
+
midsection has length `l - 2r`.
|
|
10
|
+
-->
|
|
11
|
+
<script
|
|
12
|
+
module
|
|
13
|
+
lang="ts"
|
|
14
|
+
>
|
|
15
|
+
import { CylinderGeometry, EdgesGeometry, SphereGeometry } from 'three'
|
|
16
|
+
|
|
17
|
+
const unitCylinder = new CylinderGeometry(1, 1, 1, 16, 1, true)
|
|
18
|
+
unitCylinder.rotateX(Math.PI / 2)
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Hemisphere with rounded part toward +Z and an open boundary on the XY plane.
|
|
22
|
+
* 6 height segments matches the existing sphere's density (`Mesh.svelte` uses `SphereGeometry(1, 16, 12)`).
|
|
23
|
+
*/
|
|
24
|
+
const unitHemisphere = new SphereGeometry(1, 16, 6, 0, Math.PI * 2, 0, Math.PI / 2)
|
|
25
|
+
unitHemisphere.rotateX(Math.PI / 2)
|
|
26
|
+
|
|
27
|
+
const unitCylinderEdges = new EdgesGeometry(unitCylinder, 0)
|
|
28
|
+
const unitHemisphereEdges = new EdgesGeometry(unitHemisphere, 0)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<script lang="ts">
|
|
32
|
+
import type { ColorRepresentation } from 'three'
|
|
33
|
+
|
|
34
|
+
import { T, useThrelte } from '@threlte/core'
|
|
35
|
+
import { LineBasicMaterial, MeshToonMaterial } from 'three'
|
|
36
|
+
|
|
37
|
+
import { darkenColor } from '../../color'
|
|
38
|
+
|
|
39
|
+
interface Props {
|
|
40
|
+
r: number
|
|
41
|
+
l: number
|
|
42
|
+
color: ColorRepresentation
|
|
43
|
+
opacity?: number
|
|
44
|
+
depthTest?: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let { r, l, color, opacity = 1, depthTest = true }: Props = $props()
|
|
48
|
+
|
|
49
|
+
const { invalidate } = useThrelte()
|
|
50
|
+
const material = new MeshToonMaterial()
|
|
51
|
+
const lineMaterial = new LineBasicMaterial()
|
|
52
|
+
|
|
53
|
+
$effect(() => {
|
|
54
|
+
material.color.set(color)
|
|
55
|
+
lineMaterial.color.set(darkenColor(color, 10))
|
|
56
|
+
invalidate()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
$effect(() => {
|
|
60
|
+
const isTransparent = opacity < 1
|
|
61
|
+
material.opacity = opacity
|
|
62
|
+
material.depthWrite = opacity === 1
|
|
63
|
+
material.depthTest = depthTest
|
|
64
|
+
lineMaterial.depthTest = depthTest
|
|
65
|
+
if (material.transparent !== isTransparent) {
|
|
66
|
+
material.transparent = isTransparent
|
|
67
|
+
material.needsUpdate = true
|
|
68
|
+
}
|
|
69
|
+
invalidate()
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const midsection = $derived(Math.max(0, l - 2 * r))
|
|
73
|
+
const halfMid = $derived(midsection / 2)
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
{#if midsection > 0}
|
|
77
|
+
<T.Mesh scale={[r, r, midsection]}>
|
|
78
|
+
<T
|
|
79
|
+
is={unitCylinder}
|
|
80
|
+
dispose={false}
|
|
81
|
+
/>
|
|
82
|
+
<T is={material} />
|
|
83
|
+
<T.LineSegments
|
|
84
|
+
raycast={() => null}
|
|
85
|
+
bvh={{ enabled: false }}
|
|
86
|
+
>
|
|
87
|
+
<T
|
|
88
|
+
is={unitCylinderEdges}
|
|
89
|
+
dispose={false}
|
|
90
|
+
/>
|
|
91
|
+
<T is={lineMaterial} />
|
|
92
|
+
</T.LineSegments>
|
|
93
|
+
</T.Mesh>
|
|
94
|
+
{/if}
|
|
95
|
+
|
|
96
|
+
<T.Mesh
|
|
97
|
+
position={[0, 0, halfMid]}
|
|
98
|
+
scale={r}
|
|
99
|
+
>
|
|
100
|
+
<T
|
|
101
|
+
is={unitHemisphere}
|
|
102
|
+
dispose={false}
|
|
103
|
+
/>
|
|
104
|
+
<T is={material} />
|
|
105
|
+
<T.LineSegments
|
|
106
|
+
raycast={() => null}
|
|
107
|
+
bvh={{ enabled: false }}
|
|
108
|
+
>
|
|
109
|
+
<T
|
|
110
|
+
is={unitHemisphereEdges}
|
|
111
|
+
dispose={false}
|
|
112
|
+
/>
|
|
113
|
+
<T is={lineMaterial} />
|
|
114
|
+
</T.LineSegments>
|
|
115
|
+
</T.Mesh>
|
|
116
|
+
|
|
117
|
+
<T.Mesh
|
|
118
|
+
position={[0, 0, -halfMid]}
|
|
119
|
+
rotation={[Math.PI, 0, 0]}
|
|
120
|
+
scale={[r, r, r]}
|
|
121
|
+
>
|
|
122
|
+
<T
|
|
123
|
+
is={unitHemisphere}
|
|
124
|
+
dispose={false}
|
|
125
|
+
/>
|
|
126
|
+
<T is={material} />
|
|
127
|
+
<T.LineSegments
|
|
128
|
+
raycast={() => null}
|
|
129
|
+
bvh={{ enabled: false }}
|
|
130
|
+
>
|
|
131
|
+
<T
|
|
132
|
+
is={unitHemisphereEdges}
|
|
133
|
+
dispose={false}
|
|
134
|
+
/>
|
|
135
|
+
<T is={lineMaterial} />
|
|
136
|
+
</T.LineSegments>
|
|
137
|
+
</T.Mesh>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ColorRepresentation } from 'three';
|
|
2
|
+
interface Props {
|
|
3
|
+
r: number;
|
|
4
|
+
l: number;
|
|
5
|
+
color: ColorRepresentation;
|
|
6
|
+
opacity?: number;
|
|
7
|
+
depthTest?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A compound capsule via a shared open-ended unit cylinder and two
|
|
11
|
+
* hemispheres, each scaled per `r` and `l`, so dimension changes update
|
|
12
|
+
* transforms only and cause no geometry rebuild.
|
|
13
|
+
*
|
|
14
|
+
* Viam's capsule `l` is the *total* length, including the rounded caps, so the
|
|
15
|
+
* midsection has length `l - 2r`.
|
|
16
|
+
*/
|
|
17
|
+
declare const Capsule: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type Capsule = ReturnType<typeof Capsule>;
|
|
19
|
+
export default Capsule;
|
|
@@ -20,7 +20,7 @@ Renders a Viam Frame object
|
|
|
20
20
|
|
|
21
21
|
import { asColor } from '../../buffer'
|
|
22
22
|
import { colors, resourceColors } from '../../color'
|
|
23
|
-
import { traits, useTrait } from '../../ecs'
|
|
23
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
24
24
|
import { useResourceByName } from '../../hooks/useResourceByName.svelte'
|
|
25
25
|
import { poseToObject3d } from '../../transform'
|
|
26
26
|
|
|
@@ -39,7 +39,7 @@ Renders a Viam Frame object
|
|
|
39
39
|
const resourceByName = useResourceByName()
|
|
40
40
|
|
|
41
41
|
const name = useTrait(() => entity, traits.Name)
|
|
42
|
-
const parent =
|
|
42
|
+
const parent = useParentName(() => entity)
|
|
43
43
|
const entityColors = useTrait(() => entity, traits.Colors)
|
|
44
44
|
const entityColor = useTrait(() => entity, traits.Color)
|
|
45
45
|
const entityPose = useTrait(() => entity, traits.Pose)
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { Portal, PortalTarget, type ThrelteGltf, useGltfAnimations } from '@threlte/extras'
|
|
20
20
|
import { Group, type Object3D } from 'three'
|
|
21
21
|
|
|
22
|
-
import { traits, useTrait } from '../../ecs'
|
|
22
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
23
23
|
import { poseToObject3d } from '../../transform'
|
|
24
24
|
|
|
25
25
|
import AxesHelper from '../AxesHelper.svelte'
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
const { gltf, actions } = useGltfAnimations()
|
|
36
36
|
|
|
37
37
|
const name = useTrait(() => entity, traits.Name)
|
|
38
|
-
const parent =
|
|
38
|
+
const parent = useParentName(() => entity)
|
|
39
39
|
const pose = useTrait(() => entity, traits.Pose)
|
|
40
40
|
const gltfTrait = useTrait(() => entity, traits.GLTF)
|
|
41
41
|
const scale = useTrait(() => entity, traits.Scale)
|
|
@@ -10,7 +10,7 @@ Renders a Viam Geometry object
|
|
|
10
10
|
import { T, useThrelte } from '@threlte/core'
|
|
11
11
|
import { Portal } from '@threlte/extras'
|
|
12
12
|
|
|
13
|
-
import { traits, useTrait } from '../../ecs'
|
|
13
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
14
14
|
import { use3DModels } from '../../hooks/use3DModels.svelte'
|
|
15
15
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
16
16
|
import { poseToObject3d } from '../../transform'
|
|
@@ -31,7 +31,7 @@ Renders a Viam Geometry object
|
|
|
31
31
|
const models = use3DModels()
|
|
32
32
|
|
|
33
33
|
const name = useTrait(() => entity, traits.Name)
|
|
34
|
-
const parent =
|
|
34
|
+
const parent = useParentName(() => entity)
|
|
35
35
|
const center = useTrait(() => entity, traits.Center)
|
|
36
36
|
const invisible = useTrait(() => entity, traits.Invisible)
|
|
37
37
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { Line2, LineMaterial } from 'three/examples/jsm/Addons.js'
|
|
8
8
|
|
|
9
9
|
import { isVertexColors, STRIDE } from '../../buffer'
|
|
10
|
-
import { traits, useTrait } from '../../ecs'
|
|
10
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
11
11
|
import { poseToObject3d } from '../../transform'
|
|
12
12
|
|
|
13
13
|
import AxesHelper from '../AxesHelper.svelte'
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
const { invalidate } = useThrelte()
|
|
26
26
|
const name = useTrait(() => entity, traits.Name)
|
|
27
|
-
const parent =
|
|
27
|
+
const parent = useParentName(() => entity)
|
|
28
28
|
const pose = useTrait(() => entity, traits.Pose)
|
|
29
29
|
const color = useTrait(() => entity, traits.Color)
|
|
30
30
|
const colors = useTrait(() => entity, traits.Colors)
|
|
@@ -1,20 +1,36 @@
|
|
|
1
|
+
<script
|
|
2
|
+
module
|
|
3
|
+
lang="ts"
|
|
4
|
+
>
|
|
5
|
+
import { BoxGeometry, EdgesGeometry, SphereGeometry } from 'three'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shared unit geometries — every mesh references these and sets
|
|
9
|
+
* dimensions through `mesh.scale`, so resizing never rebuilds GPU buffers.
|
|
10
|
+
*/
|
|
11
|
+
const unitBox = new BoxGeometry(1, 1, 1)
|
|
12
|
+
const unitSphere = new SphereGeometry(1, 16, 12)
|
|
13
|
+
const unitBoxEdges = new EdgesGeometry(unitBox, 0)
|
|
14
|
+
const unitSphereEdges = new EdgesGeometry(unitSphere, 0)
|
|
15
|
+
</script>
|
|
16
|
+
|
|
1
17
|
<script lang="ts">
|
|
2
18
|
import type { Pose } from '@viamrobotics/sdk'
|
|
3
19
|
import type { Entity } from 'koota'
|
|
4
20
|
|
|
5
21
|
import { T, type Props as ThrelteProps, useThrelte } from '@threlte/core'
|
|
6
22
|
import { type Snippet } from 'svelte'
|
|
7
|
-
import {
|
|
23
|
+
import { Color, DoubleSide, FrontSide, Group, Material, Mesh } from 'three'
|
|
8
24
|
|
|
9
25
|
import { asColor } from '../../buffer'
|
|
10
26
|
import { colors, darkenColor } from '../../color'
|
|
11
27
|
import { traits, useTrait } from '../../ecs'
|
|
12
|
-
import { CapsuleGeometry } from '../../three/CapsuleGeometry'
|
|
13
28
|
import { poseToObject3d } from '../../transform'
|
|
14
29
|
|
|
15
30
|
import AxesHelper from '../AxesHelper.svelte'
|
|
31
|
+
import Capsule from './Capsule.svelte'
|
|
16
32
|
|
|
17
|
-
interface Props extends ThrelteProps<Mesh> {
|
|
33
|
+
interface Props extends Omit<ThrelteProps<Mesh>, 'ref'> {
|
|
18
34
|
entity: Entity
|
|
19
35
|
color?: string
|
|
20
36
|
center?: Pose
|
|
@@ -56,6 +72,8 @@
|
|
|
56
72
|
|
|
57
73
|
const currentOpacity = $derived(opacity.current ?? 0.7)
|
|
58
74
|
|
|
75
|
+
const isCapsule = $derived(capsule.current !== undefined)
|
|
76
|
+
|
|
59
77
|
let material = $state.raw<Material>(new Material())
|
|
60
78
|
$effect(() => {
|
|
61
79
|
const isTransparent = currentOpacity < 1
|
|
@@ -69,83 +87,118 @@
|
|
|
69
87
|
})
|
|
70
88
|
|
|
71
89
|
const mesh = new Mesh()
|
|
72
|
-
|
|
90
|
+
const group = new Group()
|
|
91
|
+
|
|
92
|
+
$effect(() => {
|
|
93
|
+
const target = isCapsule ? group : mesh
|
|
73
94
|
if (center) {
|
|
74
|
-
poseToObject3d(center,
|
|
95
|
+
poseToObject3d(center, target)
|
|
75
96
|
invalidate()
|
|
76
97
|
}
|
|
77
98
|
})
|
|
78
99
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
$effect(() => {
|
|
101
|
+
if (box.current) {
|
|
102
|
+
const { x, y, z } = box.current
|
|
103
|
+
mesh.scale.set(x * 0.001, y * 0.001, z * 0.001)
|
|
104
|
+
} else if (sphere.current) {
|
|
105
|
+
mesh.scale.setScalar((sphere.current.r ?? 0) * 0.001)
|
|
106
|
+
} else {
|
|
107
|
+
mesh.scale.set(1, 1, 1)
|
|
83
108
|
}
|
|
109
|
+
invalidate()
|
|
84
110
|
})
|
|
85
|
-
|
|
86
|
-
const oncreate = (bufferGeometry: BufferGeometry) => {
|
|
87
|
-
geo = bufferGeometry
|
|
88
|
-
}
|
|
89
111
|
</script>
|
|
90
112
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<T.SphereGeometry
|
|
107
|
-
args={[r * 0.001]}
|
|
108
|
-
{oncreate}
|
|
109
|
-
/>
|
|
110
|
-
{:else if capsule.current}
|
|
111
|
-
{@const { r, l } = capsule.current ?? { r: 0, l: 0 }}
|
|
112
|
-
<T
|
|
113
|
-
is={CapsuleGeometry}
|
|
114
|
-
args={[r * 0.001, l * 0.001]}
|
|
115
|
-
{oncreate}
|
|
113
|
+
{#if isCapsule}
|
|
114
|
+
{@const { r, l } = capsule.current ?? { r: 0, l: 0 }}
|
|
115
|
+
<T
|
|
116
|
+
is={group}
|
|
117
|
+
name={entity}
|
|
118
|
+
userData.name={name}
|
|
119
|
+
renderOrder={renderOrder.current}
|
|
120
|
+
{...rest}
|
|
121
|
+
>
|
|
122
|
+
<Capsule
|
|
123
|
+
r={r * 0.001}
|
|
124
|
+
l={l * 0.001}
|
|
125
|
+
{color}
|
|
126
|
+
opacity={currentOpacity}
|
|
127
|
+
depthTest={materialProps.current?.depthTest ?? true}
|
|
116
128
|
/>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
129
|
+
|
|
130
|
+
{@render children?.()}
|
|
131
|
+
</T>
|
|
132
|
+
{:else}
|
|
133
|
+
<T
|
|
134
|
+
is={mesh}
|
|
135
|
+
name={entity}
|
|
136
|
+
userData.name={name}
|
|
137
|
+
renderOrder={renderOrder.current}
|
|
138
|
+
{...rest}
|
|
139
|
+
>
|
|
140
|
+
{#if box.current}
|
|
141
|
+
<T
|
|
142
|
+
is={unitBox}
|
|
143
|
+
dispose={false}
|
|
144
|
+
/>
|
|
145
|
+
<T.LineSegments
|
|
146
|
+
raycast={() => null}
|
|
147
|
+
bvh={{ enabled: false }}
|
|
148
|
+
>
|
|
149
|
+
<T
|
|
150
|
+
is={unitBoxEdges}
|
|
151
|
+
dispose={false}
|
|
152
|
+
/>
|
|
153
|
+
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
154
|
+
</T.LineSegments>
|
|
155
|
+
{:else if sphere.current}
|
|
156
|
+
<T
|
|
157
|
+
is={unitSphere}
|
|
158
|
+
dispose={false}
|
|
159
|
+
/>
|
|
160
|
+
<T.LineSegments
|
|
161
|
+
raycast={() => null}
|
|
162
|
+
bvh={{ enabled: false }}
|
|
163
|
+
>
|
|
164
|
+
<T
|
|
165
|
+
is={unitSphereEdges}
|
|
166
|
+
dispose={false}
|
|
167
|
+
/>
|
|
168
|
+
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
169
|
+
</T.LineSegments>
|
|
170
|
+
{:else if bufferGeometry.current}
|
|
171
|
+
<T is={bufferGeometry.current}>
|
|
172
|
+
{#snippet children({ ref: geo })}
|
|
173
|
+
<!--
|
|
174
|
+
TODO(mp) currently some bufferGeometries are coming in empty,
|
|
175
|
+
this is a quick fix but this should be handled upstream
|
|
176
|
+
-->
|
|
177
|
+
{#if geo.getAttribute('position').array.length > 0}
|
|
178
|
+
<T.LineSegments
|
|
179
|
+
raycast={() => null}
|
|
180
|
+
bvh={{ enabled: false }}
|
|
181
|
+
>
|
|
182
|
+
<T.EdgesGeometry args={[geo, 0]} />
|
|
183
|
+
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
184
|
+
</T.LineSegments>
|
|
185
|
+
{/if}
|
|
186
|
+
{/snippet}
|
|
187
|
+
</T>
|
|
188
|
+
{/if}
|
|
189
|
+
|
|
190
|
+
<T.MeshToonMaterial
|
|
191
|
+
{color}
|
|
192
|
+
side={bufferGeometry.current ? DoubleSide : FrontSide}
|
|
193
|
+
depthTest={materialProps.current?.depthTest ?? true}
|
|
194
|
+
oncreate={(m) => {
|
|
195
|
+
material = m
|
|
196
|
+
}}
|
|
121
197
|
/>
|
|
122
|
-
{/if}
|
|
123
|
-
|
|
124
|
-
<T.MeshToonMaterial
|
|
125
|
-
{color}
|
|
126
|
-
side={bufferGeometry.current ? DoubleSide : FrontSide}
|
|
127
|
-
depthTest={materialProps.current?.depthTest ?? true}
|
|
128
|
-
oncreate={(m) => {
|
|
129
|
-
material = m
|
|
130
|
-
}}
|
|
131
|
-
/>
|
|
132
198
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-->
|
|
137
|
-
{#if geo && geo.getAttribute('position').array.length > 0}
|
|
138
|
-
<T.LineSegments
|
|
139
|
-
raycast={() => null}
|
|
140
|
-
bvh={{ enabled: false }}
|
|
141
|
-
>
|
|
142
|
-
<T.EdgesGeometry args={[geo, 0]} />
|
|
143
|
-
<T.LineBasicMaterial color={darkenColor(color, 10)} />
|
|
144
|
-
</T.LineSegments>
|
|
145
|
-
{/if}
|
|
146
|
-
|
|
147
|
-
{@render children?.()}
|
|
148
|
-
</T>
|
|
199
|
+
{@render children?.()}
|
|
200
|
+
</T>
|
|
201
|
+
{/if}
|
|
149
202
|
|
|
150
203
|
{#if showAxesHelper.current}
|
|
151
204
|
<AxesHelper
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { OrthographicCamera, Points, PointsMaterial } from 'three'
|
|
8
8
|
|
|
9
9
|
import { asColor, isSingleColor } from '../../buffer'
|
|
10
|
-
import { traits, useTrait } from '../../ecs'
|
|
10
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
11
11
|
import { useSettings } from '../../hooks/useSettings.svelte'
|
|
12
12
|
import { poseToObject3d } from '../../transform'
|
|
13
13
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const { camera } = useThrelte()
|
|
25
25
|
const settings = useSettings()
|
|
26
26
|
|
|
27
|
-
const parent =
|
|
27
|
+
const parent = useParentName(() => entity)
|
|
28
28
|
const pose = useTrait(() => entity, traits.Pose)
|
|
29
29
|
const geometry = useTrait(() => entity, traits.BufferGeometry)
|
|
30
30
|
const entityColor = useTrait(() => entity, traits.Color)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { Entity } from 'koota'
|
|
4
4
|
import type { Snippet } from 'svelte'
|
|
5
5
|
|
|
6
|
-
import { traits, useTrait } from '../../ecs'
|
|
6
|
+
import { traits, useParentName, useTrait } from '../../ecs'
|
|
7
7
|
import { usePartConfig } from '../../hooks/usePartConfig.svelte'
|
|
8
8
|
import { usePose } from '../../hooks/usePose.svelte'
|
|
9
9
|
import { composeRenderedPose } from '../../transform'
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
const partConfig = usePartConfig()
|
|
18
18
|
const name = useTrait(() => entity, traits.Name)
|
|
19
|
-
const parent =
|
|
19
|
+
const parent = useParentName(() => entity)
|
|
20
20
|
const editedPose = useTrait(() => entity, traits.EditedPose)
|
|
21
21
|
const entityPose = useTrait(() => entity, traits.Pose)
|
|
22
22
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
3
|
|
|
4
|
+
import { provideHierarchy } from '../ecs'
|
|
4
5
|
import { provide3DModels } from '../hooks/use3DModels.svelte'
|
|
5
6
|
import { provideArmClient } from '../hooks/useArmClient.svelte'
|
|
6
7
|
import { provideArmKinematics } from '../hooks/useArmKinematics.svelte'
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
provideTransformControls()
|
|
42
43
|
provideLogs()
|
|
43
44
|
|
|
45
|
+
provideHierarchy()
|
|
44
46
|
provideOrigin()
|
|
45
47
|
provideDrawAPI()
|
|
46
48
|
provideRelationships()
|
|
@@ -23,7 +23,7 @@ Renders a Snapshot protobuf by spawning its transforms and drawings as entities
|
|
|
23
23
|
import { useCameraControls } from '../hooks/useControls.svelte'
|
|
24
24
|
import { useRelationships } from '../hooks/useRelationships.svelte'
|
|
25
25
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
26
|
-
import { applySceneMetadata, type SnapshotEntity
|
|
26
|
+
import { applySceneMetadata, reconcileSnapshotEntities, type SnapshotEntity } from '../snapshot'
|
|
27
27
|
|
|
28
28
|
interface Props {
|
|
29
29
|
snapshot: SnapshotProto
|
|
@@ -36,17 +36,24 @@ Renders a Snapshot protobuf by spawning its transforms and drawings as entities
|
|
|
36
36
|
const cameraControls = useCameraControls()
|
|
37
37
|
const relationships = useRelationships()
|
|
38
38
|
|
|
39
|
-
let
|
|
39
|
+
let entitiesByUuid = new Map<string, SnapshotEntity>()
|
|
40
|
+
let unkeyedEntities: SnapshotEntity[] = []
|
|
40
41
|
|
|
41
42
|
$effect(() => {
|
|
42
|
-
|
|
43
|
-
snapshot.uuid.toString()
|
|
43
|
+
void snapshot
|
|
44
44
|
|
|
45
45
|
untrack(() => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
for (const entry of unkeyedEntities) {
|
|
47
|
+
if (world.has(entry.entity)) entry.entity.destroy()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const result = reconcileSnapshotEntities(world, snapshot, entitiesByUuid)
|
|
51
|
+
entitiesByUuid = result.current
|
|
52
|
+
unkeyedEntities = result.unkeyed
|
|
53
|
+
|
|
54
|
+
for (const entry of [...result.spawned, ...result.updated]) {
|
|
55
|
+
relationships.apply(entry.entity, entry.relationships)
|
|
56
|
+
const uuid = entry.entity.get(traits.UUID)
|
|
50
57
|
if (uuid) relationships.flush(uuid)
|
|
51
58
|
}
|
|
52
59
|
})
|
|
@@ -83,8 +90,11 @@ Renders a Snapshot protobuf by spawning its transforms and drawings as entities
|
|
|
83
90
|
})
|
|
84
91
|
|
|
85
92
|
onDestroy(() => {
|
|
86
|
-
for (const
|
|
87
|
-
if (world.has(
|
|
93
|
+
for (const entry of entitiesByUuid.values()) {
|
|
94
|
+
if (world.has(entry.entity)) entry.entity.destroy()
|
|
95
|
+
}
|
|
96
|
+
for (const entry of unkeyedEntities) {
|
|
97
|
+
if (world.has(entry.entity)) entry.entity.destroy()
|
|
88
98
|
}
|
|
89
99
|
})
|
|
90
100
|
</script>
|