70 lines
2.8 KiB
TypeScript
70 lines
2.8 KiB
TypeScript
import { useEffect, useRef, useState } from "react";
|
|
import { useThree, useFrame } from "@react-three/fiber";
|
|
import { Group, Vector3 } from "three";
|
|
import { CameraControls } from '@react-three/drei';
|
|
import { useLimitDistance, useRenderDistance } from '../../../../store/builder/store';
|
|
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
|
|
import { useSceneContext } from '../../../scene/sceneContext';
|
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
|
|
|
import Model from './model/model';
|
|
import { GLTFLoader } from "three/examples/jsm/Addons";
|
|
|
|
const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
|
|
|
|
function Models({ loader }: { loader: GLTFLoader }) {
|
|
const { controls, camera } = useThree();
|
|
const assetGroupRef = useRef<Group>(null);
|
|
const { assetStore } = useSceneContext();
|
|
const { assets } = assetStore();
|
|
const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore();
|
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
|
const { limitDistance } = useLimitDistance();
|
|
const { renderDistance } = useRenderDistance();
|
|
|
|
const [renderMap, setRenderMap] = useState<Record<string, boolean>>({});
|
|
|
|
const cameraPos = useRef(new Vector3());
|
|
|
|
useEffect(() => {
|
|
distanceWorker.onmessage = (e) => {
|
|
const { shouldRender, modelUuid } = e.data;
|
|
setRenderMap((prev) => {
|
|
if (prev[modelUuid] === shouldRender) return prev;
|
|
return { ...prev, [modelUuid]: shouldRender };
|
|
});
|
|
};
|
|
}, []);
|
|
|
|
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, });
|
|
}
|
|
});
|
|
|
|
return (
|
|
<group
|
|
name='Asset Group'
|
|
ref={assetGroupRef}
|
|
onPointerMissed={(e) => {
|
|
e.stopPropagation();
|
|
if (selectedFloorAsset) {
|
|
const target = (controls as CameraControls).getTarget(new Vector3());
|
|
(controls as CameraControls).setTarget(target.x, 0, target.z, true);
|
|
setSelectedFloorAsset(null);
|
|
}
|
|
if (selectedAsset) {
|
|
clearSelectedAsset();
|
|
}
|
|
}}
|
|
>
|
|
{assets.map((asset) => (
|
|
<Model key={asset.modelUuid} asset={asset} isRendered={renderMap[asset.modelUuid] ?? false} loader={loader} />
|
|
))}
|
|
</group>
|
|
);
|
|
}
|
|
|
|
export default Models; |