added follow cam

This commit is contained in:
2025-09-17 18:20:47 +05:30
parent b1add58699
commit e60055b88f
6 changed files with 81 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
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 { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
@@ -16,28 +16,37 @@ const Header: React.FC = () => {
const { userId, userName } = getUserData();
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { activeModule } = useModuleStore();
const { toggleView } = useToggleView();
const guestUsers = collabUsers.filter((user) => user.userId !== userId);
const [userManagement, setUserManagement] = useState(false);
const { setSelectedUser } = useSelectedUserStore();
const { selectedUser, setSelectedUser, clearSelectedUser } = useSelectedUserStore();
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 = {
x: user.position?.x!,
y: user.position?.y!,
z: user.position?.z!,
x: user.camData.position.x,
y: user.camData.position.y,
z: user.camData.position.z,
};
const target = {
x: user.target?.x!,
y: user.target?.y!,
z: user.target?.z!,
x: user.camData.position.x,
y: user.camData.position.y,
z: user.camData.position.z,
};
const rotation = {
x: user.rotation?.x!,
y: user.rotation?.y!,
z: user.rotation?.z!,
x: user.camData.position.x,
y: user.camData.position.y,
z: user.camData.position.z,
};
// retun on no data
@@ -47,7 +56,7 @@ const Header: React.FC = () => {
setSelectedUser({
color: getAvatarColor(index, user.userId),
name: user.userName,
id: user.id,
id: user.userId,
location: { position, rotation, target },
});
setCamMode("FollowPerson");

View 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;

View File

@@ -3,6 +3,7 @@ import { Html, useGLTF } from "@react-three/drei";
import { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import { useSceneContext } from "../../scene/sceneContext";
import { useSelectedUserStore } from "../../../store/collaboration/useCollabStore";
import { getUserData } from "../../../functions/getUserData";
import { getAvatarColor } from "../functions/getAvatarColor";
@@ -31,6 +32,7 @@ const CamModel = ({ user, model, index }: { user: CollabUsersScheme; model: THRE
const targetPos = new THREE.Vector3();
const targetQuat = new THREE.Quaternion();
const { selectedUser, updateLocation } = useSelectedUserStore();
useFrame((_, delta) => {
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.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 (
<group ref={ref}>
<group visible={false} ref={ref}>
<primitive object={model.clone()} />
<Html
as="div"

View File

@@ -25,17 +25,10 @@ interface CollabUserIconProps {
};
}
const CollabUserIcon: React.FC<CollabUserIconProps> = ({
userImage,
userName,
id,
color,
position,
rotation,
target,
}) => {
const CollabUserIcon: React.FC<CollabUserIconProps> = ({ userImage, userName, id, color, position, rotation, target }) => {
const { setSelectedUser } = useSelectedUserStore();
const { setCamMode } = useCamMode();
return (
<div className="collab-user-live-container">
<button
@@ -53,11 +46,7 @@ const CollabUserIcon: React.FC<CollabUserIconProps> = ({
setCamMode("FollowPerson");
}}
>
{userImage ? (
<img className="user-image" src={userImage} alt={userName} />
) : (
<CustomAvatar name={userName} color={color} />
)}
{userImage ? <img className="user-image" src={userImage} alt={userName} /> : <CustomAvatar name={userName} color={color} />}
</button>
<div className="user-name" style={{ backgroundColor: color }}>
{userName}

View File

@@ -1,5 +1,6 @@
import React from "react";
import CamModelsGroup from "./camera/collabCams";
import CollabCamFollow from "./camera/collabCamFollow";
import ThreadsGroup from "./threads/threadsGroup";
import SocketResponses from "./socket/socketResponses";
@@ -8,6 +9,8 @@ const Collaboration: React.FC = () => {
<>
<CamModelsGroup />
<CollabCamFollow />
<ThreadsGroup />
<SocketResponses />

View File

@@ -4,33 +4,28 @@ interface SelectedUser {
color: string;
name: string;
id: string;
location?: {
position: {
x: number;
y: number;
z: number;
};
rotation?: {
x: number;
y: number;
z: number;
};
target?: {
x: number;
y: number;
z: number;
};
};
location?: { position: { x: number; y: number; z: number }; rotation: { x: number; y: number; z: number }; target: { x: number; y: number; z: number } };
}
interface SelectedUserStore {
selectedUser: SelectedUser | null;
setSelectedUser: (user: SelectedUser) => 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) => ({
selectedUser: null,
setSelectedUser: (user) => set({ selectedUser: user }),
clearSelectedUser: () => set({ selectedUser: null }),
updateLocation: (location) =>
set((state) => {
if (!state.selectedUser) return state;
return {
selectedUser: {
...state.selectedUser,
location: location,
},
};
}),
}));