149 lines
5.2 KiB
TypeScript
149 lines
5.2 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
|
import { Group, Vector3 } from "three";
|
|
import { CameraControls } from "@react-three/drei";
|
|
import { GLTFLoader } from "three/examples/jsm/Addons";
|
|
import { useThree, useFrame } from "@react-three/fiber";
|
|
import {
|
|
useContextActionStore,
|
|
useLimitDistance,
|
|
useRenderDistance,
|
|
} from "../../../../store/builder/store";
|
|
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
|
import { useSceneContext } from "../../../scene/sceneContext";
|
|
import useZoomMesh from "../../hooks/useZoomMesh";
|
|
import useCallBackOnKey from "../../../../utils/hooks/useCallBackOnKey";
|
|
|
|
import Model from "./model/model";
|
|
|
|
const distanceWorker = new Worker(
|
|
new URL("../../../../services/builder/webWorkers/distanceWorker.js", import.meta.url)
|
|
);
|
|
|
|
function Models({ loader }: { readonly loader: GLTFLoader }) {
|
|
const { controls, camera } = useThree();
|
|
const assetGroupRef = useRef<Group>(null);
|
|
const { assetStore, layout } = useSceneContext();
|
|
const { assets, selectedAssets, getSelectedAssetUuids, clearSelectedAssets } = assetStore();
|
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
|
const { contextAction, setContextAction } = useContextActionStore();
|
|
const { limitDistance } = useLimitDistance();
|
|
const { renderDistance } = useRenderDistance();
|
|
const [renderMap, setRenderMap] = useState<Record<string, boolean>>({});
|
|
const { zoomMeshes } = useZoomMesh();
|
|
const cameraPos = useRef(new Vector3());
|
|
|
|
useEffect(() => {
|
|
// console.log(assets);
|
|
}, [assets]);
|
|
|
|
useEffect(() => {
|
|
const initialRenderMap: Record<string, boolean> = {};
|
|
assets.forEach((asset) => {
|
|
initialRenderMap[asset.modelUuid] = true;
|
|
});
|
|
setRenderMap(initialRenderMap);
|
|
}, [assets.length]);
|
|
|
|
useEffect(() => {
|
|
if (contextAction === "focusAsset") {
|
|
zoomMeshes(getSelectedAssetUuids());
|
|
setContextAction(null);
|
|
}
|
|
}, [contextAction]);
|
|
|
|
useCallBackOnKey(
|
|
() => {
|
|
if (selectedAssets.length > 0) {
|
|
zoomMeshes(getSelectedAssetUuids());
|
|
}
|
|
},
|
|
".",
|
|
{ dependencies: [selectedAssets.length], noRepeat: true }
|
|
);
|
|
|
|
useEffect(() => {
|
|
distanceWorker.onmessage = (e) => {
|
|
const { shouldRender, modelUuid } = e.data;
|
|
setRenderMap((prev) => {
|
|
if (prev[modelUuid] === shouldRender) return prev;
|
|
return { ...prev, [modelUuid]: shouldRender };
|
|
});
|
|
};
|
|
|
|
return () => {
|
|
distanceWorker.terminate();
|
|
};
|
|
}, [distanceWorker, layout]);
|
|
|
|
useFrame(() => {
|
|
camera.getWorldPosition(cameraPos.current);
|
|
for (const asset of assets) {
|
|
const isRendered = renderMap[asset.modelUuid] ?? false;
|
|
// distanceWorker.postMessage({
|
|
// modelUuid: asset.modelUuid,
|
|
// assetPosition: { x: asset.position[0], y: asset.position[1], z: asset.position[2] },
|
|
// cameraPosition: cameraPos.current,
|
|
// limitDistance,
|
|
// renderDistance,
|
|
// isRendered,
|
|
// });
|
|
|
|
const assetVec = new Vector3(...asset.position);
|
|
const cameraVec = new Vector3(
|
|
cameraPos.current.x,
|
|
cameraPos.current.y,
|
|
cameraPos.current.z
|
|
);
|
|
const distance = assetVec.distanceTo(cameraVec);
|
|
|
|
if (limitDistance) {
|
|
if (!isRendered && distance <= renderDistance) {
|
|
setRenderMap((prev) => {
|
|
if (prev[asset.modelUuid] === true) return prev;
|
|
return { ...prev, [asset.modelUuid]: true };
|
|
});
|
|
} else if (isRendered && distance > renderDistance) {
|
|
setRenderMap((prev) => {
|
|
if (prev[asset.modelUuid] === false) return prev;
|
|
return { ...prev, [asset.modelUuid]: false };
|
|
});
|
|
}
|
|
} else if (!isRendered) {
|
|
setRenderMap((prev) => {
|
|
if (prev[asset.modelUuid] === true) return prev;
|
|
return { ...prev, [asset.modelUuid]: true };
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
return (
|
|
<group
|
|
name="Asset Group"
|
|
ref={assetGroupRef}
|
|
onPointerMissed={(e) => {
|
|
e.stopPropagation();
|
|
if (selectedAssets.length > 0) {
|
|
const target = (controls as CameraControls).getTarget(new Vector3());
|
|
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
|
clearSelectedAssets();
|
|
}
|
|
if (selectedAsset) {
|
|
clearSelectedAsset();
|
|
}
|
|
}}
|
|
>
|
|
{assets.map((asset) => (
|
|
<Model
|
|
key={asset.modelUuid}
|
|
asset={asset}
|
|
isRendered={renderMap[asset.modelUuid] ?? false}
|
|
loader={loader}
|
|
/>
|
|
))}
|
|
</group>
|
|
);
|
|
}
|
|
|
|
export default Models;
|