added follow cam
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import orgImg from "../../../assets/image/orgTemp.png";
|
import orgImg from "../../../assets/image/orgTemp.png";
|
||||||
import { useCamMode } from "../../../store/builder/store";
|
import { useCamMode, useToggleView } from "../../../store/builder/store";
|
||||||
import CollaborationPopup from "../../templates/CollaborationPopup";
|
import CollaborationPopup from "../../templates/CollaborationPopup";
|
||||||
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
||||||
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
|
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
|
||||||
@@ -16,28 +16,37 @@ const Header: React.FC = () => {
|
|||||||
const { userId, userName } = getUserData();
|
const { userId, userName } = getUserData();
|
||||||
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
|
const { toggleView } = useToggleView();
|
||||||
|
|
||||||
const guestUsers = collabUsers.filter((user) => user.userId !== userId);
|
const guestUsers = collabUsers.filter((user) => user.userId !== userId);
|
||||||
|
|
||||||
const [userManagement, setUserManagement] = useState(false);
|
const [userManagement, setUserManagement] = useState(false);
|
||||||
const { setSelectedUser } = useSelectedUserStore();
|
const { selectedUser, setSelectedUser, clearSelectedUser } = useSelectedUserStore();
|
||||||
const { setCamMode } = useCamMode();
|
const { setCamMode } = useCamMode();
|
||||||
|
|
||||||
function handleUserFollow(user: any, index: number) {
|
useEffect(() => {
|
||||||
|
if ((activeModule !== "builder" && activeModule !== "simulation") || (toggleView && selectedUser)) {
|
||||||
|
clearSelectedUser();
|
||||||
|
}
|
||||||
|
}, [toggleView, activeModule, selectedUser]);
|
||||||
|
|
||||||
|
function handleUserFollow(user: CollabUsersScheme, index: number) {
|
||||||
|
if (toggleView || (activeModule !== "builder" && activeModule !== "simulation")) return;
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
x: user.position?.x!,
|
x: user.camData.position.x,
|
||||||
y: user.position?.y!,
|
y: user.camData.position.y,
|
||||||
z: user.position?.z!,
|
z: user.camData.position.z,
|
||||||
};
|
};
|
||||||
const target = {
|
const target = {
|
||||||
x: user.target?.x!,
|
x: user.camData.position.x,
|
||||||
y: user.target?.y!,
|
y: user.camData.position.y,
|
||||||
z: user.target?.z!,
|
z: user.camData.position.z,
|
||||||
};
|
};
|
||||||
const rotation = {
|
const rotation = {
|
||||||
x: user.rotation?.x!,
|
x: user.camData.position.x,
|
||||||
y: user.rotation?.y!,
|
y: user.camData.position.y,
|
||||||
z: user.rotation?.z!,
|
z: user.camData.position.z,
|
||||||
};
|
};
|
||||||
|
|
||||||
// retun on no data
|
// retun on no data
|
||||||
@@ -47,7 +56,7 @@ const Header: React.FC = () => {
|
|||||||
setSelectedUser({
|
setSelectedUser({
|
||||||
color: getAvatarColor(index, user.userId),
|
color: getAvatarColor(index, user.userId),
|
||||||
name: user.userName,
|
name: user.userName,
|
||||||
id: user.id,
|
id: user.userId,
|
||||||
location: { position, rotation, target },
|
location: { position, rotation, target },
|
||||||
});
|
});
|
||||||
setCamMode("FollowPerson");
|
setCamMode("FollowPerson");
|
||||||
|
|||||||
26
app/src/modules/collaboration/camera/collabCamFollow.tsx
Normal file
26
app/src/modules/collaboration/camera/collabCamFollow.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
|
||||||
|
import { useFrame } from "@react-three/fiber";
|
||||||
|
import { CameraControls } from "@react-three/drei";
|
||||||
|
|
||||||
|
function CollabCamFollow() {
|
||||||
|
const { selectedUser } = useSelectedUserStore();
|
||||||
|
|
||||||
|
useFrame((state) => {
|
||||||
|
if (!selectedUser || !state.controls || !selectedUser.location) return;
|
||||||
|
const controls = state.controls as CameraControls;
|
||||||
|
|
||||||
|
controls.setLookAt(
|
||||||
|
selectedUser.location.position.x,
|
||||||
|
selectedUser.location.position.y,
|
||||||
|
selectedUser.location.position.z,
|
||||||
|
selectedUser.location.target.x,
|
||||||
|
selectedUser.location.target.y,
|
||||||
|
selectedUser.location.target.z,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CollabCamFollow;
|
||||||
@@ -3,6 +3,7 @@ import { Html, useGLTF } from "@react-three/drei";
|
|||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { useFrame } from "@react-three/fiber";
|
import { useFrame } from "@react-three/fiber";
|
||||||
import { useSceneContext } from "../../scene/sceneContext";
|
import { useSceneContext } from "../../scene/sceneContext";
|
||||||
|
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
import { getUserData } from "../../../functions/getUserData";
|
||||||
import { getAvatarColor } from "../functions/getAvatarColor";
|
import { getAvatarColor } from "../functions/getAvatarColor";
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ const CamModel = ({ user, model, index }: { user: CollabUsersScheme; model: THRE
|
|||||||
|
|
||||||
const targetPos = new THREE.Vector3();
|
const targetPos = new THREE.Vector3();
|
||||||
const targetQuat = new THREE.Quaternion();
|
const targetQuat = new THREE.Quaternion();
|
||||||
|
const { selectedUser, updateLocation } = useSelectedUserStore();
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
@@ -40,11 +42,22 @@ const CamModel = ({ user, model, index }: { user: CollabUsersScheme; model: THRE
|
|||||||
|
|
||||||
ref.current.position.lerp(targetPos, 5 * delta);
|
ref.current.position.lerp(targetPos, 5 * delta);
|
||||||
ref.current.quaternion.slerp(targetQuat, 5 * delta);
|
ref.current.quaternion.slerp(targetQuat, 5 * delta);
|
||||||
|
|
||||||
|
if (selectedUser && selectedUser.id === user.userId) {
|
||||||
|
const pos = ref.current.position;
|
||||||
|
const rot = new THREE.Euler().setFromQuaternion(ref.current.quaternion);
|
||||||
|
|
||||||
|
updateLocation({
|
||||||
|
position: { x: pos.x, y: pos.y, z: pos.z },
|
||||||
|
rotation: { x: rot.x, y: rot.y, z: rot.z },
|
||||||
|
target: user.camData.target,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group ref={ref}>
|
<group visible={false} ref={ref}>
|
||||||
<primitive object={model.clone()} />
|
<primitive object={model.clone()} />
|
||||||
<Html
|
<Html
|
||||||
as="div"
|
as="div"
|
||||||
|
|||||||
@@ -25,17 +25,10 @@ interface CollabUserIconProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
const CollabUserIcon: React.FC<CollabUserIconProps> = ({ userImage, userName, id, color, position, rotation, target }) => {
|
||||||
userImage,
|
|
||||||
userName,
|
|
||||||
id,
|
|
||||||
color,
|
|
||||||
position,
|
|
||||||
rotation,
|
|
||||||
target,
|
|
||||||
}) => {
|
|
||||||
const { setSelectedUser } = useSelectedUserStore();
|
const { setSelectedUser } = useSelectedUserStore();
|
||||||
const { setCamMode } = useCamMode();
|
const { setCamMode } = useCamMode();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="collab-user-live-container">
|
<div className="collab-user-live-container">
|
||||||
<button
|
<button
|
||||||
@@ -53,11 +46,7 @@ const CollabUserIcon: React.FC<CollabUserIconProps> = ({
|
|||||||
setCamMode("FollowPerson");
|
setCamMode("FollowPerson");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{userImage ? (
|
{userImage ? <img className="user-image" src={userImage} alt={userName} /> : <CustomAvatar name={userName} color={color} />}
|
||||||
<img className="user-image" src={userImage} alt={userName} />
|
|
||||||
) : (
|
|
||||||
<CustomAvatar name={userName} color={color} />
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
<div className="user-name" style={{ backgroundColor: color }}>
|
<div className="user-name" style={{ backgroundColor: color }}>
|
||||||
{userName}
|
{userName}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import CamModelsGroup from "./camera/collabCams";
|
import CamModelsGroup from "./camera/collabCams";
|
||||||
|
import CollabCamFollow from "./camera/collabCamFollow";
|
||||||
import ThreadsGroup from "./threads/threadsGroup";
|
import ThreadsGroup from "./threads/threadsGroup";
|
||||||
import SocketResponses from "./socket/socketResponses";
|
import SocketResponses from "./socket/socketResponses";
|
||||||
|
|
||||||
@@ -8,6 +9,8 @@ const Collaboration: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
<CamModelsGroup />
|
<CamModelsGroup />
|
||||||
|
|
||||||
|
<CollabCamFollow />
|
||||||
|
|
||||||
<ThreadsGroup />
|
<ThreadsGroup />
|
||||||
|
|
||||||
<SocketResponses />
|
<SocketResponses />
|
||||||
|
|||||||
@@ -4,33 +4,28 @@ interface SelectedUser {
|
|||||||
color: string;
|
color: string;
|
||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
location?: {
|
location?: { position: { x: number; y: number; z: number }; rotation: { x: number; y: number; z: number }; target: { x: number; y: number; z: number } };
|
||||||
position: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
};
|
|
||||||
rotation?: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
};
|
|
||||||
target?: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectedUserStore {
|
interface SelectedUserStore {
|
||||||
selectedUser: SelectedUser | null;
|
selectedUser: SelectedUser | null;
|
||||||
setSelectedUser: (user: SelectedUser) => void;
|
setSelectedUser: (user: SelectedUser) => void;
|
||||||
clearSelectedUser: () => void;
|
clearSelectedUser: () => void;
|
||||||
|
updateLocation: (location: { position: { x: number; y: number; z: number }; rotation: { x: number; y: number; z: number }; target: { x: number; y: number; z: number } }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useSelectedUserStore = create<SelectedUserStore>((set) => ({
|
export const useSelectedUserStore = create<SelectedUserStore>((set) => ({
|
||||||
selectedUser: null,
|
selectedUser: null,
|
||||||
setSelectedUser: (user) => set({ selectedUser: user }),
|
setSelectedUser: (user) => set({ selectedUser: user }),
|
||||||
clearSelectedUser: () => set({ selectedUser: null }),
|
clearSelectedUser: () => set({ selectedUser: null }),
|
||||||
|
updateLocation: (location) =>
|
||||||
|
set((state) => {
|
||||||
|
if (!state.selectedUser) return state;
|
||||||
|
return {
|
||||||
|
selectedUser: {
|
||||||
|
...state.selectedUser,
|
||||||
|
location: location,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user