il est basé sur la procedure suivante qui permet de faire la convertion entre 2 repères (un repère 3D et l'écran 2D)
cette procedure est à utiliser tel quel sans aucune modification. Je ne l'explique pas ici, je l'ai déjà fait ailleurs sur le forum.
Pour son utilisation, on lui donne les coordonnées X Y Z du point, les angles entre le repère 3D et l'écran (angle de rotation sur l'axe X, Y et Z) et Une variable de type Point3D qui va recevoir le résultat.
Le résultat étant les coodonnées du point sur l'écran 2D avec prise en compte de la perpective
Code : Tout sélectionner
Structure Point3D
x.f ; Coordonnée X
y.f ; Coordonnée Y
z.f ; Coordonnée Z
p.f ; Facteur pour la perspective
EndStructure
#Perspective = 600 ; Intensité de la perspective
Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f, XYZ)
; x, y, z : position de l'objet
; ax, ay, az : angle de rotation du point sur l'axe x, y et z, pour avoir un repère 3D décalé par rapport au repère de l'écran
Protected x2.f, y2.f, z3.f, Coord.Point3D
; Rotation sur l'axe Z
x2 = x * Cos(az) - y * Sin(az)
y2 = x * Sin(az) + y * Cos(az)
; z2 = z
; Debug StrF(x2) + " , " + StrF(y2) + " , " + StrF(z)
; Rotation sur l'axe X
; x3 = x2
Coord\y = y2 * Cos(ax) - z * Sin(ax)
z3 = y2 * Sin(ax) + z * Cos(ax)
; Debug StrF(x2) + " , " + StrF(Coord\y) + " , " + StrF(z3)
; Rotation sur l'axe Y
Coord\z = z3 * Cos(ay) - x2 * Sin(ay)
Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
; y4 = y3
; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
; Prise en compte de la perspective
Coord\p = 1 + Abs(Coord\z) / #Perspective
If Coord\z < 0
Coord\p = 1 / Coord\p
EndIf
Coord\x = Coord\x * Coord\p
Coord\y = Coord\y * Coord\p
; On copie les données
CopyMemory(@Coord, XYZ, SizeOf(Point3D))
EndProcedure
j'ai donné un effet d'écho à l'image pour avoir une impression de vitesse également. c'est réalisé simplement en dessinant plusieurs fois le cube avec des angles différents
pour lancer le code, il faut la lib Coloreffect que vous trouverez sur mon site ainsi que le resident contenant la valeur de #Pi.
le code est tourné comme un écran de veille donc si vous l'enregistrez au format *.scr, il n'ya plus qu'a le mettre dans le dossier de windows
Code : Tout sélectionner
; Auteur : Le Soldat Inconnu
; Version de PB : 3.90
;
; Explication du programme :
; Dessiner un cube filaire en 3D avec de la perspective
#TailleX = 1024
#TailleY = 768
#Couleur = $E5A974
#Cube = 175 ; Taille du cube
#Echo = 8 ; Nombre d'écho
#Echo_Espacement = 1 ; Espacement entre chaque écho
#VitesseMax = 70
#VitesseMin = 350
#VitesseEvolution = 20
Structure Point3D
x.f ; Coordonnée X
y.f ; Coordonnée Y
z.f ; Coordonnée Z
p.f ; Facteur pour la perspective
EndStructure
#Perspective = 600 ; Intensité de la perspective
Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f, XYZ)
; x, y, z : position de l'objet
; ax, ay, az : angle de rotation du point sur l'axe x, y et z, pour avoir un repère 3D décalé par rapport au repère de l'écran
Protected x2.f, y2.f, z3.f, Coord.Point3D
; Rotation sur l'axe Z
x2 = x * Cos(az) - y * Sin(az)
y2 = x * Sin(az) + y * Cos(az)
; z2 = z
; Debug StrF(x2) + " , " + StrF(y2) + " , " + StrF(z)
; Rotation sur l'axe X
; x3 = x2
Coord\y = y2 * Cos(ax) - z * Sin(ax)
z3 = y2 * Sin(ax) + z * Cos(ax)
; Debug StrF(x2) + " , " + StrF(Coord\y) + " , " + StrF(z3)
; Rotation sur l'axe Y
Coord\z = z3 * Cos(ay) - x2 * Sin(ay)
Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
; y4 = y3
; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
; Prise en compte de la perspective
Coord\p = 1 + Abs(Coord\z) / #Perspective
If Coord\z < 0
Coord\p = 1 / Coord\p
EndIf
Coord\x = Coord\x * Coord\p
Coord\y = Coord\y * Coord\p
; On copie les données
CopyMemory(@Coord, XYZ, SizeOf(Point3D))
EndProcedure
Procedure Cube3D(AngleX.f, AngleY.f, AngleZ.f, Couleur)
StartDrawing(ScreenOutput())
; On dessine une ligne du cube
XYFrom3D(#Cube, #Cube, #Cube, AngleX, AngleY, AngleZ, Coord1.Point3D) ; on calcul les coordonnées de l'extrémité de la ligne pour l'affichage sur l'écran
XYFrom3D(#Cube, -#Cube, #Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur) ; on trace une ligne à partir des coordonnées calculées
; Et on dessine les autres lignes de la même manière
XYFrom3D(#Cube, -#Cube, -#Cube, AngleX, AngleY, AngleZ, Coord1.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(-#Cube, -#Cube, #Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
XYFrom3D(-#Cube, -#Cube, -#Cube, AngleX, AngleY, AngleZ, Coord1.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(-#Cube, #Cube, #Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
XYFrom3D(-#Cube, #Cube, -#Cube, AngleX, AngleY, AngleZ, Coord1.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(#Cube, #Cube, #Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
XYFrom3D(#Cube, #Cube, -#Cube, AngleX, AngleY, AngleZ, Coord1.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
XYFrom3D(#Cube, -#Cube, -#Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(-#Cube, -#Cube, -#Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(-#Cube, #Cube, -#Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
CopyMemory(@Coord2, @Coord1, SizeOf(Point3D)) ; On copie les valeurs de Coord2 dans Coord1
XYFrom3D(#Cube, #Cube, -#Cube, AngleX, AngleY, AngleZ, Coord2.Point3D)
LineXY(Int(#TailleX / 2 + Coord1\x), Int(#TailleY / 2 + Coord1\y), Int(#TailleX / 2 + Coord2\x), Int(#TailleY / 2 + Coord2\y), Couleur)
StopDrawing()
EndProcedure
Procedure.l Objectif()
ProcedureReturn Int((Random(#VitesseMin - #VitesseMax) + #VitesseMax) / #VitesseEvolution) * #VitesseEvolution
EndProcedure
;- Début du code
; Ecran de veille : Si on veut paramétrer, on ne lance rien
Param.s = Left(ProgramParameter(), 2)
If Param = "/p"
MessageRequester("Information", "Concepteur : Le Soldat Inconnu [Bouguin Régis]" + Chr(10) + "Programmé sur PureBasic" + Chr(10) + Chr(10) + "http://perso.wanadoo.fr/lesoldatinconnu/", 4 * 16)
End
EndIf
If OpenWindow(0, 0, 0, 100, 100, #PB_Window_BorderLess | #WS_MAXIMIZE, "Cube 3D") = 0
End
EndIf
SetWindowPos_(WindowID(), -1, 0, 0, 0, 0, #SWP_NOSIZE | #SWP_NOMOVE) ; Pour mettre la fenêtre toujours au premier plan
UpdateWindow_(WindowID())
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
End
EndIf
If OpenScreen(#TailleX, #TailleY, 32, "Cube 3D") = 0
End
EndIf
AngleX.f = 0
AngleY.f = 0
AngleZ.f = 0
; Paramètres des vitesses de rotation du cube
RotationX = Objectif()
RotationY = Objectif()
RotationZ = Objectif()
; Objectif des vitesses de rotation
RotationX_Objectif = Objectif()
RotationY_Objectif = Objectif()
RotationZ_Objectif = Objectif()
Repeat
; On change l'angle d'inclinaison du cube (en fait, on change les angles entre le repère écran et le repère du dessin)
AngleX + #Pi / RotationX
AngleY + #Pi / RotationY
AngleZ + #Pi / RotationZ
; Permet de faire varier la vitesse de rotation du cube
If AngleX >= 2 * #Pi Or AngleX <= -2 * #Pi
AngleX = 0 ; On initialise l'angle car un angle de 2*#Pi est équivalent à un angle de 0
If RotationX > RotationX_Objectif
RotationX - #VitesseEvolution
ElseIf RotationX < RotationX_Objectif
RotationX + #VitesseEvolution
Else
RotationX_Objectif = Objectif() ; On fixe une nouvelle vitesse de rotation en objectif
EndIf
EndIf
If AngleY >= 2 * #Pi Or AngleY <= -2 * #Pi
AngleY = 0
If RotationY > RotationY_Objectif
RotationY - #VitesseEvolution
ElseIf RotationY < RotationY_Objectif
RotationY + #VitesseEvolution
Else
RotationY_Objectif = Objectif()
EndIf
EndIf
If AngleZ >= 2 * #Pi Or AngleZ <= -2 * #Pi
AngleZ = 0
If RotationZ > RotationZ_Objectif
RotationZ - #VitesseEvolution
ElseIf RotationZ < RotationZ_Objectif
RotationZ + #VitesseEvolution
Else
RotationZ_Objectif = Objectif()
EndIf
EndIf
ClearScreen(0, 0, 0)
For n = #Echo To 0 Step -1
Cube3D(AngleX - n * #Pi / RotationX / #Echo_Espacement, AngleY - n * #Pi / RotationY / #Echo_Espacement, AngleZ - n * #Pi / RotationZ / #Echo_Espacement, ColorLuminosity(#Couleur, 1 - n / (#Echo + 1)))
Next
; On affiche les différentes vitesses et les objectifs
; StartDrawing(ScreenOutput())
; Box(2, 2, 2 * RotationX / #VitesseEvolution, 3, $505050)
; Line(2, 5, 2 * RotationX_Objectif / #VitesseEvolution, 0, $7800)
;
; Box(2, 9, 2 * RotationY / #VitesseEvolution, 3, $505050)
; Line(2, 12, 2 * RotationY_Objectif / #VitesseEvolution, 0, $7800)
;
; Box(2, 16, 2 * RotationZ / #VitesseEvolution, 3, $505050)
; Line(2, 19, 2 * RotationZ_Objectif / #VitesseEvolution, 0, $7800)
; StopDrawing()
FlipBuffers()
ExamineKeyboard()
ExamineMouse()
Until KeyboardPushed(#PB_Key_All) Or Abs(MouseDeltaX()) > 2 Or Abs(MouseDeltaY()) > 2
voir ici :
http://perso.wanadoo.fr/lesoldatinconnu/amusement.htm
(sur la page suivante de celle qui va s'afficher)