Code: Select all
; ##############################
; # TUTORIEL 3D AVEC HOLLYWOOD #
; ##############################
; Ouverture d'écran avec choix
; Mode = "ask" : Permet de choisir entre mode fenêtre et mode plein écran
@SCREEN {Mode = "ask", Width = 640, Height = 480,Depth=16}
SetFontStyle(#EDGE, #RED, 1)
HidePointer()
CreateBrush(1,330,100)
SelectBrush(1)
TextOut(#CENTER,0,"LA GUERRE DES ETOILES")
TextOut(#CENTER,10,"A Hollywood")
TextOut(0,20,"Touche fléché pour la rotation de l'objet")
TextOut(0,30,"touche a = Zoom Arrière")
TextOut(0,40,"touche z = Zoom Avant")
TextOut(0,50,"touche e = Antialiasing")
TextOut(0,60,"touche r = Retirer l'Antialiasing")
TextOut(0,70,"touche t = 3D Surface pleine")
TextOut(0,80,"touche y = 3D filaire")
TextOut(0,90,"ctrl + c = QUITTER")
EndSelect
SetFontStyle(#NONE)
; Variables globales : elles sont utilisées pour se déplacer dans les tableaux
; Se sont les curseurs qui vont se modifier en fonction de la touche direction appuyée
ROTX=0
ROTY=0
ROTZ=16
CZ=1
; On initialise et réserve des emplacements mémoire pour les tableaux
; Y'en a beaucoup, car on précalcule beaucoup afin de gagner du temps CPU
; Plus il y aura de précalculation, plus votre moteur sera rapide.
; Si les triangles formant votre objet sont tous identiques, il est même
; possible de précalculer l'effet de lumière ou même mieux, la texturisation
; Se moteur n'est pas le meilleur, il est normalement très facile à optimiser
; Celui qui arrive à précalculer l'effet de lumière augmentera de beaucoup
; la vitesse de se moteur. Regardons ces tableaux de plus près:
Dim coord[288] ; Coordonnées des X,Y,Z de l'objet soit 96*3
Dim CO[64] ; Découpage de la rotation en 64 positions (cosX)
Dim SI[64] ; Découpage de la rotation en 64 positions (SinX)
Dim P1[510] ; Point à relié, un triangle a 3 points, donc 3*170
; Tableau d'optimisation du calcule du curseur :
; Afin d'éviter les calcules inutiles dans les boucles de PRG, on mets dans 3 tableaux
; les valeurs du curseur pour X,Y et Z
Dim GP1[170] ; valeurs possible pour le point 1 des triangles
Dim GP2[170] ; valeurs possible pour le point 2 des triangles
Dim GP3[170] ; valeurs possible pour le point 3 des triangles
; Tableau des vecteurs de chaques triangles. 3 point en X,Y soit 6 lignes
Dim TRIE[6]
; Tableau qui va servir au trie, les valeurs de se tableau seront utilisé comme index
; dans les tableaux Tri..[]
Dim ZM[96] ; Tableau de la valeur moyenne en Z
; Tableaux des coordonnées réels qui vont être utilisé pour Polygone()
; donc enregistré par la suite en TRIE.
Dim XE[96] ; Tableau coordonnées en X
Dim YE[96] ; Tableau coordonnées en Y
Dim ZE[96] ; Tableau coordonnées en Z
; Pourquoi ici?! sinon les tableau deviendrait ENORME, car ZM change de valeur tous le temps
; Tableau utilisé pour trié l'ordre d'affichage des triangles
Dim TriX1[170] ; Tableau de trie en X du point 1 de chaque triangle
Dim TriX2[170] ; Tableau de trie en X du point 2 de chaque triangle
Dim TriX3[170] ; Tableau de trie en X du point 3 de chaque triangle
Dim TriY1[170] ; Tableau de trie en Y du point 1 de chaque triangle
Dim TriY2[170] ; Tableau de trie en Y du point 2 de chaque triangle
Dim TriY3[170] ; Tableau de trie en Y du point 3 de chaque triangle
Dim TriZ1[170] ; Tableau de trie en Z du point 1 de chaque triangle
Dim TriZ2[170] ; Tableau de trie en Z du point 2 de chaque triangle
Dim TriZ3[170] ; Tableau de trie en Z du point 3 de chaque triangle
; VALEURS des coordonnées de l'objet:
; Sa se présente ainsi:
; Coord={
; X1,Y1,Z1,
; X2,Y2,Z2,
; ...
; }
coord={
-0.013836,-0.009224,-0.039999,
0.076100,0.046121,-0.536000,
0.076100,-0.046121,-0.536000,
-0.013836,-0.202934,-0.039999,
-0.034591,-0.009224,-0.039999,
-0.034591,-0.202934,-0.039999,
0.055346,-0.046121,-0.536000,
0.055346,0.046121,-0.536000,
-0.013836,-0.202934,0.039999,
0.076100,-0.046121,0.536001,
0.076100,0.046121,0.536001,
-0.013836,-0.009224,0.039999,
0.055346,0.046121,0.536001,
0.055346,-0.046121,0.536001,
-0.034591,-0.202934,0.039999,
-0.034591,-0.009224,0.039999,
0.041509,-0.341298,0.007999,
0.041509,-0.249055,0.007999,
0.152200,-0.249055,0.007999,
0.172955,-0.313625,0.007999,
0.041509,-0.249055,0.000000,
0.041509,-0.341298,0.000000,
0.172955,-0.313625,0.000000,
0.152200,-0.249055,0.000000,
0.172955,-0.202934,0.000000,
0.172955,-0.202934,0.007999,
0.172955,-0.027673,0.000000,
0.172955,-0.027673,0.007999,
0.193710,-0.027673,0.000000,
0.193710,-0.027673,0.007999,
0.193710,-0.285952,0.000000,
0.193710,-0.285952,0.007999,
-0.048427,0.451989,0.039999,
-0.013836,0.451989,0.016000,
0.013836,0.341298,0.023999,
-0.048427,0.341298,0.072000,
0.013836,0.073794,0.023999,
-0.048427,0.073794,0.072000,
-0.013836,0.451989,-0.008000,
0.013836,0.341298,-0.016000,
0.013836,0.073794,-0.016000,
-0.048427,0.451989,-0.039999,
-0.048427,0.341298,-0.056000,
-0.048427,0.073794,-0.056000,
-0.048427,0.590353,0.000000,
-0.069182,0.451989,0.023999,
-0.083018,0.341298,0.039999,
-0.083018,0.276728,0.023999,
-0.083018,0.276728,-0.016000,
-0.083018,0.341298,-0.024000,
-0.069182,0.451989,-0.016000,
-0.048427,0.599577,0.000000,
-0.083018,0.073794,-0.016000,
-0.083018,0.073794,0.023999,
-0.117609,0.083018,0.112000,
-0.166037,0.083018,0.056000,
-0.186791,0.083018,0.007999,
-0.186791,0.083018,-0.008000,
-0.166037,0.083018,-0.056000,
-0.117609,0.083018,-0.112000,
0.013836,0.083018,-0.056000,
0.055346,0.083018,-0.008000,
0.055346,0.083018,0.007999,
0.013836,0.083018,0.056000,
0.013836,-0.341298,0.056000,
-0.076100,-0.341298,0.088000,
-0.117609,-0.267504,0.112000,
0.055346,-0.341298,0.007999,
0.055346,-0.341298,-0.008000,
0.013836,-0.341298,-0.056000,
-0.117609,-0.267504,-0.112000,
-0.076100,-0.341298,-0.088000,
-0.186791,-0.166037,0.007999,
-0.186791,-0.166037,-0.008000,
-0.166037,-0.193710,-0.056000,
-0.166037,-0.193710,0.056000,
0.055346,0.184485,0.488000,
0.124528,0.184485,0.488000,
0.124528,0.184485,0.552001,
0.055346,0.184485,0.696001,
0.000000,0.184485,0.552001,
0.145282,-0.101467,0.552001,
0.145282,-0.101467,0.488000,
0.055346,-0.101467,0.488000,
-0.034591,-0.101467,0.552001,
0.055346,-0.101467,0.696001,
0.000000,0.184485,-0.552000,
0.055346,0.184485,-0.696000,
0.124528,0.184485,-0.552000,
0.124528,0.184485,-0.488000,
0.055346,0.184485,-0.488000,
0.055346,-0.119915,-0.696000,
-0.034591,-0.119915,-0.552000,
0.055346,-0.119915,-0.488000,
0.145282,-0.119915,-0.488000,
0.145282,-0.119915,-0.552000
}
For I=0 To 287
coord[I]=coord[I]*100
Next
; Les points a relier pour former les triangles
; Sa se présente ainsi:
; P1={
; point 1 du triangle 1,point 2 du triangle 1, point 3 du triangle 1,
; point 1 du triangle 2,point 2 du triangle 2, point 3 du triangle 2,
; ...
; }
; Ces valeurs sont en fait des valeurs de curseur qui vont permettre d'aller chercher
; les valeurs X,Y et Z dans le tableau Coord(). Il y a 170 triangles dans cet objet
; 1 triangle à 3 côtés donc P1 à 170*3=510 valeurs car 510 côtés
P1={
0,1,2,
0,2,3,
4,5,6,
4,6,7,
7,1,0,
7,0,4,
2,1,7,
2,7,6,
3,2,6,
3,6,5,
0,3,5,
0,5,4,
8,9,10,
8,10,11,
12,13,14,
12,14,15,
15,11,10,
15,10,12,
13,12,10,
13,10,9,
14,13,9,
14,9,8,
15,14,8,
15,8,11,
16,17,18,
16,18,19,
20,21,22,
20,22,23,
23,18,17,
23,17,20,
24,25,18,
24,18,23,
26,27,25,
26,25,24,
28,29,27,
28,27,26,
30,31,29,
30,29,28,
22,19,31,
22,31,30,
21,16,19,
21,19,22,
20,17,16,
20,16,21,
18,25,31,
18,31,19,
22,30,24,
22,24,23,
24,30,28,
24,28,26,
31,25,27,
31,27,29,
32,33,34,
32,34,35,
35,34,36,
35,36,37,
33,38,39,
33,39,34,
34,39,40,
34,40,36,
38,41,42,
38,42,39,
39,42,43,
39,43,40,
44,44,45,
44,45,46,
44,46,47,
44,47,48,
44,48,49,
44,49,50,
44,50,44,
44,44,51,
44,51,51,
51,51,38,
51,38,33,
51,44,41,
51,41,38,
41,44,50,
50,49,42,
50,42,41,
49,48,52,
49,52,43,
49,43,42,
48,47,53,
48,53,52,
46,35,37,
46,37,53,
46,53,47,
46,45,32,
46,32,35,
32,45,44,
44,51,33,
44,33,32,
36,40,43,
36,43,52,
36,52,53,
36,53,37,
36,37,37,
54,55,56,
54,56,57,
54,57,58,
54,58,59,
54,59,60,
54,60,61,
54,61,62,
54,62,63,
64,65,66,
64,66,54,
64,54,63,
63,62,67,
63,67,64,
62,61,68,
62,68,67,
61,60,69,
61,69,68,
59,70,71,
59,71,69,
59,69,60,
56,72,73,
56,73,57,
57,73,74,
57,74,58,
58,74,70,
58,70,59,
54,66,75,
54,75,55,
55,75,72,
55,72,56,
69,71,65,
69,65,64,
69,64,67,
69,67,68,
75,66,65,
75,65,71,
75,71,70,
75,70,74,
75,74,73,
75,73,72,
76,77,78,
76,78,79,
76,79,80,
81,82,83,
81,83,84,
81,84,85,
78,85,79,
77,81,78,
76,82,77,
80,83,76,
79,84,80,
85,84,79,
84,83,80,
83,82,76,
82,81,77,
81,85,78,
86,87,88,
86,88,89,
86,89,90,
91,92,93,
91,93,94,
91,94,95,
87,91,88,
88,95,89,
89,94,90,
90,93,86,
86,92,87,
87,92,91,
86,93,92,
90,94,93,
89,95,94,
88,91,95,
}
; On commence le travail de précalculation pôur gagner du temps CPU
; Se qui est précalculer sera enregistré dans des tableaux
; Il suffira donc de mettre en lien ses valeurs dans les tableaux
; avec notre moteur 3D
; On précalcule les valeurs Cosinus et Sinus utilisé pour les différentes rotation
; Et hop, on gagne 12*96 fois ses calcules par images
For Local I=0 To 63
CO[I]=Cos(I*0.1)
SI[I]=Sin(I*0.1)
Next
; On précalucle les pointeurs, argh!, on gagne 6x96 calcules/images pour les CPT et 13*169 calcules/images pour les GP
For Local I=0 To 169
Local Cpt1=I*3
GP1[I]=P1[Cpt1]
GP2[I]=P1[Cpt1+1]
GP3[I]=P1[Cpt1+2]
Next
; Tableau contenant 21 couleurs, mettez n'importe quel dégradé de couleur
Dim Couleur[11]
Couleur[0]=$FFFFFF
Couleur[1]=$EEEEEE
Couleur[2]=$DDDDDD
Couleur[3]=$CCCCCC
Couleur[4]=$BBBBBB
Couleur[5]=$AAAAAA
Couleur[6]=$999999
Couleur[7]=$888888
Couleur[8]=$777777
Couleur[9]=$666666
Couleur[10]=$555555
; Première fonction Controle() ou on test certaines touches du clavier
; Chaques touches testé quand elle est pressé renvoie à une fonction définie
Function Controle()
If IsKeyDown("Left")=True Then ROTY=ROTY+1
If IsKeyDown("Right")=True Then ROTY=ROTY-1
If IsKeyDown("Up")=True Then ROTX=ROTX+1
If IsKeyDown("Down")=True Then ROTX=ROTX+1
If IsKeyDown("*")=True Then ROTZ=ROTZ-1
If IsKeyDown("$")=True Then ROTZ=ROTZ+1
If IsKeyDown("a")=True Then CZ=CZ-1
If IsKeyDown("z")=True Then CZ=CZ+1
If ROTX<0 Then ROTX=63
If ROTX>63 Then ROTX=0
If ROTY<0 Then ROTY=63
If ROTY>63 Then ROTY=0
If ROTZ<0 Then ROTZ=63
If ROTZ>63 Then ROTZ=0
If CZ<1 Then CZ=1
If CZ>10 Then CZ=10
; La touche "e" mets en route l'antialiasing d'hollywood
If IsKeyDown("e")=True Then SetFormStyle(#ANTIALIAS)
; La touche "r" enlève l'antialiasing d'hollywood
If IsKeyDown("r")=True Then SetFormStyle(#NORMAL)
; La touche "t" mets en route le remplissage des polygon()
If IsKeyDown("t")=True Then SetFillStyle(#FILLCOLOR)
; La touche "e" enlève le remplissage des Polygon()
If IsKeyDown("y")=True Then SetFillStyle(#FILLNONE)
EndFunction
; La fonction principale
Function PRG()
; On démarre un chronomètre pour le calcule des FPS
StartTimer(1)
; On lance la fonction controle pour contrôler l'objet
Controle()
; Basculement entre les 2 écrans (doublebuffer)
Flip
; Effacement de l'écran
Cls
; Affichage du texte des indications
DisplayBrush(1,0,0)
; Première Boucle PRG() pour le calcule des 96 points de l'objet
For Local I=0 To 95 ; 96 points
; calcules de trigo...
Local Cpt1=I*3
Local Cpt2=Cpt1+1
Local Cpt3=Cpt2+1
; Enfin, les valeurs final à utiliser pour le traçage des triangles
; On les stocks dans un tableau, et oui, on est obligé pour pouvoir
; trier les triangles afin d'afficher en premier les triangles les
; plus éloigné suivant l'axe Z
XE[I]=CZ*((coord[cpt1]*CO[ROTY]+(-coord[cpt2]*SI[ROTX]+coord[cpt3]*CO[ROTX])*SI[ROTY])*CO[ROTZ]+(coord[cpt2]*CO[ROTX]+coord[cpt3]*SI[ROTX])*SI[ROTZ])
YE[I]=CZ*(-(coord[cpt1]*CO[ROTY]+(-coord[cpt2]*SI[ROTX]+coord[cpt3]*CO[ROTX])*SI[ROTY])*SI[ROTZ]+(coord[cpt2]*CO[ROTX]+coord[cpt3]*SI[ROTX])*CO[ROTZ])
ZE[I]=CZ*(-coord[cpt1]*SI[ROTY]+(-coord[cpt2]*SI[ROTX]+coord[cpt3]*CO[ROTX])*CO[ROTY])
Next
; Deuxième boucle OBLIGATOIRE : Préparation des tableaux pour le trie
For Local I=0 To 169 ; 170 triangles
; on calcule les Zmoyens qui sont la valeur moyenne en Z de chaque triangle
ZM[I]=ZE[GP1[I]]+ZE[GP2[I]]+ZE[GP3[I]]
; On utilise la valeur de ZM comme index des tableaux Tri..[]
; "comme index" ???? comment cela peut marcher Certains valeurs de Z vont exister en double et d'autres vont pas exister dans le tableau
; vaudrait mieux multiplier Z par (disons) 100 et stocker l'index du triangle comme partie décimale
ZM[I]=ZM[I] + I/1000;
TriX1[ZM[I]]=XE[GP1[I]]
TriY1[ZM[I]]=YE[GP1[I]]
TriZ1[ZM[I]]=ZE[GP1[I]]
TriX2[ZM[I]]=XE[GP2[I]]
TriY2[ZM[I]]=YE[GP2[I]]
TriZ2[ZM[I]]=ZE[GP2[I]]
TriX3[ZM[I]]=XE[GP3[I]]
TriY3[ZM[I]]=YE[GP3[I]]
TriZ3[ZM[I]]=ZE[GP3[I]]
Next
; On demande à Hollywood de trier le Tableau ZM[] de la valeur la plus petite à la plus grande
Sort(ZM, Function(a,b) Return (a>b)EndFunction)
;Troisième boucle de traçage
For Local I=0 To 169 ; 170 triangles
; Comme on a trier le tableau ZM de façon croissante,
; On utilisera les valeur en X et Y du plus éloigné selon l'axe Z au plus proche ;-)
; Calcule de trigo... décidement.
Local ABx=(TriX2[ZM[I]]-TriX1[ZM[I]])
Local ABy=(TriY2[ZM[I]]-TriY1[ZM[I]])
Local ACx=(TriX3[ZM[I]]-TriX1[ZM[I]])
Local ACy=(TriY3[ZM[I]]-TriY1[ZM[I]])
; On calcule la normal de chaque triangle (sur un plan en 2D)
; Si la normal est supérieur à 0, alors, on affiche pas le triangle (et encore de l'optimisation)
If (ABx*ACy)-(ACx*ABy)<0
Local ABz=(TriZ2[ZM[I]]-TriZ1[ZM[I]])
Local ACz=(TriZ3[ZM[I]]-TriZ1[ZM[I]])
; Calcule des normales en X pour l'effet de lumière (sur un plan en 3D)
Local Nx=(ABy*ACy)-(ABz*ACy)
; Calcule des normales en Y pour l'effet de lumière (sur un plan en 3D)
Local Ny=(ABz*ACx)-(ABx*ACz)
; Calcule des normales en Z pour l'effet de lumière (sur un plan en 3D)
Local Nz=(ABx*ACy)-(ABy*ACx)
Local D1=Sqrt(Nx^2+Ny^2+Nz^2)
If D1<0
Local D1=10
Local Nx=10
EndIf
Local Nx=Nx/D1 ; On divise NX par D1 (valeur entre -1 et 1)
Local Nx=Nx*10 ; on multiplie NX par 10 (valeur entre -10 et 10
Local Nx=Int(Nx) ; On arrondie la valeur de NX, car l'adresse 7,12 n'existe pas
If NX<0 Then NX=NX*-1
Local Xmouse=MouseX()
Local Ymouse=MouseY()
; Ensuite, Comme Nx va être compris entre -10 et 10, on utilise Nx comme valeur
; du pointeur pour choisir la couleur du triangle
; il doit y avoir une erreur qque part car dans le vaisseau les rectangles composés de 2 triangles (donc orientés pareil) devraient être de la même couleur
Polygon(Xmouse,Ymouse,{TriX1[ZM[I]],TriY1[ZM[I]],TriX2[ZM[I]],TriY2[ZM[I]],TriX3[ZM[I]],TriY3[ZM[I]]},3,Couleur[Nx])
EndIf
Next
; On efface les tableaux
; Car XM est la valeur de l'index de ses tableaux, on efface ses 6 tableaux
; afin d'éviter qu'ils ne prennent une taille trop énorme
; On récupère le temps du chrono
Local Temps=GetTimer(1)
; On affiche la vitesse en FPS
TextOut(0,100,Round((1/Temps)*1000))
TextOut(30,100,"Images par seconde")
; On remet le chronomètre à zéro
ResetTimer(1)
EndFunction
; Activation de la technique d'animation double buffer
BeginDoubleBuffer
; Interval pour la fonction PRG de 50FPS ne pas mettre 1, le programme est plus lent... Je sais pas pourquoi
SetInterval(1,PRG,20)
; boucle Infini
Repeat
WaitEvent()
Forever
; Fin, amusez vous à l'optimiser maintenant que vous avez les explications ;-)