116 lines
4.2 KiB
TypeScript
116 lines
4.2 KiB
TypeScript
import { Line } from "@react-three/drei";
|
|
import { useMemo } from "react";
|
|
import * as THREE from "three";
|
|
import { useSelectedAssets } from "../../../../store/builder/store";
|
|
|
|
interface BoundingBoxProps {
|
|
boundingBoxRef?: any;
|
|
isPerAsset?: boolean;
|
|
}
|
|
|
|
const getBoxLines = (min: THREE.Vector3, max: THREE.Vector3) => [
|
|
[min.x, min.y, min.z], [max.x, min.y, min.z],
|
|
[max.x, min.y, min.z], [max.x, max.y, min.z],
|
|
[max.x, max.y, min.z], [min.x, max.y, min.z],
|
|
[min.x, max.y, min.z], [min.x, min.y, min.z],
|
|
|
|
[min.x, min.y, max.z], [max.x, min.y, max.z],
|
|
[max.x, min.y, max.z], [max.x, max.y, max.z],
|
|
[max.x, max.y, max.z], [min.x, max.y, max.z],
|
|
[min.x, max.y, max.z], [min.x, min.y, max.z],
|
|
|
|
[min.x, min.y, min.z], [min.x, min.y, max.z],
|
|
[max.x, min.y, min.z], [max.x, min.y, max.z],
|
|
[max.x, max.y, min.z], [max.x, max.y, max.z],
|
|
[min.x, max.y, min.z], [min.x, max.y, max.z],
|
|
];
|
|
|
|
const BoundingBox = ({ boundingBoxRef, isPerAsset = true }: BoundingBoxProps) => {
|
|
const { selectedAssets } = useSelectedAssets();
|
|
const savedTheme: string = localStorage.getItem("theme") || "light";
|
|
|
|
const boxes = useMemo(() => {
|
|
if (selectedAssets.length === 0) return [];
|
|
|
|
if (isPerAsset) {
|
|
return selectedAssets.map((obj: THREE.Object3D) => {
|
|
const position = obj.position;
|
|
const rotation = obj.getWorldQuaternion(new THREE.Quaternion());
|
|
const clone = obj.clone();
|
|
clone.position.set(0, 0, 0);
|
|
clone.rotation.set(0, 0, 0);
|
|
const box = new THREE.Box3().setFromObject(clone);
|
|
const size = new THREE.Vector3();
|
|
const center = new THREE.Vector3();
|
|
box.getSize(size);
|
|
box.getCenter(center);
|
|
|
|
const halfSize = size.clone().multiplyScalar(0.5);
|
|
const min = center.clone().sub(halfSize);
|
|
const max = center.clone().add(halfSize);
|
|
|
|
return {
|
|
points: getBoxLines(min, max),
|
|
position: [position.x, center.y, position.z],
|
|
rotation: rotation.toArray(),
|
|
size: size.toArray(),
|
|
};
|
|
});
|
|
} else {
|
|
const box = new THREE.Box3();
|
|
selectedAssets.forEach((obj: any) => box.expandByObject(obj.clone()));
|
|
const size = new THREE.Vector3();
|
|
const center = new THREE.Vector3();
|
|
box.getSize(size);
|
|
box.getCenter(center);
|
|
|
|
const halfSize = size.clone().multiplyScalar(0.5);
|
|
const min = center.clone().sub(halfSize);
|
|
const max = center.clone().add(halfSize);
|
|
|
|
return [
|
|
{
|
|
points: getBoxLines(min, max),
|
|
position: center.toArray(),
|
|
rotation: [0, 0, 0, 1],
|
|
size: size.toArray(),
|
|
},
|
|
];
|
|
}
|
|
}, [selectedAssets, isPerAsset]);
|
|
|
|
return (
|
|
<>
|
|
{boxes.map((box: any, index: number) => (
|
|
<group
|
|
key={index}
|
|
name="SelectionGroupBoundingBoxLine"
|
|
>
|
|
<Line
|
|
name="SelectionGroupBoundingBox"
|
|
depthWrite={false}
|
|
points={box.points}
|
|
color={savedTheme === "dark" ? "#c4abf1" : "#6f42c1"}
|
|
lineWidth={2.7}
|
|
segments
|
|
position={[box.position[0], 0, box.position[2]]}
|
|
quaternion={new THREE.Quaternion(...box.rotation)}
|
|
/>
|
|
<mesh
|
|
name="SelectionGroupBoundingLine"
|
|
ref={index === 0 ? boundingBoxRef : null}
|
|
visible={false}
|
|
position={box.position}
|
|
quaternion={new THREE.Quaternion(...box.rotation)}
|
|
>
|
|
<boxGeometry args={box.size} />
|
|
<meshBasicMaterial />
|
|
</mesh>
|
|
</group>
|
|
))}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default BoundingBox;
|