From d113415cad5db3b35da20cd6eeec8cedc4f16917 Mon Sep 17 00:00:00 2001 From: NightfuryEquinn Date: Sun, 1 Dec 2024 16:19:42 +0800 Subject: [PATCH] Add 3D space compass --- package-lock.json | 100 +------------------------- package.json | 2 +- public/assets/textures/axes/point.png | Bin 0 -> 2035 bytes public/assets/textures/axes/x.png | Bin 0 -> 6299 bytes public/assets/textures/axes/y.png | Bin 0 -> 5595 bytes public/assets/textures/axes/z.png | Bin 0 -> 5916 bytes src/Experience.tsx | 7 +- src/components/Earth.tsx | 38 +++++----- src/components/InfiniteStarField.tsx | 28 ++++---- src/components/SpaceCompass.tsx | 54 +++++++++++++- src/index.tsx | 4 +- 11 files changed, 96 insertions(+), 137 deletions(-) create mode 100644 public/assets/textures/axes/point.png create mode 100644 public/assets/textures/axes/x.png create mode 100644 public/assets/textures/axes/y.png create mode 100644 public/assets/textures/axes/z.png diff --git a/package-lock.json b/package-lock.json index 2fb57d8..9c257d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1520,70 +1520,6 @@ "three": ">= 0.159.0" } }, - "node_modules/@motionone/animation": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz", - "integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==", - "peer": true, - "dependencies": { - "@motionone/easing": "^10.18.0", - "@motionone/types": "^10.17.1", - "@motionone/utils": "^10.18.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@motionone/dom": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.18.0.tgz", - "integrity": "sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==", - "peer": true, - "dependencies": { - "@motionone/animation": "^10.18.0", - "@motionone/generators": "^10.18.0", - "@motionone/types": "^10.17.1", - "@motionone/utils": "^10.18.0", - "hey-listen": "^1.0.8", - "tslib": "^2.3.1" - } - }, - "node_modules/@motionone/easing": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz", - "integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==", - "peer": true, - "dependencies": { - "@motionone/utils": "^10.18.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@motionone/generators": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz", - "integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==", - "peer": true, - "dependencies": { - "@motionone/types": "^10.17.1", - "@motionone/utils": "^10.18.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@motionone/types": { - "version": "10.17.1", - "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz", - "integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==", - "peer": true - }, - "node_modules/@motionone/utils": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz", - "integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==", - "peer": true, - "dependencies": { - "@motionone/types": "^10.17.1", - "hey-listen": "^1.0.8", - "tslib": "^2.3.1" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2592,15 +2528,6 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" }, - "node_modules/@types/node": { - "version": "22.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", - "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", - "peer": true, - "dependencies": { - "undici-types": "~6.19.8" - } - }, "node_modules/@types/offscreencanvas": { "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", @@ -2624,7 +2551,7 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "devOptional": true, + "dev": true, "dependencies": { "@types/react": "*" } @@ -5108,12 +5035,6 @@ "node": ">= 0.4" } }, - "node_modules/hey-listen": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", - "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==", - "peer": true - }, "node_modules/hls.js": { "version": "1.5.17", "resolved": "https://registry.npmjs.org/hls.js/-/hls.js-1.5.17.tgz", @@ -5766,18 +5687,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/motion": { - "version": "10.18.0", - "resolved": "https://registry.npmjs.org/motion/-/motion-10.18.0.tgz", - "integrity": "sha512-MVAZZmwM/cp77BrNe1TxTMldxRPjwBNHheU5aPToqT4rJdZxLiADk58H+a0al5jKLxkB0OdgNq6DiVn11cjvIQ==", - "peer": true, - "dependencies": { - "@motionone/animation": "^10.18.0", - "@motionone/dom": "^10.18.0", - "@motionone/types": "^10.17.1", - "@motionone/utils": "^10.18.0" - } - }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -7482,6 +7391,7 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7532,12 +7442,6 @@ "node": ">=14.0" } }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "peer": true - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index 134438a..78e8b3f 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "camera-controls": "^2.9.0", "gl-noise": "^1.6.1", "leva": "^0.9.35", - "postcss": "^8.4.49", + "postcss": "^8.4.49", "postprocessing": "^6.36.4", "r3f-perf": "^7.2.3", "react": "^18.3.1", diff --git a/public/assets/textures/axes/point.png b/public/assets/textures/axes/point.png new file mode 100644 index 0000000000000000000000000000000000000000..425dddb7bd0f53359fe895fc6b1c3924c09e8324 GIT binary patch literal 2035 zcmVq~!Lk#_GV;!PcfIz`_e^)cs^ZYyv%539ggVVf*ROx|@qSegVa||5 zfnGR!rnyupSm1c@eDl%6Cj(P3EGnw13JRd<({t`9V9s5+v|5ljN?4Ix5C$gNx%bce zgV3^wiVA3sFbhDcwQE;f((4VQ#ESrtwJs=>YE|5P_tulpBqAcJIl^H80;#@wy|%a8 zAB`uIghi2zbwMF47K)Wdz4!M&ZxuC%0MHo#61?%f`qpm0-y4i42@4>Rwax`$p;#`L zOO2)8pZ<~rF>{J=7yyZzKfbiJ)$Me;!%^e~5REa`T5DYp7E0x6wY<1|?>C>65-*$~ zn1k87_VfCK&8^MN?cL5`9C=m*Bm__upTuz##XcFfu8r>nr~se{xDSA!Km5VYqwRKk z`)Ow|iCK}1wbmMA5K&dUPvY3i#Jp0wgCtoQa{yHHlN%2&(< zAwvY9;(d}N!qMeZA4rCPX6pa5EBCiIHnw(qqnH8FSm&H`&RS!L5D@`H*n2N9zO??H zU|NM70DgMq{?6m}_VYpH1%QmT*15o@{)7a80IJNMg(eqT?~>|%2&6x{et+k2d#5vs zSpmryXPt9Xe@rQ$sxY(AYXtFR22~ggI7MLdjdjfe0{t7Y;O?x+&|6MG0p&>D#^IF*WbCeoFEZgtL=84_a=$zzB{DO z^Zr>DI2v}l&#G62i0S3M-d-*@VaeAaTN2R*I@n(k)R4GPO}fHBFxO5 zC61yfYTCs(Nj%F;mePla5P&4_C>V^2@x|A z+50_v@0GmgxNO5dv#8FdT9|w)1DYbFze}pCiDy>wo_%O-I<98`1UVBjHAd5q3M$It zy-&RNtVTq{+W9U^M-eh&)({2>5cBGI?~}wcLpm6&pK9iTEPwz2f`Y0Q!>P1ro`J-B z?-djX$=fK?t@$840H{c&>i{4bfcMOz2uQ|6c2G3dAfV0!0RmoCtQayx2smZHo>>?O z$r?AX&(@u@hIlpz5LHkWW60os2*Se5A__>(*|2Tf7lJUDp^yea0;(jOP9{jZKtxzX z1rUr2g0O8LQlSt!bJ$-I6a`g-F!imIfCQ~`|(3I%#-AH?NSF)*`PL{I<_RH12^ za+y$7Ks2scD#s7(##W(l#BJP4T8J1a-}p!As4nZ zYR{fi%QrkULAg?{-35XVsamTP9nB-?VQrCY$y5aZbj3=oN*{uSyBkYS>y<$)sPiNc zbefP{k^mIZhLw7CY2z-Ckz0*gqgD#&s6miRQEurMKnhB=My+v63<=!qEiIg=6&xNj z#}1s;>t@Sm&2NgTyq zju|5}hG@d-^2w8@{4XN_13(l1%7EiIIjoGw8c|qYTx+eK{_V%4U;q?9{o<(+CyD3( zg8~w{Qe(BbcILA;F<-La!8e^}@A>nCKqOaMSZy|2#b0z0vOSSH-RluZdQ3mxzrNCJ zt(|`JBhnl|>0#+BW24z9!{go2gr$X*=8G%m-ugWWaDRQay9nArWOi-*Yt~OgM=l}6~KJ=&SzT9qoIk7HRAB2N#g@{DP z70UJHwbseC^S58;{N(IkIP`Y$t3;u*nF=FdwyO~$k#&VqZE^KvYpr$qk8kWN;DIX- z-P!)yq818ay5kxmA|xVXj19tKxprdth33iCv!yrwK>LY0>e98>=?+HYIAK-+077G2 zP%KsI3yu2P+P{C@HV3MG)V1$vzuy}S$5HG#UH)wl7R!}dwYt34{oP-c4z~Pp7ti5% zG>H<=3TUhg3#DSYy42|X?X5n+p(Atb)wesG#0j$k8smaOxn841>-F(K6}vf9(tF&813c!AFDL_QOxNB>iL7{tH7dR4t}8 R2VVdH002ovPDHLkV1n~e$)ErL literal 0 HcmV?d00001 diff --git a/public/assets/textures/axes/x.png b/public/assets/textures/axes/x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe4ec9cebddf49d3ef89bd8fbdb07cf91cf63ff1 GIT binary patch literal 6299 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 - + - + + + (null) - const earthGeometry = useRef(null) + const earthMaterial = useRef( null ) + const earthGeometry = useRef( null ) const earthParameters = { atmosphereDayColor: "#2E6CCB", atmosphereNightColor: "#E06F00" } - const earthDayTexture = useLoader(THREE.TextureLoader, "../assets/textures/earth/day.jpg") - const earthNightTexture = useLoader(THREE.TextureLoader, "../assets/textures/earth/night.jpg") - const earthSpecularTexture = useLoader(THREE.TextureLoader, "../assets/textures/earth/specularClouds.jpg") + const earthDayTexture = useLoader( THREE.TextureLoader, "../assets/textures/earth/day.jpg" ) + const earthNightTexture = useLoader( THREE.TextureLoader, "../assets/textures/earth/night.jpg" ) + const earthSpecularTexture = useLoader( THREE.TextureLoader, "../assets/textures/earth/specularClouds.jpg" ) earthDayTexture.colorSpace = THREE.SRGBColorSpace earthNightTexture.colorSpace = THREE.SRGBColorSpace @@ -28,34 +28,34 @@ export default function Earth({ sunDirection }: any) { earthSpecularTexture.anisotropy = 8 // Atmosphere - const atmosphereGeometry = useRef(null) - const atmosphereMaterial = useRef(null) + const atmosphereGeometry = useRef( null ) + const atmosphereMaterial = useRef( null ) // Orbit const orbitRadius = 20 const orbitSpeed = 0.025 - const [ orbitAngle, setOrbitAngle ] = useState(0) + const [ orbitAngle, setOrbitAngle ] = useState( 0 ) useFrame(( _, delta ) => { earthMaterial.current.uniforms.uTime.value += delta earthGeometry.current.rotation.y += delta * 0.075 const newOrbitAngle = orbitAngle + delta * orbitSpeed - setOrbitAngle(newOrbitAngle) + setOrbitAngle( newOrbitAngle ) - const x = Math.cos(newOrbitAngle) * orbitRadius - const z = Math.sin(newOrbitAngle) * orbitRadius + const x = Math.cos( newOrbitAngle ) * orbitRadius + const z = Math.sin( newOrbitAngle ) * orbitRadius - earthGeometry.current.position.set(x, 0, z) - atmosphereGeometry.current.position.set(x, 0, z) + earthGeometry.current.position.set( x, 0, z ) + atmosphereGeometry.current.position.set( x, 0, z ) const sunPosition = new THREE.Vector3().subVectors( sunDirection, earthGeometry.current.position ).normalize() - earthMaterial.current.uniforms.uSunDirection.value.copy(sunPosition) - atmosphereMaterial.current.uniforms.uSunDirection.value.copy(sunPosition) + earthMaterial.current.uniforms.uSunDirection.value.copy( sunPosition ) + atmosphereMaterial.current.uniforms.uSunDirection.value.copy( sunPosition ) }) return <> @@ -71,8 +71,8 @@ export default function Earth({ sunDirection }: any) { uNightTexture: { value: earthNightTexture }, uSpecularTexture: { value: earthSpecularTexture }, uSunDirection: { value: sunDirection }, - uAtmosphereDayColor: { value: new THREE.Color(earthParameters.atmosphereDayColor) }, - uAtmosphereNightColor: { value: new THREE.Color(earthParameters.atmosphereNightColor) } + uAtmosphereDayColor: { value: new THREE.Color( earthParameters.atmosphereDayColor )}, + uAtmosphereNightColor: { value: new THREE.Color( earthParameters.atmosphereNightColor )} }} toneMapped={ true } /> @@ -88,8 +88,8 @@ export default function Earth({ sunDirection }: any) { fragmentShader={ atmosphereFragment } uniforms={{ uSunDirection: { value: sunDirection }, - uAtmosphereDayColor: { value: new THREE.Color(earthParameters.atmosphereDayColor) }, - uAtmosphereNightColor: { value: new THREE.Color(earthParameters.atmosphereNightColor) } + uAtmosphereDayColor: { value: new THREE.Color( earthParameters.atmosphereDayColor )}, + uAtmosphereNightColor: { value: new THREE.Color( earthParameters.atmosphereNightColor )} }} toneMapped={ true } /> diff --git a/src/components/InfiniteStarField.tsx b/src/components/InfiniteStarField.tsx index 7189fca..d7b04e0 100644 --- a/src/components/InfiniteStarField.tsx +++ b/src/components/InfiniteStarField.tsx @@ -7,23 +7,23 @@ const generateStars = (count: number, size: number) => { for (let i = 0; i < count; i++) { positions.push( - (Math.random() - 0.5) * size, - (Math.random() - 0.5) * size, - (Math.random() - 0.5) * size + ( Math.random() - 0.5 ) * size, + ( Math.random() - 0.5 ) * size, + ( Math.random() - 0.5 ) * size ) } - return new Float32Array(positions) + return new Float32Array( positions ) } export default function InfiniteStarField({ count, size, gridSize }: any) { - const groupRef = useRef(null) - const positions = generateStars(count, size) + const groupRef = useRef( null ) + const positions = generateStars( count, size ) useFrame(({ camera }) => { - const cameraGridX = Math.floor(camera.position.x / size) - const cameraGridY = Math.floor(camera.position.y / size) - const cameraGridZ = Math.floor(camera.position.z / size) + const cameraGridX = Math.floor( camera.position.x / size ) + const cameraGridY = Math.floor( camera.position.y / size ) + const cameraGridZ = Math.floor( camera.position.z / size ) groupRef.current.position.set( cameraGridX * size, @@ -34,13 +34,13 @@ export default function InfiniteStarField({ count, size, gridSize }: any) { return <> - {Array.from({ length: gridSize ** 3 }).map((_, i) => { - const x = (i % gridSize) - Math.floor(gridSize / 2) - const y = (Math.floor(i / gridSize) % gridSize) - Math.floor(gridSize / 2) - const z = Math.floor(i / (gridSize * gridSize)) - Math.floor(gridSize / 2) + {Array.from({ length: gridSize ** 3 }).map(( _, i ) => { + const x = ( i % gridSize ) - Math.floor( gridSize / 2 ) + const y = ( Math.floor( i / gridSize ) % gridSize ) - Math.floor( gridSize / 2 ) + const z = Math.floor( i / ( gridSize * gridSize )) - Math.floor( gridSize / 2 ) return ( - + ( null ) + const { camera, size } = useThree() + + const xAxisTexture = useLoader( THREE.TextureLoader, "../assets/textures/axes/x.png" ) + const yAxisTexture = useLoader( THREE.TextureLoader, "../assets/textures/axes/y.png" ) + const zAxisTexture = useLoader( THREE.TextureLoader, "../assets/textures/axes/z.png" ) + const pointTexture = useLoader( THREE.TextureLoader, "../assets/textures/axes/point.png" ) + + const renderAxis = ( axis: "X" | "Y" | "Z" ) => { + const axesMatcap = axis === "X" ? xAxisTexture : axis === "Y" ? yAxisTexture : zAxisTexture + + return <> + + + + + + + + + + + } + + useFrame(() => { + compassRef.current.lookAt( 0, 0, 0 ) + + const margin = 75 + const ndcX = -1 + ( margin / size.width ) * 2 + const ndcY = -1 + ( margin / size.height ) * 2 + + const vector = new THREE.Vector3( ndcX, ndcY, 0 ) + vector.unproject( camera ) + + compassRef.current.position.set( vector.x, vector.y, vector.z ) + }) + return <> - + + + { renderAxis( "X" ) } + { renderAxis( "Y" ) } + { renderAxis( "Z" ) } + + + + + + + } \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index 6bbec1b..d8c9da3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,10 +5,10 @@ import Experience from './Experience.tsx' import './styles/index.css' // Disable strict mode if Arwes not working -createRoot(document.getElementById('root')!).render( +createRoot( document.getElementById( 'root' )! ).render(