diff --git a/RIFI/script.js b/RIFI/script.js index 4e523e6f6aca18af910d0ba333d1d80eb072f41e..cce81093a6abd2e3112fbbcae6c56f10b2fe0a9e 100644 --- a/RIFI/script.js +++ b/RIFI/script.js @@ -8,8 +8,8 @@ var camera, scene, renderer; var cameraControls; var clock = new THREE.Clock(); var skull; -var candle, candleHolder, flame; // Variables pour la bougie, son support et la flamme -var backgroundMesh; // Pour accéder au fond et le modifier avec la lumière +var candle, candleHolder, flame; +var backgroundMesh; function fillScene() { scene = new THREE.Scene(); @@ -44,7 +44,7 @@ function fillScene() { createTable(); loadSkull(); createEnhancedCandle(); - createRealisticRose(); // Ajout de la rose + createRealisticRose(); } function createGradientBackground() { @@ -54,8 +54,7 @@ function createGradientBackground() { canvas.width = 512; canvas.height = 512; const context = canvas.getContext('2d'); - - // Création d'un fond très sombre, presque noir + context.fillStyle = '#000000'; context.fillRect(0, 0, 512, 512); @@ -74,17 +73,17 @@ function createGradientBackground() { } function createTable() { - // Groupe pour contenir toutes les parties de la table + const tableGroup = new THREE.Group(); - // Dimensions de la table (comme dans l'original) + const tableWidth = 600; const tableDepth = 300; const tableThickness = 20; - const sideHeight = 100; // Hauteur des panneaux latéraux - const panelThickness = 10; // Épaisseur des panneaux + const sideHeight = 100; + const panelThickness = 10; - // Chargeur de texture + const textureLoader = new THREE.TextureLoader(); const woodTexture = textureLoader.load( 'textures/dark_wood.jpg', @@ -105,8 +104,8 @@ function createTable() { // Plateau de la table (position inchangée) const tableTopGeometry = new THREE.BoxGeometry(tableWidth, tableThickness, tableDepth); const tableTop = new THREE.Mesh(tableTopGeometry, tableMaterial); - tableTop.position.y = 0; // Garder la même position y=0 - tableTop.receiveShadow = true; // Le plateau reçoit des ombres + tableTop.position.y = 0; + tableTop.receiveShadow = true; tableGroup.add(tableTop); // Panneau latéral gauche (placé sous le plateau) @@ -133,7 +132,7 @@ function createTable() { frontPanel.castShadow = true; tableGroup.add(frontPanel); - // Panneau arrière + const backPanelGeometry = new THREE.BoxGeometry(tableWidth - panelThickness*2, sideHeight, panelThickness); const backPanel = new THREE.Mesh(backPanelGeometry, tableMaterial); backPanel.position.set(0, -(sideHeight/2 + tableThickness/2), -(tableDepth/2 - panelThickness/2)); @@ -141,7 +140,7 @@ function createTable() { backPanel.castShadow = true; tableGroup.add(backPanel); - // Panneau inférieur (base/fond du bureau) + const bottomPanelGeometry = new THREE.BoxGeometry(tableWidth - panelThickness*2, panelThickness, tableDepth - panelThickness*2); const bottomPanel = new THREE.Mesh(bottomPanelGeometry, tableMaterial); bottomPanel.position.set(0, -(sideHeight + tableThickness/2), 0); @@ -173,8 +172,8 @@ function loadSkull() { skull.traverse(function(child) { if (child.isMesh) { child.material = skullMaterial; - child.castShadow = true; // Le crâne projette des ombres - child.receiveShadow = true; // Le crâne peut aussi recevoir des ombres + child.castShadow = true; + child.receiveShadow = true; } }); scene.add(skull); @@ -186,10 +185,10 @@ function createRealisticRose() { // Groupe principal pour la fleur const roseGroup = new THREE.Group(); - // Chargeur de textures + const textureLoader = new THREE.TextureLoader(); - // Texture pour les pétales (simulation de texture rose) + const petalTexture = textureLoader.load( 'textures/rose_petal.jpg', undefined, @@ -199,24 +198,24 @@ function createRealisticRose() { } ); - // Définir les matériaux avec une couleur rose réaliste pour les pétales + const petalMaterial = new THREE.MeshPhysicalMaterial({ - color: 0xde5d83, // Rose moyen - roughness: 0.3, // Légèrement lisse - metalness: 0.0, // Pas métallique - map: petalTexture, // Texture de base (si disponible) - clearcoat: 0.3, // Léger revêtement pour imiter l'aspect lustré + color: 0xde5d83, + roughness: 0.3, + metalness: 0.0, + map: petalTexture, + clearcoat: 0.3, clearcoatRoughness: 0.4, - transmission: 0.2, // Légère translucidité pour un effet réaliste + transmission: 0.2, side: THREE.DoubleSide }); - // Matériau plus foncé pour les pétales intérieurs + const innerPetalMaterial = new THREE.MeshPhysicalMaterial({ - color: 0xc94c7c, // Rose plus foncé pour l'intérieur + color: 0xc94c7c, roughness: 0.4, metalness: 0.0, - map: petalTexture, // Même texture de base + map: petalTexture, clearcoat: 0.3, clearcoatRoughness: 0.5, transmission: 0.15, @@ -225,13 +224,13 @@ function createRealisticRose() { // Matériau pour la tige et les feuilles const stemMaterial = new THREE.MeshPhysicalMaterial({ - color: 0x2d5d3a, // Vert foncé pour la tige + color: 0x2d5d3a, roughness: 0.6, metalness: 0.0 }); const leafMaterial = new THREE.MeshPhysicalMaterial({ - color: 0x3a8c54, // Vert pour les feuilles + color: 0x3a8c54, roughness: 0.5, metalness: 0.0, side: THREE.DoubleSide @@ -246,11 +245,11 @@ function createRealisticRose() { stem.castShadow = true; stem.receiveShadow = true; - // Légère courbure de la tige + stem.rotation.x = Math.PI * 0.05; roseGroup.add(stem); - // FEUILLES (3 feuilles) + const createLeaf = (posY, rotY, scale) => { // Forme de goutte pour la feuille const leafShape = new THREE.Shape(); @@ -281,7 +280,7 @@ function createRealisticRose() { return leaf; }; - // Ajouter trois feuilles à différentes hauteurs et orientations + roseGroup.add(createLeaf(stemHeight * 0.2, Math.PI / 4, 0.35)); roseGroup.add(createLeaf(stemHeight * 0.4, -Math.PI / 3, 0.4)); roseGroup.add(createLeaf(stemHeight * 0.6, Math.PI / 6, 0.3)); @@ -291,7 +290,7 @@ function createRealisticRose() { const centerHeight = 4; const centerGeometry = new THREE.SphereGeometry(centerRadius, 16, 16); const centerMaterial = new THREE.MeshPhysicalMaterial({ - color: 0xb3405c, // Rose foncé pour le centre + color: 0xb3405c, roughness: 0.7, metalness: 0.0 }); @@ -303,19 +302,19 @@ function createRealisticRose() { roseGroup.add(flowerCenter); // CRÉATION DES PÉTALES - const petalCount = 25; // Nombre total de pétales - const layerCount = 5; // Nombre de couches concentriques + const petalCount = 25; + const layerCount = 5; for (let layer = 0; layer < layerCount; layer++) { - const layerPetals = Math.floor(5 + layer * 2); // Plus de pétales dans les couches extérieures - const radiusOffset = 3 + layer * 2.5; // Plus grand rayon pour les couches extérieures - const heightOffset = 1 + layer * 1.2; // Position en hauteur + const layerPetals = Math.floor(5 + layer * 2); + const radiusOffset = 3 + layer * 2.5; + const heightOffset = 1 + layer * 1.2; for (let i = 0; i < layerPetals; i++) { // Créer une forme arrondie pour le pétale const petalShape = new THREE.Shape(); - // Dessiner une forme de pétale avec des courbes de Bézier + petalShape.moveTo(0, 0); petalShape.bezierCurveTo(2, 2, 3, 5, 2, 8); petalShape.bezierCurveTo(0, 10, -2, 8, -2, 8); @@ -350,9 +349,9 @@ function createRealisticRose() { // Positionner et orienter chaque pétale petal.scale.set(scaleFactor, scaleFactor, scaleFactor * 0.5); - // Faire pivoter le pétale pour l'orienter correctement + petal.rotation.set( - -Math.PI / 2 + Math.PI * tiltFactor, // Inclinaison par rapport au centre + -Math.PI / 2 + Math.PI * tiltFactor, 0, angle ); @@ -364,7 +363,6 @@ function createRealisticRose() { Math.sin(angle) * radiusOffset ); - // Ajouter de légères variations aléatoires pour un aspect plus naturel petal.rotation.x += (Math.random() - 0.5) * 0.2; petal.rotation.y += (Math.random() - 0.5) * 0.1; petal.rotation.z += (Math.random() - 0.5) * 0.1; @@ -391,81 +389,79 @@ function createRealisticRose() { function createEnhancedCandle() { - // Groupe pour contenir tous les éléments de la bougie + const candleGroup = new THREE.Group(); - // Modification: Porte-bougie plus grand et plus élaboré - const holderBaseRadius = 22; // Augmenté - const holderBaseHeight = 8; // Augmenté + const holderBaseRadius = 22; + const holderBaseHeight = 8; const holderBaseGeometry = new THREE.CylinderGeometry(holderBaseRadius, holderBaseRadius * 1.3, holderBaseHeight, 32); - // Pied central du chandelier plus grand et plus décoratif - const holderStemRadius = 4.5; // Augmenté - const holderStemHeight = 25; // Beaucoup plus haut + + const holderStemRadius = 4.5; + const holderStemHeight = 25; const holderStemGeometry = new THREE.CylinderGeometry(holderStemRadius * 0.8, holderStemRadius * 1.2, holderStemHeight, 16); - // Coupelle supérieure du chandelier plus grande - const holderTopRadius = 16; // Augmenté - const holderTopHeight = 4; // Augmenté + + const holderTopRadius = 16; + const holderTopHeight = 4; const holderTopGeometry = new THREE.CylinderGeometry(holderTopRadius, holderTopRadius * 0.85, holderTopHeight, 32); - // Décoration plus élaborée pour le chandelier + const decorRadius = 18; const decorHeight = 1.5; const decorGeometry = new THREE.TorusGeometry(decorRadius * 0.7, 1.5, 12, 48); - // Ajout de décorations supplémentaires const smallDecorRadius = 10; const smallDecorGeometry = new THREE.TorusGeometry(smallDecorRadius * 0.7, 1, 8, 32); - // Matériau bronze vieilli pour le porte-bougie avec texture améliorée + const holderMaterial = new THREE.MeshStandardMaterial({ - color: 0xFFD700, // Couleur dorée - roughness: 0.2, // Réduire la rugosité pour plus de brillance - metalness: 0.8, // Augmenter la métallicité - envMapIntensity: 1 // Augmenter l'intensité des reflets + color: 0xFFD700, + roughness: 0.2, + metalness: 0.8, + envMapIntensity: 1 }); // Variante plus foncée et plus détaillée const holderDarkMaterial = new THREE.MeshStandardMaterial({ - color: 0xFFD700, // Couleur dorée légèrement différente pour le contraste - roughness: 0.25, // Légèrement plus rugueux que le matériau principal - metalness: 0.8, // Presque aussi métallique + color: 0xFFD700, + roughness: 0.25, + metalness: 0.8, envMapIntensity: 1 }); // Assemblage du chandelier const holderBase = new THREE.Mesh(holderBaseGeometry, holderMaterial); holderBase.position.y = holderBaseHeight / 2; - holderBase.castShadow = true; // Permet au support de projeter une ombre - holderBase.receiveShadow = true; // Permet au support de recevoir une ombre + holderBase.castShadow = true; + holderBase.receiveShadow = true; const holderStem = new THREE.Mesh(holderStemGeometry, holderDarkMaterial); holderStem.position.y = holderBaseHeight + holderStemHeight / 2; - holderStem.castShadow = true; // Permet à la tige de projeter une ombre - holderStem.receiveShadow = true; // Permet à la tige de recevoir une ombre + holderStem.castShadow = true; + holderStem.receiveShadow = true; const holderTop = new THREE.Mesh(holderTopGeometry, holderMaterial); holderTop.position.y = holderBaseHeight + holderStemHeight + holderTopHeight / 2; - holderTop.castShadow = true; // Permet à la coupelle de projeter une ombre - holderTop.receiveShadow = true; // Permet à la coupelle de recevoir une ombre + holderTop.castShadow = true; + holderTop.receiveShadow = true; const decor = new THREE.Mesh(decorGeometry, holderDarkMaterial); decor.position.y = holderBaseHeight + 6; decor.rotation.x = Math.PI / 2; - decor.castShadow = true; // Permet à la décoration de projeter une ombre - decor.receiveShadow = true; // Permet à la décoration de recevoir une ombre + decor.castShadow = true; + decor.receiveShadow = true; // Décoration supplémentaire au milieu du stem const middleDecor = new THREE.Mesh(smallDecorGeometry, holderMaterial); middleDecor.position.y = holderBaseHeight + holderStemHeight / 2; middleDecor.rotation.x = Math.PI / 2; - middleDecor.castShadow = true; // Permet à la décoration du milieu de projeter une ombre - middleDecor.receiveShadow = true; // Permet à la décoration du milieu de recevoir une ombre + middleDecor.castShadow = true; + middleDecor.receiveShadow = true; - // Modification: Bougie plus petite - const candleRadius = 5; // Réduit - const candleHeight = 20; // Réduit + + const candleRadius = 5; + const candleHeight = 20; const candleGeometry = new THREE.CylinderGeometry(candleRadius * 0.9, candleRadius, candleHeight, 32); // Matériau de cire pour la bougie plus réaliste @@ -474,10 +470,10 @@ function createEnhancedCandle() { roughness: 0.8, metalness: 0.05, transparent: true, - opacity: 0.95 // Légèrement translucide + opacity: 0.95 }); - // Ajout d'un effet de cire fondue + const meltedWaxGeometry = new THREE.SphereGeometry(candleRadius * 1.2, 16, 16, 0, Math.PI * 2, 0, Math.PI / 2); meltedWaxGeometry.translate(0, -candleHeight/2, 0); const meltedWaxMaterial = new THREE.MeshStandardMaterial({ @@ -494,8 +490,8 @@ function createEnhancedCandle() { candle = new THREE.Mesh(candleGeometry, candleMaterial); candle.position.y = holderBaseHeight + holderStemHeight + holderTopHeight + candleHeight / 2 - 2; // Ajusté pour s'enfoncer légèrement - candle.castShadow = true; // Permet à la bougie de projeter une ombre - candle.receiveShadow = true; // Permet à la bougie de recevoir une ombre + candle.castShadow = true; + candle.receiveShadow = true; candle.add(meltedWax); // Création d'une mèche plus détaillée @@ -513,11 +509,10 @@ function createEnhancedCandle() { const wick = new THREE.Mesh(wickGeometry, wickMaterial); wick.position.y = holderBaseHeight + holderStemHeight + holderTopHeight + candleHeight + wickHeight / 2 - 2; - wick.castShadow = true; // Permet à la mèche de projeter une ombre - wick.receiveShadow = true; // Permet à la mèche de recevoir une ombre + wick.castShadow = true; + wick.receiveShadow = true; - // Améliorations pour la flamme - // Flamme intérieure (plus chaude/blanche) + const innerFlameHeight = 8; const innerFlameRadius = 1.5; const innerFlameGeometry = new THREE.ConeGeometry(innerFlameRadius, innerFlameHeight, 16, 5, true); @@ -532,22 +527,19 @@ function createEnhancedCandle() { const innerFlame = new THREE.Mesh(innerFlameGeometry, innerFlameMaterial); innerFlame.position.y = holderBaseHeight + holderStemHeight + holderTopHeight + candleHeight + wickHeight + innerFlameHeight / 2 - 2; - // Les flammes n'ont généralement pas besoin de projeter d'ombres car elles sont des sources de lumière - - // Flamme extérieure améliorée avec une forme plus naturelle + const outerFlameHeight = 12; const outerFlameRadius = 2.5; - // Utilisation d'une géométrie personnalisée pour une flamme plus naturelle const outerFlameGeometry = new THREE.ConeGeometry(outerFlameRadius, outerFlameHeight, 20, 8, true); - // Déformer légèrement la géométrie pour un aspect plus réaliste + const positionAttribute = outerFlameGeometry.getAttribute('position'); for (let i = 0; i < positionAttribute.count; i++) { const x = positionAttribute.getX(i); const y = positionAttribute.getY(i); const z = positionAttribute.getZ(i); - // Déformation aléatoire pour donner un aspect plus naturel + if (y > outerFlameHeight * 0.3) { const distortFactor = (y / outerFlameHeight) * 0.4; positionAttribute.setX(i, x + (Math.random() - 0.5) * distortFactor); @@ -558,7 +550,7 @@ function createEnhancedCandle() { // Matériau amélioré pour la flamme extérieure const outerFlameMaterial = new THREE.MeshBasicMaterial({ - color: 0xffaa33, // Orange plus chaud + color: 0xffaa33, transparent: true, opacity: 0.85, side: THREE.DoubleSide, @@ -568,7 +560,7 @@ function createEnhancedCandle() { flame = new THREE.Mesh(outerFlameGeometry, outerFlameMaterial); flame.position.y = holderBaseHeight + holderStemHeight + holderTopHeight + candleHeight + wickHeight + outerFlameHeight / 2 - 2; - // Ajout d'une flamme externe très subtile pour un effet de halo + // Ajout d'une flamme externe très subtile pour un effet const subtleFlameHeight = 15; const subtleFlameRadius = 4; const subtleFlameGeometry = new THREE.ConeGeometry(subtleFlameRadius, subtleFlameHeight, 16, 4, true); @@ -584,32 +576,31 @@ function createEnhancedCandle() { const subtleFlame = new THREE.Mesh(subtleFlameGeometry, subtleFlameMaterial); subtleFlame.position.y = holderBaseHeight + holderStemHeight + holderTopHeight + candleHeight + wickHeight + subtleFlameHeight / 2 - 3; - // Système de lumières amélioré - // Lumière principale de la flamme - Configuration pour projeter des ombres + const flameLight = new THREE.PointLight(0xff9933, 2.2, 400); flameLight.position.copy(flame.position); - flameLight.power = 120; // Intensité augmentée pour plus d'impact visuel - flameLight.castShadow = true; // Permet à la lumière de projeter des ombres + flameLight.power = 120; + flameLight.castShadow = true; // Configuration des paramètres d'ombre pour une meilleure qualité flameLight.shadow.mapSize.width = 1024; flameLight.shadow.mapSize.height = 1024; flameLight.shadow.camera.near = 0.1; flameLight.shadow.camera.far = 1000; - flameLight.shadow.bias = -0.002; // Réduire les artifacts d'ombre - flameLight.shadow.radius = 3; // Adoucir les bords de l'ombre + flameLight.shadow.bias = -0.002; + flameLight.shadow.radius = 3; // Seconde lumière pour effet réaliste const innerLight = new THREE.PointLight(0xffffcc, 1.2, 150); innerLight.position.copy(innerFlame.position); innerLight.power = 70; - innerLight.castShadow = false; // Cette lumière secondaire n'a pas besoin de projeter des ombres + innerLight.castShadow = false; // Troisième lumière très subtile pour l'ambiance const ambientFlameLight = new THREE.PointLight(0xff5500, 0.6, 600); ambientFlameLight.position.set(flame.position.x, flame.position.y - 5, flame.position.z); ambientFlameLight.power = 40; - ambientFlameLight.castShadow = false; // Cette lumière d'ambiance n'a pas besoin de projeter des ombres + ambientFlameLight.castShadow = false; // Halo lumineux amélioré const flameHaloGeometry = new THREE.SphereGeometry(8, 24, 24); @@ -624,7 +615,6 @@ function createEnhancedCandle() { const flameHalo = new THREE.Mesh(flameHaloGeometry, flameHaloMaterial); flameHalo.position.copy(flame.position); - // Particules de feu/braises (simulées par de petites sphères) const particlesGroup = new THREE.Group(); const particleCount = 15; const particleGeometry = new THREE.SphereGeometry(0.15, 8, 8); @@ -637,7 +627,7 @@ function createEnhancedCandle() { for (let i = 0; i < particleCount; i++) { const particle = new THREE.Mesh(particleGeometry, particleMaterial); - // Position aléatoire autour de la flamme + particle.position.set( (Math.random() - 0.5) * 2, flame.position.y + Math.random() * 3 - 2, @@ -743,7 +733,7 @@ function animateFlame() { flameHalo.material.opacity = 0.15 + 0.05 * Math.sin(time * 1.2); } - // *** AMÉLIORATION PRINCIPALE: Intensité des lumières pour projection sur le fond *** + if (flameLight) { // Augmenter la portée et l'intensité pour mieux éclairer l'environnement flameLight.distance = 600; // Augmenter la portée @@ -765,12 +755,11 @@ function animateFlame() { if (ambientLight) { // Lumière ambiante plus forte pour illuminer tout l'environnement ambientLight.intensity = 0.7 + 0.2 * Math.sin(time * 0.9); - ambientLight.distance = 800; // Grande portée pour atteindre le fond + ambientLight.distance = 800; ambientLight.position.set(flame.position.x, flame.position.y - 5, flame.position.z); ambientLight.power = 60 + 15 * Math.sin(time * 0.8); // Pouvoir lumineux augmenté } - - // Animation simplifiée des particules + if (particles) { particles.children.forEach(particle => { particle.position.y += particle.userData.velocity.y * 0.5; @@ -798,7 +787,7 @@ function animateFlame() { }); } - // *** AMÉLIORATION CRUCIALE: Mise à jour améliorée du fond pour mieux refléter la flamme *** + updateBackgroundWithCandleLight(time, heightVariation, swayX, swayZ); } } @@ -844,18 +833,18 @@ function updateBackgroundWithCandleLight(time, flickerFactor, swayX, swayZ) { gradient.addColorStop(0.7, 'rgba(3, 1, 0, 0.3)'); gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); - // Appliquer le gradient par-dessus le fond noir + context.fillStyle = gradient; context.fillRect(0, 0, 512, 512); - // Ajouter un effet de lueur diffuse très subtil + if (pulseFactor > 0.85) { const glowGradient = context.createRadialGradient( centerX, centerY, radius * 0.3, centerX, centerY, radius * 0.9 ); - // Lueur encore plus subtile + glowGradient.addColorStop(0, `rgba(255, 140, 50, ${0.02 * (pulseFactor - 0.85) * 10})`); glowGradient.addColorStop(1, 'rgba(255, 140, 50, 0)'); @@ -863,13 +852,13 @@ function updateBackgroundWithCandleLight(time, flickerFactor, swayX, swayZ) { context.fillRect(0, 0, 512, 512); } - // Mettre à jour la texture du fond + backgroundMesh.material.map.dispose(); backgroundMesh.material.map = new THREE.CanvasTexture(canvas); backgroundMesh.material.needsUpdate = true; } } -// Fonction d'animation mise à jour + function animate() { requestAnimationFrame(animate); var delta = clock.getDelta();