diff --git a/public/models copy/model.glb b/public/models copy/model.glb new file mode 100644 index 0000000..9dbb630 Binary files /dev/null and b/public/models copy/model.glb differ diff --git a/src/components/EditPage/PageData/Edit3d.jsx b/src/components/EditPage/PageData/Edit3d.jsx index 57087fe..61b4213 100644 --- a/src/components/EditPage/PageData/Edit3d.jsx +++ b/src/components/EditPage/PageData/Edit3d.jsx @@ -12,13 +12,14 @@ function Edit3d({ objecturl }) { const dataSize = useRecoilValue(objectSizeState); const [isMouseDown, setIsMouseDown] = useState(false); + const [isDragging, setIsDragging] = useState(false); useEffect(() => { const sensitivity = 0.002; const euler = new Euler(0, 0, 0, 'YXZ'); const handleMouseMove = (event) => { - if (!isMouseDown) return; + if (!isMouseDown || isDragging) return; const { movementX, movementY } = event; @@ -44,7 +45,7 @@ function Edit3d({ objecturl }) { window.removeEventListener('mousedown', handleMouseDown); window.removeEventListener('mouseup', handleMouseUp); }; - }, [camera, isMouseDown]); + }, [camera, isMouseDown, isDragging]); const objectList = Object.values(objecturl || {}); return ( @@ -77,6 +78,7 @@ function Edit3d({ objecturl }) { x={url.x} y={url.y} z={url.z} + setIsDragging={setIsDragging} /> ) : null, )} diff --git a/src/components/EditPage/PageData/Edit3d/EditGltfLoader.jsx b/src/components/EditPage/PageData/Edit3d/EditGltfLoader.jsx index 2e55eb3..496d9ec 100644 --- a/src/components/EditPage/PageData/Edit3d/EditGltfLoader.jsx +++ b/src/components/EditPage/PageData/Edit3d/EditGltfLoader.jsx @@ -1,19 +1,21 @@ 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 } from 'three'; +import { Color, Box3, Vector3, AxesHelper } 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'; -function EditGltfLoader({ objecturl, size, x, y, z }) { +function EditGltfLoader({ objecturl, size, x, y, z, setIsDragging }) { const modelRef = useRef(); - const { camera, scene } = useThree(); + 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'); @@ -60,7 +62,37 @@ function EditGltfLoader({ objecturl, size, x, y, z }) { }); 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); + }); + return () => { + controlsRef.current.dispose(); + }; + } + return undefined; + }, [camera, gl]); + useEffect(() => { + const axesHelper = new AxesHelper(100); + scene.add(axesHelper); + return () => { + scene.remove(axesHelper); + }; + }, [scene]); return ( {gltf ? ( diff --git a/src/components/Modal/atom/Test.jsx b/src/components/Modal/atom/Test.jsx new file mode 100644 index 0000000..187ecee --- /dev/null +++ b/src/components/Modal/atom/Test.jsx @@ -0,0 +1,76 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useThree } from '@react-three/fiber'; +import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; +import { Color, Box3, Vector3 } from 'three'; +import { useRecoilState } from 'recoil'; +import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'; +import { LodingState } from '../../../store/modalState'; + +function TestOBJ({ objecturl, x, y, z }) { + const modelRef = useRef(); + const [loadingValue, setLoadingValue] = useRecoilState(LodingState); + const [object, setObject] = useState(null); + + const { scene } = useThree(); + + useEffect(() => { + scene.background = new Color('#FFFFFF'); + }, [scene]); + + useEffect(() => { + if (!objecturl?.obj) { + setLoadingValue(false); + setObject(null); + return; + } + setLoadingValue(true); + + const materialUrl = objecturl?.mtl || null; + const loadUrl = objecturl?.obj || null; + + const loadModel = () => { + const objLoader = new OBJLoader(); + const onLoad = (obj) => { + // 모델의 경계 계산 + const box = new Box3().setFromObject(obj); + const size = new Vector3(); + box.getSize(size); + const maxDimension = Math.max(size.x, size.y, size.z); + + const scale = 5 / maxDimension; + + obj.scale.set(scale, scale, scale); + + setObject(obj); + setLoadingValue(false); + }; + + if (materialUrl) { + const mtlLoader = new MTLLoader(); + mtlLoader.load(materialUrl, (materials) => { + materials.preload(); + objLoader.setMaterials(materials); + objLoader.load(loadUrl, onLoad); + }); + } else { + objLoader.load(loadUrl, onLoad); + } + }; + + loadModel(); + }, [objecturl, setLoadingValue]); + + useEffect(() => { + if (object) { + setLoadingValue(false); + } + }, [object, setLoadingValue]); + + return ( + + {object ? : null} + + ); +} + +export default TestOBJ;