armbot ui added
This commit is contained in:
@@ -8,11 +8,13 @@ import {
|
||||
useSelectedEventSphere,
|
||||
useSelectedEventData,
|
||||
} from "../../../../../store/simulation/useSimulationStore";
|
||||
import PickDropPoints from "../../../../../components/ui/arm/PickDropPoints";
|
||||
import PickDropPoints from "../../../ui/arm/PickDropPoints";
|
||||
|
||||
import armPick from "../../../../../assets/gltf-glb/arm_ui_pick.glb";
|
||||
import armDrop from "../../../../../assets/gltf-glb/arm_ui_drop.glb";
|
||||
import useDraggableGLTF from "../../../../../components/ui/arm/useDraggableGLTF";
|
||||
import useDraggableGLTF from "../../../ui/arm/useDraggableGLTF";
|
||||
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
|
||||
interface Process {
|
||||
startPoint: number[] | null;
|
||||
@@ -47,117 +49,53 @@ interface RoboticArmEvent {
|
||||
function PointsCreator() {
|
||||
const { events, updatePoint, getPointByUuid, getEventByModelUuid } =
|
||||
useEventsStore();
|
||||
|
||||
const [armBotStatusSample, setArmBotStatusSample] = useState<
|
||||
RoboticArmEvent[]
|
||||
>([
|
||||
{
|
||||
modelUuid: "b3556818-9e46-48b0-a869-a75c92857125",
|
||||
modelName: "robotic_arm",
|
||||
position: [0, 0, 0],
|
||||
rotation: [0, 0, 0],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1.5,
|
||||
point: {
|
||||
uuid: "point-123",
|
||||
position: [0, 1.5, 0],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: "action-001",
|
||||
actionName: "Pick Component",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
{
|
||||
actionUuid: "action-002",
|
||||
actionName: "Pick Component",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
modelUuid: "16a394c7-0808-4bdf-a5d3-e5ca141ffb9f",
|
||||
modelName: "arm without rig (1)",
|
||||
position: [0, 0, 0],
|
||||
rotation: [0, 0, 0],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1.5,
|
||||
point: {
|
||||
uuid: "point-123",
|
||||
position: [0, 1.5, 0],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: "action-001",
|
||||
actionName: "Pick Component",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
},
|
||||
triggers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
const { armBots, updateArmBot, addArmBot, removeArmBot } = useArmBotStore()
|
||||
|
||||
const armUiPick = useGLTF(armPick) as any;
|
||||
const armUiDrop = useGLTF(armDrop) as any;
|
||||
|
||||
const updatePointToState = (obj: THREE.Object3D) => {
|
||||
const { modelUuid, pointUuid, actionType, actionUuid } = obj.userData;
|
||||
const newPosition = obj.position.toArray();
|
||||
|
||||
const newPosition = new THREE.Vector3();
|
||||
obj.getWorldPosition(newPosition);
|
||||
const worldPositionArray = newPosition.toArray();
|
||||
|
||||
setArmBotStatusSample((prev) =>
|
||||
prev.map((event) => {
|
||||
if (event.modelUuid === modelUuid) {
|
||||
const updatedActions = event.point.actions.map((action) => {
|
||||
if (action.actionUuid === actionUuid) {
|
||||
const updatedProcess = { ...action.process };
|
||||
if (actionType === "pick") {
|
||||
updatedProcess.startPoint = newPosition;
|
||||
} else if (actionType === "drop") {
|
||||
updatedProcess.endPoint = newPosition;
|
||||
}
|
||||
return {
|
||||
...action,
|
||||
process: updatedProcess,
|
||||
};
|
||||
}
|
||||
return action;
|
||||
});
|
||||
const armBot = armBots.find((a) => a.modelUuid === modelUuid);
|
||||
if (!armBot) return;
|
||||
|
||||
return {
|
||||
...event,
|
||||
point: {
|
||||
...event.point,
|
||||
actions: updatedActions,
|
||||
},
|
||||
};
|
||||
const updatedActions = armBot.point.actions.map((action: any) => {
|
||||
if (action.actionUuid === actionUuid) {
|
||||
const updatedProcess = { ...action.process };
|
||||
|
||||
if (actionType === "pick") {
|
||||
updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray);
|
||||
}
|
||||
return event;
|
||||
})
|
||||
);
|
||||
if (actionType === "drop") {
|
||||
updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray);
|
||||
}
|
||||
return {
|
||||
...action,
|
||||
process: updatedProcess,
|
||||
};
|
||||
}
|
||||
return action;
|
||||
});
|
||||
|
||||
updateArmBot(modelUuid, {
|
||||
point: {
|
||||
...armBot.point,
|
||||
actions: updatedActions,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { handlePointerDown } = useDraggableGLTF(updatePointToState);
|
||||
|
||||
const { handlePointerDown } = useDraggableGLTF(updatePointToState);
|
||||
const { scene } = useThree();
|
||||
const { activeModule } = useModuleStore();
|
||||
const transformRef = useRef<any>(null);
|
||||
const groupRef = useRef<any>(null);
|
||||
const [transformMode, setTransformMode] = useState<
|
||||
"translate" | "rotate" | null
|
||||
>(null);
|
||||
@@ -206,12 +144,13 @@ function PointsCreator() {
|
||||
const getDefaultPositions = (modelUuid: string) => {
|
||||
const modelData = getModelByUuid(modelUuid);
|
||||
if (modelData) {
|
||||
|
||||
const baseX = modelData.position?.[0] || 0;
|
||||
const baseY = modelData.position?.[1] + 2.8 || 1.5;
|
||||
const baseY = 2.6;
|
||||
const baseZ = modelData.position?.[2] || 0;
|
||||
return {
|
||||
pick: [baseX, baseY, baseZ - 2.5],
|
||||
drop: [baseX, baseY, baseZ - 0.5],
|
||||
pick: [baseX, baseY, baseZ + 0.4],
|
||||
drop: [baseX, baseY, baseZ - 1.2],
|
||||
default: [baseX, baseY, baseZ - 1.5],
|
||||
};
|
||||
}
|
||||
@@ -231,113 +170,61 @@ function PointsCreator() {
|
||||
}
|
||||
const storeModels = (useModuleStore.getState() as any).models || [];
|
||||
return storeModels.find((m: any) => m.modelUuid === modelUuid);
|
||||
} catch (error) {}
|
||||
} catch (error) { }
|
||||
return null;
|
||||
};
|
||||
|
||||
function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null {
|
||||
if (worldPosArray) {
|
||||
const worldPos = new THREE.Vector3(...worldPosArray);
|
||||
const localPos = worldPos.clone();
|
||||
|
||||
const parentObject = scene.getObjectByProperty('uuid', parentUuid);
|
||||
if (parentObject) {
|
||||
parentObject.worldToLocal(localPos);
|
||||
|
||||
return [localPos.x, localPos.y, localPos.z];
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("armBotStatusSample: ", armBotStatusSample);
|
||||
}, [armBotStatusSample]);
|
||||
|
||||
}, [armBots]);
|
||||
return (
|
||||
<>
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<group name="EventPointsGroup">
|
||||
{events.map((event, i) => {
|
||||
if (event.type === "transfer") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
{event.points.map((point, j) => (
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[point.uuid]
|
||||
);
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}}
|
||||
key={`${i}-${j}`}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="orange" />
|
||||
</mesh>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "vehicle") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="blue" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "roboticArm") {
|
||||
{armBots.map((event, i) => {
|
||||
if (event.type === "roboticArm") {
|
||||
const defaultPositions = getDefaultPositions(event.modelUuid);
|
||||
const isSelected =
|
||||
selectedPoint?.userData?.modelUuid === event.modelUuid;
|
||||
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
rotation={new THREE.Euler(...event.rotation)}
|
||||
>
|
||||
<mesh
|
||||
name='Event-Sphere'
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||
setSelectedPoint(e.object as THREE.Mesh);
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}}
|
||||
position={new THREE.Vector3(...defaultPositions.default)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial
|
||||
@@ -346,6 +233,7 @@ function PointsCreator() {
|
||||
</mesh>
|
||||
{event.point.actions.map((action) => {
|
||||
if (action.actionType === "pickAndPlace") {
|
||||
|
||||
const pickPosition =
|
||||
action.process.startPoint || defaultPositions.pick;
|
||||
const dropPosition =
|
||||
@@ -385,37 +273,6 @@ function PointsCreator() {
|
||||
})}
|
||||
</group>
|
||||
);
|
||||
} else if (event.type === "machine") {
|
||||
return (
|
||||
<group
|
||||
key={i}
|
||||
position={new THREE.Vector3(...event.position)}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={event.point.uuid}
|
||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEventSphere(
|
||||
sphereRefs.current[event.point.uuid]
|
||||
);
|
||||
}}
|
||||
onPointerMissed={() => {
|
||||
clearSelectedEventSphere();
|
||||
setTransformMode(null);
|
||||
}}
|
||||
position={new THREE.Vector3(...event.point.position)}
|
||||
userData={{
|
||||
modelUuid: event.modelUuid,
|
||||
pointUuid: event.point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="purple" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||
}
|
||||
//Waiting for trigger.
|
||||
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) {
|
||||
console.log("trigger");
|
||||
logStatus(robot.modelUuid, "Waiting to trigger CurrentAction")
|
||||
setTimeout(() => {
|
||||
addCurrentAction(robot.modelUuid, 'action-003');
|
||||
}, 3000);
|
||||
|
||||
@@ -15,7 +15,7 @@ type IKInstanceProps = {
|
||||
setArmBotCurvePoints: any
|
||||
};
|
||||
function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) {
|
||||
|
||||
|
||||
const { scene } = useThree();
|
||||
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
||||
const draco = new DRACOLoader();
|
||||
@@ -65,17 +65,8 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe
|
||||
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
|
||||
setIkSolver(solver);
|
||||
|
||||
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05);
|
||||
// if (solver) {
|
||||
// const bone = solver.mesh.skeleton.bones.find(
|
||||
// (b: any) => b.name === targetBoneName
|
||||
// ) ?? "";
|
||||
// if (bone) {
|
||||
// const position = new THREE.Vector3();
|
||||
// bone.getWorldPosition(position);
|
||||
// console.log("world position", position.x, position.y, position.z); // this is the bone's world position
|
||||
// }
|
||||
// }
|
||||
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05)
|
||||
|
||||
scene.add(helper)
|
||||
|
||||
|
||||
|
||||
@@ -6,12 +6,12 @@ import { useFloorItems } from "../../../store/store";
|
||||
function RoboticArm() {
|
||||
const { armBots, addArmBot, removeArmBot } = useArmBotStore();
|
||||
const { floorItems } = useFloorItems();
|
||||
|
||||
|
||||
|
||||
const armBotStatusSample: RoboticArmEventSchema[] = [
|
||||
{
|
||||
state: "idle",
|
||||
modelUuid: "armbot-xyz-001",
|
||||
modelUuid: "3abf5d46-b59e-4e6b-9c02-a4634b64b82d",
|
||||
modelName: "ArmBot-X200",
|
||||
position: [0.20849215906958463, 0, 0.32079278127773675],
|
||||
rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15],
|
||||
@@ -19,7 +19,7 @@ function RoboticArm() {
|
||||
speed: 1.5,
|
||||
point: {
|
||||
uuid: "point-123",
|
||||
position: [0, 1.5, 0],
|
||||
position: [0, 2.6, 0],
|
||||
rotation: [0, 0, 0],
|
||||
actions: [
|
||||
{
|
||||
@@ -30,6 +30,18 @@ function RoboticArm() {
|
||||
startPoint: [-1, 2, 1],
|
||||
endPoint: [-2, 1, -1],
|
||||
},
|
||||
// process: {
|
||||
// "startPoint": [
|
||||
// 0.37114476008711866,
|
||||
// 1.9999999999999998,
|
||||
// 1.8418816116721384
|
||||
// ],
|
||||
// "endPoint": [
|
||||
// -0.42197069459490777,
|
||||
// 1,
|
||||
// -3.159515927851809
|
||||
// ]
|
||||
// },
|
||||
triggers: [
|
||||
{
|
||||
triggerUuid: "trigger-001",
|
||||
@@ -154,7 +166,7 @@ function RoboticArm() {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
//
|
||||
|
||||
}, [armBots]);
|
||||
|
||||
return (
|
||||
|
||||
54
app/src/modules/simulation/ui/arm/PickDropPoints.tsx
Normal file
54
app/src/modules/simulation/ui/arm/PickDropPoints.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import React, { useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { ThreeEvent } from "@react-three/fiber";
|
||||
|
||||
interface PickDropProps {
|
||||
position: number[];
|
||||
modelUuid: string;
|
||||
pointUuid: string;
|
||||
actionType: "pick" | "drop";
|
||||
actionUuid: string;
|
||||
gltfScene: THREE.Group;
|
||||
selectedPoint: THREE.Mesh | null;
|
||||
handlePointerDown: (e: ThreeEvent<PointerEvent>) => void;
|
||||
isSelected: boolean;
|
||||
}
|
||||
|
||||
const PickDropPoints: React.FC<PickDropProps> = ({
|
||||
position,
|
||||
modelUuid,
|
||||
pointUuid,
|
||||
actionType,
|
||||
actionUuid,
|
||||
gltfScene,
|
||||
selectedPoint,
|
||||
handlePointerDown,
|
||||
isSelected,
|
||||
}) => {
|
||||
const groupRef = useRef<THREE.Group>(null);
|
||||
|
||||
return (
|
||||
<group
|
||||
ref={groupRef}
|
||||
position={
|
||||
Array.isArray(position) && position.length === 3
|
||||
? new THREE.Vector3(...position)
|
||||
: new THREE.Vector3(0, 0, 0)
|
||||
}
|
||||
onPointerDown={(e) => {
|
||||
e.stopPropagation(); // Important to prevent event bubbling
|
||||
if (!isSelected) return;
|
||||
handlePointerDown(e);
|
||||
}}
|
||||
userData={{ modelUuid, pointUuid, actionType, actionUuid }}
|
||||
>
|
||||
<primitive
|
||||
object={gltfScene.clone()}
|
||||
position={[0, 0, 0]} // Ensure this stays at origin
|
||||
scale={[0.5, 0.5, 0.5]}
|
||||
/>
|
||||
</group>
|
||||
);
|
||||
};
|
||||
|
||||
export default PickDropPoints;
|
||||
131
app/src/modules/simulation/ui/arm/useDraggableGLTF.ts
Normal file
131
app/src/modules/simulation/ui/arm/useDraggableGLTF.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { ThreeEvent, useThree } from "@react-three/fiber";
|
||||
|
||||
type OnUpdateCallback = (object: THREE.Object3D) => void;
|
||||
|
||||
export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
|
||||
const { camera, gl, controls, scene } = useThree();
|
||||
const activeObjRef = useRef<THREE.Object3D | null>(null);
|
||||
const planeRef = useRef<THREE.Plane>(
|
||||
new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)
|
||||
);
|
||||
const offsetRef = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||
const initialPositionRef = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const pointer = new THREE.Vector2();
|
||||
|
||||
const handlePointerDown = (e: ThreeEvent<PointerEvent>) => {
|
||||
e.stopPropagation();
|
||||
|
||||
let obj: THREE.Object3D | null = e.object;
|
||||
|
||||
// Traverse up until we find modelUuid in userData
|
||||
while (obj && !obj.userData?.modelUuid) {
|
||||
obj = obj.parent;
|
||||
}
|
||||
|
||||
if (!obj) return;
|
||||
|
||||
// Disable orbit controls while dragging
|
||||
if (controls) (controls as any).enabled = false;
|
||||
|
||||
activeObjRef.current = obj;
|
||||
initialPositionRef.current.copy(obj.position);
|
||||
|
||||
// Get world position
|
||||
const objectWorldPos = new THREE.Vector3();
|
||||
obj.getWorldPosition(objectWorldPos);
|
||||
|
||||
// Set plane at the object's Y level
|
||||
planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y);
|
||||
|
||||
// Convert pointer to NDC
|
||||
const rect = gl.domElement.getBoundingClientRect();
|
||||
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
// Raycast to intersection
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
const intersection = new THREE.Vector3();
|
||||
raycaster.ray.intersectPlane(planeRef.current, intersection);
|
||||
|
||||
// Calculate offset
|
||||
offsetRef.current.copy(objectWorldPos).sub(intersection);
|
||||
|
||||
// Start listening for drag
|
||||
gl.domElement.addEventListener("pointermove", handlePointerMove);
|
||||
gl.domElement.addEventListener("pointerup", handlePointerUp);
|
||||
};
|
||||
|
||||
const handlePointerMove = (e: PointerEvent) => {
|
||||
if (!activeObjRef.current) return;
|
||||
|
||||
// Check if Shift key is pressed
|
||||
const isShiftKeyPressed = e.shiftKey;
|
||||
|
||||
// Get the mouse position relative to the canvas
|
||||
const rect = gl.domElement.getBoundingClientRect();
|
||||
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||
|
||||
// Update raycaster to point to the mouse position
|
||||
raycaster.setFromCamera(pointer, camera);
|
||||
|
||||
// Create a vector to store intersection point
|
||||
const intersection = new THREE.Vector3();
|
||||
const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection);
|
||||
if (!intersects) return;
|
||||
|
||||
// Add offset for dragging
|
||||
intersection.add(offsetRef.current);
|
||||
console.log('intersection: ', intersection);
|
||||
|
||||
// Get the parent's world matrix if exists
|
||||
const parent = activeObjRef.current.parent;
|
||||
const targetPosition = new THREE.Vector3();
|
||||
|
||||
if (isShiftKeyPressed) {
|
||||
console.log('isShiftKeyPressed: ', isShiftKeyPressed);
|
||||
// For Y-axis only movement, maintain original X and Z
|
||||
console.log('initialPositionRef: ', initialPositionRef);
|
||||
console.log('intersection.y: ', intersection);
|
||||
targetPosition.set(
|
||||
initialPositionRef.current.x,
|
||||
intersection.y,
|
||||
initialPositionRef.current.z
|
||||
);
|
||||
} else {
|
||||
// For free movement
|
||||
targetPosition.copy(intersection);
|
||||
}
|
||||
|
||||
// Convert world position to local if object is nested inside a parent
|
||||
if (parent) {
|
||||
parent.worldToLocal(targetPosition);
|
||||
}
|
||||
|
||||
// Update object position
|
||||
activeObjRef.current.position.copy(targetPosition);
|
||||
};
|
||||
|
||||
const handlePointerUp = () => {
|
||||
if (controls) (controls as any).enabled = true;
|
||||
|
||||
if (activeObjRef.current) {
|
||||
// Pass the updated position to the onUpdate callback to persist it
|
||||
onUpdate(activeObjRef.current);
|
||||
}
|
||||
|
||||
gl.domElement.removeEventListener("pointermove", handlePointerMove);
|
||||
gl.domElement.removeEventListener("pointerup", handlePointerUp);
|
||||
|
||||
activeObjRef.current = null;
|
||||
};
|
||||
|
||||
return { handlePointerDown };
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user