[THREEJS] Actualiser une scene / Réinitialiser l'objet Canvas
Bonjour à tous,
Je m'arrache les cheveux depuis plusieurs jours concernant la mise à jour d'un objet canvas avec THREEJS :
Il s'agît d'une représentation 3d du modèle Bohr des atomes, après l'appui sur un bouton de la table périodique d'un élément s'ouvre une modale représentant l'atome et ses électrons gravitant autour du noyau en 3d...
Tout fonctionne bien au niveau de la représentation et rendering sauf que la scene ne s'actualise pas sauf en rafraichissant manuellement la page !
J'ai tout essayé : placer l'init de ma classe dans l'eventListener de la modale, ne créer l'objet 'BohrModel' qu'à ce moment là, rien n'y fait...
Soit la scene ne s'actualise pas complétement, soit plusieurs instances de celle-ci se rajoutent au fur et à mesure dans la modale...
J'ai tenté aussi :
Code:
1 2
| this.renderer.forceContextLoss()
this.renderer.dispose(); |
Je pensais qu'il existait un moyen de réinitialiser l'objet à chaque fois que la modale ou l'action d'un bouton était demandé mais apparemment la scène le canvas et le render persistent en mémoire...
Je vois dans les forum énormément de questions du même ordre qui ne sont même pas répondues ...
Quelle serait la bonne méthode svp ?
Modale :
app.js :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| import { Atoms } from "./Atoms.js";
import { BohrModel } from "./BohrModel.js";
const bohrModel = new BohrModel();
console.log(window.screen.width)
const btnClose = document.querySelector(".btn-close");
const modaleAtome = document.querySelector(".modale__atome");
const btnAjouter = document.querySelector(".btn__ajouter");
const cardAtome = document.querySelector(".card__atome");
const atomSymbol = document.querySelector(".atom__symbol");
const nomAtome = document.querySelector(".nom__atome");
const qteAtome = document.querySelector(".qte__atome");
const atoms = new Atoms();
//Afficher la liste de boutons pour chaque atome en asynchrone
await atoms.getAtomsList();
const atomsButtons = document.querySelectorAll(".btn__atome");
//Ecouteur sur le bouton d'atomes
atomsButtons.forEach((btn) => {
btn.addEventListener("click", (e) => {
showAtomModal(e);
});
});
//Affiche la modale de l'atome choisi
const showAtomModal = (e) => {
modaleAtome.style.display = "flex";
nomAtome.innerHTML = "";
nomAtome.innerText = e.currentTarget.dataset.atomName;
atomSymbol.innerText = e.currentTarget.dataset.atomSymbol;
bohrModel.init();
let electronsLayers = "";
electronsLayers = e.currentTarget.dataset.electronConfiguration;
//Extrait la configuration électronique de l'atome actif
let atomConfig = atoms.getElectronConfig(electronsLayers);
console.log("tbl config = ", atomConfig);
//Calcul du nombre d'orbites représentant les couches électroniques
let atomOrbits = 0;
atomOrbits = atomConfig.length;
console.log("orbits =", atomOrbits);
//Crée les orbites pour l'atome actif
bohrModel.createOrbits(atomOrbits);
//Crée le noyau de l'atome actif
//Place les electrons sur les orbites
for (let i = 0; i < atomConfig.length; i++) {
bohrModel.placeElectrons(atomConfig[i], i + 1);
console.log(`orbite ${i + 1} nbrElectrons =${atomConfig[i]}`);
}
};
//Traitement bouton ajouter
btnAjouter.addEventListener("click", () => {
modaleAtome.style.display = "none";
});
//Traitement incrémentation clavier
document.addEventListener("keyup", (e) => {
let keyName = e.key;
console.log("control cliqué");
if (keyName === "+" && this.qteAtome.value >= 1) {
this.qteAtome.value++;
}
if (keyName === "-" && this.qteAtome.value > 1) {
this.qteAtome.value--;
}
});
//Fermeture modale atome
btnClose.addEventListener("click", () => {
modaleAtome.style.display = "none";
}); |
classe BohrModel.js :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
export class BohrModel {
constructor() {
//Données et distance de séparation par rapport au nucleus
this.distFromNucleus = 1;
this.orbits = [];
}
init() {
if (this.canvas) {
this.canvas="";
}
if (this.renderer) {
this.renderer.forceContextLoss()
this.renderer.dispose();
}
// if (this.scene) {
// this.scene='';
// }
this.createCanvas();
this.createScene();
this.createRenderer();
this.createCamera();
this.createSpot();
this.createNucleus();
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.light = new THREE.DirectionalLight(0xffffff);
this.scene.add(this.light);
this.createAnimations();
this.animate();
}
createCanvas() {
//Données canvas
this.canvas = document.querySelector("#bohr-model");
this.canvasWidth = 200;
this.canvasHeight = 200;
}
createScene() {
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color("lightsmoke");
}
createCamera() {
this.camera = new THREE.PerspectiveCamera(
75,
this.canvasWidth / this.canvasHeight,
0.1,
1000
);
this.camera.position.z = 15;
}
createRenderer() {
this.renderer = new THREE.WebGLRenderer({
antialias: true,
});
this.renderer.setSize(this.canvasWidth, this.canvasHeight);
this.renderer.setClearColor(0x000, 1.0);
this.canvas.appendChild(this.renderer.domElement);
}
createSpot() {
const spot1 = new THREE.SpotLight(0xffffff);
spot1.position.set(100, 100, 150);
this.scene.add(spot1);
}
createNucleus() {
this.nucleusRadius = 1;
this.nucleusGeo = new THREE.SphereGeometry(this.nucleusRadius, 32, 32);
this.nucleusMat = new THREE.MeshPhongMaterial({ color: "lightblue" });
this.nucleus = new THREE.Mesh(this.nucleusGeo, this.nucleusMat);
this.scene.add(this.nucleus);
}
//Création de chaque orbite représentant les couches électroniques
createOrbits(nbrOrbits) {
//On retire de la scène tous les éléments (orbits) anciens
if (this.orbits.length > 0) {
for (let i = 0; i < this.orbits.length; i++) {
this.scene.remove(this.orbits[i]);
}
}
this.innerOrbitRadius = this.nucleusRadius + this.distFromNucleus;
this.outerOrbitRadius = this.innerOrbitRadius + 0.02;
const orbitMat = new THREE.MeshBasicMaterial({
color: "lightgray",
side: THREE.DoubleSide,
});
for (let i = 0; i < nbrOrbits; i++) {
const orbitGeo = new THREE.RingGeometry(
this.innerOrbitRadius,
this.outerOrbitRadius,
50
);
this.orbits[i] = new THREE.Mesh(orbitGeo, orbitMat);
this.orbits.push(this.orbits[i]);
this.scene.add(this.orbits[i]);
this.innerOrbitRadius++;
this.outerOrbitRadius++;
}
return this.orbits;
}
//calcul des positions et placement d'électrons sur une orbite:
placeElectrons(nbrElectrons, targetedOrbit) {
const maxRadius = targetedOrbit + 1;
const sphereGeo = new THREE.SphereGeometry(0.2, 16, 16);
let sphereMat = new THREE.MeshPhongMaterial({ color: "white" });
for (let i = 0; i < nbrElectrons + 1; i++) {
if (this.orbits.length - 1 === targetedOrbit) {
sphereMat = new THREE.MeshPhongMaterial({ color: "red" });
}
const sphere = new THREE.Mesh(sphereGeo, sphereMat);
//Calculs répartition des sphères sur orbites par angles
const angle = i * ((2 * Math.PI) / nbrElectrons);
const x = maxRadius * Math.cos(angle);
const y = maxRadius * Math.sin(angle);
sphere.position.x = x;
sphere.position.y = y;
this.orbits[targetedOrbit].add(sphere);
}
}
createAnimations() {
this.animate = () => {
this.nucleus.rotateY(0.004);
for (let i = 0; i < this.orbits.length; i++) {
this.orbits[i].rotation.z += -0.001;
}
this.controls.update();
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.animate);
};
}
} |