Skip to content

Commit

Permalink
Add 3D space compass
Browse files Browse the repository at this point in the history
  • Loading branch information
NightfuryEquinn committed Dec 1, 2024
1 parent 2c1918b commit d113415
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 137 deletions.
100 changes: 2 additions & 98 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Binary file added public/assets/textures/axes/point.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/textures/axes/x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/textures/axes/y.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/textures/axes/z.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions src/Experience.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Perf } from "r3f-perf"
import * as THREE from "three"
import Earth from './components/Earth'
import InfiniteStarField from './components/InfiniteStarField'
import SpaceCompass from './components/SpaceCompass'
import Star from './components/Star'

export default function Experience() {
Expand All @@ -12,7 +13,7 @@ export default function Experience() {
return <>
<Perf position='top-left' />

<color args={["#161A1D"]} attach="background" />
<color args={[ "#161A1D" ]} attach="background" />

<Environment
background
Expand Down Expand Up @@ -44,7 +45,9 @@ export default function Experience() {
<InfiniteStarField count={ 10 } size={ 800 } gridSize={ 8 } />

<ambientLight intensity={ 0.375 } />
<pointLight castShadow intensity={ 5 } position={[0, 0, 0]} />
<pointLight castShadow intensity={ 5 } position={[ 0, 0, 0 ]} color="#DEE2E6" />

<SpaceCompass />

<OrbitControls
enableDamping
Expand Down
38 changes: 19 additions & 19 deletions src/components/Earth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import atmosphereVertex from "../shaders/earth_atmosphere/vertex.glsl"

export default function Earth({ sunDirection }: any) {
// Earth
const earthMaterial = useRef<any>(null)
const earthGeometry = useRef<any>(null)
const earthMaterial = useRef<any>( null )
const earthGeometry = useRef<any>( 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
Expand All @@ -28,34 +28,34 @@ export default function Earth({ sunDirection }: any) {
earthSpecularTexture.anisotropy = 8

// Atmosphere
const atmosphereGeometry = useRef<any>(null)
const atmosphereMaterial = useRef<any>(null)
const atmosphereGeometry = useRef<any>( null )
const atmosphereMaterial = useRef<any>( 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 <>
Expand All @@ -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 }
/>
Expand All @@ -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 }
/>
Expand Down
28 changes: 14 additions & 14 deletions src/components/InfiniteStarField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<any>(null)
const positions = generateStars(count, size)
const groupRef = useRef<any>( 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,
Expand All @@ -34,13 +34,13 @@ export default function InfiniteStarField({ count, size, gridSize }: any) {

return <>
<group ref={ groupRef }>
{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 (
<points key={ i } position={ [x * size, y * size, z * size] }>
<points key={ i } position={[ x * size, y * size, z * size ]}>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
Expand Down
54 changes: 53 additions & 1 deletion src/components/SpaceCompass.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,57 @@
import { useFrame, useLoader, useThree } from "@react-three/fiber"
import { useRef } from "react"
import * as THREE from "three"

export default function SpaceCompass() {
const compassRef = useRef<any>( 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 <>
<mesh>
<cylinderGeometry args={[ 0.02, 0.02, 0.1875, 32 ]} />
<meshMatcapMaterial matcap={ axesMatcap } />

<mesh position={[ 0, 0.125, 0 ]}>
<coneGeometry args={[ 0.05, 0.125, 32 ]} />
<meshMatcapMaterial matcap={ axesMatcap } />
</mesh>
</mesh>
</>
}

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

<group ref={ compassRef } scale={ 0.25 }>
<group>
<group position={[ 0, 0, 0.1875 ]} rotation={[ Math.PI / 2, 0, 0 ]}>{ renderAxis( "X" ) }</group>
<group position={[ 0, 0.1875, 0 ]} rotation={[ 0, Math.PI, 0 ]}>{ renderAxis( "Y" ) }</group>
<group position={[ -0.1875, 0, 0 ]} rotation={[ 0, 0, Math.PI / 2 ]}>{ renderAxis( "Z" ) }</group>
</group>

<mesh scale={ 0.25 }>
<sphereGeometry args={[ 0.5, 16, 16 ]} />
<meshMatcapMaterial matcap={ pointTexture } />
</mesh>
</group>
</>
}
Loading

0 comments on commit d113415

Please sign in to comment.