textures, keys

This commit is contained in:
2026-01-30 17:25:26 +01:00
parent b70bdfb955
commit 94bf853589
8 changed files with 109 additions and 81 deletions

View File

@@ -157,7 +157,15 @@
</div> </div>
<div id="loadingMessage">Construction du labyrinthe : <span id="progress">0</span>%</div> <div id="loadingMessage">Construction du labyrinthe : <span id="progress">0</span>%</div>
<div> <div>
Se déplacer : ↑←↓→, ZQSD ou clic<br/> Se déplacer : <table class="keysTable">
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>, <table class="keysTable">
<tr><td></td><td>Z</td><td></td></tr>
<tr><td>Q</td><td></td><td>D</td></tr>
<tr><td></td><td>S</td><td></td></tr>
</table> ou clic<br/>
Sauter : ESPACE<br/> Sauter : ESPACE<br/>
Regarder : Souris Regarder : Souris
</div> </div>

172
main.js
View File

@@ -5,6 +5,7 @@ import { Water } from 'three/addons/objects/Water.js'
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js' import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'
import { GUI } from 'three/addons/libs/lil-gui.module.min.js' import { GUI } from 'three/addons/libs/lil-gui.module.min.js'
import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js' import { OctreeHelper } from 'three/addons/helpers/OctreeHelper.js'
import { CSM } from 'three/addons/csm/CSM.js';
import Stats from 'three/addons/libs/stats.module.js' import Stats from 'three/addons/libs/stats.module.js'
import MazeMesh from './MazeMesh.js' import MazeMesh from './MazeMesh.js'
@@ -130,8 +131,11 @@ const renderer = new THREE.WebGLRenderer({
renderer.setPixelRatio(window.devicePixelRatio) renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight) renderer.setSize(window.innerWidth, window.innerHeight)
renderer.toneMapping = THREE.ACESFilmicToneMapping renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 1.0
renderer.shadowMap.enabled = true renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.physicallyCorrectLights = true
renderer.outputColorSpace = THREE.SRGBColorSpace
container.appendChild(renderer.domElement) container.appendChild(renderer.domElement)
@@ -164,15 +168,51 @@ const mazeCollisionner = new THREE.Group()
const wallMaterial = new THREE.MeshStandardMaterial({ const wallMaterial = new THREE.MeshStandardMaterial({
map : loader.load('Poly-cobblestone-wall/color_map.webp'), map : loader.load('Poly-cobblestone-wall/color_map.webp'),
normalMap : loader.load('Poly-cobblestone-wall/normal_map_opengl.webp'), normalMap : loader.load('Poly-cobblestone-wall/normal_map_opengl.webp'),
aoMap : loader.load('Poly-cobblestone-wall/ao_map.webp'), aoMapIntensity : 1,
roughnessMap : loader.load('Poly-cobblestone-wall/roughness_map.webp'), roughnessMap : loader.load('Poly-cobblestone-wall/roughness_map.webp'),
roughness : 1 roughness : 1,
metalness : 1
})
const sideGroundMaterial = new THREE.MeshStandardMaterial({
map : wallMaterial.map.clone(),
normalMap : wallMaterial.normalMap.clone(),
normalScale : new THREE.Vector2(0.6, 0.6),
aoMapIntensity : wallMaterial.aoMapIntensity,
roughnessMap : wallMaterial.roughnessMap.clone(),
roughness : wallMaterial.roughness,
metalness : wallMaterial.metalness,
envMap : scene.environment,
})
loader.load('Poly-cobblestone-wall/ao_map.jpg', (texture) => {
wallMaterial.aoMap = texture
wallMaterial.metalnessMap = texture
wallMaterial.needsUpdate = true
const sidegroundTexture = texture.clone()
sidegroundTexture.wrapS = sidegroundTexture.wrapT = THREE.RepeatWrapping
sidegroundTexture.repeat.set(mazeWidth, 20)
sidegroundTexture.rotation = Math.PI
sideGroundMaterial.map.wrapS = sideGroundMaterial.map.wrapT = THREE.RepeatWrapping
sideGroundMaterial.map.repeat.set(mazeWidth, 20)
sideGroundMaterial.map.rotation = Math.PI
sideGroundMaterial.normalMap.wrapS = sideGroundMaterial.normalMap.wrapT = THREE.RepeatWrapping
sideGroundMaterial.normalMap.repeat.set(mazeWidth, 20)
sideGroundMaterial.normalMap.rotation = Math.PI
sideGroundMaterial.aoMap = sidegroundTexture
sideGroundMaterial.roughnessMap.wrapS = sideGroundMaterial.roughnessMap.wrapT = THREE.RepeatWrapping
sideGroundMaterial.roughnessMap.repeat.set(mazeWidth, 20)
sideGroundMaterial.roughnessMap.rotation = Math.PI
sideGroundMaterial.metalnessMap = sidegroundTexture
sideGroundMaterial.needsUpdate = true
}) })
const maze = new MazeMesh(mazeWidth, mazeWidth, 1, wallMaterial) const maze = new MazeMesh(mazeWidth, mazeWidth, 1, wallMaterial)
maze.castShadow = true maze.castShadow = true
maze.receiveShadow = true maze.receiveShadow = true
maze.matrixAutoUpdate = false maze.matrixAutoUpdate = false
scene.add(maze) scene.add(maze)
console.log(String(maze)) console.log(String(maze))
@@ -202,7 +242,7 @@ function repeatGroundMaterial (texture) {
} }
const groundMaterial = new THREE.MeshStandardMaterial({ const groundMaterial = new THREE.MeshStandardMaterial({
map : loader.load('angled-blocks-vegetation/albedo.webp', repeatGroundMaterial), map : loader.load('angled-blocks-vegetation/albedo.webp', repeatGroundMaterial),
aoMap : loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial), aoMap : loader.load('angled-blocks-vegetation/ao.webp', repeatGroundMaterial),
metalnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial), metalnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial),
normalMap : loader.load('angled-blocks-vegetation/normal-dx.webp', repeatGroundMaterial), normalMap : loader.load('angled-blocks-vegetation/normal-dx.webp', repeatGroundMaterial),
roughnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial), roughnessMap: loader.load('angled-blocks-vegetation/ao-roughness-metalness.webp', repeatGroundMaterial),
@@ -214,27 +254,6 @@ const groundMaterial = new THREE.MeshStandardMaterial({
}*/ }*/
}) })
const sideGroundMaterial = new THREE.MeshStandardMaterial({
map : wallMaterial.map.clone(),
normalMap : wallMaterial.normalMap.clone(),
normalScale : new THREE.Vector2(0.6, 0.6),
aoMap : wallMaterial.aoMap.clone(),
roughnessMap : wallMaterial.roughnessMap.clone(),
roughness : 1,
})
sideGroundMaterial.map.wrapS = sideGroundMaterial.map.wrapT = THREE.RepeatWrapping
sideGroundMaterial.map.repeat.set(mazeWidth, 20)
sideGroundMaterial.map.rotation = Math.PI
sideGroundMaterial.normalMap.wrapS = sideGroundMaterial.normalMap.wrapT = THREE.RepeatWrapping
sideGroundMaterial.normalMap.repeat.set(mazeWidth, 20)
sideGroundMaterial.normalMap.rotation = Math.PI
sideGroundMaterial.aoMap.wrapS = sideGroundMaterial.aoMap.wrapT = THREE.RepeatWrapping
sideGroundMaterial.aoMap.repeat.set(mazeWidth, 20)
sideGroundMaterial.aoMap.rotation = Math.PI
sideGroundMaterial.roughnessMap.wrapS = sideGroundMaterial.roughnessMap.wrapT = THREE.RepeatWrapping
sideGroundMaterial.roughnessMap.repeat.set(mazeWidth, 20)
sideGroundMaterial.roughnessMap.rotation = Math.PI
const ground = new THREE.Mesh( const ground = new THREE.Mesh(
groundGeometry, groundGeometry,
[ [
@@ -283,7 +302,6 @@ ocean.position.y = -0.2
ocean.material.transparent = true ocean.material.transparent = true
ocean.material.onBeforeCompile = function (shader) { ocean.material.onBeforeCompile = function (shader) {
shader.uniforms.size = { value: 6 } shader.uniforms.size = { value: 6 }
shader.uniforms.waveA = { shader.uniforms.waveA = {
@@ -312,7 +330,6 @@ ocean.material.onBeforeCompile = function (shader) {
} }
shader.vertexShader = document.getElementById('vertexShader').textContent shader.vertexShader = document.getElementById('vertexShader').textContent
shader.fragmentShader = document.getElementById('fragmentShader').textContent shader.fragmentShader = document.getElementById('fragmentShader').textContent
} }
scene.add(ocean) scene.add(ocean)
@@ -320,12 +337,12 @@ const oceanOctree = new Octree().fromGraphNode(ocean)
// Lights // Lights
const sun = new THREE.Vector3() const sunPosition = new THREE.Vector3()
const ambientLight = new THREE.AmbientLight(0x404040, 5) const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight) scene.add(ambientLight)
const sunLight = new THREE.DirectionalLight(0xffffff, 1) const sunLight = new THREE.DirectionalLight(0xffffff, 3)
sunLight.castShadow = true sunLight.castShadow = true
sunLight.shadow.camera.near = 0.1 sunLight.shadow.camera.near = 0.1
sunLight.shadow.camera.far = 1.4 * mazeWidth sunLight.shadow.camera.far = 1.4 * mazeWidth
@@ -343,17 +360,15 @@ scene.add(sunLight)
updateSun() updateSun()
function updateSun() { function updateSun() {
const phi = THREE.MathUtils.degToRad(90 - parameters.elevation) const phi = THREE.MathUtils.degToRad(90 - parameters.elevation)
const theta = THREE.MathUtils.degToRad(parameters.azimuth) const theta = THREE.MathUtils.degToRad(parameters.azimuth)
sun.setFromSphericalCoords(1.4 * mazeWidth/2, phi, theta) sunPosition.setFromSphericalCoords(1.4 * mazeWidth/2, phi, theta)
ocean.material.uniforms['sunDirection'].value.copy(sun).normalize() ocean.material.uniforms['sunDirection'].value.copy(sunPosition).normalize()
sunLight.position.copy(sun) sunLight.position.copy(sunPosition)
//ambientLight.intensity = 5 + 5 * Math.sin(Math.max(THREE.MathUtils.degToRad(parameters.elevation), 0))
ambientLight.intensity = 0.5 + 0.5 * Math.sin(Math.max(THREE.MathUtils.degToRad(parameters.elevation), 0))
} }
// Raft // Raft
@@ -388,30 +403,28 @@ const raftOctree = new Octree().fromGraphNode(raft)
const stats = new Stats() const stats = new Stats()
if (dev) { if (dev) {
container.appendChild(stats.dom) container.appendChild(stats.dom)
const gui = new GUI() const gui = new GUI()
const lightHelper = new THREE.DirectionalLightHelper(sunLight, .5) /*const lightHelper = new THREE.DirectionalLightHelper(sunLight, .5)
lightHelper.position.copy(maze.start) lightHelper.position.copy(maze.start)
lightHelper.visible = false lightHelper.visible = false*/
const octreeHelper = new OctreeHelper(mazeOctree) const octreeHelper = new OctreeHelper(mazeOctree)
octreeHelper.visible = false octreeHelper.visible = false
scene.add(octreeHelper) scene.add(octreeHelper)
const showHelper = gui.add({ helpers: false }, "helpers") const showHelper = gui.add({ helpers: false }, "helpers")
showHelper.onChange(function (value) { showHelper.onChange(function (value) {
lightHelper.visible = value lightHelper.visible = value
octreeHelper.visible = value octreeHelper.visible = value
}) })
const cameraFolder = gui.addFolder("camera") const cameraFolder = gui.addFolder("camera")
cameraFolder.add(camera, "focus", 0, 200).onChange(() => camera.updateProjectionMatrix()) cameraFolder.add(camera, "focus", 0, 200).onChange(() => camera.updateProjectionMatrix())
cameraFolder.add(camera, "fov", 0, 200).onChange(() => camera.updateProjectionMatrix()) cameraFolder.add(camera, "fov", 0, 200).onChange(() => camera.updateProjectionMatrix())
cameraFolder.add(camera, "filmGauge", 0, 200).onChange(() => camera.updateProjectionMatrix()) cameraFolder.add(camera, "filmGauge", 0, 200).onChange(() => camera.updateProjectionMatrix())
cameraFolder.close()
const raftFolder = gui.addFolder("Raft") const raftFolder = gui.addFolder("Raft")
const raftPositionFolder = raftFolder.addFolder("position") const raftPositionFolder = raftFolder.addFolder("position")
@@ -508,22 +521,31 @@ if (dev) {
}) })
waveCFolder.open() waveCFolder.open()
const hexTilingFolder = gui.addFolder('Hex Tiling') const wallMaterialFolder = gui.addFolder("wallMaterial")
if (wallMaterial?.hexTiling?.patchScale) { wallMaterialFolder.add(wallMaterial, "roughness").min(0).max(1)
const wallMaterialFolder = hexTilingFolder.addFolder("wall") wallMaterialFolder.add(wallMaterial, "metalness").min(0).max(1)
wallMaterialFolder.add(wallMaterial.hexTiling, "patchScale", 0, 10) wallMaterialFolder.add(wallMaterial, "aoMapIntensity").min(-10).max(10)
wallMaterialFolder.add(wallMaterial.hexTiling, "useContrastCorrectedBlending") wallMaterialFolder.add(wallMaterial, "bumpScale").min(-10).max(10).onChange(() => wallMaterial.needsUpdate = true)
wallMaterialFolder.add(wallMaterial.hexTiling, "lookupSkipThreshold", 0, 1) wallMaterialFolder.close()
wallMaterialFolder.add(wallMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
if (wallMaterial?.hexTiling) {
const hexTilingFolder = gui.addFolder('Hex Tiling')
if (wallMaterial?.hexTiling?.patchScale) {
const wallMaterialFolder = hexTilingFolder.addFolder("wall")
wallMaterialFolder.add(wallMaterial.hexTiling, "patchScale", 0, 10)
wallMaterialFolder.add(wallMaterial.hexTiling, "useContrastCorrectedBlending")
wallMaterialFolder.add(wallMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
wallMaterialFolder.add(wallMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
}
if (groundMaterial?.hexTiling?.patchScale) {
const groundMaterialFolder = hexTilingFolder.addFolder("ground")
groundMaterialFolder.add(groundMaterial.hexTiling, "patchScale", 0, 10)
groundMaterialFolder.add(groundMaterial.hexTiling, "useContrastCorrectedBlending")
groundMaterialFolder.add(groundMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
groundMaterialFolder.add(groundMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
}
hexTilingFolder.close()
} }
if (groundMaterial?.hexTiling?.patchScale) {
const groundMaterialFolder = hexTilingFolder.addFolder("ground")
groundMaterialFolder.add(groundMaterial.hexTiling, "patchScale", 0, 10)
groundMaterialFolder.add(groundMaterial.hexTiling, "useContrastCorrectedBlending")
groundMaterialFolder.add(groundMaterial.hexTiling, "lookupSkipThreshold", 0, 1)
groundMaterialFolder.add(groundMaterial.hexTiling, "textureSampleCoefficientExponent", 0, 64).name("SampleCoefExp")
}
hexTilingFolder.close()
} }
// //
@@ -552,15 +574,25 @@ let escaped = false
const pointerLockControls = new PointerLockControls(camera, document.body) const pointerLockControls = new PointerLockControls(camera, document.body)
pointerLockControls.pointerSpeed = 0.7 pointerLockControls.pointerSpeed = 0.7
const keys = [
"ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight",
"KeyW", "KeyS", "KeyA", "KeyD", "Space"
]
const keyStates = {} const keyStates = {}
document.addEventListener('keydown', (event) => { document.addEventListener('keydown', (event) => {
keyStates[event.code] = true if (keys.includes(event.code)) {
event.preventDefault()
keyStates[event.code] = true
}
}) })
document.addEventListener('keyup', (event) => { document.addEventListener('keyup', (event) => {
keyStates[event.code] = false if (keys.includes(event.code)) {
if (event.code == 'Space') jumping = false event.preventDefault()
keyStates[event.code] = false
if (event.code == 'Space') jumping = false
}
}) })
let mouseButtonsStates = [] let mouseButtonsStates = []
@@ -587,10 +619,9 @@ pointerLockControls.addEventListener('unlock', function () {
document.removeEventListener('mouseup', onMouseChange) document.removeEventListener('mouseup', onMouseChange)
}) })
scene.add(pointerLockControls.getObject()) scene.add(pointerLockControls.object)
function playerCollisions() { function playerCollisions() {
const playerOnMaze = mazeOctree.capsuleIntersect(playerCollider) const playerOnMaze = mazeOctree.capsuleIntersect(playerCollider)
const playerOnRaft = raftOctree.capsuleIntersect(playerCollider) const playerOnRaft = raftOctree.capsuleIntersect(playerCollider)
const playerOnWater = oceanOctree.capsuleIntersect(playerCollider) const playerOnWater = oceanOctree.capsuleIntersect(playerCollider)
@@ -618,11 +649,9 @@ function playerCollisions() {
camera.position.y = ocean.position.y + waveInfo.position.y + 0.2 camera.position.y = ocean.position.y + waveInfo.position.y + 0.2
} }
} }
} }
function gameEnd() { function gameEnd() {
escaped = true escaped = true
message.innerHTML = '<h2>Libre !</h2><a href="">Rejouer</a>' message.innerHTML = '<h2>Libre !</h2><a href="">Rejouer</a>'
message.className = "escaped" message.className = "escaped"
@@ -630,11 +659,9 @@ function gameEnd() {
document.exitPointerLock() document.exitPointerLock()
//container.style.cursor = "default" //container.style.cursor = "default"
} }
function updatePlayer(deltaTime) { function updatePlayer(deltaTime) {
let damping = Math.exp(- 4 * deltaTime) - 1 let damping = Math.exp(- 4 * deltaTime) - 1
if (!playerOnFloor) { if (!playerOnFloor) {
@@ -650,32 +677,26 @@ function updatePlayer(deltaTime) {
camera.position.copy(playerCollider.end) camera.position.copy(playerCollider.end)
playerCollisions() playerCollisions()
} }
function getForwardVector() { function getForwardVector() {
camera.getWorldDirection(playerDirection) camera.getWorldDirection(playerDirection)
playerDirection.y = 0 playerDirection.y = 0
playerDirection.normalize() playerDirection.normalize()
return playerDirection return playerDirection
} }
function getSideVector() { function getSideVector() {
camera.getWorldDirection(playerDirection) camera.getWorldDirection(playerDirection)
playerDirection.y = 0 playerDirection.y = 0
playerDirection.normalize() playerDirection.normalize()
playerDirection.cross(camera.up) playerDirection.cross(camera.up)
return playerDirection return playerDirection
} }
function controls(deltaTime) { function controls(deltaTime) {
// gives a bit of air control // gives a bit of air control
const speedDelta = deltaTime * (playerOnFloor ? 100 : 20) / STEPS_PER_FRAME const speedDelta = deltaTime * (playerOnFloor ? 100 : 20) / STEPS_PER_FRAME
@@ -700,7 +721,6 @@ function controls(deltaTime) {
} }
function getWaveInfo(x, z, time) { function getWaveInfo(x, z, time) {
const pos = new THREE.Vector3() const pos = new THREE.Vector3()
const tangent = new THREE.Vector3(1, 0, 0) const tangent = new THREE.Vector3(1, 0, 0)
const binormal = new THREE.Vector3(0, 0, 1) const binormal = new THREE.Vector3(0, 0, 1)
@@ -731,11 +751,9 @@ function getWaveInfo(x, z, time) {
const normal = binormal.cross(tangent).normalize() const normal = binormal.cross(tangent).normalize()
return { position: pos, normal: normal } return { position: pos, normal: normal }
} }
function updateRaft(delta) { function updateRaft(delta) {
const t = ocean.material.uniforms['time'].value const t = ocean.material.uniforms['time'].value
const waveInfo = getWaveInfo(raft.position.x, raft.position.z, t) const waveInfo = getWaveInfo(raft.position.x, raft.position.z, t)
@@ -744,22 +762,18 @@ function updateRaft(delta) {
new THREE.Euler().setFromVector3(waveInfo.normal) new THREE.Euler().setFromVector3(waveInfo.normal)
) )
raft.quaternion.rotateTowards(quat, delta * 0.5) raft.quaternion.rotateTowards(quat, delta * 0.5)
} }
window.addEventListener('resize', onWindowResize) window.addEventListener('resize', onWindowResize)
function onWindowResize() { function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix() camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight) renderer.setSize(window.innerWidth, window.innerHeight)
} }
function animate() { function animate() {
const delta = Math.min(0.05, clock.getDelta()) const delta = Math.min(0.05, clock.getDelta())
const deltaTime = delta / STEPS_PER_FRAME const deltaTime = delta / STEPS_PER_FRAME
@@ -771,7 +785,6 @@ function animate() {
// an object traversing another too quickly for detection. // an object traversing another too quickly for detection.
for (let i = 0; i < STEPS_PER_FRAME; i++) { for (let i = 0; i < STEPS_PER_FRAME; i++) {
controls(deltaTime) controls(deltaTime)
updatePlayer(deltaTime) updatePlayer(deltaTime)
@@ -784,5 +797,4 @@ function animate() {
renderer.render(scene, camera) renderer.render(scene, camera)
if (dev) stats.update() if (dev) stats.update()
}
}

View File

@@ -19,6 +19,12 @@ body {
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
.keysTable {
display: inline-table;
vertical-align: middle;
text-align: center;
}
@keyframes perspective { @keyframes perspective {
from { from {
transform: rotateX(0deg) perspective(0px); transform: rotateX(0deg) perspective(0px);
@@ -38,6 +44,8 @@ body {
margin-top: 20vh; margin-top: 20vh;
margin-bottom: 5vh; margin-bottom: 5vh;
animation: perspective 30s; animation: perspective 30s;
transform: rotateX(40deg) perspective(150px);
filter: drop-shadow(0px 10px 0px #0f2437);
} }
@keyframes rotation { @keyframes rotation {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB