diff --git a/ROBAIL/index.css b/ROBAIL/index.css index 973cf573fa8998c52adb548ad6f56df438994abb..052d9f70df68b1dda149f6b3aaa3cf431d8c3748 100644 --- a/ROBAIL/index.css +++ b/ROBAIL/index.css @@ -38,12 +38,17 @@ h3 { /* WebGL Container */ #webGL { - width: 400px; - height: 400px; - background-color: #ddd; - border: 2px solid #999; - margin: 0 auto; - position: relative; + width: 50%; /* Utiliser toute la largeur de la div */ + height: 500px; /* Ajuster la hauteur comme souhaité */ + display: flex; + justify-content: center; + align-items: center; + background-color: #ddd; /* Pour voir où est la div */ + margin:auto; + +} +canvas { + display: block; } /* Légende des axes */ diff --git a/ROBAIL/index.html b/ROBAIL/index.html index 7407e374d88c6d8e5392bd953ec039c27ee7c5f3..5a1e609a545baa44bc84dd90bb20ae028411fde5 100644 --- a/ROBAIL/index.html +++ b/ROBAIL/index.html @@ -23,7 +23,8 @@ <div> <h3>Modèle</h3> <div id="webGL"> - + <script class="center" type="module" src="script.js"></script> + <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> </div> </div> @@ -42,7 +43,7 @@ </p> - <script class="center" type="module" src="main.js"></script> - <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script> + + </body> </html> diff --git a/ROBAIL/models/backwall_texture.jpg b/ROBAIL/models/backwall_texture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..23b182d498dd3a0239a39bdcc5102721f2776c12 Binary files /dev/null and b/ROBAIL/models/backwall_texture.jpg differ diff --git a/ROBAIL/models/ceiling_texture.jpeg b/ROBAIL/models/ceiling_texture.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..685842738199c805c2fd7e6513d025a7815fce52 Binary files /dev/null and b/ROBAIL/models/ceiling_texture.jpeg differ diff --git a/ROBAIL/models/floor_texture.jpg b/ROBAIL/models/floor_texture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f3186ad196ef1765d44969a6b34005ada81d452 Binary files /dev/null and b/ROBAIL/models/floor_texture.jpg differ diff --git a/ROBAIL/models/glass_texture.png b/ROBAIL/models/glass_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..9f353bf15abccf3c5015d18be21fbc76c9404424 Binary files /dev/null and b/ROBAIL/models/glass_texture.png differ diff --git a/ROBAIL/models/grass_texture.jpg b/ROBAIL/models/grass_texture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..caa949ccc108aeafc2f63c956dd6516eb9c4be55 Binary files /dev/null and b/ROBAIL/models/grass_texture.jpg differ diff --git a/ROBAIL/models/long_table.glb b/ROBAIL/models/long_table.glb new file mode 100644 index 0000000000000000000000000000000000000000..41edf5d4f43e19f3d02a19c07f5e989c81f1622c Binary files /dev/null and b/ROBAIL/models/long_table.glb differ diff --git a/ROBAIL/models/skybox_day.jpg b/ROBAIL/models/skybox_day.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ee65bc019b097a785bdb59ab9e01ab5638d27cae Binary files /dev/null and b/ROBAIL/models/skybox_day.jpg differ diff --git a/ROBAIL/models/skybox_night.jpg b/ROBAIL/models/skybox_night.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74d3e44ea3aa5dfd0f1d88d5844c317847bd8bdc Binary files /dev/null and b/ROBAIL/models/skybox_night.jpg differ diff --git a/ROBAIL/models/threejs_tutorial.pdf b/ROBAIL/models/threejs_tutorial.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7cbc3d9fe98eb777f634388c53854513ae1d6045 Binary files /dev/null and b/ROBAIL/models/threejs_tutorial.pdf differ diff --git a/ROBAIL/models/wall_texture.jpeg b/ROBAIL/models/wall_texture.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..611a4d38b19f7274af928e92a52d4004b5f55ca1 Binary files /dev/null and b/ROBAIL/models/wall_texture.jpeg differ diff --git a/ROBAIL/script.js b/ROBAIL/script.js new file mode 100644 index 0000000000000000000000000000000000000000..021f37a122882e136090fc6b3e23499729021868 --- /dev/null +++ b/ROBAIL/script.js @@ -0,0 +1,370 @@ +import * as THREE from 'three'; +import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; + +// 1) SCENE, CAMERA, RENDERER +const scene = new THREE.Scene(); +const camera = new THREE.PerspectiveCamera( + 75, + window.innerWidth / window.innerHeight, + 0.1, + 1000 +); +const renderer = new THREE.WebGLRenderer({ antialias: true }); +renderer.setSize(window.innerWidth, window.innerHeight); + +// Sélection de la div +const container = document.getElementById('webGL'); +if (container) { + container.appendChild(renderer.domElement); + const cw = container.clientWidth; + const ch = container.clientHeight; + renderer.setSize(cw, ch); + camera.aspect = cw / ch; + camera.updateProjectionMatrix(); +} + +// 2) CONTROLS +const controls = new OrbitControls(camera, renderer.domElement); +controls.enableDamping = true; +controls.dampingFactor = 0.05; +controls.screenSpacePanning = false; +controls.minDistance = 3; +controls.maxDistance = 20; +controls.maxPolarAngle = Math.PI; // autorise la caméra à pivoter complètement vers le bas + + +// 3️⃣ LUMIÈRES (Jour par défaut) +const ambientLight = new THREE.AmbientLight(0xffffff, 1.2); +scene.add(ambientLight); + +const directionalLight = new THREE.DirectionalLight(0xffffff, 2); +directionalLight.position.set(0, 5, -5); +scene.add(directionalLight); + +const nightLight = new THREE.PointLight(0x111144, 2, 50); +nightLight.position.set(0, 10, 0); +nightLight.visible = false; // Lumière nuit désactivée au départ +scene.add(nightLight); + +// 4) TEXTURES +const textureLoader = new THREE.TextureLoader(); +const wallTexture = textureLoader.load('models/wall_texture.jpeg'); +const floorTexture = textureLoader.load('models/floor_texture.jpg'); +const ceilingTexture = textureLoader.load('models/ceiling_texture.jpeg'); +const skyboxDayTexture = textureLoader.load('models/skybox_day.jpg'); +const skyboxNightTexture = textureLoader.load('models/skybox_night.jpg'); +// ➡ Texture pour le mur du fond +const backWallTexture = textureLoader.load('models/backwall_texture.jpg'); +const glassTexture = textureLoader.load('models/glass_texture.png') +const grassTexture = textureLoader.load('models/grass_texture.jpg'); +// Murs normaux : RepeatWrapping +wallTexture.wrapS = THREE.RepeatWrapping; +wallTexture.wrapT = THREE.RepeatWrapping; +wallTexture.repeat.set(2, 1); + +// Mur du fond : clamp +backWallTexture.wrapS = THREE.ClampToEdgeWrapping; +backWallTexture.wrapT = THREE.ClampToEdgeWrapping; +backWallTexture.repeat.set(1,1); + +// 5) MATÉRIAUX +const wallMaterial = new THREE.MeshStandardMaterial({ + map: wallTexture, + side: THREE.DoubleSide +}); +const floorMaterial = new THREE.MeshStandardMaterial({ + map: floorTexture, + side: THREE.DoubleSide +}); +const ceilingMaterial = new THREE.MeshStandardMaterial({ + map: ceilingTexture, + side: THREE.DoubleSide +}); +const backWallMaterial = new THREE.MeshStandardMaterial({ + map: backWallTexture, + side: THREE.DoubleSide +}); +const glassMaterial = new THREE.MeshPhysicalMaterial({ + map: glassTexture, + transparent: true, + opacity: 0.5, + roughness: 0.1, + metalness: 0.5, + reflectivity: 0.8, + side: THREE.DoubleSide +}); +// 6) SKY SPHERE +const skyboxGeometry = new THREE.SphereGeometry(100, 32, 32); +skyboxGeometry.scale(-1, 1, 1); +const skyboxMaterial = new THREE.MeshBasicMaterial({ map: skyboxDayTexture }); +const skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial); + +scene.add(skybox); + +// ───────────────────────────────────────────────────────────── +// B R O U I L L A R D +// On ajoute un brouillard exponentiel pour l'ambiance +scene.fog = new THREE.FogExp2(0xcce0ff, 0.01); + +// ───────────────────────────────────────────────────────────── +// DIMENSIONS DE LA SALLE +const roomWidth = 12; +const roomLength = 16; +const roomHeight = 9; // Hauteur sous plafond augmentée + +// 7) MURS LATÉRAUX +const sideWallGeo = new THREE.BoxGeometry(0.2, roomHeight, roomLength); +const leftWall = new THREE.Mesh(sideWallGeo, wallMaterial); +leftWall.position.set(-roomWidth / 2, roomHeight / 2, 0); +scene.add(leftWall); + +const rightWall = new THREE.Mesh(sideWallGeo, wallMaterial); +rightWall.position.set(roomWidth / 2, roomHeight / 2, 0); +scene.add(rightWall); + +// 8) MUR AVANT +const frontWallGeo = new THREE.BoxGeometry(roomWidth, roomHeight, 0.2); +const frontWall = new THREE.Mesh(frontWallGeo, wallMaterial); +frontWall.position.set(0, roomHeight / 2, roomLength / 2); +scene.add(frontWall); + +// 9) SOL +const floorGeo = new THREE.PlaneGeometry(roomWidth, roomLength); +const floor = new THREE.Mesh(floorGeo, floorMaterial); +floor.rotation.x = -Math.PI / 2; +floor.position.y = 0; +scene.add(floor); + + +grassTexture.wrapS = THREE.RepeatWrapping; +grassTexture.wrapT = THREE.RepeatWrapping; +grassTexture.repeat.set(50, 50); // Nombre de répétitions + +const grassMaterial = new THREE.MeshStandardMaterial({ + map: grassTexture, + side: THREE.DoubleSide +}); + +// Création d'un plan très grand pour l’herbe +const grassGeometry = new THREE.PlaneGeometry(500, 500); // Un terrain immense +const grass = new THREE.Mesh(grassGeometry, grassMaterial); +grass.rotation.x = -Math.PI / 2; // Rotation pour être à plat +grass.position.y = -0.1; // Légèrement sous le sol de la salle +scene.add(grass); + + +// 🔟 PLAFOND +const ceiling = new THREE.Mesh(floorGeo, ceilingMaterial); +ceiling.rotation.x = Math.PI / 2; +ceiling.position.y = roomHeight; +scene.add(ceiling); + +// 1️⃣1️⃣ MUR DU FOND (EXTRUDÉ) AVEC BEVEL => relief autour des fenêtres +const shape = new THREE.Shape(); +shape.moveTo(-roomWidth / 2, 0); +shape.lineTo(-roomWidth / 2, roomHeight); +shape.lineTo(roomWidth / 2, roomHeight); +shape.lineTo(roomWidth / 2, 0); +shape.lineTo(-roomWidth / 2, 0); + +// Fenêtres / Porte +const window1 = new THREE.Path(); +window1.moveTo(-4.3, 1); +window1.lineTo(-2.3, 1); +window1.lineTo(-2.3, 5); +window1.lineTo(-4.3, 5); +window1.lineTo(-4.3, 1); + +const window2 = new THREE.Path(); +window2.moveTo(-1.5, 0); +window2.lineTo(-1.5, 5); +window2.lineTo(1.5, 5); +window2.lineTo(1.5, 0); +window2.lineTo(-1.5, 0); + +const window3 = new THREE.Path(); +window3.moveTo(2.3, 1); +window3.lineTo(4.3, 1); +window3.lineTo(4.3, 5); +window3.lineTo(2.3, 5); +window3.lineTo(2.3, 1); + +shape.holes.push(window1, window2, window3); + +// Relief (bevel) autour des fenêtres +const extrudeSettings = { + depth: 0.2, + bevelEnabled: true, + bevelSegments: 1, + steps: 1, + bevelSize: 0.05, + bevelThickness: 0.05 +}; + +const backWallGeo = new THREE.ExtrudeGeometry(shape, extrudeSettings); +backWallGeo.computeVertexNormals(true); + +const backWall = new THREE.Mesh(backWallGeo, backWallMaterial); +backWall.position.set(0, 0, -roomLength / 2); +scene.add(backWall); + +// CORNICHE (inchangé) +const shapeCornice = new THREE.Shape(); +shapeCornice.moveTo(-1.8, roomHeight); +shapeCornice.lineTo(1.8, roomHeight); +shapeCornice.lineTo(1.5, roomHeight + 0.3); +shapeCornice.lineTo(-1.5, roomHeight + 0.3); +shapeCornice.lineTo(-1.8, roomHeight); + +const extrudeCorniceSettings = { + depth: 0.2, + bevelEnabled: true, + bevelSegments: 1, + steps: 1, + bevelSize: 0.05, + bevelThickness: 0.05 +}; +const corniceGeo = new THREE.ExtrudeGeometry(shapeCornice, extrudeCorniceSettings); +corniceGeo.computeVertexNormals(true); +const cornice = new THREE.Mesh(corniceGeo, wallMaterial); +cornice.position.set(0, 0, -roomLength / 2 - 0.1); +scene.add(cornice); + +// 1️⃣1️⃣ TER : POUTRES +function createCeilingBeamsNoEdges( + scene, + beamCountX, beamCountZ, + width, length, + yCeiling, + beamThickness, beamHeight, + material +) { + const stepX = width / (beamCountX + 1); + const stepZ = length / (beamCountZ + 1); + + // POUTRES VERTICALES + for (let i = 1; i <= beamCountX; i++) { + const xPos = -width/2 + i * stepX; + const geo = new THREE.BoxGeometry(beamThickness, beamHeight, length); + const beam = new THREE.Mesh(geo, material); + beam.position.set(xPos, yCeiling - beamHeight / 2 - 0.01, 0); + scene.add(beam); + } + // POUTRES HORIZONTALES + for (let j = 1; j <= beamCountZ; j++) { + const zPos = -length/2 + j * (length / beamCountZ); + const geo = new THREE.BoxGeometry(width, beamHeight, beamThickness); + const beam = new THREE.Mesh(geo, material); + beam.position.set(0, yCeiling - beamHeight / 2 - 0.01, zPos); + scene.add(beam); + } +} +createCeilingBeamsNoEdges( + scene, + 5, 10, + roomWidth, roomLength, + roomHeight, + 0.2, // beamThickness + 0.4, // beamHeight + wallMaterial +); + +// PLINTHES => 0.4 x 0.2 +function createCeilingMolding(scene, width, length, yCeiling, thick, depth, mat) { + // FRONT + { + const frontGeo = new THREE.BoxGeometry(width - 0.2, thick, depth); + const front = new THREE.Mesh(frontGeo, mat); + front.position.set(0, yCeiling - thick / 2 - 0.02, length / 2 - depth / 2 - 0.1); + scene.add(front); + } + // BACK + { + const backGeo = new THREE.BoxGeometry(width - 0.2, thick, depth); + const back = new THREE.Mesh(backGeo, mat); + back.position.set(0, yCeiling - thick / 2 - 0.02, -length / 2 + depth / 2 + 0.1); + scene.add(back); + } + // LEFT + { + const leftGeo = new THREE.BoxGeometry(depth, thick, length - 0.2); + const left = new THREE.Mesh(leftGeo, mat); + left.position.set(-width / 2 + depth / 2 + 0.1, yCeiling - thick / 2 - 0.02, 0); + scene.add(left); + } + // RIGHT + { + const rightGeo = new THREE.BoxGeometry(depth, thick, length - 0.2); + const right = new THREE.Mesh(rightGeo, mat); + right.position.set(width / 2 - depth / 2 - 0.1, yCeiling - thick / 2 - 0.02, 0); + scene.add(right); + } +} +createCeilingMolding( + scene, + roomWidth, roomLength, roomHeight, + 0.4, 0.2, + wallMaterial +); + +function createGlassPane(x, y, z, width, height) { + const glassGeo = new THREE.PlaneGeometry(width, height); + const glassPane = new THREE.Mesh(glassGeo, glassMaterial); + glassPane.position.set(x, y, z); + scene.add(glassPane); +} + +createGlassPane(-3.3, 3, -roomLength / 2 + 0.1, 2, 4); + +createGlassPane(3.3, 3, -roomLength / 2 + 0.1, 2, 4); + +// ----- CAMERA +camera.position.set(0, 2, 6); +controls.target.set(0, 2, -8); + +// ----- RESIZE +window.addEventListener('resize', () => { + const cw = container.clientWidth; + const ch = container.clientHeight; + renderer.setSize(cw, ch); + camera.aspect = cw / ch; + camera.updateProjectionMatrix(); +}); + +const button = document.createElement('button'); +button.innerText = 'Mode Nuit'; +button.style.position = 'absolute'; +button.style.top = '10px'; +button.style.left = '10px'; +button.style.padding = '10px 20px'; +button.style.fontSize = '16px'; +button.style.cursor = 'pointer'; +document.body.appendChild(button); + +let isNight = false; +button.addEventListener('click', () => { + isNight = !isNight; + + if (isNight) { + button.innerText = 'Mode Jour'; + skyboxMaterial.map = skyboxNightTexture; + ambientLight.intensity = 0.05; + directionalLight.visible = false; + nightLight.visible = true; + } else { + button.innerText = 'Mode Nuit'; + skyboxMaterial.map = skyboxDayTexture; + ambientLight.intensity = 1; + directionalLight.visible = true; + nightLight.visible = false; + } + skyboxMaterial.needsUpdate = true; +}); + +// ----- ANIMATION +function animate() { + requestAnimationFrame(animate); + controls.update(); + renderer.render(scene, camera); +} +animate();