Bonjour tout le monde,
Bon, je sais que mon problème n'est pas purement mathématique, dès lors, je ne suis pas certain que ce post ai sa place sur ce forum, et si ce n'est pas le cas, je m'en excuse.
En fait voila, je suis développeur, et pour les besoins d'une application Web, je dois faire un mini moteur 3D Javascript. Avant de crier au scandale laissez moi m'expliquer: Je ne veux pas faire de vertex ou autre particules, j'ai juste besoin de projeter des points 3D sur un plan 2D en tenant compte des angles de rotation X et Y de la caméra...rien d'autre que quelques calculs matriciels.
N'étant pas à votre niveau en mathématique, j'ai suivi un article de Wikipedia donnant le principe de la rasterisation ainsi que les principales matrices de transformation à utiliser (http://fr.wikipedia.org/wiki/Rast%C3%A9risation#Voir_aussi)
Je me suis donc coder mon truc en Javascript mais évidement, ca marche po
J'ai pourtant vérifier l'ensemble de mes calculs, tout me semble correct....je commence donc à me dire que c'est peut etre le principe meme utilisé qui n'est pas le bon, on pas bien compris dans son implémentation, c'est pourquoi j'ai eu l'idée de faire appel à mes "matheux" (qui accessoirement peuvent lire du code JavaScript, mais ca j'ai pas trop de doute)
Voila, bah si vous avez le temps et l'envie de m'aider, ca serait super sympa
Merci par avance
Voici le code JS (je suis désolé, ce forum n'étant pas prévu pour du code, il n'y à pas de balise spécialisée, du coup je suis obligé d'utiliser celle pour la citation qui supprime toutes les indentations...si vous voulez le code originel, envoyer moi un MP, et je vous le donnerai par mail):
Bonjour,
Ouah, en effet, je ne suis pas sûr que tu puisse obtenir beaucoup de réponses, mais pourquoi pas.. l'infographie matricielle reste fortement liée aux mathématiques (quaternions, etc).
Je ne peux pas vraiment t'aider, mais au moins je peux reposter ton code en respectant les identations pour ceux qui veulent le lire plus clairement :
Bon courage.
Le code JS :
var ads3d = new function() { /*** Propriété ***/ // Tableau contenant la liste des vecteurs (Point) à afficher this.plotsList = new Array(); //Permet d'accéder aux différent paramètres du viewport (zone d'affichage) this.viewport = function() { this.domReference = null; //Reference vers le contener DOM affichant le viewport (DIV) this.minWidth = 0; //Position des pixels du bord gauche du viewport this.maxWidth = 0; //Position des pixels du bord droit du viewport this.minHeight = 0; //Position des pixels du bord bas du viewport this.maxHeight = 0; //Position des pixels du bord haut du viewport this.minDist = 0; //Distance depuis la caméra à partir delaquelle on commence à "voir" les objets 3D this.maxDist = 500; //Distance maximale depuis la caméra à partir de laquelle on arrète de "voir" les objets }; this.camera = function() { //Point ou est placée la caméra this.origin = null; //Point ou regarde la caméra this.target = null; //Position de la caméra (Droite, couchée à droite, couchée à gauche ou la tete en bas) this.position = null; //valeur positive non null sur Y, la caméra est droite //Angle de rotation de la caméra autour de l'axe Y (droite <=> gauche) this.rotationY = 0.0; //Angle de rotation de la caméra autour de l'axe X (haut <=> bas) this.rotationX = 0.0; }; /*** Methodes ***/ //Permet d'attacher le moteur à la référence vers l'objet DOM passé en argument this.setViewPort = function(poDomElement) { this.viewport.domReference = poDomElement; this.viewport.minWidth = 0; this.viewport.maxWidth = poDomElement.offsetWidth; this.viewport.minHeight = 0; this.viewport.maxHeight = poDomElement.offsetHeight; this.viewport.minDist = 0; this.viewport.maxDist = 500; }; //Ajoute un point en 3D dans le monde aux coordonnées passées en argument this.add3dPlot = function(piPlotX, piPlotY, piPlotZ) { this.plotsList.push(new ads3d.vector(piPlotX, piPlotY, piPlotZ)); }; //Effectue tous les calculs de rendu à un instant T et met à jour l'affichage this.updateViewport = function() { //On commence par créer la matrice WORLD qui est le produit de toutes les matrices de transformation //Pour le moment on ne gère que les rotation X et Y var loMatRotX = new ads3d.matrix(4, 4); loMatRotX.setToRotationX(this.camera.rotationX); var loMatRotY = new ads3d.matrix(4, 4); loMatRotY.setToRotationY(this.camera.rotationY); var loMatWORLD = loMatRotX.multiplyToMatrix(loMatRotY); //On parcours maintenant la liste des points 3D dans le monde for(liPlotIndex in this.plotsList) { var loPlotVector = this.plotsList[liPlotIndex]; /*** RASTERISATION ETAPE 1 (ModelToWorld) ***/ //On en fait un vecteur unitaire pour que les calculs soient plus propres loPlotVector = loPlotVector.getUnitVector(); //On passe le point au travers de la matrice WORLD pour lui affecter toutes les transformations (Etape ModelToWorld de la rasterisation) loPlotVector = loMatWORLD.multiplyToVector(loPlotVector); /*** RASTERISATION ETAPE 2 (WorldToView) ***/ //On passe maintenant au calcul de la matrice de vue qui permet de transposer le point 3D sur un plan prenant en compte la position et l'orientation de la caméra //(Etape WorldToView de la rasteritation) //Pour plus de clareté, j'ai décomposer cette matrice de vue selon les 2 sous matrices (A et B) qui la compose en se multipliant //On commence par calculer les Vecteurs transposant les paramètres de la caméra var loVectorF = ads3d.camera.origin.substractToVector(ads3d.camera.target); var loVectorS = loVectorF.multiplyToVector(ads3d.camera.position); var loVectorU = loVectorS.multiplyToVector(loVectorF); //Puis la matrice view en elle meme var loMatViewPartA = new ads3d.matrix(4, 4); loMatViewPartA.setToViewMatrixPartA(loVectorS, loVectorU, loVectorF); var loMatViewPartB = new ads3d.matrix(4, 4); loMatViewPartB.setToViewMatrixPartB(ads3d.camera.origin); var loMatView = loMatViewPartA.multiplyToMatrix(loMatViewPartB); //enfin on passe notre point dans cette view loPlotVector = loMatView.multiplyToVector(loPlotVector); /*** RASTERISATION ETAPE 3 (ViewToProjection) ***/ //Cette dernière étape consiste à faire une projection de la matrice View sur le plan du viewport, les tailles de ce dernier sont donc necessaires var loMatProj = new ads3d.matrix(4, 4); loMatProj.setToOrthogonalMatrixProjection(this.viewport.minWidth, this.viewport.maxWidth, this.viewport.minHeight, this.viewport.maxHeight, this.viewport.minDist, this.viewport.maxDist); //Voici enfin le vecteur qui contient les coordonnées 2D pour l'affichage loPlotVector = loMatProj.multiplyToVector(loPlotVector); alert("Vector.X: " + loPlotVector.X + " Vector.Y: " + loPlotVector.Y + " Vector.Z: " + loPlotVector.Z); } }; /*** Gestion de la caméra ***/ this.initCamera = function() { //Point ou est placée la caméra this.camera.origin = new ads3d.vector(0.1, 0.1, 0.1); //Point ou regarde la caméra this.camera.target = new ads3d.vector(0, 0, 500); //Position de la caméra (Droite, couchée à droite, couchée à gauche ou la tete en bas) this.camera.position = new ads3d.vector(0, 1, 0); //valeur positive non null sur Y, la caméra est droite //Angle de rotation de la caméra autour de l'axe Y (droite <=> gauche) this.camera.rotationY = 0.0; //Angle de rotation de la caméra autour de l'axe X (haut <=> bas) this.camera.rotationX = 0.0; }; /*** Gestion d'un Vecteur 3d ***/ this.vector = function(pPosX, pPosY, pPosZ) { //Coordonnée X du Vecteur this.X = pPosX; //Coordonnée Y du Vecteur this.Y = pPosY; //Coordonnée Z du Vecteur this.Z = pPosZ; //Magnitude du vecteur (distance spaciale du point) this.Magnitude = function() { return Math.sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); }; //Permet de récupérer le vecteur unitaire du vecteur considéré //Retourne un nouveau vecteur this.getUnitVector = function() { var liTmp = 1.0 / this.Magnitude(); return new ads3d.vector( this.X *= liTmp, this.Y *= liTmp, this.Z *= liTmp ); }; //Permet de multiplier le vecteur courant par celui passer en argument. //Retourne un nouveau vecteur this.multiplyToVector = function(poVector) { return new ads3d.vector( this.X * poVector.X, this.Y * poVector.Y, this.Z * poVector.Z ); }; //Permet d'ajouter le vecteur courant à celui passer en argument //Retourne un nouveau vecteur this.addToVector = function(poVector) { return new ads3d.vector( this.X + poVector.X, this.Y + poVector.Y, this.Z + poVector.Z ); }; //Permet de soustraire au vecteur courant celui passer en argument //Retourne un nouveau vecteur this.substractToVector = function(poVector) { return new ads3d.vector( this.X - poVector.X, this.Y - poVector.Y, this.Z - poVector.Z ); }; }; /*** Gestion d'une Matrice ***/ this.matrix = function(pWidth, pHeight) { //Contenu de la matrice this.content = new Array(); //Initialisation de la matrice à 0.0 for(var liCptRow = 0; liCptRow < pHeight; liCptRow++) { this.content[liCptRow] = new Array(); for(var liCptCol = 0; liCptCol < pWidth; liCptCol++) { this.content[liCptRow][liCptCol] = 0.0; } } //Permet de positionner la matrice comme unitaire //(ce qui permet qu'elle ne donne pas 0 partout si on la multiplie avec une autre matrice) this.setToIdentity = function() { for (var c = 0; c < 4; ++c) { for (var r = 0; r < 4; ++r) { this.content[c][r] = (c == r) ? 1.0 : 0.0; } } } //Permet de positionner la matrice comme une matrice de rotation sur l'axe des X selon l'angle passé en argument //l'angle est exprimé en degré this.setToRotationX = function(poAngleDegre) { var liAngleRadian = Math.PI * poAngleDegre / 180; this.setToIdentity(); this.content[1][1] = Math.cos(liAngleRadian); this.content[1][2] = Math.sin(liAngleRadian) * -1.0; this.content[2][1] = Math.sin(liAngleRadian); this.content[2][2] = Math.cos(liAngleRadian); } //Permet de positionner la matrice comme une matrice de rotation sur l'axe des Y selon l'angle passé en argument //l'angle est exprimé en degré this.setToRotationY = function(poAngleDegre) { var liAngleRadian = Math.PI * poAngleDegre / 180; this.setToIdentity(); this.content[0][0] = Math.cos(liAngleRadian); this.content[0][2] = Math.sin(liAngleRadian); this.content[2][0] = Math.sin(liAngleRadian) * -1.0; this.content[2][2] = Math.cos(liAngleRadian); } //Permet de positionner la matrice comme une matrice de vue (PARTIE A) selon les 3 vecteurs identifiants la caméra et son point de vue this.setToViewMatrixPartA = function(poVectorS, poVectorU, poVectorF) { this.content[0][0] = poVectorS.X; this.content[0][1] = poVectorS.Y; this.content[0][2] = poVectorS.Z; this.content[1][0] = poVectorU.X; this.content[1][1] = poVectorU.Y; this.content[1][2] = poVectorU.Z; this.content[2][0] = poVectorF.X * -1.0; this.content[2][1] = poVectorF.Y * -1.0; this.content[2][2] = poVectorF.Z * -1.0; this.content[3][3] = 1.0; } //Permet de positionner la matrice comme une matrice de vue (PARTIE B) selon le vecteur de position de la caméra this.setToViewMatrixPartB = function(poVectorPosCam) { this.setToIdentity(); this.content[0][3] = poVectorPosCam.X * -1.0; this.content[1][3] = poVectorPosCam.Y * -1.0; this.content[2][3] = poVectorPosCam.Z * -1.0; } //Permet de positionner la matrice comme une matrice de projection de type Orthogonale en fonction de la taille du viewport this.setToOrthogonalMatrixProjection = function(piScreenMinWidth, piScreenMaxWidth, piScreenMinHeight, piScreenMaxHeight, piMinDistanceView, piMaxDistanceView) { this.content[0][0] = 2.0 / (piScreenMaxWidth - piScreenMinWidth); this.content[0][3] = -1.0 * (piScreenMaxWidth + piScreenMinWidth) / (piScreenMaxWidth - piScreenMinWidth); this.content[1][1] = 2.0 / (piScreenMaxHeight - piScreenMinHeight); this.content[1][3] = -1.0 * (piScreenMaxHeight + piScreenMinHeight) / (piScreenMaxHeight - piScreenMinHeight); this.content[2][2] = -2.0 / (piMaxDistanceView - piMinDistanceView); this.content[2][3] = -1.0 * (piMaxDistanceView + piMinDistanceView) / (piMaxDistanceView - piMinDistanceView); this.content[3][3] = 1.0; } //Permet de multiplier la matrice courante avec celle passée en argument //Renvoi une nouvelle matrice this.multiplyToMatrix = function(poMatrix) { var loReturnMatrix = new ads3d.matrix(4, 4); for (var r = 0; r < 4; ++r) { for (var c = 0; c < 4; ++c) { for (var k = 0; k < 4; ++k) { loReturnMatrix.content[c][r] += this.content[k][r] * poMatrix.content[c][k]; } } } return loReturnMatrix; }; //Permet de multiplier la matrice courante avec le vecteur passé en argument //Renvoi un nouveau vecteur this.multiplyToVector = function(poVector) { return new ads3d.vector( this.content[0][0] * poVector.X + this.content[1][0] * poVector.Y + this.content[2][0] * poVector.Z + this.content[3][0] * 1.0, this.content[0][1] * poVector.X + this.content[1][1] * poVector.Y + this.content[2][1] * poVector.Z + this.content[3][1] * 1.0, this.content[0][2] * poVector.X + this.content[1][2] * poVector.Y + this.content[2][2] * poVector.Z + this.content[3][2] * 1.0 ); }; }; } function debugMatrix44(poMatrix) { var oTable = document.createElement('TABLE'); for(liCptRow = 0; liCptRow < 4; liCptRow++) { var oTR = document.createElement('TR'); for(liCptCol = 0; liCptCol < 4; liCptCol++) { var oTD = document.createElement('TD'); oTD.innerHTML = poMatrix.content[liCptRow][liCptCol]; oTR.appendChild(oTD); } oTable.appendChild(oTR); } document.getElementById('DEBUG').appendChild(oTable); } window.onload = function() { ads3d.setViewPort(document.getElementById('viewport')); ads3d.initCamera(); ads3d.add3dPlot(300, 300, 20); ads3d.updateViewport(); }
<html> <head> <script type="text/javascript" src="ads3d.js"></script> </head> <body> <div id="viewport" style="width:600px; height:600px; border:solid 1px #000;"></div> <div id="DEBUG"></div> </body> </html>
salut,
Merci pour l'indentation, effectivement c'est plus clair comme ca
Je sais bien que m'a demande est un peu particulière pour ce forum, mais je pense que mon problème se situe bel et bien au niveau des matrices et de leur calcul (donc au niveau mathématique), j'ai donc espoir que l'un d'entre vous un peu courageux acceptera de lire et comprendre le code (je pense qu'avec un esprit scientifique ce code est compréhensible sans avoir de fortes notions de programmation)...
Toujours est-il que les informations sur ce type de développement sur le web sont vraiment très minces... quelques librairies font déja tout ce travail et surtout, rare sont ceux qui tente l'expérience avec du simple Javascript (c'est vrai qu'a premier abord ca parait stupide ) du coup ,j'ai vraiment beaucoup de mal à trouver de l'aide, alors je frappe aux portes qui me paraissent les moins mal placées..
Bonjour adsofts,
Je me suis penché sur votre problème, mais j'ai quelques questions:
1: je n'ai pas compris le calcul de la matrice de projection
Bonjour Michel,
Merci d'avoir prit le temps de regarde mon code.
A vrai dire, j'avais oublier que j'avais poster ici...
En fait, j'ai finalement réussis à faire ce que je voulais, une version (avec encore quelques bugs) est visible ici: http://www.australe.fr/space/ (bouger avec la souris)
Je n'ai plus de problème en ce qui concerne la 3D en soit...
Merci encore
Vous devez être membre accéder à ce service...
Pas encore inscrit ?
1 compte par personne, multi-compte interdit !
Ou identifiez-vous :