Skip to content

Commit

Permalink
feat: 오브젝트 마우스 컨트롤 추가
Browse files Browse the repository at this point in the history
Feat/object create
  • Loading branch information
play3step authored Jul 12, 2024
2 parents 4e58de0 + fbb488e commit 5dc4391
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 124 deletions.
9 changes: 7 additions & 2 deletions src/components/EditPage/PageData/Edit3d.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import EditObjLoader from './Edit3d/EditObjLoader';
import EditGltfLoader from './Edit3d/EditGltfLoader';
import { objectSizeState } from '../../../store/toolState';

function Edit3d({ objecturl }) {
function Edit3d({ objecturl, setObjectValue, pageRendering }) {
const { camera } = useThree();
const dataSize = useRecoilValue(objectSizeState);

Expand Down Expand Up @@ -50,7 +50,7 @@ function Edit3d({ objecturl }) {

return (
<>
<PerspectiveCamera makeDefault position={[2, 5, 15]} />
<PerspectiveCamera makeDefault position={[0, 0, 10]} />
<hemisphereLight
skyColor={0xffffbb}
groundColor={0x080820}
Expand All @@ -69,6 +69,9 @@ function Edit3d({ objecturl }) {
x={url.x}
y={url.y}
z={url.z}
setIsDragging={setIsDragging}
setObjectValue={setObjectValue}
pageRendering={pageRendering}
/>
) : url?.extension === 'gltf' ? (
<EditGltfLoader
Expand All @@ -79,6 +82,8 @@ function Edit3d({ objecturl }) {
y={url.y}
z={url.z}
setIsDragging={setIsDragging}
setObjectValue={setObjectValue}
pageRendering={pageRendering}
/>
) : null,
)}
Expand Down
57 changes: 24 additions & 33 deletions src/components/EditPage/PageData/Edit3d/EditGltfLoader.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import React, { useRef, useEffect, useState } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { Color, Box3, Vector3, AxesHelper } from 'three';
import { Color, Box3, Vector3 } from 'three';
import { useRecoilState } from 'recoil';
import { DragControls } from 'three/examples/jsm/controls/DragControls';

import { LodingState } from '../../../../store/modalState';
import useKeyDown from '../../../../hooks/EditPage/Handlers/useKeyDown';
import useObjectDrag from '../../../../hooks/EditPage/useObjectDrag';

function EditGltfLoader({ objecturl, size, x, y, z, setIsDragging }) {
function EditGltfLoader({
objecturl,
size,
x,
y,
z,
setIsDragging,
setObjectValue,
pageRendering,
}) {
const modelRef = useRef();
const { camera, scene, gl } = useThree();
const [loadingValue, setLoadingValue] = useRecoilState(LodingState);
const [gltf, setGltf] = useState(null);
const [initialScale, setInitialScale] = useState([1, 1, 1]);
const movement = useRef({ forward: 0, right: 0, up: 0 });
const gltfUrl = typeof objecturl === 'string' ? objecturl : objecturl.gltf;
const controlsRef = useRef();

useEffect(() => {
scene.background = new Color('#FFFFFF');
Expand All @@ -40,6 +49,8 @@ function EditGltfLoader({ objecturl, size, x, y, z, setIsDragging }) {

setGltf(loadedGltf);
setInitialScale([scale, scale, scale]);
loadedGltf.scene.position.set(x, y, z); // 초기 위치 설정

setLoadingValue(false);
},
undefined,
Expand All @@ -62,37 +73,17 @@ function EditGltfLoader({ objecturl, size, x, y, z, setIsDragging }) {
});

useKeyDown(movement, modelRef);
useEffect(() => {
if (modelRef.current) {
controlsRef.current = new DragControls(
[modelRef.current],
camera,
gl.domElement,
);

controlsRef.current.addEventListener('dragstart', (event) => {
event.object.material.emissive.set(0xaaaaaa);
setIsDragging(true);
});

controlsRef.current.addEventListener('dragend', (event) => {
event.object.material.emissive.set(0x000000);
setIsDragging(false);
});
useObjectDrag({
modelRef,
camera,
domElement: gl.domElement,
setIsDragging,
setObjectValue,
pageRendering,
objectId: objecturl.id,
});

return () => {
controlsRef.current.dispose();
};
}
return undefined;
}, [camera, gl]);
useEffect(() => {
const axesHelper = new AxesHelper(100);
scene.add(axesHelper);
return () => {
scene.remove(axesHelper);
};
}, [scene]);
return (
<mesh ref={modelRef} visible={!loadingValue}>
{gltf ? (
Expand Down
33 changes: 24 additions & 9 deletions src/components/EditPage/PageData/Edit3d/EditObjLoader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ import { useRecoilState } from 'recoil';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
import { LodingState } from '../../../../store/modalState';
import useKeyDown from '../../../../hooks/EditPage/Handlers/useKeyDown';

function EditObjLoader({ objecturl, size, x, y, z }) {
import useObjectDrag from '../../../../hooks/EditPage/useObjectDrag';

function EditObjLoader({
objecturl,
size,
x,
y,
z,
setIsDragging,
setObjectValue,
pageRendering,
}) {
const modelRef = useRef();
const { camera } = useThree();
const { camera, gl } = useThree();
const [loadingValue, setLoadingValue] = useRecoilState(LodingState);
const [object, setObject] = useState(null);
const [initialScale, setInitialScale] = useState([1, 1, 1]);
Expand All @@ -27,6 +37,7 @@ function EditObjLoader({ objecturl, size, x, y, z }) {
setObject(null);
return;
}

setLoadingValue(true);

const materialUrl = objecturl?.mtl || null;
Expand Down Expand Up @@ -63,12 +74,6 @@ function EditObjLoader({ objecturl, size, x, y, z }) {
loadModel();
}, [objecturl, setLoadingValue]);

useEffect(() => {
if (object) {
setLoadingValue(false);
}
}, [object, setLoadingValue]);

useFrame(() => {
if (!modelRef.current) return;
const speed = 0.1;
Expand All @@ -83,6 +88,16 @@ function EditObjLoader({ objecturl, size, x, y, z }) {

useKeyDown(movement, modelRef);

useObjectDrag({
modelRef,
camera,
domElement: gl.domElement,
setIsDragging,
setObjectValue,
pageRendering,
objectId: objecturl.id,
});

return (
<mesh ref={modelRef} visible={!loadingValue}>
{object ? (
Expand Down
76 changes: 0 additions & 76 deletions src/components/Modal/atom/Test.jsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/hooks/AddItem/useObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const useObject = () => {
textures: texturesUrl,
size: 0.25,
x: getRandomCoordinate(),
y: getRandomCoordinate(),
y: 0,
z: getRandomCoordinate(),
};
const updatedImages = {
Expand Down
5 changes: 3 additions & 2 deletions src/hooks/EditPage/useItemValue.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilState } from 'recoil';
import {
imageList,
object3dState,
Expand All @@ -7,13 +7,14 @@ import {
} from '../../store/recoil';

const useItemValue = () => {
const objectValue = useRecoilValue(object3dState);
const [objectValue, setObjectValue] = useRecoilState(object3dState);
const [shapeValue, setShapeValue] = useRecoilState(shapeList);
const [textValue, setTextValue] = useRecoilState(textList);
const [imgValue, setImgValue] = useRecoilState(imageList);

return {
objectValue,
setObjectValue,
shapeValue,
setShapeValue,
textValue,
Expand Down
89 changes: 89 additions & 0 deletions src/hooks/EditPage/useObjectDrag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useRef, useEffect } from 'react';
import { DragControls } from 'three/examples/jsm/controls/DragControls';
import { Vector3 } from 'three';

const useObjectDrag = ({
modelRef,
camera,
domElement,
setIsDragging,
setObjectValue,
pageRendering,
objectId,
scaleFactor = 0.05,
}) => {
const controlsRef = useRef();
const startPosition = useRef(new Vector3());
const deltaPosition = useRef(new Vector3());

const handlePositionChange = (id, axis, value) => {
setObjectValue((prev) => ({
...prev,
[pageRendering]: prev[pageRendering].map((obj) =>
obj.id === id ? { ...obj, [axis]: value } : obj,
),
}));
};

useEffect(() => {
if (modelRef.current) {
controlsRef.current = new DragControls(
[modelRef.current],
camera,
domElement,
);

controlsRef.current.addEventListener('dragstart', (event) => {
if (event.object.material && event.object.material.emissive) {
event.object.material.emissive.set(0xaaaaaa);
}
if (typeof setIsDragging === 'function') {
setIsDragging(true);
}
startPosition.current.copy(event.object.position);
});

controlsRef.current.addEventListener('drag', (event) => {
const { object } = event;
object.position.y = 0; // y축 고정

deltaPosition.current.set(
(object.position.x - startPosition.current.x) * scaleFactor,
0,
(object.position.z - startPosition.current.z) * scaleFactor,
);

object.position.x = startPosition.current.x + deltaPosition.current.x;
object.position.z = startPosition.current.z + deltaPosition.current.z;

// 여기에서 실시간으로 위치를 저장
handlePositionChange(objectId, 'x', Math.round(object.position.x));
handlePositionChange(objectId, 'z', Math.round(object.position.z));
});

controlsRef.current.addEventListener('dragend', (event) => {
const { object } = event;

if (object.material && object.material.emissive) {
object.material.emissive.set(0x000000);
}
if (typeof setIsDragging === 'function') {
setIsDragging(false);
}
// 드래그가 끝난 후 최종 위치를 저장
handlePositionChange(objectId, 'x', Math.round(object.position.x));
handlePositionChange(objectId, 'z', Math.round(object.position.z));
});

return () => {
controlsRef.current.dispose();
};
}
// 명시적으로 undefined 반환
return undefined;
}, [camera, domElement, modelRef]);

return controlsRef;
};

export default useObjectDrag;
Loading

0 comments on commit 5dc4391

Please sign in to comment.