Moteur 3d

0/5 (16 avis)

Vue 10 089 fois - Téléchargée 616 fois

Description

C'est un... moteur 3D !
Il fait un seul rendu bien évidemment et utilise les mêmes techniques de rendu software que les vrais moteurs. Pour l'instant, il affiche les arêtes d'un cube (mais on peut modifier et mettre autre chose qu'un cube) selon la position de la caméra que l'on peut définir en modifiant la source

J'ai fait cela pour prouver qu'il n'était pas si compliqué de faire un moteur 3D, même en php
Il utilise GD. J'ai fait ça pour me faciliter la vie... après on peut aussi faire un .bmp avec et ne pas utiliser GD

Le backbuffer ne fonctionne pas correctement, j'ai mis la partie qui utiliser le backbuffer en commentaire

Source / Exemple :


$width = 320;
$height = 240;

$clipping = 500;

$wireframe = false; // mode fil de fer

header("Content-type: image/jpeg");

function drawtriangle($im, $backbuffer, $pt1, $pt2, $pt3, $width, $height, $wireframe) {
	if ($pt1[1] > $pt2[1]) { $tmp = $pt2; $pt2 = $pt1; $pt1 = $tmp; }
	if ($pt1[1] > $pt3[1]) { $tmp = $pt3; $pt3 = $pt1; $pt1 = $tmp; }
	if ($pt2[1] > $pt3[1]) { $tmp = $pt3; $pt3 = $pt2; $pt2 = $tmp; }
	if ($pt1[1] > $pt2[1]) { $tmp = $pt2; $pt2 = $pt1; $pt1 = $tmp; }
	if ($pt1[1] > $pt3[1]) { $tmp = $pt3; $pt3 = $pt1; $pt1 = $tmp; }
	if ($pt2[1] > $pt3[1]) { $tmp = $pt3; $pt3 = $pt2; $pt2 = $tmp; }
	
	for ($i = 0; $i <= ($pt3[1] - $pt1[1]); ++$i) {
		if ($i + $pt1[1] > $height || $i + $pt1[1] < 0)
			continue;
	
		$num1 = $pt1[0] + $i * ($pt3[0] - $pt1[0]) / ($pt3[1] - $pt1[1]);
		$num1z = $pt1[2] + $i * ($pt3[2] - $pt1[2]) / ($pt3[1] - $pt1[1]);
		$num1r = $pt1[3] + $i * ($pt3[3] - $pt1[3]) / ($pt3[1] - $pt1[1]);
		$num1g = $pt1[4] + $i * ($pt3[4] - $pt1[4]) / ($pt3[1] - $pt1[1]);
		$num1b = $pt1[5] + $i * ($pt3[5] - $pt1[5]) / ($pt3[1] - $pt1[1]);
		
		if ($i > ($pt2[1] - $pt1[1])) {
			$num2 = $pt2[0] + ($pt3[0] - $pt2[0]) * ($i - ($pt2[1] - $pt1[1])) / ($pt3[1] - $pt2[1]);
			$num2z = $pt2[2] + ($pt3[2] - $pt2[2]) * ($i - ($pt2[1] - $pt1[1])) / ($pt3[1] - $pt2[1]);
			$num2r = $pt2[3] + ($pt3[3] - $pt2[3]) * ($i - ($pt2[1] - $pt1[1])) / ($pt3[1] - $pt2[1]);
			$num2g = $pt2[4] + ($pt3[4] - $pt2[4]) * ($i - ($pt2[1] - $pt1[1])) / ($pt3[1] - $pt2[1]);
			$num2b = $pt2[5] + ($pt3[5] - $pt2[5]) * ($i - ($pt2[1] - $pt1[1])) / ($pt3[1] - $pt2[1]);
		} else {
			$num2 = $pt1[0] + ($pt2[0] - $pt1[0]) * $i / ($pt2[1] - $pt1[1]);
			$num2z = $pt1[2] + ($pt2[2] - $pt1[2]) * $i / ($pt2[1] - $pt1[1]);
			$num2r = $pt1[3] + ($pt2[3] - $pt1[3]) * $i / ($pt2[1] - $pt1[1]);
			$num2g = $pt1[4] + ($pt2[4] - $pt1[4]) * $i / ($pt2[1] - $pt1[1]);
			$num2b = $pt1[5] + ($pt2[5] - $pt1[5]) * $i / ($pt2[1] - $pt1[1]);
		}
			
		if ($num1 > $num2) {
			$tmp = $num2;
			$num2 = $num1;
			$num1 = $tmp;
			
			$tmp = $num2z;
			$num2z = $num1z;
			$num1z = $tmp;
			
			$tmp = $num2r;
			$num2r = $num1r;
			$num1r = $tmp;
			
			$tmp = $num2g;
			$num2g = $num1g;
			$num1g = $tmp;
			
			$tmp = $num2b;
			$num2b = $num1b;
			$num1b = $tmp;
		}
		
		if ($num1 == $num2) $num2 = $num1 + 1;
		for ($j = $num1; $j <= $num2; $j += $wireframe?($num2 - $num1):1) {
			if ($j > $width || $j < 0) continue;
		
			$zcoord = $num1z + ($num2z - $num1z) * (($j - $num1) / ($num2 - $num1));
			/*if ($zcoord > ($backbuffer[$j + ($i + $pt1[1]) * $width]))
				continue;
			$backbuffer[$j + ($i + $pt1[1]) * $width] = $zcoord;*/
			
			$red = $num1r + ($num2r - $num1r) * (($j - $num1) / ($num2 - $num1));
			$green = $num1g + ($num2g - $num1g) * (($j - $num1) / ($num2 - $num1));
			$blue = $num1b + ($num2b - $num1b) * (($j - $num1) / ($num2 - $num1));
			
			imagesetpixel($im, $j, $i + $pt1[1], imagecolorallocate($im, $red, $green, $blue));
		}
	}
	
	return $backbuffer;
}

class mesh {
	var $points;
	var $triangle1;
	var $triangle2;
	var $triangle3;
	
	var $scale;
	var $translation;
	
	function render($matrix, $width, $height, $im, $backbuffer, $wireframe) {
		$matrix2 = multiply(multiply($matrix, $this->translation), $this->scale);
	
		for ($i = 0; $i < sizeof($this->triangle1); ++$i) {
			if (!isset($this->triangle1[$i])) continue;
			if (!isset($this->triangle2[$i])) continue;
			if (!isset($this->triangle3[$i])) continue;
			
			$pt1 = $this->points[$this->triangle1[$i]];
			$pt2 = $this->points[$this->triangle2[$i]];
			$pt3 = $this->points[$this->triangle3[$i]];
			
			$tmp1 = $pt1->calculate($matrix2);
			$tmp2 = $pt2->calculate($matrix2);
			$tmp3 = $pt3->calculate($matrix2);
			
			$tmp1[0] = ($tmp1[0] + 1) * $width / 2;
			$tmp1[1] = ($tmp1[1] + 1) * $height / 2;
			$tmp2[0] = ($tmp2[0] + 1) * $width / 2;
			$tmp2[1] = ($tmp2[1] + 1) * $height / 2;
			$tmp3[0] = ($tmp3[0] + 1) * $width / 2;
			$tmp3[1] = ($tmp3[1] + 1) * $height / 2;
			
			$backbuffer = drawtriangle($im, $backbuffer, $tmp1, $tmp2, $tmp3, $width, $height, $wireframe);
		}
	}
	
	function mesh() {
		$this->points = array();
		$this->triangle1 = array();
		$this->triangle2 = array();
		$this->triangle3 = array();
		
		$this->scale = new matrix();
		$this->scale->loadIdentity();
		$this->translation = new matrix();
		$this->translation->loadIdentity();
	}
};

class point {
	var $x;
	var $y;
	var $z;
	
	var $cr;
	var $cg;
	var $cb;
	
	function point($x = 0, $y = 0, $z = 0, $r = 255, $g = 255, $b = 255) {
		$this->x = $x;
		$this->y = $y;
		$this->z = $z;
		$this->cr = $r;
		$this->cg = $g;
		$this->cb = $b;
	}
	
	function calculate($matrix) {
		$retour = array(0, 0, 0, 255, 255, 255);
		$retour[0] = $this->x * $matrix->values[0] + $this->y * $matrix->values[1] + $this->z * $matrix->values[2] + $matrix->values[3];
		$retour[1] = $this->x * $matrix->values[4] + $this->y * $matrix->values[5] + $this->z * $matrix->values[6] + $matrix->values[7];
		$retour[2] = $this->x * $matrix->values[8] + $this->y * $matrix->values[9] + $this->z * $matrix->values[10] + $matrix->values[11];
		$retour[3] = $this->cr;
		$retour[4] = $this->cg;
		$retour[5] = $this->cb;
		return $retour;
	}
};

class matrix {
	var $values;
	
	function get($x, $y) {
		return $y + $x * 4;
	}
	
	function loadIdentity() {
		$this->values = array(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
	}
	
	function projection($angle, $ratio, $zNear, $zFar) {
		$angle = $angle;
		$yScale = atan($angle / 2);
		
		$this->loadIdentity();
		$this->values[0] = $ratio / $yScale;
		$this->values[5] = $yScale;
		$this->values[10] = $zFar / ($zFar - $zNear);
		$this->values[11] = -$zNear * $zFar / ($zFar - $zNear);
		$this->values[14] = 1;
		$this->values[15] = 0;
	}
	
	function lookat($eye, $at, $up) {
		$zaxis = new point();
		$zaxis->x = $eye->x - $at->x; $zaxis->y = $eye->y - $at->y; $zaxis->z = $eye->z - $at->z;
		$dist = sqrt($zaxis->x * $zaxis->x + $zaxis->y * $zaxis->y + $zaxis->z * $zaxis->z);
		$zaxis->x /= $dist; $zaxis->y /= $dist; $zaxis->z /= $dist;
		
		$xaxis = new point();
		$xaxis->x = $up->y * $zaxis->z - $up->z * $zaxis->y;
		$xaxis->y = $up->z * $zaxis->x - $up->x * $zaxis->z;
		$xaxis->z = $up->x * $zaxis->y - $up->y * $zaxis->x;
		$dist = sqrt($xaxis->x * $xaxis->x + $xaxis->y * $xaxis->y + $xaxis->z * $xaxis->z);
		$xaxis->x /= $dist; $xaxis->y /= $dist; $xaxis->z /= $dist;
		
		$yaxis = new point();
		$yaxis->x = $zaxis->y * $xaxis->z - $zaxis->z * $xaxis->y;
		$yaxis->y = $zaxis->z * $xaxis->x - $zaxis->x * $xaxis->z;
		$yaxis->z = $zaxis->x * $xaxis->y - $zaxis->y * $xaxis->x;
		
		$dot1 = $xaxis->x * $eye->x + $xaxis->y * $eye->y + $xaxis->z * $eye->z;
		$dot2 = $yaxis->x * $eye->x + $yaxis->y * $eye->y + $yaxis->z * $eye->z;
		$dot3 = $zaxis->x * $eye->x + $zaxis->y * $eye->y + $zaxis->z * $eye->z;

		$this->loadIdentity();
		$this->values[0] = $xaxis->x;
		$this->values[1] = $xaxis->y;
		$this->values[2] = $xaxis->z;
		$this->values[3] = -$dot1;
		$this->values[4] = $yaxis->x;
		$this->values[5] = $yaxis->y;
		$this->values[6] = $yaxis->z;
		$this->values[7] = -$dot2;
		$this->values[8] = $zaxis->x;
		$this->values[9] = $zaxis->y;
		$this->values[10] = $zaxis->z;
		$this->values[11] = -$dot3;
		$this->values[15] = 1;
	}
	
	function translate($x, $y, $z) {
		$this->loadIdentity();
		$this->values[3] = $x;
		$this->values[7] = $y;
		$this->values[11] = $z;
	}
	
	function scale($x, $y, $z) {
		$this->loadIdentity();
		$this->values[0] = $x;
		$this->values[5] = $y;
		$this->values[10] = $z;
	}
	
	function matrix() {
		$this->values = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	}
};

function multiply($matrix1, $matrix2) {
	$retour = new matrix();
		
	for ($i = 0; $i < 4; ++$i)
		for ($j = 0; $j < 4; ++$j)
			for ($k = 0; $k < 4; ++$k)
				$retour->values[$retour->get($i, $j)] += $matrix1->values[$matrix1->get($i, $k)] * $matrix2->values[$matrix2->get($k, $j)];
	return $retour;
}

$im = imagecreatetruecolor($width, $height);

$fond = imagecolorallocate($im, 0, 0, 0);
$blanc = imagecolorallocate($im, 255, 255, 255);

$backbuffer = array($width * $height);
for ($i = 0; $i < $width * $height; ++$i)
	$backbuffer[$i] = $clipping;

$projection = new matrix();
$projection->projection(45, $width / $height, 1, $clipping);

$view = new matrix();
$view->lookat(new point(2.5, 0.7, 1.3), new point(0, 0, 0), new point(0, 1, 0));

$matrice = multiply($projection, $view);

$cube = new mesh();

$taille = 0.5;
$cube->points[0] = new point($taille, $taille, $taille, 255, 0, 0);
$cube->points[1] = new point(-$taille, $taille, $taille, 255, 128, 128);
$cube->points[2] = new point(-$taille, -$taille, $taille, 200, 200, 0);
$cube->points[3] = new point($taille, -$taille, $taille, 255, 255, 60);
$cube->points[4] = new point($taille, -$taille, -$taille, 128, 128, 0);
$cube->points[5] = new point($taille, $taille, -$taille, 200, 0, 0);
$cube->points[6] = new point(-$taille, $taille, -$taille, 255, 45, 45);
$cube->points[7] = new point(-$taille, -$taille, -$taille, 255, 255, 128);

$cube->triangle1[0] = 0; $cube->triangle2[0] = 1; $cube->triangle3[0] = 2;
$cube->triangle1[1] = 0; $cube->triangle2[1] = 2; $cube->triangle3[1] = 3;
$cube->triangle1[2] = 4; $cube->triangle2[2] = 5; $cube->triangle3[2] = 7;
$cube->triangle1[3] = 5; $cube->triangle2[3] = 6; $cube->triangle3[3] = 7;
$cube->triangle1[4] = 0; $cube->triangle2[4] = 3; $cube->triangle3[4] = 4;
$cube->triangle1[5] = 0; $cube->triangle2[5] = 4; $cube->triangle3[5] = 5;
$cube->triangle1[6] = 1; $cube->triangle2[6] = 2; $cube->triangle3[6] = 7;
$cube->triangle1[7] = 1; $cube->triangle2[7] = 6; $cube->triangle3[7] = 7;
$cube->triangle1[8] = 0; $cube->triangle2[8] = 1; $cube->triangle3[8] = 6;
$cube->triangle1[9] = 0; $cube->triangle2[9] = 5; $cube->triangle3[9] = 6;
$cube->triangle1[10] = 2; $cube->triangle2[10] = 3; $cube->triangle3[10] = 7;
$cube->triangle1[11] = 3; $cube->triangle2[11] = 4; $cube->triangle3[11] = 7;

$cube->scale->scale(0.5, 0.5, 0.5);
$cube->translation->translate(0.2, 0.5, 0.3);

$cube->render($matrice, $width, $height, $im, $backbuffer, $wireframe);

imagejpeg($im);

Conclusion :


J'utilise les mêmes matrices que DirectX

Voici le site qui contient les explications :
http://aaprog.free.fr/?page=php/examples/3dengine1
http://aaprog.free.fr/?page=php/examples/3dengine2

Si un jour je supprime le site je mettrai ces explications dans une page html dans le zip
Le zip, qui d'ailleurs contient plusieurs fichiers .php
Le dernier est celui qui a le plus grand numéro (ils s'appelent tous moteur3d#.php où # est un nombre)
J'ai mis les anciennes versions tout simplement pour que vous arriviez à comprendre au fur et à mesure

Codes Sources

A voir également

Ajouter un commentaire Commentaires
CyberP
Messages postés
283
Date d'inscription
mercredi 8 janvier 2003
Statut
Membre
Dernière intervention
4 juillet 2007
2
5 mai 2006 à 17:11
ben il faut mettre les balises php autour
<?php tout devant et ?> à la fin
cs_spyro666
Messages postés
137
Date d'inscription
lundi 10 janvier 2005
Statut
Membre
Dernière intervention
28 août 2007

5 mai 2006 à 09:39
J'ai un tout autre problème avec ce script : il ne s'exécute tout simplement pas :(... quand j'affiche la page tel quel il m'affiche le code et quand je donne la page comme source d'image ça ne fonctionne pas non plus. Tu pourrais me donner un exemple d'implémentation qui fonctionne ?Merci
CyberP
Messages postés
283
Date d'inscription
mercredi 8 janvier 2003
Statut
Membre
Dernière intervention
4 juillet 2007
2
2 août 2005 à 09:29
en effet c'est un problème avec les bmp 8 (je viens de le remarquer)
je vais essayer de dépanner
merci
cs_MATHIS49
Messages postés
368
Date d'inscription
vendredi 10 octobre 2003
Statut
Membre
Dernière intervention
14 mai 2010
1
1 août 2005 à 18:30
Super ton site, bravo ;)
Par contre j'ai juste un probleme avec ton script pour le BMP , sou s firefox jai des caracteres et sous IE l'image ne s'affiche pas
: http://angersbouge.com/Projet%20BMP/
CyberP
Messages postés
283
Date d'inscription
mercredi 8 janvier 2003
Statut
Membre
Dernière intervention
4 juillet 2007
2
1 août 2005 à 14:47
Voilà j'ai mis à jour...
Notez que le premier lien que j'ai mis pour les explications n'est pas tout à fait terminé au moment où j'ai fait la mise à jour mais ça ne devrait pas tarder. Le deuxième n'est pas encore fait et je le ferai quand le backbuffer marchera (histoire d'avoir un beau cube)
Afficher les 16 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.