object attach and detach added
This commit is contained in:
parent
19d41a775c
commit
cea9a32ce4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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<THREE.Mesh>(null);
|
||||||
|
const boneWorldPosition = new THREE.Vector3();
|
||||||
|
const [isRendered, setIsRendered] = useState<boolean>(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 && (
|
||||||
|
<mesh ref={sphereRef}>
|
||||||
|
<boxGeometry args={[0.5, 0.5, 0.5]} />
|
||||||
|
<meshStandardMaterial color="yellow" />
|
||||||
|
</mesh>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ function RoboticArmAnimator({
|
||||||
ikSolver,
|
ikSolver,
|
||||||
targetBone,
|
targetBone,
|
||||||
armBot,
|
armBot,
|
||||||
logStatus,
|
|
||||||
path
|
path
|
||||||
}: any) {
|
}: any) {
|
||||||
const progressRef = useRef(0);
|
const progressRef = useRef(0);
|
||||||
|
@ -30,9 +29,11 @@ function RoboticArmAnimator({
|
||||||
// Zustand stores
|
// Zustand stores
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { isReset, setReset } = useResetButtonStore();
|
const { isReset } = useResetButtonStore();
|
||||||
const { speed } = useAnimationPlaySpeed();
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
|
||||||
|
const CIRCLE_RADIUS = 1.6
|
||||||
|
|
||||||
// Update path state whenever `path` prop changes
|
// Update path state whenever `path` prop changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
|
@ -40,13 +41,13 @@ function RoboticArmAnimator({
|
||||||
|
|
||||||
// Handle circle points based on armBot position
|
// Handle circle points based on armBot position
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const points = generateRingPoints(1.6, 64)
|
const points = generateRingPoints(CIRCLE_RADIUS, 64)
|
||||||
setCirclePoints(points);
|
setCirclePoints(points);
|
||||||
}, [armBot.position]);
|
}, [armBot.position]);
|
||||||
|
|
||||||
//Handle Reset Animation
|
//Handle Reset Animation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isReset ) {
|
if (isReset) {
|
||||||
progressRef.current = 0;
|
progressRef.current = 0;
|
||||||
curveRef.current = null;
|
curveRef.current = null;
|
||||||
setCurrentPath([]);
|
setCurrentPath([]);
|
||||||
|
@ -109,14 +110,6 @@ function RoboticArmAnimator({
|
||||||
const raisedStart = [start[0], start[1] + 0.5, start[2]] as [number, number, number];
|
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 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 nearestToStart = findNearest(raisedStart);
|
||||||
const nearestToEnd = findNearest(raisedEnd);
|
const nearestToEnd = findNearest(raisedEnd);
|
||||||
|
|
||||||
|
@ -187,6 +180,7 @@ function RoboticArmAnimator({
|
||||||
if (!ikSolver) return;
|
if (!ikSolver) return;
|
||||||
|
|
||||||
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
const bone = ikSolver.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
|
|
||||||
if (!bone) return;
|
if (!bone) return;
|
||||||
|
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
|
@ -252,7 +246,7 @@ function RoboticArmAnimator({
|
||||||
</mesh>
|
</mesh>
|
||||||
)}
|
)}
|
||||||
<mesh position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]} rotation={[-Math.PI / 2, 0, 0]}>
|
<mesh position={[armBot.position[0], armBot.position[1] + 1.5, armBot.position[2]]} rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
<ringGeometry args={[1.59, 1.61, 64]} />
|
<ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.02, 64]} />
|
||||||
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
<meshBasicMaterial color="green" side={THREE.DoubleSide} />
|
||||||
</mesh>
|
</mesh>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -3,12 +3,11 @@ import IKInstance from '../ikInstance/ikInstance';
|
||||||
import RoboticArmAnimator from '../animator/roboticArmAnimator';
|
import RoboticArmAnimator from '../animator/roboticArmAnimator';
|
||||||
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
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 { useThree } from "@react-three/fiber";
|
||||||
import useModuleStore from '../../../../../store/useModuleStore';
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useSelectedAction, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
|
import MaterialAnimator from '../animator/materialAnimator';
|
||||||
import { useProductStore } from '../../../../../store/simulation/useProductStore';
|
|
||||||
|
|
||||||
|
|
||||||
function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
|
@ -25,13 +24,11 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
let startTime: number;
|
let startTime: number;
|
||||||
//zustand
|
//zustand
|
||||||
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
||||||
const { getActionByUuid } = useProductStore();
|
|
||||||
const { selectedProduct } = useSelectedProduct();
|
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { isReset, setReset } = useResetButtonStore();
|
const { isReset, setReset } = useResetButtonStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { selectedAction } = useSelectedAction();
|
|
||||||
|
|
||||||
function firstFrame() {
|
function firstFrame() {
|
||||||
startTime = performance.now();
|
startTime = performance.now();
|
||||||
|
@ -114,7 +111,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
|
logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// setReset(false);
|
|
||||||
}
|
}
|
||||||
}, [isReset, isPlaying])
|
}, [isReset, isPlaying])
|
||||||
|
|
||||||
|
@ -123,13 +119,10 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
if (targetMesh) {
|
if (targetMesh) {
|
||||||
targetMesh.visible = activeModule !== "simulation"
|
targetMesh.visible = activeModule !== "simulation"
|
||||||
}
|
}
|
||||||
const targetBones = ikSolver?.mesh.skeleton.bones.find(
|
const targetBones = ikSolver?.mesh.skeleton.bones.find((b: any) => b.name === targetBone);
|
||||||
(b: any) => b.name === targetBone
|
|
||||||
);
|
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
//Moving armBot from initial point to rest position.
|
//Moving armBot from initial point to rest position.
|
||||||
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
|
if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {
|
||||||
|
|
||||||
setArmBotActive(armBot.modelUuid, true)
|
setArmBotActive(armBot.modelUuid, true)
|
||||||
setArmBotState(armBot.modelUuid, "running")
|
setArmBotState(armBot.modelUuid, "running")
|
||||||
setCurrentPhase("init-to-rest");
|
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) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
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) {
|
else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
|
||||||
requestAnimationFrame(firstFrame);
|
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])
|
}, [currentPhase, armBot, isPlaying, ikSolver])
|
||||||
|
@ -258,10 +209,6 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const logStatus = (id: string, status: string) => {
|
const logStatus = (id: string, status: string) => {
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -269,6 +216,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
|
||||||
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
|
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
|
||||||
<RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
|
<RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
|
||||||
logStatus={logStatus} path={path} currentPhase={currentPhase} />
|
logStatus={logStatus} path={path} currentPhase={currentPhase} />
|
||||||
|
<MaterialAnimator ikSolver={ikSolver} armBot={armBot} currentPhase={currentPhase} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,12 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, armBot, groupRef }: IKIns
|
||||||
rotationMin: new THREE.Vector3(0, 0, 0),
|
rotationMin: new THREE.Vector3(0, 0, 0),
|
||||||
rotationMax: new THREE.Vector3(2, 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: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) },
|
||||||
{ index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
|
{ index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
|
||||||
],
|
],
|
||||||
|
|
|
@ -138,7 +138,7 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
|
||||||
targetPosition.x = centerX + Math.cos(angle) * clampedDistance;
|
targetPosition.x = centerX + Math.cos(angle) * clampedDistance;
|
||||||
targetPosition.z = centerZ + Math.sin(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
|
// Convert world position to local if object is nested inside a parent
|
||||||
if (parent) {
|
if (parent) {
|
||||||
parent.worldToLocal(targetPosition);
|
parent.worldToLocal(targetPosition);
|
||||||
|
|
Loading…
Reference in New Issue