mirror of
https://github.com/Floriansylvain/generic-threejs-game.git
synced 2026-08-19 11:43:18 +02:00
feat: postprocessing + shadows
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-three/drei": "^9.99.7",
|
"@react-three/drei": "^9.99.7",
|
||||||
"@react-three/fiber": "^8.15.19",
|
"@react-three/fiber": "^8.15.19",
|
||||||
|
"@react-three/postprocessing": "^2.16.2",
|
||||||
"@types/three": "^0.162.0",
|
"@types/three": "^0.162.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
Generated
+51
@@ -11,6 +11,9 @@ dependencies:
|
|||||||
'@react-three/fiber':
|
'@react-three/fiber':
|
||||||
specifier: ^8.15.19
|
specifier: ^8.15.19
|
||||||
version: 8.15.19(react-dom@18.2.0)(react@18.2.0)(three@0.162.0)
|
version: 8.15.19(react-dom@18.2.0)(react@18.2.0)(three@0.162.0)
|
||||||
|
'@react-three/postprocessing':
|
||||||
|
specifier: ^2.16.2
|
||||||
|
version: 2.16.2(@react-three/fiber@8.15.19)(@types/three@0.162.0)(react@18.2.0)(three@0.162.0)
|
||||||
'@types/three':
|
'@types/three':
|
||||||
specifier: ^0.162.0
|
specifier: ^0.162.0
|
||||||
version: 0.162.0
|
version: 0.162.0
|
||||||
@@ -752,6 +755,25 @@ packages:
|
|||||||
zustand: 3.7.2(react@18.2.0)
|
zustand: 3.7.2(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@react-three/postprocessing@2.16.2(@react-three/fiber@8.15.19)(@types/three@0.162.0)(react@18.2.0)(three@0.162.0):
|
||||||
|
resolution: {integrity: sha512-2ya1gXLDpzyfbELobi3rPHNNZZCrCfyq20GMYJD1yD7ZyBFSpRG9YSPMBnOal6A89kXanPBw273h6/Dqev0n7g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@react-three/fiber': '>=8.0'
|
||||||
|
react: '>=18.0'
|
||||||
|
three: '>= 0.138.0'
|
||||||
|
dependencies:
|
||||||
|
'@react-three/fiber': 8.15.19(react-dom@18.2.0)(react@18.2.0)(three@0.162.0)
|
||||||
|
buffer: 6.0.3
|
||||||
|
maath: 0.6.0(@types/three@0.162.0)(three@0.162.0)
|
||||||
|
n8ao: 1.8.1(postprocessing@6.35.2)(three@0.162.0)
|
||||||
|
postprocessing: 6.35.2(three@0.162.0)
|
||||||
|
react: 18.2.0
|
||||||
|
three: 0.162.0
|
||||||
|
three-stdlib: 2.29.5(three@0.162.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@types/three'
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@rollup/rollup-android-arm-eabi@4.12.1:
|
/@rollup/rollup-android-arm-eabi@4.12.1:
|
||||||
resolution: {integrity: sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==}
|
resolution: {integrity: sha512-iU2Sya8hNn1LhsYyf0N+L4Gf9Qc+9eBTJJJsaOGUp+7x4n2M9dxTt8UvhJl3oeftSjblSlpCfvjA/IfP3g5VjQ==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
@@ -1820,6 +1842,16 @@ packages:
|
|||||||
three: 0.162.0
|
three: 0.162.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/maath@0.6.0(@types/three@0.162.0)(three@0.162.0):
|
||||||
|
resolution: {integrity: sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/three': '>=0.144.0'
|
||||||
|
three: '>=0.144.0'
|
||||||
|
dependencies:
|
||||||
|
'@types/three': 0.162.0
|
||||||
|
three: 0.162.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/merge2@1.4.1:
|
/merge2@1.4.1:
|
||||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -1862,6 +1894,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/n8ao@1.8.1(postprocessing@6.35.2)(three@0.162.0):
|
||||||
|
resolution: {integrity: sha512-biKUW09KnflZpeWmbCy1gjuiyZsbeG6y+EsqV+1IDqQ1KqEydXc6nUUseZp9ZRbjvEOPnsvsjaTce8Pta0803A==}
|
||||||
|
peerDependencies:
|
||||||
|
postprocessing: '>=6.30.0'
|
||||||
|
three: '>=0.137'
|
||||||
|
dependencies:
|
||||||
|
postprocessing: 6.35.2(three@0.162.0)
|
||||||
|
three: 0.162.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/nanoid@3.3.7:
|
/nanoid@3.3.7:
|
||||||
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
|
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
|
||||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
@@ -1957,6 +1999,15 @@ packages:
|
|||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/postprocessing@6.35.2(three@0.162.0):
|
||||||
|
resolution: {integrity: sha512-yGmidrVzA1dSEmExYGgWOGcRvyOVahvurNo9iuzOonRCY6f1hnJe6/HMVSnKV9ppjLtCTqzZOI9iz8CACkmijw==}
|
||||||
|
engines: {node: '>= 0.13.2'}
|
||||||
|
peerDependencies:
|
||||||
|
three: '>= 0.152.0 < 0.163.0'
|
||||||
|
dependencies:
|
||||||
|
three: 0.162.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/potpack@1.0.2:
|
/potpack@1.0.2:
|
||||||
resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
|
resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|||||||
+35
-32
@@ -1,16 +1,12 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
import { Canvas } from "@react-three/fiber";
|
import { Canvas } from "@react-three/fiber";
|
||||||
import {
|
import { KeyboardControls } from "@react-three/drei";
|
||||||
KeyboardControls,
|
|
||||||
Sparkles,
|
|
||||||
Text,
|
|
||||||
TransformControls,
|
|
||||||
} from "@react-three/drei";
|
|
||||||
import { MutableRefObject, useEffect, useRef, useState } from "react";
|
import { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||||
import { Vector3 } from "three";
|
import { Vector3 } from "three";
|
||||||
import { Cubes } from "./components/Cubes";
|
import { Cubes } from "./components/Cubes";
|
||||||
import { Player } from "./components/Player";
|
import { Player } from "./components/Player";
|
||||||
|
import { Bloom, EffectComposer, Vignette } from "@react-three/postprocessing";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const CUBES_QT = 20;
|
const CUBES_QT = 20;
|
||||||
@@ -35,35 +31,21 @@ function App() {
|
|||||||
className="container"
|
className="container"
|
||||||
onClick={() => container.current?.requestPointerLock()}
|
onClick={() => container.current?.requestPointerLock()}
|
||||||
>
|
>
|
||||||
<Canvas className="canvas" ref={container}>
|
<Canvas className="canvas" ref={container} shadows>
|
||||||
<Cubes cubesPosition={cubes}></Cubes>
|
<Cubes cubesPosition={cubes}></Cubes>
|
||||||
<TransformControls position={[20, 10, 0]}>
|
|
||||||
<Text
|
<mesh
|
||||||
color={"green"}
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
fontSize={8}
|
position={[0, 0, 0]}
|
||||||
anchorX={"center"}
|
receiveShadow
|
||||||
anchorY={"middle"}
|
>
|
||||||
>
|
|
||||||
Bonsoir
|
|
||||||
</Text>
|
|
||||||
</TransformControls>
|
|
||||||
<group>
|
|
||||||
<Sparkles
|
|
||||||
color={"blue"}
|
|
||||||
count={100}
|
|
||||||
size={20}
|
|
||||||
scale={[20, 10, 20]}
|
|
||||||
speed={25}
|
|
||||||
position={[20, 0, 20]}
|
|
||||||
></Sparkles>
|
|
||||||
</group>
|
|
||||||
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, 0, 0]}>
|
|
||||||
<planeGeometry attach={"geometry"} args={[100, 100]}></planeGeometry>
|
<planeGeometry attach={"geometry"} args={[100, 100]}></planeGeometry>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
attach={"material"}
|
attach={"material"}
|
||||||
color={"lightblue"}
|
color={"green"}
|
||||||
></meshStandardMaterial>
|
></meshStandardMaterial>
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
<KeyboardControls
|
<KeyboardControls
|
||||||
map={[
|
map={[
|
||||||
{ keys: ["w", "ArrowUp"], name: "moveForward" },
|
{ keys: ["w", "ArrowUp"], name: "moveForward" },
|
||||||
@@ -80,11 +62,32 @@ function App() {
|
|||||||
}
|
}
|
||||||
></Player>
|
></Player>
|
||||||
</KeyboardControls>
|
</KeyboardControls>
|
||||||
|
|
||||||
<ambientLight intensity={Math.PI / 2} />
|
<ambientLight intensity={Math.PI / 2} />
|
||||||
<directionalLight
|
<directionalLight
|
||||||
intensity={Math.PI / 2}
|
castShadow
|
||||||
position={[2, 2, 2]}
|
position={[100, 100, 100]}
|
||||||
></directionalLight>
|
shadow-mapSize={[4096, 4096]}
|
||||||
|
intensity={5}
|
||||||
|
>
|
||||||
|
<orthographicCamera
|
||||||
|
attach="shadow-camera"
|
||||||
|
args={[-50, 50, 50, -50]}
|
||||||
|
/>
|
||||||
|
</directionalLight>
|
||||||
|
|
||||||
|
<color args={["lightblue"]} attach={"background"}></color>
|
||||||
|
<fog attach={"fog"} args={["lightblue", 0, 100]}></fog>
|
||||||
|
<gridHelper args={[100, 100]}></gridHelper>
|
||||||
|
<axesHelper args={[100]}></axesHelper>
|
||||||
|
<EffectComposer>
|
||||||
|
<Bloom
|
||||||
|
luminanceThreshold={0.2}
|
||||||
|
luminanceSmoothing={0.8}
|
||||||
|
height={300}
|
||||||
|
/>
|
||||||
|
<Vignette eskil={false} offset={0.2} darkness={0.8} />
|
||||||
|
</EffectComposer>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useFrame } from "@react-three/fiber";
|
|||||||
export function Cubes(props: { cubesPosition: Vector3[] }) {
|
export function Cubes(props: { cubesPosition: Vector3[] }) {
|
||||||
const CUBE_SPEED = 10;
|
const CUBE_SPEED = 10;
|
||||||
const CUBE_AMPLITUDE = 2;
|
const CUBE_AMPLITUDE = 2;
|
||||||
const CUBE_HEIGHT = 2;
|
const CUBE_HEIGHT = 4;
|
||||||
|
|
||||||
const [cubes, setCubes] = useState<Vector3[]>(
|
const [cubes, setCubes] = useState<Vector3[]>(
|
||||||
Array.from(props.cubesPosition)
|
Array.from(props.cubesPosition)
|
||||||
@@ -30,7 +30,12 @@ export function Cubes(props: { cubesPosition: Vector3[] }) {
|
|||||||
return cubes.map((cube) => {
|
return cubes.map((cube) => {
|
||||||
if (!cube) return;
|
if (!cube) return;
|
||||||
return (
|
return (
|
||||||
<mesh position={cube} key={`${cube.x}-${cube.z}`}>
|
<mesh
|
||||||
|
position={cube}
|
||||||
|
key={`${cube.x}-${cube.z}`}
|
||||||
|
castShadow
|
||||||
|
receiveShadow
|
||||||
|
>
|
||||||
<boxGeometry attach={"geometry"}></boxGeometry>
|
<boxGeometry attach={"geometry"}></boxGeometry>
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
attach={"material"}
|
attach={"material"}
|
||||||
|
|||||||
+12
-10
@@ -1,7 +1,7 @@
|
|||||||
import { useAnimations, useGLTF, useKeyboardControls } from "@react-three/drei";
|
import { useAnimations, useGLTF, useKeyboardControls } from "@react-three/drei";
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { MutableRefObject, useCallback, useEffect, useState } from "react";
|
import { MutableRefObject, useCallback, useEffect, useState } from "react";
|
||||||
import { Euler, Quaternion, Vector2, Vector3 } from "three";
|
import { Euler, Mesh, Quaternion, Vector2, Vector3 } from "three";
|
||||||
import { degToRad } from "three/src/math/MathUtils.js";
|
import { degToRad } from "three/src/math/MathUtils.js";
|
||||||
|
|
||||||
export interface KeyPressed {
|
export interface KeyPressed {
|
||||||
@@ -13,13 +13,15 @@ export interface KeyPressed {
|
|||||||
sprint: boolean;
|
sprint: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PLAYER_SPEED = 4.75; // TODO NERF
|
||||||
|
|
||||||
export function Player(props: {
|
export function Player(props: {
|
||||||
container: MutableRefObject<HTMLCanvasElement>;
|
container: MutableRefObject<HTMLCanvasElement>;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const model = useGLTF("/Adventurer.glb");
|
const model = useGLTF("/Adventurer.glb");
|
||||||
const animations = useAnimations(model.animations, model.scene);
|
const animations = useAnimations(model.animations, model.scene);
|
||||||
|
|
||||||
// const walk = animations.actions["CharacterArmature|Walk"];
|
// const walk = animations.actions["CharacterArmature|Walk"];
|
||||||
const run = animations.actions["CharacterArmature|Run"];
|
const run = animations.actions["CharacterArmature|Run"];
|
||||||
const idle = animations.actions["CharacterArmature|Idle"];
|
const idle = animations.actions["CharacterArmature|Idle"];
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ export function Player(props: {
|
|||||||
const [pivotY, setPivotY] = useState(0);
|
const [pivotY, setPivotY] = useState(0);
|
||||||
const [player, setPlayer] = useState<Vector3>(new Vector3(0, 0, 0));
|
const [player, setPlayer] = useState<Vector3>(new Vector3(0, 0, 0));
|
||||||
const [mouseRef, setMouseRef] = useState(new Vector2());
|
const [mouseRef, setMouseRef] = useState(new Vector2());
|
||||||
|
|
||||||
const camera = useThree((state) => state.camera);
|
const camera = useThree((state) => state.camera);
|
||||||
|
|
||||||
const radius = 2;
|
const radius = 2;
|
||||||
@@ -37,20 +40,21 @@ export function Player(props: {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
idle?.play();
|
idle?.play();
|
||||||
|
model.scene.traverse((child) => {
|
||||||
|
if (child instanceof Mesh) child.castShadow = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
const speed = 8;
|
|
||||||
const move = new Vector3();
|
const move = new Vector3();
|
||||||
// TODO Replace getKeys with the subscription system
|
// TODO Replace getKeys with the subscription system
|
||||||
// const keyPressed = getKeys() as unknown as KeyPressed;
|
|
||||||
if (getKeys().moveForward) move.z += 1;
|
if (getKeys().moveForward) move.z += 1;
|
||||||
if (getKeys().moveBackward) move.z -= 1;
|
if (getKeys().moveBackward) move.z -= 1;
|
||||||
if (getKeys().moveLeft) move.x += 1;
|
if (getKeys().moveLeft) move.x += 1;
|
||||||
if (getKeys().moveRight) move.x -= 1;
|
if (getKeys().moveRight) move.x -= 1;
|
||||||
|
|
||||||
move.applyEuler(new Euler(0, pivotX - degToRad(180), 0));
|
move.applyEuler(new Euler(0, pivotX - degToRad(180), 0));
|
||||||
move.multiplyScalar(speed * delta);
|
move.multiplyScalar(PLAYER_SPEED * delta);
|
||||||
|
|
||||||
camera.position.x = radius * Math.sin(pivotX) * Math.cos(pivotY) + player.x;
|
camera.position.x = radius * Math.sin(pivotX) * Math.cos(pivotY) + player.x;
|
||||||
camera.position.y = radius * Math.sin(pivotY) + player.y + yOffset;
|
camera.position.y = radius * Math.sin(pivotY) + player.y + yOffset;
|
||||||
@@ -66,11 +70,7 @@ export function Player(props: {
|
|||||||
if (Object.values(getKeys()).some((key) => key)) {
|
if (Object.values(getKeys()).some((key) => key)) {
|
||||||
setPlayer(player.clone().add(move));
|
setPlayer(player.clone().add(move));
|
||||||
setIsWalking(true);
|
setIsWalking(true);
|
||||||
} else {
|
|
||||||
setIsWalking(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isWalking) {
|
|
||||||
const targetRotation = new Quaternion();
|
const targetRotation = new Quaternion();
|
||||||
targetRotation.setFromEuler(
|
targetRotation.setFromEuler(
|
||||||
new Euler(
|
new Euler(
|
||||||
@@ -89,7 +89,9 @@ export function Player(props: {
|
|||||||
new Quaternion().setFromEuler(new Euler(0, -cameraRotation.y, 0))
|
new Quaternion().setFromEuler(new Euler(0, -cameraRotation.y, 0))
|
||||||
);
|
);
|
||||||
|
|
||||||
model.scene.quaternion.slerp(targetRotation, 0.05);
|
model.scene.quaternion.slerp(targetRotation, 0.2);
|
||||||
|
} else {
|
||||||
|
setIsWalking(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user