Utiliser les memblocks avec 3d games creator pro - Games Creators Network
Article     Discussion     Modifier     Historique     Forums     Salon IRC

Utiliser les memblocks avec 3d games creator pro

Un article de Games Creators Network.


Sommaire

[modifier] Qu'est-ce qu'un memblock ?

Un memblock est une zone de mémoire utilisable par 3D Games Creator Pro (DBP). Les memblocks peuvent contenir des images, des objets 3D ou même des sons, mais il faut connaître les différents formats pour pouvoir les utiliser. On peut créer des memblocks grâce à la commande "make memblock", mais il est aussi possible de récupérer le memblock d'une image avec "make memblock from image" (ou l'inverse : "make image from memblock"). Voici un exemple montrant comment écrire dans un memblock :

make memblock 1, 15
for t=0 to 14
   write memblock byte 1, t, 10+3*t
next t
for t=0 to 14
   print memblock byte(1, t)
next t
wait key

Vous pouvez remarquer que le premier byte du memblock est numéroté 0, donc le dernier est 14 si le memblock contient 15 bytes.

Note : le mot "byte" désigne tout simplement un octet en anglais, ne le confondez pas avec le mot "bit" ! En effet, un byte/octet contient 8 bits.

Il est possible d'écrire autre chose que des bytes dans un memblock. En effet, on peut y écrire :

  • des bytes
  • des words (composés de 2 bytes)
  • des dwords (composés de 4 bytes)
  • des floats (composés de 4 bytes)

Il est important de connaître le nombre de bytes composant la variable qu'on veut y écrire. Voici un exemple expliquant pourquoi

Le programmeur ayant écrit cela a oublié que les dwords font 4 bytes de long, donc lorsqu'il lance le programme, il y a une erreur. En écrivant 4 bytes à partir du onzième, on arrive à 14 bytes, donc on sort du memblock.

make memblock 1, 12
 for t=0 to 11
 	write memblock dword 1, t, 2*t
 next t
 for t=0 to 11
 	print memblock dword(1, t)
 next t
 wait key

En cherchant un peu, le programmeur comprend son erreur et change la taille de son memblock. Cela marche parfaitement, mais les valeurs sont fantaisistes...

make memblock 1, 15
 for t=0 to 11
 	write memblock dword 1, t, 2*t
 next t
 for t=0 to 11
 	print memblock dword(1, t)
 next t
 wait key

Finalement, il comprend que si on écrit 4 bytes à partir du zéro, puis 4 à partir du 1, on "écrase" ce qu'on avait écrit en premier lieu. Voici un schéma expliquant mieux ce problème :

Position 0 1 2 3 4 5 6
Premier dword A1 A2 A3 A4
Seconddword B1 B2 B3 B4
Troisième dword C1 C2 C3 C4
Quatrième dword D1 D2 D3 D4
Résultat A1 B1 C1 D1 D2 D3 D4

Il faut donc écrire un dword tous les 4 bytes :

make memblock 1, 12*4
 for t=0 to 11
 	write memblock dword 1, 4*t, 2*t
 next t
 for t=0 to 11
 	print memblock dword(1, 4*t)
 next t
 wait key

Je vous conseille de vous exercer un peu avec les memblocks si vous ne les avez jamais utilisés avant de poursuivre ce tutoriel.

[modifier] Comment est composée une image ?

Remarque 1 : le format de l'image contenue dans un memblock dépend de la résolution choisie par l'utilisateur et non celle du jeu. Toutes les informations contenues dans ce tutoriel ne sont valables que pour une profondeur de 32 bits.

Remarque 2 : Les bitmaps sont composés exactement de la même manière que les images. Tout ce qui est dit ici est aussi valable pour les bitmaps.

Alors, une image, qu'est-ce que c'est ? Ce sont des pixels. Mais ils ne sont pas placés n'importe comment : ils sont numérotés de gauche à droite et de bas en haut de cette manière :

1234
5678
9101112

Si je vous disais qu'une image a 24 pixels, seriez-vous capables de me donner sa largeur et sa hauteur ? Non, vous ne pourriez que faire des suppositions. Il faut donc aussi préciser ces deux informations. Ainsi, notre image se compose de :

  • largeur
  • hauteur
  • nombre de pixels

Si vous connaissez les deux premières informations, vous pouvez retrouver la troisième sans problème. De plus, il faut préciser le nombre de bits par pixels. Comme je l'ai précisé plus haut, ce tutoriel ne tiendra compte que des images en 32 bits. Ainsi, les informations concernant une image sont :

  • largeur
  • hauteur
  • 32

Ces informations sont stockées sous forme de dwords par DBP, les en-têtes de l'image font donc 12 bytes. Voici un programme qui montre comment utiliser ces en-têtes :

get image 1, 0, 0, 24, 16
 make memblock from image 1,1
 print "Largeur> ", memblock dword(1, 0)
 print "Hauteur> ", memblock dword(1, 4)
 print "Profondeur> ", memblock dword(1, 8)
 print "Nombre de pixels> ", memblock dword(1, 0)*memblock dword(1, 4)
 wait key

Bon, et cela nous avance à quoi ? Pour le moment pas à grand chose. Vous pouvez maintenant connaître les dimensions d'une image, mais c'est tout. Cela nous mène au point suivant :

[modifier] Comment sont stockées les couleurs dans une image et comment les modifier ?

La résolution est de 32 bits. Un byte est composé de 8 bits. Il y a donc 4 bytes par pixel, ce qui fait un dword. Pour créer une image de X * Y pixels, il faut créer un memblock contenant 12 + X*Y*4 bytes, cela donne :

taillex = 128
 tailley = 64
 make memblock 1, 12 + (taillex*tailley*4)

Ensuite, il faut insérer les données, puis créer l'image...

taillex = 128
 tailley = 64
 make memblock 1, 12 + (taillex*tailley*4)
 write memblock dword 1, 0, taillex
 write memblock dword 1, 4, tailley
 write memblock dword 1, 8, 32
 make image from memblock 1,1
 paste image 1, 0,0
 wait key

L'image ne contient rien, ou alors quelques pixels colorés bizarrement ? C'est normal. Si l'image ne contient rien, c'est que le memblock a été crée dans une zone vierge. S'il y a quelques pixels colorés, c'est que la zone contenait encore quelques informations, mais ce n'est absolument pas grave.

La manière la plus simple pour colorer les pixels est d'attribuer une valeur aléatoire à chaque byte du memblock - sauf les 12 premiers contenant les en-têtes bien entendu. Cela donne :

taillex = 128
 tailley = 256
 make memblock 1, 12 + (taillex*tailley)*4
 write memblock dword 1, 0, taillex
 write memblock dword 1, 4, tailley
 write memblock dword 1, 8, 32
 for t=12 to get memblock size(1)-1
 	write memblock byte 1, t, rnd(255)
 next t
 make image from memblock 1,1
 paste image 1, 0,0
 wait key

D'accord, ce code est absolument inutile, cette image est moche et on ne contrôle pas la couleur de chaque pixel. Il va falloir arranger ça. Comme je l'ai dit plus haut, un pixel est codé sur 4 bytes, c'est-à-dire un dword. Il faut donc chercher le numéro du premier byte du pixel.


Combien y a-t-il de pixels avant celui se trouvant aux coordonnées (x,y) ? Image:Image montrant comment trouver le numéro d\'un pixel.PNG Une fois ce résultat trouvé, il suffira de multiplier par 4 puis d'ajouter 12 pour avoir le numéro du premier byte.

Tout d'abord, il faut se demander combien de lignes il y a en-dessus du pixel : c'est y-1

Comme il y a taillex pixels par ligne, on peut dire qu'il y a (y-1)*taillex pixels en-dessus de celui dont les coordonnées sont (x,y)

Ensuite, combien y a-t-il de pixels à sa gauche ? Il y en a x-1

Après, il suffit de faire la somme, donc n = ( y - 1 ) * taillex + x - 1

Et à quel byte cela correspond ? Il faut d'abord multiplier n par 4 puis ajouter 12 : b = 12 + 4*n. Voici maintenant le programme que nous pouvons faire :

taillex = 128
 tailley = 256
 make memblock 1, 12 + (taillex*tailley)*4
 write memblock dword 1, 0, taillex
 write memblock dword 1, 4, tailley
 write memblock dword 1, 8, 32
 for x=1 to taillex-1
 	for y=1 to tailley-1
 		n = ( y - 1 ) * taillex + x - 1
 		b = 12 + 4*n
 		write memblock dword 1, b, rgb(128,128,128)
 	next y
 next x
 make image from memblock 1,1
 paste image 1, 0,0
 wait key

Maintenant que ce code fonctionne, il serait intéressant d'en faire des fonctions pour pouvoir l'utiliser plus facilement. En voici quelques :

m_dot() : équivalent de dot

function m_dot(mem, x, y, color)
 if memblock exist(mem)
 	if x>0
 		if y>0
 			if x<=memblock dword(mem,0)
 				if y<=memblock dword(mem,4)
 					b = 12 + 4*(( y - 1 ) * memblock dword(1,0) + x - 1)
 					write memblock dword mem, b, color
 				endif
 			endif
 		endif
 	endif
 endif
 endfunction

m_point() : équivalent de point

function m_point(mem, x, y)
 if memblock exist(mem)
 	if x>0
 		if y>0
 			if x<=memblock dword(mem,0)
 				if y<=memblock dword(mem,4)
 					b = 12 + 4*(( y - 1 ) * memblock dword(1,0) + x - 1)
 					color = memblock dword(mem, b)
 				endif
 			endif
 		endif
 	endif
 endif
 endfunction color

Dans ces deux fonctions, j'ai ajouté quatre conditions vérifiant si le pixel se trouve bien dans l'image. C'est une sécurité pour empêcher le programme de planter, mais cela le ralenti aussi. Si vous êtes sûr que vous n'essaierez pas d'atteindre un pixel en dehors de l'image, vous pouvez enlever ces conditions.


[modifier] Quelques applications des memblocks et des images

L'avantage des memblocks est qu'il est possible de modifier des images en temps réel. Vous pouvez utiliser la commande make image from memblock sans à avoir à effacer l'image, cela représente donc un gain de temps considérable.

Animer la texture d'un objet avec une courbe

Sync on
 Sync rate 0
 
 rem création d'un memblock
 taillex = 128
 tailley = 64
 make memblock 1, 12 + (taillex*tailley*4)
 write memblock dword 1, 0, taillex
 write memblock dword 1, 4,tailley
 write memblock dword 1, 8,32 
 
 rem création d'un plain texturé
 make object plain 1, 128, 64
 make image from memblock 1,1
 texture object 1,1
 
 do
 
 	rem modification de la texture
 	inc angle,5
 	for x=1 to 128
 		inc angle2
 		for y=1 to 64
 			if (y-32) = int(32*sin(angle+(5*x))*cos(angle2*3))
 				color = rgb(255,0,0)
 			else
 				color = rgb(0,255,0)
 			endif
 			b = 12 + 4*(( y - 1 ) * memblock dword(1,0) + x - 1)
 			write memblock dword 1, b, color
 		next y
 	next x
 	rem mise à jour de la texture
 	make image from memblock 1, 1
 	rem rotation du plain
 	yrotate object 1, wrapvalue(object angle y(1)+1)
 	sync
 loop

La ligne "if (y-32) = int(32*sin(angle+(5*x))*cos(angle2*3))" peut sembler un peu compliquée, mais ne l'est finalement pas. Je regarde si le pixel est sur la courbe dessinée par la fonction utilisant le sinus et le cosinus, c'est tout.

Je n'ai pas utilisé la fonction m_dot() pour avoir une vitesse plus grande.


Animer la texture d'un objet de manière étrange

Sync on
 Sync rate 0
 
 taillex = 32
 tailley = 32
 make memblock 1, 12 + (taillex*tailley*4)
 write memblock dword 1, 0, taillex
 write memblock dword 1, 4, tailley
 write memblock dword 1, 8, 32
 
 make image from memblock 1, 1
 make object cube 1,1
 texture object 1, 1
 fade object 1, 200
 
 angle1 as float
 angle2 as float
 angle3 as float
 angle1 = rnd(360)
 angle2 = rnd(360)
 angle3 = rnd(360)
 do
 	inc angle1, 0.25
 	inc angle2, 0.31
 	inc angle3, 0.17
 	for x=1 to 32
 		for y=1 to 32
 			red = sqrt((16-x)^2 + (16-y)^2)*cos(angle1)*3.75
 			green = abs(16-x)*7.75*sin(angle2)
 			blue = sqrt(x^2-y)*cos(angle3)
 			b = 12 + 4*(( y - 1 ) * memblock dword(1,0) + x - 1)
 			write memblock dword 1, b, rgb(red,green,blue)
 		next y
 	next x
 
 	make image from memblock 1,1
 	yrotate object 1, wrapvalue(object angle y(1)+1)
 	sync
 loop

[modifier] Comment est composé un objet 3D ?

Remarque : je me base sur un bout de code que Kevil a posté sur le forum officiel en mai 2003

Image:Matrice_crée_par_des_memblocks.jpg

La, ça devient un tout petit peu plus compliqué que les images. Une image n'a besoin que de trois types d'informations (largeur, hauteur, couleur de pixel), mais un objet 3D est plus complexe. Tout d'abord, un peu de vocabulaire, pour que vous puissiez comprendre la suite. Regardez ceci :

make object triangle 1,-0.5,-0.5,-0.5,0.5,0.5,0.5,1.5,0,-1.5
 set object wireframe 1,1
 do
 	yrotate object 1, wrapvalue(object angle y(1)+0.1)
 loop

Ce que vous voyez pivoter à l'écran est l'objet 3D le plus simple qui soit : un triangle. Tous les objets 3D sont composés exclusivement de triangles.

L'endroit où deux "lignes" se rejoignent s'appelle un vertex. Chaque triangle en a trois. Le pluriel de vertex est "vertices".

Le triangle formé par trois vertices est appelé "face". Les objets 3D peuvent être composés de plusieurs centaines de faces, mais plus ils en ont, plus ils ralentiront le jeu. Il faut noter que les objets 3D téléchargeable sur des sites comme [3DCafé] contiennent souvent un nombre impressionnant de faces, les rendant totalement inutilisables pour un jeu.

Je ne sais pas s'il est possible de créer des objets 3d animés avec les memblocks, et je dois dire que ce n'est pas mon principal soucis : créer un objet statique est déjà très difficile, l'animer est encore pire. Pour cela, autant utiliser un logiciel...

[modifier] Les informations contenues dans les objets 3D

Chaque vertex doit contenir ces informations :

  • Coordonnées : trois floats représentant ses coordonnées X, Y et Z par rapport au centre de l'objet
  • Le vecteur normale : trois floats qui indiquent comment la face devra renvoyer la lumière, j'en parlerai plus loin.
  • La couleur : un dword qui spécifie la couleur du vertex
  • Les coordonnées UV : deux floats (dont la valeur varie entre 0 et 1) indiquant quelle partie de la texture prendre

Si vous comptez les bytes composant un vertex, vous arrivez à 36.


Comme les images, il y a des en-têtes donnant des informations sur le futur objet 3D. Si je parle des en-têtes seulement maintenant, c'est parce qu'il fallait d'abord que vous ayez quelques notions de bases sur le contenu d'un objet 3D. Les en-têtes contiennent :

  • Le format : un dword contenant la valeur 338.
  • Le nombre de bytes par vertex : dans notre cas, 36. Il est possible d'en avoir un autre nombre, mais je n'ai pas trouvé d'informations supplémentaires.
  • Le nombre de vertices : aussi un dword, mais comme on ne peut avoir plus de 65535 faces, la valeur maximale est 196 605.

Tout comme ceux des images, les en-têtes des memblocks contiennent 12 bytes, donc lorsque vous créez un memblock pour faire un objet 3D de n faces, il faudra que sa taille soit 12 + (3*36*n).

[modifier] Un exemple d'objet 3D fait avec les memblocks

De la théorie, c'est bien beau, mais un exemple, c'est mieux, non ? Voici l'exemple (traduit) que Kevil a écrit sur le forum officiel :

sync on
 
 rem choix des informations sur le triangle
 polys=1
 x1#=-3.0 : y1#=2.0 : z1#=1.0
 x2#=3.0 : y2#=2.0 : z2#=-1.0
 x3#=-1.0 : y3#=-1.0 : z3#=0.0
 
 rem créer un memblock avec la bonne taille
 make memblock 1,(polys*3*36)+12
 
 rem écriture des en-têtes
 rem format FVF
 write memblock dword 1,0,338
 
 rem nombre de bytes par vertex
 write memblock dword 1,4,36
 
 rem Nombre de vertices
 write memblock dword 1,8,polys*3
 
 rem écriture des données pour le premier vertex
 rem position : trois floats
 write memblock float 1,12,x1#
 write memblock float 1,16,y1#
 write memblock float 1,20,z1#
 rem la normale (elle n'a pas été calculée rigoureusement !)
 write memblock float 1,24,0
 write memblock float 1,28,0
 write memblock float 1,32,-1.00
 rem la couleur (rouge)
 write memblock dword 1,36,rgb(255,0,0)
 rem les coordonnées UV pour la texture.
 rem Pour l'instant, elles ne servent à rien car on ne texture pas.
 write memblock float 1,40,0.00
 write memblock float 1,44,0.00
 
 rem données du second vertex. Tout est identique au premier, sauf la
 rem couleur (ici : verte)
 write memblock float 1,12+36,x2#
 write memblock float 1,16+36,y2#
 write memblock float 1,20+36,z2#
 write memblock float 1,24+36,0
 write memblock float 1,28+36,0
 write memblock float 1,32+36,-1.00
 write memblock dword 1,36+36,rgb(0,255,0)
 write memblock float 1,40+36,1.00
 write memblock float 1,44+36,0.00
 
 rem et le dernier vertex (bleu)
 write memblock float 1,12+72,x3#
 write memblock float 1,16+72,y3#
 write memblock float 1,20+72,z3#
 write memblock float 1,24+72,0
 write memblock float 1,28+72,0
 write memblock float 1,32+72,-1.00
 write memblock dword 1,36+72,rgb(0,0,255)
 write memblock float 1,40+72,0.50
 write memblock float 1,44+72,1.00
 
 rem créer un mesh à partir du memblock
 make mesh from memblock 1,1
 
 rem créer un objet à partir du mesh
 make object 1,1,0
 
 position camera 0,0,-10
 
 do
 
 sync
 loop

Bon, ce n'est qu'un triangle, mais vous pouvez remarquer qu'il est joliement coloré. On ne peut faire cela avec les commandes de base, il faut passer par les memblocks pour pouvoir le faire.

[modifier] L'ordre des vertices...

... est très important. On ne peut voir une face que depuis un côté et c'est l'ordre des vertices qui le définit. Dans le code précédent, remplacez la boucle principale par celle-ci :

do
 yrotate object 1, wrapvalue(object angle y(1)+0.1)
 sync
 loop

Vous remarquerez que le triangle n'est visible que depuis un côté. De plus, il a une coloration plutôt étrange lorsqu'on le voit sur le côté. Pour la coloration, on verra plus tard, il faut s'amuser avec les normales. Et pour qu'on le voie depuis l'autre côté ? Il suffit d'inverser deux vertices pour changer leur ordre :

x3#=-3.0 : y3#=2.0 : z3#=1.0
 x2#=3.0 : y2#=2.0 : z2#=-1.0
 x1#=-1.0 : y1#=-1.0 : z1#=0.0

J'ai remplacé les 3 par 1 et vice-versa.

Et pour pouvoir voir la face depuis les deux côtés ? Ce n'est pas directement possible. Il faut soit créer une seconde face et la plaquer derrière, soit régler l'objet lui-même pour qu'on puisse voir les faces cachées :

rem créer un mesh à partir du memblock
 make mesh from memblock 1,1
 
 rem créer un objet à partir du mesh
 make object 1,1,0
 
 rem réglage pour qu'on puisse voir les faces cachées
 set object cull 1, 0

(J'ai laissé les quelques lignes précédentes pour qu'on puisse mieux se situer dans le code)

[modifier] Les normales

Comme vous avez pu le constater, lorsque l'objet pivote, ses jolies couleurs ne résistent pas au lavage. Il devient gris et terne : la lumière n'est pas gérée correctement. C'est pourquoi il faut maintenant jeter un oeil au normales. Qu'est-ce qu'une normale ? C'est un vecteur qui est perpendiculaire à un plan.

Image:La normale d\'une face.PNG

Et la normale, on la calcule comment ? Il suffit de faire le produit vectoriel de deux vecteurs. Comme vecteurs, on peut prendre deux côtés du triangle. Voici ce que cela donne :

v1x# = x2# - x1#
 v1y# = y2# - y1#
 v1z# = z2# - z1#
 
 v2x# = x3# - x1#
 v2y# = y3# - y1#
 v2z# = z3# - z1#
 
 nx# = y1#*(z2#-z3#) - y2#*(z1#-z3#) + y3#*(z1#-z2#)
 ny# = x1#*(z3#-z2#) + x2#*(z1#-z3#) - x3#*(z1#-z2#)
 nz# = x1#*(y2#-y3#) - x2#*(y1#-y3#) + x3#*(y1#-y2#)

nx#, ny# et nz# sont les composantes du vecteur normale. On regarde ce que cela donne ? Voici le code complet :

sync on
 
 rem choix des informations sur le triangle
 polys=1
 x1#=-3.0 : y1#=2.0 : z1#=1.0
 x2#=3.0 : y2#=2.0 : z2#=-1.0
 x3#=-1.0 : y3#=-1.0 : z3#=0.0
 
 rem calcul du vecteur normale
 v1x# = x2# - x1#
 v1y# = y2# - y1#
 v1z# = z2# - z1#
 
 v2x# = x3# - x1#
 v2y# = y3# - y1#
 v2z# = z3# - z1#
 
 nx# = y1#*(z2#-z3#) - y2#*(z1#-z3#) + y3#*(z1#-z2#)
 ny# = x1#*(z3#-z2#) + x2#*(z1#-z3#) - x3#*(z1#-z2#)
 nz# = x1#*(y2#-y3#) - x2#*(y1#-y3#) + x3#*(y1#-y2#)
 
 rem créer un memblock avec la bonne taille
 make memblock 1,(polys*3*36)+12
 
 rem écriture des en-têtes
 rem format FVF
 write memblock dword 1,0,338
 
 rem nombre de bytes par vertex
 write memblock dword 1,4,36
 
 rem Nombre de vertices
 write memblock dword 1,8,polys*3
 
 rem écriture des données pour le premier vertex
 rem position : trois floats
 write memblock float 1,12,x1#
 write memblock float 1,16,y1#
 write memblock float 1,20,z1#
 write memblock float 1,24,nx#
 write memblock float 1,28,ny#
 write memblock float 1,32,nz#
 rem la couleur (rouge)
 write memblock dword 1,36,rgb(255,0,0)
 rem les coordonnées UV pour la texture.
 write memblock float 1,40,0.00
 write memblock float 1,44,0.00
 
 rem données du second vertex. Tout est identique au premier, sauf la
 rem couleur (ici : verte)
 write memblock float 1,12+36,x2#
 write memblock float 1,16+36,y2#
 write memblock float 1,20+36,z2#
 write memblock float 1,24+36,nx#
 write memblock float 1,28+36,ny#
 write memblock float 1,32+36,nz#
 write memblock dword 1,36+36,rgb(0,255,0)
 write memblock float 1,40+36,1.00
 write memblock float 1,44+36,0.00
 
 rem et le dernier vertex (bleu)
 write memblock float 1,12+72,x3#
 write memblock float 1,16+72,y3#
 write memblock float 1,20+72,z3#
 write memblock float 1,24+72,nx#
 write memblock float 1,28+72,ny#
 write memblock float 1,32+72,nz#
 write memblock dword 1,36+72,rgb(0,0,255)
 write memblock float 1,40+72,0.50
 write memblock float 1,44+72,1.00
 
 rem créer un mesh à partir du memblock
 make mesh from memblock 1,1
 
 rem créer un objet à partir du mesh
 make object 1,1,0
 
 rem réglage pour qu'on puisse voir les faces cachées
 set object cull 1, 0
 
 position camera 0,0,-10
 
 make light 1
 position light 1, 0, 0, -10
 set light range 1, 100
 
 do
    yrotate object 1, wrapvalue(object angle y(1)+0.1)
    sync
 loop

Vous remarquerez que j'ai ajouté une lumière pour que ça soit plus joli. Bon, c'est déjà mieux, mais ... lorsque la face "nous tourne" le dos, c'est toujours aussi terne. On peut y faire quelque chose ?

Malheureusement non : la seule solution est d'avoir deux faces, chacune avec son propre vecteur normal. Allons, ce n'est pas la fin du monde : qui sait faire une face sait en faire plusieurs.


[modifier] Les coordonnées UV

Le dernier point de ce tutoriel sera la texture de votre objet. J'ai failli oublier ce point même s'il est très important. Bon, si vous jetez un oeil un peu plus haut, vous pourrez remarquer dans le code créant un triangle que pour chaque vertex on a deux floats : les coordonnées UV.

Jetez un oeil à cette image :

Image:Trois_vertices_sur_une_photo.JPG

Comme vous devez vous en douter, la figure blanche sur l'image représente une face de votre objet 3D. Et les trois carrés blancs aux sommets du triangle ? Ce sont les vertices. Les coordonnées UV sont les coordonnées des vertices sur l'image.

Attention, ce ne sont pas des coordonnées en pixels mais une valeur comprise entre 0 et 1. (0, 0) correspond au pixel se trouvant en haut à gauche et (0.5, 0.5) à celui se trouvant au milieu. L'avantage de cette méthode est que la taille de la texture n'influence pas les coordonnées UV.

Je pense que maintenant vous en savez assez pour vous contenter d'un dernier exemple d'objet texturé.

sync on
 rem création d'une texture
 for x=1 to 64
 	for y=1 to 64
 		dot x, y, rgb(4*x,4*y, 2*(x+y))
 	next y
 next x
 get image 1, 0, 0, 64, 64
 
 rem choix des informations sur le triangle
 polys=1
 x1#=-3.0 : y1#=2.0 : z1#=1.0
 x2#=3.0 : y2#=2.0 : z2#=-1.0
 x3#=-1.0 : y3#=-1.0 : z3#=0.0
 
 rem calcul du vecteur normale
 v1x# = x2# - x1#
 v1y# = y2# - y1#
 v1z# = z2# - z1#
 
 v2x# = x3# - x1#
 v2y# = y3# - y1#
 v2z# = z3# - z1#
 
 nx# = y1#*(z2#-z3#) - y2#*(z1#-z3#) + y3#*(z1#-z2#)
 ny# = x1#*(z3#-z2#) + x2#*(z1#-z3#) - x3#*(z1#-z2#)
 nz# = x1#*(y2#-y3#) - x2#*(y1#-y3#) + x3#*(y1#-y2#)
 
 rem créer un memblock avec la bonne taille
 make memblock 1,(polys*3*36)+12
 
 rem écriture des en-têtes
 rem format FVF
 write memblock dword 1,0,338
 
 rem nombre de bytes par vertex
 write memblock dword 1,4,36
 
 rem Nombre de vertices
 write memblock dword 1,8,polys*3
 
 rem écriture des données pour le premier vertex
 rem position : trois floats
 write memblock float 1,12,x1#
 write memblock float 1,16,y1#
 write memblock float 1,20,z1#
 write memblock float 1,24,nx#
 write memblock float 1,28,ny#
 write memblock float 1,32,nz#
 rem la couleur (rouge)
 write memblock dword 1,36,rgb(128,128,128)
 rem les coordonnées UV pour la texture.
 write memblock float 1,40,0.00
 write memblock float 1,44,0.00
 
 rem données du second vertex. Tout est identique au premier, sauf la
 rem couleur (ici : verte)
 write memblock float 1,12+36,x2#
 write memblock float 1,16+36,y2#
 write memblock float 1,20+36,z2#
 write memblock float 1,24+36,nx#
 write memblock float 1,28+36,ny#
 write memblock float 1,32+36,nz#
 write memblock dword 1,36+36,rgb(128,128,128)
 write memblock float 1,40+36,1.00
 write memblock float 1,44+36,0.00
 
 rem et le dernier vertex (bleu)
 write memblock float 1,12+72,x3#
 write memblock float 1,16+72,y3#
 write memblock float 1,20+72,z3#
 write memblock float 1,24+72,nx#
 write memblock float 1,28+72,ny#
 write memblock float 1,32+72,nz#
 write memblock dword 1,36+72,rgb(128,128,128)
 write memblock float 1,40+72,1.00
 write memblock float 1,44+72,1.00
 
 rem créer un mesh à partir du memblock
 make mesh from memblock 1,1
 
 rem créer un objet à partir du mesh
 make object 1,1,1
 
 rem réglage pour qu'on puisse voir les faces cachées
 set object cull 1, 0
 
 position camera 0,0,-10
 
 make light 1
 position light 1, 0, 0, -10
 set light range 1, 100
 
 do
 	paste image 1, 0, 0
 	yrotate object 1, wrapvalue(object angle y(1)+0.1)
 	sync
 loop

Remarques

  • Si vous jetez un oeil aux coordonnées UV, vous remarquerez que je texture l'objet avec la partie supérieure droite de l'image.
  • J'ai changé la couleur des vertices en gris (RGB 128 128 128) pour ne pas modifier l'affichage de la texture
  • Si vous ne comprendez pas pourquoi l'objet est texturé, jetez un oeil à l'aide sur "make object".

[modifier] Modifier un objet 3D en temps réel

Le principe est simple : dans la boucle principale, modifiez les données du memblock puis mettez à jour l'objet. Si vous êtes arrivé jusqu'ici, vous comprendrez sans problème ce code.

rem création d'un memblock d'objet 3D, mais sans remplir les normales
 rem et les sommets maintenant : ils seront modifiés en temps 
 polys=1
 make memblock 1,(polys*3*36)+12
 write memblock dword 1,0,338
 write memblock dword 1,4,36
 write memblock dword 1,8,polys*3
 write memblock dword 1,36,rgb(255,0,0)
 write memblock float 1,40,0.00
 write memblock float 1,44,0.00
 write memblock dword 1,36+36,rgb(0,255,0)
 write memblock float 1,40+36,1.00
 write memblock float 1,44+36,0.00
 write memblock dword 1,36+72,rgb(0,0,255)
 write memblock float 1,40+72,0.50
 write memblock float 1,44+72,1.00
 
 rem créer un objet à partir du mesh
 make mesh from memblock 1, 1
 make object 1,1,0
 set object cull 1, 0
 
 rem création d'un "sol" pour avoir un repère dans l'espace
 make matrix 1, 20, 20, 10, 10
 position matrix 1, -10,0,-10
 
 rem des angles qui serviront à modifier les coordonnées des vertices
 dim angle(9) as float
 for t=1 to 9
 	angle(9)=rnd(360)
 next t
 do
 	rem modification des coordonnées des vertices
 	x1#=-3.0 + 3*sin(angle(1))
 	y1#=2.0 + 2*sin(angle(2))
 	z1#=1.0 + 3*sin(angle(3))
 	x2#=3.0 + 2*sin(angle(4))
 	y2#=2.0 + 2*sin(angle(5))
 	z2#=-1.0 + 3*sin(angle(6))
 	x3#=-1.0 + 3*sin(angle(7))
 	y3#=-1.0 + 2*sin(angle(8))
 	z3#=0.0 + 3*sin(angle(9))
 	for t=1 to 9
 		inc angle(t), 0.2+0.1*t+0.15*cos(angle(t))
 	next t
 
 	rem calcul de la normale
 	v1x# = x2# - x1#
 	v1y# = y2# - y1#
 	v1z# = z2# - z1#
 	v2x# = x3# - x1#
 	v2y# = y3# - y1#
 	v2z# = z3# - z1#
 	nx# = y1#*(z2#-z3#) - y2#*(z1#-z3#) + y3#*(z1#-z2#)
 	ny# = x1#*(z3#-z2#) + x2#*(z1#-z3#) - x3#*(z1#-z2#)
 	nz# = x1#*(y2#-y3#) - x2#*(y1#-y3#) + x3#*(y1#-y2#)
 
 	rem écriture des vertices dans le memblock
 	write memblock float 1,12,x1#
 	write memblock float 1,16,y1#
 	write memblock float 1,20,z1#
 	write memblock float 1,24,nx#
 	write memblock float 1,28,ny#
 	write memblock float 1,32,nz#
 	write memblock float 1,12+36,x2#
 	write memblock float 1,16+36,y2#
 	write memblock float 1,20+36,z2#
 	write memblock float 1,24+36,nx#
 	write memblock float 1,28+36,ny#
 	write memblock float 1,32+36,nz#
 	write memblock float 1,12+72,x3#
 	write memblock float 1,16+72,y3#
 	write memblock float 1,20+72,z3#
 	write memblock float 1,24+72,nx#
 	write memblock float 1,28+72,ny#
 	write memblock float 1,32+72,nz#
 
 	rem màj du mesh
 	make mesh from memblock 1,1
 
 	rem màj de l'objet
 	change mesh 1,0,1
 	set object cull 1, 0
 
 	rem gestion de la caméra
 	inc angle, mousemovex()
 	set camera to follow 0,0,0,angle, 10, 5, 10, 0
 	point camera 0,0,0
 	sync
 loop

[modifier] Conclusion

Je n'ai jamais été vraiment doué pour écrire des tutoriels. Je me suis donné pas mal de peine pour celui-ci, mais je pense qu'il y a de nombreuses phrases difficilement compréhensibles ainsi que des manques de précisions. N'hésitez pas à éditer un point s'il vous semble qu'il nécessite une retouche.

 

Rechercher
Installer l'extension de recherche Plus d'informations

 

Comprendre
Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. - Benjamin Franklin

 

Partager
La connaissance est la seule chose qui s'accroit lorsqu'on la partage. - Sacha Boudjema

 

Créer
L'imagination est plus importante que la connaissance. - Albert Einstein

 

 

Le wiki en images Le wiki en images Image du mois: «Snowball: un prototype de jeu développé avec NeL.