diff --git a/app/src/assets/gltf-glb/arm_ui_drop.glb b/app/src/assets/gltf-glb/arm_ui_drop.glb index 2a75e7e..ce3a012 100644 Binary files a/app/src/assets/gltf-glb/arm_ui_drop.glb and b/app/src/assets/gltf-glb/arm_ui_drop.glb differ diff --git a/app/src/assets/gltf-glb/arm_ui_pick.glb b/app/src/assets/gltf-glb/arm_ui_pick.glb index 979ade4..0ea6a23 100644 Binary files a/app/src/assets/gltf-glb/arm_ui_pick.glb and b/app/src/assets/gltf-glb/arm_ui_pick.glb differ diff --git a/app/src/assets/gltf-glb/rigged/ik_arm.glb b/app/src/assets/gltf-glb/rigged/ik_arm.glb new file mode 100644 index 0000000..22e26a8 Binary files /dev/null and b/app/src/assets/gltf-glb/rigged/ik_arm.glb differ diff --git a/app/src/assets/gltf-glb/rigged/ik_arm_1.glb b/app/src/assets/gltf-glb/rigged/ik_arm_1.glb new file mode 100644 index 0000000..326efad Binary files /dev/null and b/app/src/assets/gltf-glb/rigged/ik_arm_1.glb differ diff --git a/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx new file mode 100644 index 0000000..893f759 --- /dev/null +++ b/app/src/modules/simulation/roboticArm/instances/animator/materialAnimator.tsx @@ -0,0 +1,66 @@ +import { useFrame } from '@react-three/fiber'; +import React, { useEffect, useRef, useState } from 'react'; +import * as THREE from 'three'; +import { useLogger } from '../../../../../components/ui/log/LoggerContext'; + +type MaterialAnimatorProps = { + ikSolver: any; + armBot: any; + currentPhase: string; +}; + +export default function MaterialAnimator({ ikSolver, armBot, currentPhase }: MaterialAnimatorProps) { + const sphereRef = useRef(null); + const boneWorldPosition = new THREE.Vector3(); + const [isRendered, setIsRendered] = useState(false); + + useEffect(() => { + if (currentPhase === "start-to-end") { + setIsRendered(true); + } else { + setIsRendered(false); + } + }, [currentPhase]); + + useFrame(() => { + if (!ikSolver || !sphereRef.current) return; + + const boneTarget = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === "Bone004"); + const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === "Effector"); + + if (!boneTarget || !bone) return; + + if (currentPhase === "start-to-end") { + // Get world positions + const boneTargetWorldPos = new THREE.Vector3(); + const boneWorldPos = new THREE.Vector3(); + boneTarget.getWorldPosition(boneTargetWorldPos); + bone.getWorldPosition(boneWorldPos); + + // Calculate direction + const direction = new THREE.Vector3(); + direction.subVectors(boneWorldPos, boneTargetWorldPos).normalize(); + const downwardDirection = direction.clone().negate(); + const adjustedPosition = boneWorldPos.clone().addScaledVector(downwardDirection, -0.25); + + //set position + sphereRef.current.position.copy(adjustedPosition); + + // Set rotation + const worldQuaternion = new THREE.Quaternion(); + bone.getWorldQuaternion(worldQuaternion); + sphereRef.current.quaternion.copy(worldQuaternion); + } + }); + + return ( + <> + {isRendered && ( + + + + + )} + + ); +} diff --git a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx index fd649c6..34f191b 100644 --- a/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx +++ b/app/src/modules/simulation/roboticArm/instances/animator/roboticArmAnimator.tsx @@ -15,7 +15,6 @@ function RoboticArmAnimator({ ikSolver, targetBone, armBot, - logStatus, path }: any) { const progressRef = useRef(0); @@ -30,9 +29,11 @@ function RoboticArmAnimator({ // Zustand stores const { isPlaying } = usePlayButtonStore(); const { isPaused } = usePauseButtonStore(); - const { isReset, setReset } = useResetButtonStore(); + const { isReset } = useResetButtonStore(); const { speed } = useAnimationPlaySpeed(); + const CIRCLE_RADIUS = 1.6 + // Update path state whenever `path` prop changes useEffect(() => { setCurrentPath(path); @@ -40,13 +41,13 @@ function RoboticArmAnimator({ // Handle circle points based on armBot position useEffect(() => { - const points = generateRingPoints(1.6, 64) + const points = generateRingPoints(CIRCLE_RADIUS, 64) setCirclePoints(points); }, [armBot.position]); //Handle Reset Animation useEffect(() => { - if (isReset ) { + if (isReset) { progressRef.current = 0; curveRef.current = null; setCurrentPath([]); @@ -98,7 +99,7 @@ function RoboticArmAnimator({ return distance < nearestDistance ? point : nearest; }, circlePoints[0]); }; - + // Handle nearest points and final path (including arc points) useEffect(() => { if (circlePoints.length > 0 && currentPath.length > 0) { @@ -109,14 +110,6 @@ function RoboticArmAnimator({ const raisedStart = [start[0], start[1] + 0.5, start[2]] as [number, number, number]; const raisedEnd = [end[0], end[1] + 0.5, end[2]] as [number, number, number]; - // const findNearest = (target: [number, number, number]) => { - // return circlePoints.reduce((nearest, point) => { - // const distance = Math.hypot(target[0] - point[0], target[1] - point[1], target[2] - point[2]); - // const nearestDistance = Math.hypot(target[0] - nearest[0], target[1] - nearest[1], target[2] - nearest[2]); - // return distance < nearestDistance ? point : nearest; - // }, circlePoints[0]); - // }; - const nearestToStart = findNearest(raisedStart); const nearestToEnd = findNearest(raisedEnd); @@ -187,6 +180,7 @@ function RoboticArmAnimator({ if (!ikSolver) return; const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone); + if (!bone) return; if (isPlaying) { @@ -252,7 +246,7 @@ function RoboticArmAnimator({ )} - + diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index c67d6f6..21bbc7e 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -3,12 +3,11 @@ import IKInstance from '../ikInstance/ikInstance'; import RoboticArmAnimator from '../animator/roboticArmAnimator'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore'; -import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb"; +import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb"; import { useThree } from "@react-three/fiber"; import useModuleStore from '../../../../../store/useModuleStore'; import * as THREE from "three"; -import { useSelectedAction, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; -import { useProductStore } from '../../../../../store/simulation/useProductStore'; +import MaterialAnimator from '../animator/materialAnimator'; function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { @@ -25,13 +24,11 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { let startTime: number; //zustand const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore(); - const { getActionByUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); const { activeModule } = useModuleStore(); const { isPlaying } = usePlayButtonStore(); const { isReset, setReset } = useResetButtonStore(); const { isPaused } = usePauseButtonStore(); - const { selectedAction } = useSelectedAction(); + function firstFrame() { startTime = performance.now(); @@ -114,7 +111,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.") } } - // setReset(false); } }, [isReset, isPlaying]) @@ -123,13 +119,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { if (targetMesh) { targetMesh.visible = activeModule !== "simulation" } - const targetBones = ikSolver?.mesh.skeleton.bones.find( - (b: any) => b.name === targetBone - ); + const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone); if (isPlaying) { //Moving armBot from initial point to rest position. if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") { - setArmBotActive(armBot.modelUuid, true) setArmBotState(armBot.modelUuid, "running") setCurrentPhase("init-to-rest"); @@ -167,52 +160,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) { requestAnimationFrame(firstFrame); - // setArmBotActive(armBot.modelUuid, true); - // setArmBotState(armBot.modelUuid, "running"); - // setCurrentPhase("start-to-end"); - // const startPoint = armBot.point.actions[0].process.startPoint; - // const endPoint = armBot.point.actions[0].process.endPoint; - // if (startPoint && endPoint) { - // let curve = createCurveBetweenTwoPoints( - // new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]), - // new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])); - // if (curve) { - // setTimeout(() => { - // logStatus(armBot.modelUuid, "picking the object"); - // setPath(curve.points.map(point => [point.x, point.y, point.z])); - // }, 1500) - // } - // } - // logStatus(armBot.modelUuid, "Moving armBot from start point to end position.") } else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) { requestAnimationFrame(firstFrame); - // setArmBotActive(armBot.modelUuid, true); - // setArmBotState(armBot.modelUuid, "running"); - // setCurrentPhase("end-to-rest"); - // const endPoint = armBot.point.actions[0].process.endPoint; - // if (endPoint) { - // let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition); - // if (curve) { - // setTimeout(() => { - // logStatus(armBot.modelUuid, "dropping the object"); - // setPath(curve.points.map(point => [point.x, point.y, point.z])); - // }, 1500) - // } - // } - // logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.") } - } else { - // logStatus(armBot.modelUuid, "Simulation Play Exited") - // setArmBotActive(armBot.modelUuid, false) - // setArmBotState(armBot.modelUuid, "idle") - // setCurrentPhase("init"); - // setPath([]) - // isPausedRef.current = false - // pauseTimeRef.current = null - // isPausedRef.current = false - // startTime = 0 - // removeCurrentAction(armBot.modelUuid) } }, [currentPhase, armBot, isPlaying, ikSolver]) @@ -258,10 +209,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { } } const logStatus = (id: string, status: string) => { - - - // - } return ( @@ -269,6 +216,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) { + ) } diff --git a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx index c090a92..be41a95 100644 --- a/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/ikInstance/ikInstance.tsx @@ -57,6 +57,12 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns rotationMin: new THREE.Vector3(0, 0, 0), rotationMax: new THREE.Vector3(2, 0, 0), }, + // { + // index: 1, + // enabled: true, + // rotationMin: new THREE.Vector3(0, -Math.PI, 0), + // rotationMax: new THREE.Vector3(0, Math.PI, 0), + // }, { index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) }, { index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) }, ], diff --git a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts index ab89507..dae90ee 100644 --- a/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/ui/arm/useDraggableGLTF.ts @@ -138,7 +138,7 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { targetPosition.x = centerX + Math.cos(angle) * clampedDistance; targetPosition.z = centerZ + Math.sin(angle) * clampedDistance; } - targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.5); + targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.9); // Convert world position to local if object is nested inside a parent if (parent) { parent.worldToLocal(targetPosition);