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 :
| 1 | 2 | 3 | 4 |
| 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 |
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
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 :
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.


