feat: Refactor asset loading and model handling; remove unused loadInitialWallItems function and streamline GLTFLoader usage across components
This commit is contained in:
@@ -1,110 +0,0 @@
|
|||||||
// import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
||||||
// import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
|
||||||
// import * as THREE from "three";
|
|
||||||
// import * as Types from "../../../types/world/worldTypes";
|
|
||||||
// import { getWallItems } from "../../../services/factoryBuilder/asset/wallAsset/getWallItemsApi";
|
|
||||||
// import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
|
|
||||||
// import { getUserData } from "../../../functions/getUserData";
|
|
||||||
|
|
||||||
// async function loadInitialWallItems(
|
|
||||||
// setWallItems: Types.setWallItemSetState,
|
|
||||||
// projectId?: string,
|
|
||||||
// versionId?: string
|
|
||||||
// ): Promise<void> {
|
|
||||||
// if (!projectId || !versionId) return;
|
|
||||||
// try {
|
|
||||||
// const { organization, email } = getUserData();
|
|
||||||
|
|
||||||
// if (!email) {
|
|
||||||
// console.error("No email found in localStorage");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const items = await getWallItems(organization, projectId, versionId);
|
|
||||||
|
|
||||||
// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
|
||||||
|
|
||||||
// if (!items || items.length === 0) {
|
|
||||||
// localStorage.removeItem("WallItems");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// localStorage.setItem("WallItems", JSON.stringify(items));
|
|
||||||
|
|
||||||
// const loader = new GLTFLoader();
|
|
||||||
// const dracoLoader = new DRACOLoader();
|
|
||||||
// dracoLoader.setDecoderPath(
|
|
||||||
// "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
|
|
||||||
// );
|
|
||||||
// loader.setDRACOLoader(dracoLoader);
|
|
||||||
|
|
||||||
// const loadedWallItems = await Promise.all(
|
|
||||||
// items.map(async (item: Types.WallItem) => {
|
|
||||||
// // Check THREE.js cache first
|
|
||||||
// const cachedModel = THREE.Cache.get(item.assetId!);
|
|
||||||
// if (cachedModel) {
|
|
||||||
// return processModel(cachedModel, item);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Check IndexedDB cache
|
|
||||||
// const cachedModelBlob = await retrieveGLTF(item.assetId!);
|
|
||||||
// if (cachedModelBlob) {
|
|
||||||
// const blobUrl = URL.createObjectURL(cachedModelBlob);
|
|
||||||
// return new Promise<Types.WallItem>((resolve) => {
|
|
||||||
// loader.load(blobUrl, (gltf) => {
|
|
||||||
// URL.revokeObjectURL(blobUrl);
|
|
||||||
// THREE.Cache.add(item.assetId!, gltf);
|
|
||||||
// resolve(processModel(gltf, item));
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Load from original URL if not cached
|
|
||||||
// const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`;
|
|
||||||
// return new Promise<Types.WallItem>((resolve) => {
|
|
||||||
// loader.load(modelUrl, async (gltf) => {
|
|
||||||
// try {
|
|
||||||
// // Cache the model
|
|
||||||
// const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
|
||||||
// await storeGLTF(item.assetId!, modelBlob);
|
|
||||||
// THREE.Cache.add(item.assetId!, gltf);
|
|
||||||
// resolve(processModel(gltf, item));
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Failed to cache model:", error);
|
|
||||||
// resolve(processModel(gltf, item));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
|
|
||||||
// setWallItems(loadedWallItems);
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error("Failed to load wall items:", error);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem {
|
|
||||||
// const model = gltf.scene.clone();
|
|
||||||
// model.uuid = item.modelUuid!;
|
|
||||||
|
|
||||||
// model.children[0]?.children?.forEach((child: THREE.Object3D) => {
|
|
||||||
// if (child.name !== "CSG_REF") {
|
|
||||||
// child.castShadow = true;
|
|
||||||
// child.receiveShadow = true;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// type: item.type,
|
|
||||||
// model: model,
|
|
||||||
// modelName: item.modelName,
|
|
||||||
// assetId: item.assetId,
|
|
||||||
// scale: item.scale,
|
|
||||||
// csgscale: item.csgscale,
|
|
||||||
// csgposition: item.csgposition,
|
|
||||||
// position: item.position,
|
|
||||||
// quaternion: item.quaternion,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export default loadInitialWallItems;
|
|
||||||
@@ -44,6 +44,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!projectId || !selectedVersion) return;
|
if (!projectId || !selectedVersion) return;
|
||||||
|
|
||||||
clearEvents();
|
clearEvents();
|
||||||
|
|
||||||
let totalAssets = 0;
|
let totalAssets = 0;
|
||||||
@@ -304,7 +305,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, selectedVersion, projectId, userId);
|
addAssetModel(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, loader, selectedVersion, projectId, userId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -348,7 +349,7 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
|
|||||||
}, [selectedItem, camera, activeModule, controls, isRenameMode]);
|
}, [selectedItem, camera, activeModule, controls, isRenameMode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Models />
|
<Models loader={loader} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ async function addAssetModel(
|
|||||||
addEvent: (event: EventsSchema) => void,
|
addEvent: (event: EventsSchema) => void,
|
||||||
addAsset: (asset: Asset) => void,
|
addAsset: (asset: Asset) => void,
|
||||||
plane: Types.RefMesh,
|
plane: Types.RefMesh,
|
||||||
|
loader: GLTFLoader,
|
||||||
selectedVersion?: Version | null,
|
selectedVersion?: Version | null,
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
userId?: string
|
userId?: string
|
||||||
@@ -29,12 +30,6 @@ async function addAssetModel(
|
|||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const loader = new GLTFLoader();
|
|
||||||
const dracoLoader = new DRACOLoader();
|
|
||||||
|
|
||||||
dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/");
|
|
||||||
loader.setDRACOLoader(dracoLoader);
|
|
||||||
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
raycaster.setFromCamera(pointer, camera);
|
||||||
const wallFloorsGroup = scene.getObjectByName("Walls-Floors-Group") as Types.Group | null;
|
const wallFloorsGroup = scene.getObjectByName("Walls-Floors-Group") as Types.Group | null;
|
||||||
const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null;
|
const floorsGroup = scene.getObjectByName("Floors-Group") as Types.Group | null;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import * as THREE from 'three';
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
import { retrieveGLTF, storeGLTF } from '../../../../../utils/indexDB/idbUtils';
|
||||||
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
|
||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { ThreeEvent, useThree } from '@react-three/fiber';
|
||||||
import { useActiveTool, useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
import { useActiveTool, useDeletableFloorItem, useSelectedAssets, useSelectedFloorItem, useSocketStore, useToggleView, useToolMode } from '../../../../../store/builder/store';
|
||||||
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
import { AssetBoundingBox } from '../../functions/assetBoundingBox';
|
||||||
@@ -21,8 +20,7 @@ import { upsertProductOrEventApi } from '../../../../../services/simulation/prod
|
|||||||
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
|
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
|
||||||
import { ModelAnimator } from './animator/modelAnimator';
|
import { ModelAnimator } from './animator/modelAnimator';
|
||||||
|
|
||||||
|
function Model({ asset, isRendered, loader }: { readonly asset: Asset, isRendered: boolean, loader: GLTFLoader }) {
|
||||||
function Model({ asset, isRendered }: { readonly asset: Asset, isRendered: boolean }) {
|
|
||||||
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
const url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
const savedTheme: string = localStorage.getItem("theme") || "light";
|
const savedTheme: string = localStorage.getItem("theme") || "light";
|
||||||
const { controls, gl } = useThree();
|
const { controls, gl } = useThree();
|
||||||
@@ -109,11 +107,6 @@ function Model({ asset, isRendered }: { readonly asset: Asset, isRendered: boole
|
|||||||
}, [isRendered, selectedFloorItem])
|
}, [isRendered, selectedFloorItem])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loader = new GLTFLoader();
|
|
||||||
const dracoLoader = new DRACOLoader();
|
|
||||||
|
|
||||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
|
||||||
loader.setDRACOLoader(dracoLoader);
|
|
||||||
const loadModel = async () => {
|
const loadModel = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import { useSelectedAsset } from '../../../../store/simulation/useSimulationStor
|
|||||||
import { useSceneContext } from '../../../scene/sceneContext';
|
import { useSceneContext } from '../../../scene/sceneContext';
|
||||||
|
|
||||||
import Model from './model/model';
|
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));
|
const distanceWorker = new Worker(new URL("../../../../services/factoryBuilder/webWorkers/distanceWorker.js", import.meta.url));
|
||||||
|
|
||||||
function Models() {
|
function Models({ loader }: { loader: GLTFLoader }) {
|
||||||
const { controls, camera } = useThree();
|
const { controls, camera } = useThree();
|
||||||
const { assetStore } = useSceneContext();
|
const { assetStore } = useSceneContext();
|
||||||
const { assets } = assetStore();
|
const { assets } = assetStore();
|
||||||
@@ -57,7 +58,7 @@ function Models() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{assets.map((asset) => (
|
{assets.map((asset) => (
|
||||||
<Model key={asset.modelUuid} asset={asset} isRendered={renderMap[asset.modelUuid] ?? false} />
|
<Model key={asset.modelUuid} asset={asset} isRendered={renderMap[asset.modelUuid] ?? false} loader={loader} />
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ function WallAssetInstance({ wallAsset }: { wallAsset: WallAsset }) {
|
|||||||
|
|
||||||
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
|
||||||
loader.setDRACOLoader(dracoLoader);
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
const loadModel = async () => {
|
const loadModel = async () => {
|
||||||
try {
|
try {
|
||||||
// Check Cache
|
// Check Cache
|
||||||
|
|||||||
@@ -17,295 +17,292 @@ import setCameraView from "../functions/setCameraView";
|
|||||||
import { getUserData } from "../../../functions/getUserData";
|
import { getUserData } from "../../../functions/getUserData";
|
||||||
|
|
||||||
const CamModelsGroup = () => {
|
const CamModelsGroup = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const groupRef = useRef<THREE.Group>(null);
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
const { userId, organization, email } = getUserData();
|
const { organization, email } = getUserData();
|
||||||
const { setActiveUsers } = useActiveUsers();
|
const { setActiveUsers } = useActiveUsers();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const { selectedUser, setSelectedUser } = useSelectedUserStore();
|
const { selectedUser, setSelectedUser } = useSelectedUserStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
const loader = new GLTFLoader();
|
|
||||||
const dracoLoader = new DRACOLoader();
|
|
||||||
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
|
|
||||||
loader.setDRACOLoader(dracoLoader);
|
|
||||||
|
|
||||||
|
|
||||||
const { camMode } = useCamMode();
|
|
||||||
const { camera, controls } = useThree(); // Access R3F camera and controls
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (camMode !== "FollowPerson") return;
|
|
||||||
// If a user is selected, set the camera view to their location
|
|
||||||
// and update the camera and controls accordingly
|
|
||||||
if (selectedUser?.location) {
|
|
||||||
const { position, rotation, target } = selectedUser.location;
|
|
||||||
if (rotation && target)
|
|
||||||
setCameraView({
|
|
||||||
controls,
|
|
||||||
camera,
|
|
||||||
position,
|
|
||||||
rotation,
|
|
||||||
target,
|
|
||||||
username: selectedUser.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [selectedUser, camera, controls, camMode]);
|
|
||||||
|
|
||||||
const [cams, setCams] = useState<any[]>([]);
|
|
||||||
const [models, setModels] = useState<
|
|
||||||
Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
targetPosition: THREE.Vector3;
|
|
||||||
targetRotation: THREE.Euler;
|
|
||||||
target: THREE.Vector3;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>({});
|
|
||||||
|
|
||||||
const dedupeCams = (cams: any[]) => {
|
|
||||||
const seen = new Set();
|
|
||||||
return cams.filter((cam) => {
|
|
||||||
if (seen.has(cam.uuid)) return false;
|
|
||||||
seen.add(cam.uuid);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const dedupeUsers = (users: any[]) => {
|
|
||||||
const seen = new Set();
|
|
||||||
return users.filter((user) => {
|
|
||||||
if (seen.has(user._id)) return false;
|
|
||||||
seen.add(user._id);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!email) navigate("/");
|
|
||||||
|
|
||||||
if (!socket) return;
|
|
||||||
|
|
||||||
socket.on("userConnectResponse", (data: any) => {
|
|
||||||
if (!groupRef.current) return;
|
|
||||||
if (data.data.userData.email === email) return;
|
|
||||||
if (socket.id === data.socketId || organization !== data.organization)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const model = groupRef.current.getObjectByProperty(
|
|
||||||
"uuid",
|
|
||||||
data.data.userData._id
|
|
||||||
);
|
|
||||||
if (model) {
|
|
||||||
groupRef.current.remove(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
loader.load(camModel, (gltf) => {
|
|
||||||
const newModel = gltf.scene.clone();
|
|
||||||
newModel.uuid = data.data.userData._id;
|
|
||||||
newModel.position.set(
|
|
||||||
data.data.position.x,
|
|
||||||
data.data.position.y,
|
|
||||||
data.data.position.z
|
|
||||||
);
|
|
||||||
newModel.rotation.set(
|
|
||||||
data.data.rotation.x,
|
|
||||||
data.data.rotation.y,
|
|
||||||
data.data.rotation.z
|
|
||||||
);
|
|
||||||
newModel.userData = data.data.userData;
|
|
||||||
newModel.userData.target = new THREE.Vector3(
|
|
||||||
data.data.target.x,
|
|
||||||
data.data.target.y,
|
|
||||||
data.data.target.z
|
|
||||||
);
|
|
||||||
|
|
||||||
setCams((prev) => dedupeCams([...prev, newModel]));
|
|
||||||
setActiveUsers((prev: any) =>
|
|
||||||
dedupeUsers([...prev, data.data.userData])
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("userDisConnectResponse", (data: any) => {
|
|
||||||
if (!groupRef.current) return;
|
|
||||||
if (socket.id === data.socketId || organization !== data.organization)
|
|
||||||
return;
|
|
||||||
|
|
||||||
setCams((prev) =>
|
|
||||||
prev.filter((cam) => cam.uuid !== data.data.userData._id)
|
|
||||||
);
|
|
||||||
setActiveUsers((prev: any) =>
|
|
||||||
prev.filter((user: any) => user._id !== data.data.userData._id)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("v1:camera:Response:update", (data: any) => {
|
|
||||||
// console.log('data: ', data);
|
|
||||||
if (
|
|
||||||
!groupRef.current ||
|
|
||||||
socket.id === data.socketId ||
|
|
||||||
organization !== data.organization
|
|
||||||
)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (selectedUser && selectedUser?.id === data.data.userId) {
|
|
||||||
setSelectedUser({
|
|
||||||
color: selectedUser.color,
|
|
||||||
name: selectedUser.name,
|
|
||||||
id: selectedUser.id,
|
|
||||||
location: {
|
|
||||||
position: data.data.position,
|
|
||||||
rotation: data.data.rotation,
|
|
||||||
target: data.data.target,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setModels((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[data.data.userId]: {
|
|
||||||
targetPosition: new THREE.Vector3(
|
|
||||||
data.data.position.x,
|
|
||||||
data.data.position.y,
|
|
||||||
data.data.position.z
|
|
||||||
),
|
|
||||||
targetRotation: new THREE.Euler(
|
|
||||||
data.data.rotation.x,
|
|
||||||
data.data.rotation.y,
|
|
||||||
data.data.rotation.z
|
|
||||||
),
|
|
||||||
target: new THREE.Vector3(
|
|
||||||
data.data.target.x,
|
|
||||||
data.data.target.y,
|
|
||||||
data.data.target.z
|
|
||||||
),
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
socket.off("userConnectResponse");
|
|
||||||
socket.off("userDisConnectResponse");
|
|
||||||
socket.off("v1:camera:Response:update");
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [email, loader, navigate, setActiveUsers, socket]);
|
const loader = new GLTFLoader();
|
||||||
|
const dracoLoader = new DRACOLoader();
|
||||||
|
dracoLoader.setDecoderPath("three/examples/jsm/libs/draco/gltf/");
|
||||||
|
loader.setDRACOLoader(dracoLoader);
|
||||||
|
|
||||||
useFrame(() => {
|
const { camMode } = useCamMode();
|
||||||
if (!groupRef.current) return;
|
const { camera, controls } = useThree();
|
||||||
Object.keys(models).forEach((uuid) => {
|
|
||||||
const model = groupRef.current!.getObjectByProperty("uuid", uuid);
|
|
||||||
if (!model) return;
|
|
||||||
|
|
||||||
const { targetPosition, targetRotation } = models[uuid];
|
useEffect(() => {
|
||||||
model.position.lerp(targetPosition, 0.1);
|
if (camMode !== "FollowPerson") return;
|
||||||
model.rotation.x = THREE.MathUtils.lerp(
|
if (selectedUser?.location) {
|
||||||
model.rotation.x,
|
const { position, rotation, target } = selectedUser.location;
|
||||||
targetRotation.x,
|
if (rotation && target)
|
||||||
0.1
|
setCameraView({
|
||||||
);
|
controls,
|
||||||
model.rotation.y = THREE.MathUtils.lerp(
|
camera,
|
||||||
model.rotation.y,
|
position,
|
||||||
targetRotation.y,
|
rotation,
|
||||||
0.1
|
target,
|
||||||
);
|
username: selectedUser.name,
|
||||||
model.rotation.z = THREE.MathUtils.lerp(
|
});
|
||||||
model.rotation.z,
|
}
|
||||||
targetRotation.z,
|
}, [selectedUser, camera, controls, camMode]);
|
||||||
0.1
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
const [cams, setCams] = useState<any[]>([]);
|
||||||
if (!groupRef.current) return;
|
const [models, setModels] = useState<
|
||||||
|
Record<
|
||||||
getActiveUsersData(organization).then((data) => {
|
string,
|
||||||
const filteredData = data.cameraDatas.filter(
|
{
|
||||||
(camera: any) => camera.userData.email !== email
|
targetPosition: THREE.Vector3;
|
||||||
);
|
targetRotation: THREE.Euler;
|
||||||
|
target: THREE.Vector3;
|
||||||
if (filteredData.length > 0) {
|
}
|
||||||
loader.load(camModel, (gltf) => {
|
|
||||||
const newCams = filteredData.map((cam: any) => {
|
|
||||||
const newModel = gltf.scene.clone();
|
|
||||||
newModel.uuid = cam.userData._id;
|
|
||||||
newModel.position.set(
|
|
||||||
cam.position.x,
|
|
||||||
cam.position.y,
|
|
||||||
cam.position.z
|
|
||||||
);
|
|
||||||
newModel.rotation.set(
|
|
||||||
cam.rotation.x,
|
|
||||||
cam.rotation.y,
|
|
||||||
cam.rotation.z
|
|
||||||
);
|
|
||||||
newModel.userData = cam.userData;
|
|
||||||
cam.userData.position = newModel.position;
|
|
||||||
cam.userData.rotation = newModel.rotation;
|
|
||||||
newModel.userData.target = cam.target;
|
|
||||||
|
|
||||||
return newModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
const users = filteredData.map((cam: any) => cam.userData);
|
|
||||||
setActiveUsers((prev: any) => dedupeUsers([...prev, ...users]));
|
|
||||||
setCams((prev) => dedupeCams([...prev, ...newCams]));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
console.log('Error fetching active users data')
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<group ref={groupRef} name="Cam-Model-Group">
|
|
||||||
{cams.map((cam, index) => (
|
|
||||||
<primitive
|
|
||||||
key={cam.uuid}
|
|
||||||
//eslint-disable-next-line
|
|
||||||
object={cam}
|
|
||||||
visible={
|
|
||||||
selectedUser?.name !== cam.userData.userName &&
|
|
||||||
activeModule !== "visualization" &&
|
|
||||||
!isPlaying
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Html
|
>({});
|
||||||
as="div"
|
|
||||||
center
|
const dedupeCams = (cams: any[]) => {
|
||||||
zIndexRange={[1, 0]}
|
const seen = new Set();
|
||||||
sprite
|
return cams.filter((cam) => {
|
||||||
style={{
|
if (seen.has(cam.uuid)) return false;
|
||||||
color: "white",
|
seen.add(cam.uuid);
|
||||||
textAlign: "center",
|
return true;
|
||||||
fontFamily: "Arial, sans-serif",
|
});
|
||||||
display: `${activeModule !== "visualization" ? "" : "none"}`,
|
};
|
||||||
opacity: `${selectedUser?.name !== cam.userData.userName && !isPlaying
|
|
||||||
? 1
|
const dedupeUsers = (users: any[]) => {
|
||||||
: 0
|
const seen = new Set();
|
||||||
}`,
|
return users.filter((user) => {
|
||||||
transition: "opacity .2s ease",
|
if (seen.has(user._id)) return false;
|
||||||
}}
|
seen.add(user._id);
|
||||||
position={[-0.015, 0, 0.7]}
|
return true;
|
||||||
>
|
});
|
||||||
<CollabUserIcon
|
};
|
||||||
userImage={cam.userData.userImage ?? ""}
|
|
||||||
userName={cam.userData.userName}
|
useEffect(() => {
|
||||||
id={cam.userData._id}
|
if (!email) navigate("/");
|
||||||
color={getAvatarColor(index, cam.userData.userName)}
|
|
||||||
position={cam.position}
|
if (!socket) return;
|
||||||
rotation={cam.rotation}
|
|
||||||
target={cam.userData.target}
|
socket.on("userConnectResponse", (data: any) => {
|
||||||
/>
|
if (!groupRef.current) return;
|
||||||
</Html>
|
if (data.data.userData.email === email) return;
|
||||||
</primitive>
|
if (socket.id === data.socketId || organization !== data.organization)
|
||||||
))}
|
return;
|
||||||
</group>
|
|
||||||
);
|
const model = groupRef.current.getObjectByProperty(
|
||||||
|
"uuid",
|
||||||
|
data.data.userData._id
|
||||||
|
);
|
||||||
|
if (model) {
|
||||||
|
groupRef.current.remove(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.load(camModel, (gltf) => {
|
||||||
|
const newModel = gltf.scene.clone();
|
||||||
|
newModel.uuid = data.data.userData._id;
|
||||||
|
newModel.position.set(
|
||||||
|
data.data.position.x,
|
||||||
|
data.data.position.y,
|
||||||
|
data.data.position.z
|
||||||
|
);
|
||||||
|
newModel.rotation.set(
|
||||||
|
data.data.rotation.x,
|
||||||
|
data.data.rotation.y,
|
||||||
|
data.data.rotation.z
|
||||||
|
);
|
||||||
|
newModel.userData = data.data.userData;
|
||||||
|
newModel.userData.target = new THREE.Vector3(
|
||||||
|
data.data.target.x,
|
||||||
|
data.data.target.y,
|
||||||
|
data.data.target.z
|
||||||
|
);
|
||||||
|
|
||||||
|
setCams((prev) => dedupeCams([...prev, newModel]));
|
||||||
|
setActiveUsers((prev: any) =>
|
||||||
|
dedupeUsers([...prev, data.data.userData])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("userDisConnectResponse", (data: any) => {
|
||||||
|
if (!groupRef.current) return;
|
||||||
|
if (socket.id === data.socketId || organization !== data.organization)
|
||||||
|
return;
|
||||||
|
|
||||||
|
setCams((prev) =>
|
||||||
|
prev.filter((cam) => cam.uuid !== data.data.userData._id)
|
||||||
|
);
|
||||||
|
setActiveUsers((prev: any) =>
|
||||||
|
prev.filter((user: any) => user._id !== data.data.userData._id)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("v1:camera:Response:update", (data: any) => {
|
||||||
|
// console.log('data: ', data);
|
||||||
|
if (
|
||||||
|
!groupRef.current ||
|
||||||
|
socket.id === data.socketId ||
|
||||||
|
organization !== data.organization
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (selectedUser && selectedUser?.id === data.data.userId) {
|
||||||
|
setSelectedUser({
|
||||||
|
color: selectedUser.color,
|
||||||
|
name: selectedUser.name,
|
||||||
|
id: selectedUser.id,
|
||||||
|
location: {
|
||||||
|
position: data.data.position,
|
||||||
|
rotation: data.data.rotation,
|
||||||
|
target: data.data.target,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setModels((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[data.data.userId]: {
|
||||||
|
targetPosition: new THREE.Vector3(
|
||||||
|
data.data.position.x,
|
||||||
|
data.data.position.y,
|
||||||
|
data.data.position.z
|
||||||
|
),
|
||||||
|
targetRotation: new THREE.Euler(
|
||||||
|
data.data.rotation.x,
|
||||||
|
data.data.rotation.y,
|
||||||
|
data.data.rotation.z
|
||||||
|
),
|
||||||
|
target: new THREE.Vector3(
|
||||||
|
data.data.target.x,
|
||||||
|
data.data.target.y,
|
||||||
|
data.data.target.z
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.off("userConnectResponse");
|
||||||
|
socket.off("userDisConnectResponse");
|
||||||
|
socket.off("v1:camera:Response:update");
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [email, loader, navigate, setActiveUsers, socket]);
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (!groupRef.current) return;
|
||||||
|
Object.keys(models).forEach((uuid) => {
|
||||||
|
const model = groupRef.current!.getObjectByProperty("uuid", uuid);
|
||||||
|
if (!model) return;
|
||||||
|
|
||||||
|
const { targetPosition, targetRotation } = models[uuid];
|
||||||
|
model.position.lerp(targetPosition, 0.1);
|
||||||
|
model.rotation.x = THREE.MathUtils.lerp(
|
||||||
|
model.rotation.x,
|
||||||
|
targetRotation.x,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
|
model.rotation.y = THREE.MathUtils.lerp(
|
||||||
|
model.rotation.y,
|
||||||
|
targetRotation.y,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
|
model.rotation.z = THREE.MathUtils.lerp(
|
||||||
|
model.rotation.z,
|
||||||
|
targetRotation.z,
|
||||||
|
0.1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!groupRef.current) return;
|
||||||
|
|
||||||
|
getActiveUsersData(organization).then((data) => {
|
||||||
|
const filteredData = data.cameraDatas.filter(
|
||||||
|
(camera: any) => camera.userData.email !== email
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filteredData.length > 0) {
|
||||||
|
loader.load(camModel, (gltf) => {
|
||||||
|
const newCams = filteredData.map((cam: any) => {
|
||||||
|
const newModel = gltf.scene.clone();
|
||||||
|
newModel.uuid = cam.userData._id;
|
||||||
|
newModel.position.set(
|
||||||
|
cam.position.x,
|
||||||
|
cam.position.y,
|
||||||
|
cam.position.z
|
||||||
|
);
|
||||||
|
newModel.rotation.set(
|
||||||
|
cam.rotation.x,
|
||||||
|
cam.rotation.y,
|
||||||
|
cam.rotation.z
|
||||||
|
);
|
||||||
|
newModel.userData = cam.userData;
|
||||||
|
cam.userData.position = newModel.position;
|
||||||
|
cam.userData.rotation = newModel.rotation;
|
||||||
|
newModel.userData.target = cam.target;
|
||||||
|
|
||||||
|
return newModel;
|
||||||
|
});
|
||||||
|
|
||||||
|
const users = filteredData.map((cam: any) => cam.userData);
|
||||||
|
setActiveUsers((prev: any) => dedupeUsers([...prev, ...users]));
|
||||||
|
setCams((prev) => dedupeCams([...prev, ...newCams]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('Error fetching active users data')
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group ref={groupRef} name="Cam-Model-Group">
|
||||||
|
{cams.map((cam, index) => (
|
||||||
|
<primitive
|
||||||
|
key={cam.uuid}
|
||||||
|
//eslint-disable-next-line
|
||||||
|
object={cam}
|
||||||
|
visible={
|
||||||
|
selectedUser?.name !== cam.userData.userName &&
|
||||||
|
activeModule !== "visualization" &&
|
||||||
|
!isPlaying
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Html
|
||||||
|
as="div"
|
||||||
|
center
|
||||||
|
zIndexRange={[1, 0]}
|
||||||
|
sprite
|
||||||
|
style={{
|
||||||
|
color: "white",
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: "Arial, sans-serif",
|
||||||
|
display: `${activeModule !== "visualization" ? "" : "none"}`,
|
||||||
|
opacity: `${selectedUser?.name !== cam.userData.userName && !isPlaying
|
||||||
|
? 1
|
||||||
|
: 0
|
||||||
|
}`,
|
||||||
|
transition: "opacity .2s ease",
|
||||||
|
}}
|
||||||
|
position={[-0.015, 0, 0.7]}
|
||||||
|
>
|
||||||
|
<CollabUserIcon
|
||||||
|
userImage={cam.userData.userImage ?? ""}
|
||||||
|
userName={cam.userData.userName}
|
||||||
|
id={cam.userData._id}
|
||||||
|
color={getAvatarColor(index, cam.userData.userName)}
|
||||||
|
position={cam.position}
|
||||||
|
rotation={cam.rotation}
|
||||||
|
target={cam.userData.target}
|
||||||
|
/>
|
||||||
|
</Html>
|
||||||
|
</primitive>
|
||||||
|
))}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CamModelsGroup;
|
export default CamModelsGroup;
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function Controls() {
|
|||||||
ref={controlsRef}
|
ref={controlsRef}
|
||||||
minDistance={toggleView ? CONSTANTS.twoDimension.minDistance : CONSTANTS.threeDimension.minDistance}
|
minDistance={toggleView ? CONSTANTS.twoDimension.minDistance : CONSTANTS.threeDimension.minDistance}
|
||||||
maxDistance={CONSTANTS.thirdPersonControls.maxDistance}
|
maxDistance={CONSTANTS.thirdPersonControls.maxDistance}
|
||||||
minZoom={CONSTANTS.thirdPersonControls.minZoom}
|
minZoom={CONSTANTS.thirdPersonControls.minZoom}
|
||||||
maxZoom={CONSTANTS.thirdPersonControls.maxZoom}
|
maxZoom={CONSTANTS.thirdPersonControls.maxZoom}
|
||||||
maxPolarAngle={CONSTANTS.thirdPersonControls.maxPolarAngle}
|
maxPolarAngle={CONSTANTS.thirdPersonControls.maxPolarAngle}
|
||||||
camera={state.camera}
|
camera={state.camera}
|
||||||
|
|||||||
@@ -79,17 +79,17 @@ export default function PostProcessing() {
|
|||||||
denoiseRadius={6}
|
denoiseRadius={6}
|
||||||
denoiseSamples={16}
|
denoiseSamples={16}
|
||||||
/>
|
/>
|
||||||
<DepthOfField
|
{/* <DepthOfField
|
||||||
focusDistance={0}
|
focusDistance={0}
|
||||||
focalLength={0.15}
|
focalLength={0.15}
|
||||||
bokehScale={2}
|
bokehScale={2}
|
||||||
/>
|
/> */}
|
||||||
<Bloom
|
{/* <Bloom
|
||||||
intensity={0.1}
|
intensity={0.1}
|
||||||
luminanceThreshold={0.9}
|
luminanceThreshold={0.9}
|
||||||
luminanceSmoothing={0.025}
|
luminanceSmoothing={0.025}
|
||||||
mipmapBlur={false}
|
mipmapBlur={false}
|
||||||
/>
|
/> */}
|
||||||
{selectedWallAsset && (
|
{selectedWallAsset && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(selectedWallAsset.children)}
|
selection={flattenChildren(selectedWallAsset.children)}
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ const ArmBotUI = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch and setup selected ArmBot data
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedEventSphere) {
|
if (selectedEventSphere) {
|
||||||
const selectedArmBot = getEventByModelUuid(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
|
const selectedArmBot = getEventByModelUuid(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
|
||||||
@@ -86,13 +85,11 @@ const ArmBotUI = () => {
|
|||||||
const modelData = getEventByModelUuid(selectedProduct.productUuid, modelUuid);
|
const modelData = getEventByModelUuid(selectedProduct.productUuid, modelUuid);
|
||||||
|
|
||||||
if (modelData?.type === "roboticArm") {
|
if (modelData?.type === "roboticArm") {
|
||||||
const baseX = modelData.point.position?.[0] || 0;
|
const baseY = modelData.point.position?.[1] || 0;
|
||||||
const baseY = modelData.point.position?.[1] || 0;;
|
|
||||||
const baseZ = modelData.point.position?.[2] || 0;
|
|
||||||
return {
|
return {
|
||||||
pick: [baseX, baseY, baseZ + 0.5],
|
pick: [0, baseY, 0 + 0.5],
|
||||||
drop: [baseX, baseY, baseZ - 0.5],
|
drop: [0, baseY, 0 - 0.5],
|
||||||
default: [baseX, baseY, baseZ],
|
default: [0, baseY, 0],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +222,7 @@ const ArmBotUI = () => {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null; // important! must return something
|
return null;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user