3D vers 2D avec perspective

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

3D vers 2D avec perspective

Message par Le Soldat Inconnu »

Salut,

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.
Les calculs peuvent sembler barbare mais c'est de la mécanique de base : Le changement de repère. J'ai simplement retranscris mes cours.

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 :D

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... :mrgreen:

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")
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: 3D vers 2D avec perspective

Message par Backup »

autour de 600 ms sur mon petit NC10 (processeur ATOM / sans carte 3D) :)

impressionnant ! :)

ps: premier code tres fluide :)
Warkering
Messages : 808
Inscription : ven. 08/janv./2010 1:14
Localisation : Québec, Canada

Re: 3D vers 2D avec perspective

Message par Warkering »

189 ms! :mrgreen:
Je dois dire que c'est cool! :o
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

Re: 3D vers 2D avec perspective

Message par kelebrindae »

25 ms sur mon AMD 2.3 Ghz.

Super pratique pour générer les 6 textures d'un skycube à partir d'une liste d'étoiles: on recalcule les coordonnées de chaque étoile par rapport à la position du joueur, on les projette dans les 6 directions voulues (haut, bas, devant, derrière, gauche, droite), on sauvegarde les images et boum: voyage spatial instantané => on peut regarder le ciel tel qu'on le verrait depuis Alpha du Centaure. :D
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Re: 3D vers 2D avec perspective

Message par kernadec »

Bonjour Soldat inconnu
merci,
je peux pas rivaliser avec les 25ms de kelebrindae?

Compaq CQ71 dual-core T4300 2.10ghz - 4Go - Seven 64 Familial-premium
197ms seulement!!!!

j'avais trouvé ici une biblio 3d Sympa
AndyX a mis des bibliothèque.pbi "test.zip" ici : http://www.purebasic.fr/english/viewtop ... 12&t=25845&

Cordialement
Warkering
Messages : 808
Inscription : ven. 08/janv./2010 1:14
Localisation : Québec, Canada

Re: 3D vers 2D avec perspective

Message par Warkering »

La vache! Comment tu peux pogner du 25 ms? 8O
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

Re: 3D vers 2D avec perspective

Message par kelebrindae »

En enlevant le debugger ?
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Re: 3D vers 2D avec perspective

Message par kernadec »

merci, 28ms.... aie!!! les quiches c'est ça!!!!! :mrgreen: :mrgreen: :mrgreen:
Warkering
Messages : 808
Inscription : ven. 08/janv./2010 1:14
Localisation : Québec, Canada

Re: 3D vers 2D avec perspective

Message par Warkering »

18 ms! C'est cool! :mrgreen:
Avatar de l’utilisateur
venom
Messages : 3128
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: 3D vers 2D avec perspective

Message par venom »

14 ms pour ma part






@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: 3D vers 2D avec perspective

Message par Le Soldat Inconnu »

Ce qui ralentit le calcul, ce sont les cos et sin.
il faut que j'essaie de passer par des tables précalculées pour voir
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: 3D vers 2D avec perspective

Message par Le Soldat Inconnu »

et voilà, je suis tombé à 9ms pour le calcul de 120000 points.
J'utilise un précalcul sur les cos et sin

Code : Tout sélectionner

Structure Point3D
	x.d
	y.d
	z.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

Origine.Point3D
Origine\x = 10
Origine\y = 10
Origine\z = 10

Final.Point3D

Temps1 = ElapsedMilliseconds()
For nn = 1 To 40
	For n = 1 To 120000
		XYZ_Rotate(@Origine, 0.1, 0.1, 0, @Final)
	Next
Next
Temps2 = ElapsedMilliseconds()

MessageRequester("Temps", Str((Temps2 - Temps1)/40) + " ms")
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Avatar de l’utilisateur
venom
Messages : 3128
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Re: 3D vers 2D avec perspective

Message par venom »

en effet la différence 8O Bravo.
Je suis tomber a 4ms 8)






@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Warkering
Messages : 808
Inscription : ven. 08/janv./2010 1:14
Localisation : Québec, Canada

Re: 3D vers 2D avec perspective

Message par Warkering »

Moi 5! 8O :D
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: 3D vers 2D avec perspective

Message par Le Soldat Inconnu »

Version optimiser du repère 3D

Avec cette optimisation, il faut faire attention a toujours donner un angle de rotation compris entre 0 et 2 PI

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

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.f = 0
AngleY.f = 0
AngleZ.f = 0

FontID = LoadFont(0, "tahoma", 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
  AngleX + 0.01
	If AngleX > 2 * #PI
		AngleX - 2 * #PI
	ElseIf AngleX < 0
		AngleX + 2 * #PI
	EndIf
	
  AngleY + 0.005
	If AngleY > 2 * #PI
		AngleY - 2 * #PI
	ElseIf AngleY < 0
		AngleY + 2 * #PI
	EndIf
	
  AngleZ + 0.02
	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
    Line(250, 250, Coord\x, 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
    Line(250, 250, Coord\x, 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
    Line(250, 250, Coord\x, 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 = #PB_Event_CloseWindow
			End
		EndIf
		
	Until Event = 0
	
ForEver
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Répondre