From 705572ba08bc9d4972b79a8c05667ff458779350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=B0=B1=EB=B2=94?= Date: Thu, 16 Nov 2023 20:38:35 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20=20Make=20Galaxy=20mem?= =?UTF-8?q?orize=20Stars?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존에 저장되지 않던 은하의 별들에 관한 정보를 useMemo를 통해 기억하도록 했다. --- .../src/components/feature/Galaxy/index.tsx | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/client/src/components/feature/Galaxy/index.tsx b/packages/client/src/components/feature/Galaxy/index.tsx index b4a6018..34de714 100644 --- a/packages/client/src/components/feature/Galaxy/index.tsx +++ b/packages/client/src/components/feature/Galaxy/index.tsx @@ -1,7 +1,7 @@ import * as THREE from 'three'; import Star from '../Star'; import { getRandomInt, getGaussianRandomFloat } from '@utils/random'; -import { useRef } from 'react'; +import { useRef, useMemo } from 'react'; import { useFrame } from '@react-three/fiber'; import { ARMS, @@ -31,43 +31,46 @@ const getSpiralPositions = (offset: number) => { export default function Galaxy() { const galaxyRef = useRef(null!); - const stars = []; - useFrame((_, delta) => (galaxyRef.current.rotation.y += delta / 100)); + useFrame((_, delta) => (galaxyRef.current.rotation.y += delta / 200)); + + const stars = useMemo(() => { + const starList = []; + for (let arm = 0; arm < ARMS; arm++) { + for (let star = 0; star < STARS_NUM / (ARMS + 1); star++) { + const size = getRandomInt(STAR_MIN_SIZE, STAR_MAX_SIZE); + const position = getSpiralPositions((arm * 2 * Math.PI) / ARMS); + + starList.push( + , + ); + } + } - for (let arm = 0; arm < ARMS; arm++) { for (let star = 0; star < STARS_NUM / (ARMS + 1); star++) { const size = getRandomInt(STAR_MIN_SIZE, STAR_MAX_SIZE); - const position = getSpiralPositions((arm * 2 * Math.PI) / ARMS); + const position = new THREE.Vector3( + getGaussianRandomFloat(0, (ARMS_X_MEAN + ARMS_X_DIST) / 4), + getGaussianRandomFloat(0, GALAXY_THICKNESS * 2), + getGaussianRandomFloat(0, (ARMS_X_MEAN + ARMS_X_DIST) / 4), + ); - stars.push( + starList.push( , ); } - } - - for (let star = 0; star < STARS_NUM / (ARMS + 1); star++) { - const size = getRandomInt(STAR_MIN_SIZE, STAR_MAX_SIZE); - const position = new THREE.Vector3( - getGaussianRandomFloat(0, (ARMS_X_MEAN + ARMS_X_DIST) / 4), - getGaussianRandomFloat(0, GALAXY_THICKNESS * 2), - getGaussianRandomFloat(0, (ARMS_X_MEAN + ARMS_X_DIST) / 4), - ); - - stars.push( - , - ); - } + return starList; + }, []); return {stars}; } From 9537ce3f396de7a292c2c17a3131cc730cd4f200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=B0=B1=EB=B2=94?= Date: Thu, 16 Nov 2023 20:41:55 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20=20Improved=20the=20ca?= =?UTF-8?q?mera=20movement=20more=20naturally?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존에 직선으로 움직이던 카메라 움직임을 좀 더 자연스럽게 포물선을 그리며 움직이도록 개선했다. - 카메라와 currentView 사이의 거리를 distance 만큼으로 유지하도록 개선했다. --- .../components/feature/Controls/Controls.tsx | 19 ++++++++++++++++--- .../src/components/feature/Screen/index.tsx | 8 +++++++- packages/client/src/store/useCameraStore.ts | 5 +++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/feature/Controls/Controls.tsx b/packages/client/src/components/feature/Controls/Controls.tsx index f263fca..1645dcc 100644 --- a/packages/client/src/components/feature/Controls/Controls.tsx +++ b/packages/client/src/components/feature/Controls/Controls.tsx @@ -2,12 +2,25 @@ import { useRef } from 'react'; import { OrbitControls } from '@react-three/drei'; import * as THREE from 'three'; import { useCameraStore } from 'store/useCameraStore'; -import { useFrame } from '@react-three/fiber'; +import { Camera, useFrame } from '@react-three/fiber'; import type { OrbitControls as OrbitControlsImpl } from 'three-stdlib'; +function setCameraPosition( + camera: Camera, + currentView: THREE.Vector3, + distance: number, +) { + const direction = currentView + .clone() + .sub(camera.position) + .setLength(camera.position.distanceTo(currentView) - distance); + camera.position.add(direction); +} + export default function Controls() { const controlsRef = useRef(null!); - const { currentView, setCurrentView, targetView } = useCameraStore(); + const { distance, currentView, setCurrentView, targetView } = + useCameraStore(); useFrame((state, delta) => { const targetPosition = new THREE.Vector3(0, 0, 0); @@ -21,7 +34,7 @@ export default function Controls() { if (direction.length() > LENGTH_LIMIT) direction.setLength(LENGTH_LIMIT); setCurrentView(currentView.add(direction)); - state.camera.position.add(direction); + setCameraPosition(state.camera, currentView, distance); controlsRef.current.target = currentView; } diff --git a/packages/client/src/components/feature/Screen/index.tsx b/packages/client/src/components/feature/Screen/index.tsx index e017c7d..2e74f2e 100644 --- a/packages/client/src/components/feature/Screen/index.tsx +++ b/packages/client/src/components/feature/Screen/index.tsx @@ -5,6 +5,7 @@ import { EffectComposer, Bloom } from '@react-three/postprocessing'; import { useControls } from 'leva'; import { CAMERA_POSITION, CAMERA_ROTATION, CAMERA_FAR } from 'constants/camera'; import Controls from '../Controls/Controls.tsx'; +import { useCameraStore } from 'store/useCameraStore.ts'; export default function Screen() { const camera = { @@ -13,6 +14,8 @@ export default function Screen() { far: CAMERA_FAR, }; + const { distance, setDistance } = useCameraStore(); + const { intensity, mipmapBlur, luminanceThreshold, luminanceSmoothing } = useControls('Bloom', { intensity: { value: 0.4, min: 0, max: 1.5, step: 0.01 }, @@ -23,7 +26,10 @@ export default function Screen() { return (
- + setDistance(distance + e.deltaY / 20)} + > void; targetView: THREE.Mesh | null; setTargetView: (star: THREE.Mesh | null) => void; + distance: number; + setDistance: (distance: number) => void; } export const useCameraStore = create()((set) => ({ @@ -13,4 +15,7 @@ export const useCameraStore = create()((set) => ({ setCurrentView: (position: THREE.Vector3) => set({ currentView: position }), targetView: null, setTargetView: (star: THREE.Mesh | null) => set({ targetView: star }), + distance: 100, + setDistance: (distance: number) => + set({ distance: distance > 100 ? distance : 100 }), })); From 18a0bbb21c11b92c727c0a1ee10f005e72b908a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=B0=B1=EB=B2=94?= Date: Thu, 16 Nov 2023 21:07:02 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=8E=A8=20=20Separate=20constant=20val?= =?UTF-8?q?ue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 카메라와 물체의 최소 거리를 상수 처리했다. --- packages/client/src/components/feature/Galaxy/index.tsx | 2 +- packages/client/src/constants/camera.ts | 1 + packages/client/src/store/useCameraStore.ts | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/feature/Galaxy/index.tsx b/packages/client/src/components/feature/Galaxy/index.tsx index 34de714..1c0a905 100644 --- a/packages/client/src/components/feature/Galaxy/index.tsx +++ b/packages/client/src/components/feature/Galaxy/index.tsx @@ -32,7 +32,7 @@ const getSpiralPositions = (offset: number) => { export default function Galaxy() { const galaxyRef = useRef(null!); - useFrame((_, delta) => (galaxyRef.current.rotation.y += delta / 200)); + useFrame((_, delta) => (galaxyRef.current.rotation.y += delta / 100)); const stars = useMemo(() => { const starList = []; diff --git a/packages/client/src/constants/camera.ts b/packages/client/src/constants/camera.ts index 3b97eff..351d86f 100644 --- a/packages/client/src/constants/camera.ts +++ b/packages/client/src/constants/camera.ts @@ -3,3 +3,4 @@ type Vector3 = [number, number, number]; export const CAMERA_POSITION: Vector3 = [0, 2000, 2000]; export const CAMERA_ROTATION: Vector3 = [-0.5, 0, 0]; export const CAMERA_FAR = 100000; +export const CAMERA_MIN_DISTANCE = 100; diff --git a/packages/client/src/store/useCameraStore.ts b/packages/client/src/store/useCameraStore.ts index 9fd8cb6..fa5ba5a 100644 --- a/packages/client/src/store/useCameraStore.ts +++ b/packages/client/src/store/useCameraStore.ts @@ -1,5 +1,6 @@ import { create } from 'zustand'; import * as THREE from 'three'; +import { CAMERA_MIN_DISTANCE } from 'constants/camera'; interface cameraState { currentView: THREE.Vector3; @@ -17,5 +18,7 @@ export const useCameraStore = create()((set) => ({ setTargetView: (star: THREE.Mesh | null) => set({ targetView: star }), distance: 100, setDistance: (distance: number) => - set({ distance: distance > 100 ? distance : 100 }), + set({ + distance: distance > CAMERA_MIN_DISTANCE ? distance : CAMERA_MIN_DISTANCE, + }), })); From 5290981aac63ef0033d92e9df432edc05e0ce186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=B0=B1=EB=B2=94?= Date: Thu, 16 Nov 2023 21:50:14 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20Reflect=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존에 일반 함수를 함수 선언식으로 선언 했던 것을 화살표 함수로 바꿔 주었다. - 의미가 직관적이지 않았던 distance 전역환경변수를 cameraToCurrentView로 바꿔주었다. --- .../src/components/feature/Controls/Controls.tsx | 10 +++++----- .../client/src/components/feature/Screen/index.tsx | 6 ++++-- packages/client/src/store/useCameraStore.ts | 11 ++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/client/src/components/feature/Controls/Controls.tsx b/packages/client/src/components/feature/Controls/Controls.tsx index 1645dcc..d35753f 100644 --- a/packages/client/src/components/feature/Controls/Controls.tsx +++ b/packages/client/src/components/feature/Controls/Controls.tsx @@ -5,21 +5,21 @@ import { useCameraStore } from 'store/useCameraStore'; import { Camera, useFrame } from '@react-three/fiber'; import type { OrbitControls as OrbitControlsImpl } from 'three-stdlib'; -function setCameraPosition( +const setCameraPosition = ( camera: Camera, currentView: THREE.Vector3, distance: number, -) { +) => { const direction = currentView .clone() .sub(camera.position) .setLength(camera.position.distanceTo(currentView) - distance); camera.position.add(direction); -} +}; export default function Controls() { const controlsRef = useRef(null!); - const { distance, currentView, setCurrentView, targetView } = + const { cameraToCurrentView, currentView, setCurrentView, targetView } = useCameraStore(); useFrame((state, delta) => { @@ -34,7 +34,7 @@ export default function Controls() { if (direction.length() > LENGTH_LIMIT) direction.setLength(LENGTH_LIMIT); setCurrentView(currentView.add(direction)); - setCameraPosition(state.camera, currentView, distance); + setCameraPosition(state.camera, currentView, cameraToCurrentView); controlsRef.current.target = currentView; } diff --git a/packages/client/src/components/feature/Screen/index.tsx b/packages/client/src/components/feature/Screen/index.tsx index 2e74f2e..3b60a34 100644 --- a/packages/client/src/components/feature/Screen/index.tsx +++ b/packages/client/src/components/feature/Screen/index.tsx @@ -14,7 +14,7 @@ export default function Screen() { far: CAMERA_FAR, }; - const { distance, setDistance } = useCameraStore(); + const { cameraToCurrentView, setCameraToCurrentView } = useCameraStore(); const { intensity, mipmapBlur, luminanceThreshold, luminanceSmoothing } = useControls('Bloom', { @@ -28,7 +28,9 @@ export default function Screen() {
setDistance(distance + e.deltaY / 20)} + onWheel={(e) => + setCameraToCurrentView(cameraToCurrentView + e.deltaY / 20) + } > void; targetView: THREE.Mesh | null; setTargetView: (star: THREE.Mesh | null) => void; - distance: number; - setDistance: (distance: number) => void; + cameraToCurrentView: number; + setCameraToCurrentView: (distance: number) => void; } export const useCameraStore = create()((set) => ({ @@ -16,9 +16,10 @@ export const useCameraStore = create()((set) => ({ setCurrentView: (position: THREE.Vector3) => set({ currentView: position }), targetView: null, setTargetView: (star: THREE.Mesh | null) => set({ targetView: star }), - distance: 100, - setDistance: (distance: number) => + cameraToCurrentView: CAMERA_MIN_DISTANCE, + setCameraToCurrentView: (distance: number) => set({ - distance: distance > CAMERA_MIN_DISTANCE ? distance : CAMERA_MIN_DISTANCE, + cameraToCurrentView: + distance > CAMERA_MIN_DISTANCE ? distance : CAMERA_MIN_DISTANCE, }), }));