Skip to content

Commit 9f7e852

Browse files
authored
Merge pull request #87 from chrisweb/preview
Preview to main
2 parents 64e2def + 16fe6c3 commit 9f7e852

File tree

6 files changed

+319
-193
lines changed

6 files changed

+319
-193
lines changed

components/neonRoad/Canvas.tsx

Lines changed: 61 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
import { Suspense } from 'react'
44
import { Canvas } from '@react-three/fiber'
5-
import { PerspectiveCamera, SoftShadows, AdaptiveDpr/*, OrbitControls*//*, PerformanceMonitor, PerformanceMonitorApi/*, Hud, useDetectGPU, useProgress, StatsGl*/ } from '@react-three/drei'
5+
import { PerspectiveCamera, SoftShadows, AdaptiveDpr /*, Loader, OrbitControls*//*, PerformanceMonitor, PerformanceMonitorApi/*, Hud, useDetectGPU, useProgress, StatsGl*/ } from '@react-three/drei'
66
import NightSky from './NightSky'
77
import Sun from './Sun'
88
import SunLight from './SunLight'
99
import City from './City'
10-
import Trees from './Trees'
11-
import Terrains from './Terrains'
10+
//import Trees from './Trees'
11+
//import Terrains from './Terrains'
12+
import Landscape from './Landscape'
1213
//import { EffectComposer, Bloom } from '@react-three/postprocessing'
1314

1415
interface IProps extends React.PropsWithChildren {
@@ -71,65 +72,69 @@ const NeonRoadCanvas: React.FC<IProps> = (props) => {
7172
}
7273

7374
return (
74-
<Canvas
75-
// https://docs.pmnd.rs/react-three-fiber/tutorials/v8-migration-guide#new-pixel-ratio-default
76-
//dpr={Math.min(window.devicePixelRatio, 2)} // pixel ratio, should be 1 or 2
77-
// https://docs.pmnd.rs/react-three-fiber/api/canvas#render-defaults
78-
shadows="soft" // PCFsoft
79-
fallback={<Fallback />}
80-
aria-label={props.altText}
81-
role="img"
82-
gl={rendererProps}
83-
//frameloop="never"
84-
//onCreated={onCanvasCreatedHandler}
85-
>
86-
<Suspense fallback={<Fallback />}>
87-
<AdaptiveDpr pixelated />
88-
{/*<Loader />*/}
89-
<PerspectiveCamera
90-
makeDefault={true}
91-
fov={75}
92-
near={0.01}
93-
far={3}
94-
position={[0, 0.06, 1]}
95-
aspect={aspect}
96-
/>
97-
{/*<PerformanceMonitor onChange={onPerformanceChangeHandler} />*/}
98-
<color attach="background" args={['#2f0f30']} />
99-
<ambientLight color="#ecd7e2" intensity={15} />
100-
<SoftShadows />
101-
<NightSky
102-
position={[0, 1, -2.1]}
103-
scale={[20, 3, 1]}
104-
/>
105-
<Sun
106-
position={[0, 0.5, -1.6]}
107-
scale={[2, 2, 0]}
108-
/>
109-
<SunLight
110-
position={[0, 0.5, -1.4]}
111-
intensity={8}
112-
/>
113-
<City
114-
position={[0, 0.12, -1]}
115-
scale={[0.8, 0.3, 0]}
116-
/>
117-
<Trees />
118-
<Terrains />
119-
{/* <EffectComposer>
75+
<>
76+
<Canvas
77+
// https://docs.pmnd.rs/react-three-fiber/tutorials/v8-migration-guide#new-pixel-ratio-default
78+
//dpr={Math.min(window.devicePixelRatio, 2)} // pixel ratio, should be 1 or 2
79+
// https://docs.pmnd.rs/react-three-fiber/api/canvas#render-defaults
80+
shadows="soft" // PCFsoft
81+
fallback={<Fallback />}
82+
aria-label={props.altText}
83+
role="img"
84+
gl={rendererProps}
85+
//frameloop="never"
86+
//onCreated={onCanvasCreatedHandler}
87+
>
88+
<Suspense fallback={<Fallback />}>
89+
<AdaptiveDpr pixelated />
90+
{/*<Loader />*/}
91+
<PerspectiveCamera
92+
makeDefault={true}
93+
fov={75}
94+
near={0.01}
95+
far={3}
96+
position={[0, 0.06, 1]}
97+
aspect={aspect}
98+
/>
99+
{/*<PerformanceMonitor onChange={onPerformanceChangeHandler} />*/}
100+
<color attach="background" args={['#2f0f30']} />
101+
<ambientLight color="#ecd7e2" intensity={15} />
102+
<SoftShadows />
103+
<NightSky
104+
position={[0, 1, -2.1]}
105+
scale={[20, 3, 1]}
106+
/>
107+
<Sun
108+
position={[0, 0.5, -1.6]}
109+
scale={[2, 2, 0]}
110+
/>
111+
<SunLight
112+
position={[0, 0.5, -1.4]}
113+
intensity={8}
114+
/>
115+
<City
116+
position={[0, 0.12, -1]}
117+
scale={[0.8, 0.3, 0]}
118+
/>
119+
{/* <Terrains /> */}
120+
{/* <Trees /> */}
121+
<Landscape />
122+
{/* <EffectComposer>
120123
<Bloom
121124
luminanceThreshold={0.08}
122125
intensity={0.7}
123126
luminanceSmoothing={0.01}
124127
/>
125128
</EffectComposer> */}
126-
{/* the following components can be useful in development */}
127-
{/*<axesHelper />*/}
128-
{/*<OrbitControls camera={cameraRef.current} />*/}
129-
{/*<StatsGl />*/}
130-
{/* GUI: https://github.com/pmndrs/leva */}
131-
</Suspense>
132-
</Canvas>
129+
{/* the following components can be useful in development */}
130+
{/*<axesHelper />*/}
131+
{/*<OrbitControls camera={cameraRef.current} />*/}
132+
{/*<StatsGl />*/}
133+
{/* GUI: https://github.com/pmndrs/leva */}
134+
</Suspense>
135+
</Canvas>
136+
{/*<Loader />*/}
137+
</>
133138
)
134139
}
135140

components/neonRoad/Landscape.tsx

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
'use client'
2+
3+
import { useLayoutEffect, useRef, useState, Suspense, useCallback } from 'react'
4+
import { useFrame } from '@react-three/fiber'
5+
import Terrain from './Terrain'
6+
import { Mesh } from 'three'
7+
import { moveFromAToBInLoop } from './lib/helpers'
8+
import PalmModel from './Palm'
9+
import { Vector3, Euler, type Group } from 'three'
10+
11+
12+
13+
const Terrains: React.FC = () => {
14+
15+
const [terrainElementsState, setTerrainElementsState] = useState<React.ReactElement[]>([])
16+
const [treesElementsState, setTreesElementsState] = useState<React.ReactElement[]>([])
17+
18+
const terrainsRefs = useRef<Mesh[]>([])
19+
20+
// movement for trees on the left side
21+
const leftSideTreesRefs = useRef<Group[]>([])
22+
23+
// movement for trees on the right side
24+
const rightSideTreesRefs = useRef<Group[]>([])
25+
26+
useFrame((state, delta /*, xrFrame*/) => {
27+
moveFromAToBInLoop(delta, terrainsRefs.current, 1, 1)
28+
})
29+
useFrame((state, delta /*, xrFrame*/) => {
30+
moveFromAToBInLoop(delta, leftSideTreesRefs.current, 1, 0.2)
31+
})
32+
useFrame((state, delta /*, xrFrame*/) => {
33+
moveFromAToBInLoop(delta, rightSideTreesRefs.current, 1, 0.2)
34+
})
35+
36+
const createTerrain = useCallback((i: number, zPosition: number) => {
37+
return (
38+
<Terrain
39+
zPosition={zPosition}
40+
key={i}
41+
ref={(terrainMesh) => {
42+
terrainsRefs.current[i] = terrainMesh
43+
}}
44+
/>
45+
)
46+
}, [])
47+
48+
const randomDegrees = useCallback(() => {
49+
const min = 0
50+
const max = 360
51+
return Math.floor(Math.random() * (max - min + 1) + min)
52+
}, [])
53+
54+
const createPalm = useCallback((i: number, side: string, positionChange: number) => {
55+
56+
const position = new Vector3(side === 'left' ? 0.21 : -0.21, 0, positionChange)
57+
const scale = new Vector3(0.009, 0.009, 0.009)
58+
const rotation = new Euler(0, randomDegrees(), 0)
59+
60+
return (
61+
<PalmModel
62+
key={i.toString() + side}
63+
position={position}
64+
scale={scale}
65+
rotation={rotation}
66+
ref={(palmMesh) => {
67+
if (side === 'left') {
68+
leftSideTreesRefs.current[i] = palmMesh
69+
} else {
70+
rightSideTreesRefs.current[i] = palmMesh
71+
}
72+
}}
73+
/>
74+
)
75+
76+
}, [randomDegrees])
77+
78+
useLayoutEffect(() => {
79+
80+
// TERRAINS
81+
const terrainElements: React.ReactElement[] = []
82+
83+
// the distance between the city (when the terrain comes
84+
// into view) and the bottom of the camera field of view
85+
// (at which point the terrain goes out of view)
86+
// is approximately 2 units, so we need 3 terrains
87+
// panels (of 1x1 in size), to ensure the distance between
88+
// the camera and city is covered at all times
89+
const terrainsZStartPositions = [0.5, -0.5, -1.5]
90+
91+
for (let i = 0; i < terrainsZStartPositions.length; i++) {
92+
93+
const zPosition = terrainsZStartPositions[i]
94+
95+
terrainElements.push(createTerrain(i, zPosition))
96+
}
97+
98+
setTerrainElementsState(terrainElements)
99+
100+
// TREES
101+
const treesElements: React.ReactElement[] = []
102+
103+
const sides = ['left', 'right']
104+
const amountOfTreesPerSide = 12
105+
106+
sides.forEach((side) => {
107+
108+
let positionChange = -1.5
109+
110+
for (let i = 0; i < amountOfTreesPerSide; i++) {
111+
treesElements.push(createPalm(i, side, positionChange))
112+
positionChange += 0.2
113+
}
114+
115+
})
116+
117+
setTreesElementsState(treesElements)
118+
119+
}, [createTerrain, createPalm])
120+
121+
return (<Suspense>{terrainElementsState}{treesElementsState}</Suspense>)
122+
}
123+
124+
export default Terrains

components/neonRoad/Terrains.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,19 @@ const Terrains: React.FC = () => {
1717
moveFromAToBInLoop(delta, terrains, 1, 1)
1818
})
1919

20-
const createTerrains = useCallback(() => {
20+
const createTerrain = useCallback((i: number, zPosition: number) => {
21+
return (
22+
<Terrain
23+
zPosition={zPosition}
24+
key={i}
25+
ref={(terrainMesh) => {
26+
terrainsRefs.current[i] = terrainMesh
27+
}}
28+
/>
29+
)
30+
}, [])
31+
32+
useLayoutEffect(() => {
2133

2234
const terrainElements: React.ReactElement[] = []
2335

@@ -33,24 +45,12 @@ const Terrains: React.FC = () => {
3345

3446
const zPosition = terrainsZStartPositions[i]
3547

36-
terrainElements.push(
37-
<Terrain
38-
zPosition={zPosition}
39-
key={i}
40-
ref={(terrainMesh) => {
41-
terrainsRefs.current[i] = terrainMesh
42-
}}
43-
/>
44-
)
48+
terrainElements.push(createTerrain(i, zPosition))
4549
}
4650

47-
return terrainElements
51+
setTerrainElementsState(terrainElements)
4852

49-
}, [])
50-
51-
useLayoutEffect(() => {
52-
setTerrainElementsState(createTerrains())
53-
}, [createTerrains])
53+
}, [createTerrain])
5454

5555
return (<Suspense>{terrainElementsState}</Suspense>)
5656
}

components/neonRoad/Trees.tsx

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,31 @@ const Trees: React.FC = () => {
2828
moveFromAToBInLoop(delta, rightSideTreesRefs.current, 1, 0.2)
2929
})
3030

31-
const createTrees = useCallback(() => {
31+
const createPalm = useCallback((i: number, side: string, positionChange: number) => {
32+
33+
const position = new Vector3(side === 'left' ? 0.21 : -0.21, 0, positionChange)
34+
const scale = new Vector3(0.009, 0.009, 0.009)
35+
const rotation = new Euler(0, randomDegrees(), 0)
36+
37+
return (
38+
<PalmModel
39+
key={i.toString() + side}
40+
position={position}
41+
scale={scale}
42+
rotation={rotation}
43+
ref={(palmMesh) => {
44+
if (side === 'left') {
45+
leftSideTreesRefs.current[i] = palmMesh
46+
} else {
47+
rightSideTreesRefs.current[i] = palmMesh
48+
}
49+
}}
50+
/>
51+
)
52+
53+
}, [])
54+
55+
useLayoutEffect(() => {
3256

3357
const treesElements: React.ReactElement[] = []
3458

@@ -40,42 +64,15 @@ const Trees: React.FC = () => {
4064
let positionChange = -1.5
4165

4266
for (let i = 0; i < amountOfTreesPerSide; i++) {
43-
44-
const position = new Vector3(side === 'right' ? -0.21 : 0.21, 0, positionChange)
45-
const scale = new Vector3(0.009, 0.009, 0.009)
46-
const rotation = new Euler(0, randomDegrees(), 0)
47-
48-
treesElements.push(
49-
<PalmModel
50-
position={position}
51-
ref={(treeGroup) => {
52-
if (side === 'right') {
53-
rightSideTreesRefs.current[i] = treeGroup
54-
} else {
55-
leftSideTreesRefs.current[i] = treeGroup
56-
}
57-
}}
58-
scale={scale}
59-
castShadow={true} // default is false
60-
receiveShadow={false}
61-
key={side + '_' + i.toString()}
62-
rotation={rotation}
63-
/>
64-
)
65-
67+
treesElements.push(createPalm(i, side, positionChange))
6668
positionChange += 0.2
67-
6869
}
6970

7071
})
7172

72-
return treesElements
73+
setTreesElementsState(treesElements)
7374

74-
}, [])
75-
76-
useLayoutEffect(() => {
77-
setTreesElementsState(createTrees())
78-
}, [createTrees])
75+
}, [createPalm])
7976

8077
return (<Suspense>{treesElementsState}</Suspense>)
8178

0 commit comments

Comments
 (0)