Je reprend un vieux code que j'essaie d'optimiser pour faire un programme qui affiche une carte du ciel.
Le but de ce code est de passer d'une position dans un repère 3D en rotation vers un repère 2D (votre écran) en ajoutant un effet de perspective
Donc voici un code qui affiche un repère XYZ en rotation avec un effet de perspective.
Si vous appuyer sur "entrée" vous passer en rotation manuelle
Il faut alors appuyer sur X, Y, ou Z pour faire tourner le repère sur l'axe X, Y ou Z
- La fonction XYZ_Rotate gère uniquement la rotation entre 2 repère 3D
- La fonction XYFrom3D gère la positon d'un point du repère 3D vers l'écran en y ajoutant la perspective.
Code : Tout sélectionner
; Auteur : Le Soldat Inconnu
; Version de PB : 4.5
;
; Explication du programme :
; Exemple qui montre comment dessiner un repère XYZ en 3D
; Touche d'utilisation :
; Enter : Passage de la rotation automatique à manuelle
; X : En mode de rotation manuelle, change l'angle sur l'axe X
; Y : En mode de rotation manuelle, change l'angle sur l'axe Y
; Z : En mode de rotation manuelle, change l'angle sur l'axe Z
Structure Point3D
x.d
y.d
z.d
EndStructure
Structure Point3DP
x.d
y.d
z.d
p.d
EndStructure
#Angle_Resolution = 100
Global Dim Calculation_Cos.d(360 * #Angle_Resolution * 2)
Global Dim Calculation_Sin.d(360 * #Angle_Resolution * 2)
For i = -360 * #Angle_Resolution To 360 * #Angle_Resolution
Calculation_Cos(i + 360 * #Angle_Resolution) = Cos(i * #PI / (180 * #Angle_Resolution))
Calculation_Sin(i + 360 * #Angle_Resolution) = Sin(i * #PI / (180 * #Angle_Resolution))
Next
Procedure XYZ_Rotate(*Origine.Point3D, Angle_X_Axis.d, Angle_Y_Axis.d, Angle_Z_Axis.d, *Final.Point3D)
; Angle_X_Axis, ay, Angle_Z_Axis : angle de rotation du point sur l'Angle_X_Axise x, y et z, pour avoir un repère 3D décalé par rapport au repère de l'écran
Protected Calcul.Point3D, Sin.d, Cos.d
; Rotation sur l'axe Z
If Angle_Z_Axis
; Cos = Cos(Angle_Z_Axis)
; Sin = Sin(Angle_Z_Axis)
Angle.i = Angle_Z_Axis * #Angle_Resolution * 180 / #PI + 360 * #Angle_Resolution
Cos = Calculation_Cos(Angle)
Sin = Calculation_Sin(Angle)
Calcul\x = *Origine\x * Cos - *Origine\y * Sin
Calcul\y = *Origine\x * Sin + *Origine\y * Cos
Else
Calcul\x = *Origine\x
Calcul\y = *Origine\y
EndIf
; Debug StrD(Calcul\x) + " , " + StrD(Calcul\y) + " , " + StrD(*Origine\z)
; Rotation sur l'axe X
If Angle_X_Axis
; Cos = Cos(Angle_X_Axis)
; Sin = Sin(Angle_X_Axis)
Angle.i = Angle_X_Axis * #Angle_Resolution * 180 / #PI + 360 * #Angle_Resolution
Cos = Calculation_Cos(Angle)
Sin = Calculation_Sin(Angle)
*Final\y = Calcul\y * Cos - *Origine\z * Sin
Calcul\z = Calcul\y * Sin + *Origine\z * Cos
Else
*Final\y = Calcul\y
Calcul\z = *Origine\z
EndIf
; Debug StrD(Calcul\x) + " , " + StrD(*Final\y) + " , " + StrD(Calcul\z)
; Rotation sur l'axe Y
If Angle_Y_Axis
; Cos = Cos(Angle_Y_Axis)
; Sin = Sin(Angle_Y_Axis)
Angle.i = Angle_Y_Axis * #Angle_Resolution * 180 / #PI + 360 * #Angle_Resolution
Cos = Calculation_Cos(Angle)
Sin = Calculation_Sin(Angle)
*Final\z = Calcul\z * Cos - Calcul\x * Sin
*Final\x = Calcul\z * Sin + Calcul\x * Cos
Else
*Final\z = Calcul\z
*Final\x = Calcul\x
EndIf
; Debug StrD(*Final\x) + " , " + StrD(*Final\y) + " , " + StrD(*Final\z)
EndProcedure
Procedure XYFrom3D(*Origine.Point3D, Angle_X_Axis.d, Angle_Y_Axis.d, Angle_Z_Axis.d, Perspective.q, *Final.Point3DP)
; Angle_X_Axis, ay, Angle_Z_Axis : angle de rotation du point sur l'Angle_X_Axise x, y et z, pour avoir un repère 3D décalé par rapport au repère de l'écran
XYZ_Rotate(*Origine.Point3D, Angle_X_Axis.d, Angle_Y_Axis.d, Angle_Z_Axis.d, *Final.Point3DP)
*Final\p = 1 + Abs(*Final\z) / Perspective
If *Final\z < 0
*Final\p = 1 / *Final\p
EndIf
*Final\x * *Final\p
*Final\y * *Final\p
EndProcedure
If InitSprite() = 0
End
EndIf
If OpenWindow(0, 0, 0, 500, 500, "Le Soldat Inconnu", #PB_Window_ScreenCentered | #PB_Window_SystemMenu) = 0
End
EndIf
If OpenWindowedScreen(WindowID(0), 0, 0, 500, 500, 1, 0, 0) = 0
End
EndIf
AngleX.d = 0
AngleY.d = 0
AngleZ.d = 0
Rotation_Auto = 1
FontID = LoadFont(0, "Verdana", 8, #PB_Font_HighQuality)
Repeat
ClearScreen($FFFFFF)
; On change l'angle d'inclinaison du texte (en fait, on change les angles entre le repère écran et le repère du texte)
; Vous pouver mettre les paramètres que vous voulez pour changer la rotation du repère 3D
If Rotation_Auto
AngleX + 0.005
AngleY + 0.003
AngleZ + 0.002
EndIf
If AngleX > 2 * #PI
AngleX - 2 * #PI
ElseIf AngleX < 0
AngleX + 2 * #PI
EndIf
If AngleY > 2 * #PI
AngleY - 2 * #PI
ElseIf AngleY < 0
AngleY + 2 * #PI
EndIf
If AngleZ > 2 * #PI
AngleZ - 2 * #PI
ElseIf AngleZ < 0
AngleZ + 2 * #PI
EndIf
X_Origine.Point3D
X_Origine\x = 200
Y_Origine.Point3D
Y_Origine\y = 200
Z_Origine.Point3D
Z_Origine\z = 200
StartDrawing(ScreenOutput())
DrawingFont(FontID)
DrawingMode(#PB_2DDrawing_Transparent)
; On affiche le repère
; la ligne représentant l'axe X en vert
XYFrom3D(@X_Origine, AngleX, AngleY, AngleZ, 400, @Coord.Point3DP) ; on calcul les coordonnées de l'extrémité de la ligne pour l'affichage sur l'écran
LineXY(250, 250, 250 + Coord\x, 250 - Coord\y, RGB(0, 255, 0)) ; on trace une ligne verte à partir du centre de l'image vers les coordonnées calculées
Circle(250 + Coord\x, 250 - Coord\y, 5 * Coord\p, RGB(0, 255, 0)) ; on trace un cerle sur le bout de la ligne. La variable Coord\p permet de prendre en compte la perspective sur une forme de taille définie, ici un cercle mais également une image par exemple.
DrawText(255 + Coord\x, 255 - Coord\y, "X", 0) ;On affiche le label de l'axe
; la ligne représentant l'axe Y en rouge
XYFrom3D(@Y_Origine, AngleX, AngleY, AngleZ, 400, @Coord.Point3DP) ; on calcul les coordonnées de l'extrémité de la ligne pour l'affichage sur l'écran
LineXY(250, 250, 250 + Coord\x, 250 - Coord\y, RGB(255, 0, 0))
Circle(250 + Coord\x, 250 - Coord\y, 5 * Coord\p, RGB(255, 0, 0))
DrawText(255 + Coord\x, 255 - Coord\y, "Y", 0)
; la ligne représentant l'axe Z en bleu
XYFrom3D(@Z_Origine, AngleX, AngleY, AngleZ, 400, @Coord.Point3DP) ; on calcul les coordonnées de l'extrémité de la ligne pour l'affichage sur l'écran
LineXY(250, 250, 250 + Coord\x, 250 - Coord\y, RGB(0, 0, 255))
Circle(250 + Coord\x, 250 - Coord\y, 5 * Coord\p, RGB(0, 0, 255))
DrawText(255 + Coord\x, 255 - Coord\y, "Z", 0)
StopDrawing()
FlipBuffers()
Repeat
Event = WindowEvent()
If Event = #WM_KEYUP
Select EventwParam()
Case 'X'
AngleX + #PI/6
Case 'Y'
AngleY + #PI/6
Case 'Z'
AngleZ + #PI/6
Case 13
Rotation_Auto = 1 - Rotation_Auto
AngleX = 0
AngleY = 0
AngleZ = 0
EndSelect
EndIf
If Event = #PB_Event_CloseWindow
End
EndIf
Until Event = 0
ForEver
Si vous avez des idées pour optimiser encore la fonction XYZ_Rotate(), je suis preneur

Voici un code pour tester la vitesse. Il regarde en combien de temps je calcul la position de 120000 points (vue que j'ai chopé la position de 118000 étoiles). je suis tombé à 18 ms, ça donne 55 images par seconde sans affichage sur l'écran, alors si il est possible d'avoir mieux...

Code : Tout sélectionner
Structure Point3D
x.d
y.d
z.d
EndStructure
Procedure XYZ_Rotate(*Origine.Point3D, Angle_X_Axis.d, Angle_Y_Axis.d, Angle_Z_Axis.d, *Final.Point3D)
; Angle_X_Axis, ay, Angle_Z_Axis : angle de rotation du point sur l'Angle_X_Axise x, y et z, pour avoir un repère 3D décalé par rapport au repère de l'écran
Protected Calcul.Point3D, Sin.d, Cos.d
; Rotation sur l'axe Z
If Angle_Z_Axis
Cos = Cos(Angle_Z_Axis)
Sin = Sin(Angle_Z_Axis)
Calcul\x = *Origine\x * Cos - *Origine\y * Sin
Calcul\y = *Origine\x * Sin + *Origine\y * Cos
Else
Calcul\x = *Origine\x
Calcul\y = *Origine\y
EndIf
; Debug StrD(Calcul\x) + " , " + StrD(Calcul\y) + " , " + StrD(*Origine\z)
; Rotation sur l'axe X
If Angle_X_Axis
Cos = Cos(Angle_X_Axis)
Sin = Sin(Angle_X_Axis)
*Final\y = Calcul\y * Cos - *Origine\z * Sin
Calcul\z = Calcul\y * Sin + *Origine\z * Cos
Else
*Final\y = Calcul\y
Calcul\z = *Origine\z
EndIf
; Debug StrD(Calcul\x) + " , " + StrD(*Final\y) + " , " + StrD(Calcul\z)
; Rotation sur l'axe Y
If Angle_Y_Axis
Cos = Cos(Angle_Y_Axis)
Sin = Sin(Angle_Y_Axis)
*Final\z = Calcul\z * Cos - Calcul\x * Sin
*Final\x = Calcul\z * Sin + Calcul\x * Cos
Else
*Final\z = Calcul\z
*Final\x = Calcul\x
EndIf
; Debug StrD(*Final\x) + " , " + StrD(*Final\y) + " , " + StrD(*Final\z)
EndProcedure
Origine.Point3D
Origine\x = 10
Origine\y = 10
Origine\z = 10
Final.Point3D
Temps1 = ElapsedMilliseconds()
For nn = 1 To 30
For n = 1 To 120000
XYZ_Rotate(@Origine, 0.1, 0.1, 0, @Final)
Next
Next
Temps2 = ElapsedMilliseconds()
MessageRequester("Temps", Str((Temps2 - Temps1)/30) + " ms")