Texte en rotation - Dessin en 3D sur un écran 2D

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 :

Texte en rotation - Dessin en 3D sur un écran 2D

Message par Le Soldat Inconnu »

Salut,

Un petit code d'animation 3D, je dessine un texte qui tourne avec des points de couleur

Code : Tout sélectionner

#Pi = 3.14159274

#ImageFondX = 500
#ImageFondY = 200
#ImageTexteX = 500
#ImageTexteY = 70

#DepartZ = 0
#Espacement = 10

#Duree = 100
#AngleDepartX.f = #Pi / 2
#AngleDepartY.f = #Pi
#AngleDepartZ.f = 0 ; #Pi / 2

Structure Point3D
  x.f
  y.f
  z.f
EndStructure

Global Coord.Point3D

Structure TInfo
  Couleur.l
  z.l
EndStructure

Dim Texte.TInfo(#ImageTexteX, #ImageTexteY)

Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f)
  ; 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
  
  ; 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) - x3 * Sin(ay)
  Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
  ; y4 = y3
  ; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
EndProcedure


If InitSprite() = 0
  End
EndIf

If OpenWindow(0, 0, 0, #ImageFondX, #ImageFondY, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Le Soldat Inconnu") = 0
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, #ImageFondX, #ImageFondY, 1, 0, 0) = 0
  End
EndIf

UsePNGImageDecoder()

LoadSprite(0, "Fond.png")

DisplaySprite(0, 0, 0)
FlipBuffers()

LoadSprite(1, "Texte.png")
StartDrawing(SpriteOutput(1))
  For n = 0 To #ImageTexteX - 1
    For nn = 0 To #ImageTexteY - 1
      Texte(n, nn)\Couleur = Point(n, nn) ; On charge la couleur de l'image dans un tableau
      Texte(n, nn)\z = #DepartZ + Random(#Espacement) - #Espacement / 2 ; on crée une position en z aléatoire
    Next
  Next
StopDrawing()

AngleX.f = #AngleDepartX
AngleY.f = #AngleDepartY
AngleZ.f = #AngleDepartZ
Duree = 0

Repeat
  
  DisplaySprite(0, 0, 0)
  
  ; 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)
  Duree + 1
  AngleX - #AngleDepartX / #Duree
  AngleY - #AngleDepartY / #Duree
  AngleZ - #AngleDepartZ / #Duree
  
  ; On affiche les points
  StartDrawing(ScreenOutput())
    For n = 0 To #ImageTexteX - 1
      For nn = 0 To #ImageTexteY - 1
        XYFrom3D(n - #ImageTexteX / 2, nn - #ImageTexteY / 2, Texte(n, nn)\z, AngleX, AngleY, AngleZ) ; Calcul de la position des points du texte sur le repère de l'écran
        If Coord\x + #ImageTexteX / 2 >= 0 And Coord\x + #ImageTexteX / 2 < #ImageFondX And Coord\y + #ImageTexteY / 2 >= 0 And Coord\y + #ImageTexteY / 2 < #ImageFondY And Texte(n, nn)\Couleur <> $3C0000 ; si le point est sur la zone de dessin et si la couleur est différente de la couleur de fond de l'image représentant le texte
          Plot(Coord\x + #ImageTexteX / 2, Coord\y + #ImageTexteY / 2, Texte(n, nn)\Couleur) ; on affiche le point
        EndIf
      Next
    Next
    
  StopDrawing()
  
  FlipBuffers()

Until Duree = #Duree

Delay(3000)
pour lancer ce code, il faut des images donc voici un zip complet (code + images)
http://perso.wanadoo.fr/lesoldatinconnu ... etoile.zip (138 ko)



la partie du code intéressante est celle-ci

Code : Tout sélectionner

Structure Point3D
  x.f
  y.f
  z.f
EndStructure

Global Coord.Point3D

Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f)
  ; 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
  
  ; 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) - x3 * Sin(ay)
  Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
  ; y4 = y3
  ; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
EndProcedure
cette procedure permet de passer d'un repère en rotation 3D au repère de l'écran (2D)
donc si les coordonnée d'un point sont x, y, z
que le repère dans lequel vous l'affiché en orienté d'un angle de #Pi/4 radians sur l'axe des x par exemple, on obtient les coordonnées du point sur l'écran comme suit :

Code : Tout sélectionner

XYFrom3D(x, y, z, #Pi/2, 0, 0)
les coordonnées correspondant à l'affichage seront alors calculés et récupèrable par la variable Coord.Point3D globale au code

donc pour faire tourner un sprite dans l'espace, il suffit de jouer sur les angles entre le repère 3D et celui de l'écran.

pour afficher les repères des 2 plans (écran et 3D) et bien comprendre le phénomène, lancer le code suivant :

Code : Tout sélectionner

Structure Point3D
  x.f
  y.f
  z.f
EndStructure

Global Coord.Point3D

Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f)
  ; 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
  
  ; 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) - x3 * Sin(ay)
  Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
  ; y4 = y3
  ; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0
  End
EndIf

If OpenWindow(0, 0, 0, 500, 500, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Le Soldat Inconnu") = 0
  End
EndIf

If OpenWindowedScreen(WindowID(), 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(255, 255, 255)
  
  ; 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
  AngleY + 0.005
  AngleZ + 0.02
  
  StartDrawing(ScreenOutput())
    DrawingFont(FontID)
    
    ; On affiche le repère
    ; la ligne représentant l'axe X en vert
    XYFrom3D(200, 0, 0, AngleX, AngleY, AngleZ) ; 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, RGB(0, 255, 0)) ; on trace un cerle sur le bout de la ligne
    Locate(255 + Coord\x, 255 + Coord\y)
    DrawText("X") ;On affiche le label de l'axe
    
    ; la ligne représentant l'axe Y en rouge
    XYFrom3D(0, 200, 0, AngleX, AngleY, AngleZ) ; 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, RGB(255, 0, 0))
    Locate(255 + Coord\x, 255 + Coord\y)
    DrawText("Y")
    
    ; la ligne représentant l'axe Z en bleu
    XYFrom3D(0, 0, 200, AngleX, AngleY, AngleZ) ; 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, RGB(0, 0, 255))
    Locate(255 + Coord\x, 255 + Coord\y)
    DrawText("Z")
    
  StopDrawing()
  
  FlipBuffers()

  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
le principe est simple, il suffit ensuite pour obtenir des objets 3D en rotation de gérer une liste de point ou sprite dans l'espace et de changer l'angle du repère.
et si vous souhaiter avoir des objets en mouvement, il suffit de modifier les coordonnées de ces points ou sprites pendant la rotation du repère 3D comme si vous étiez en 2D, la procedure de calcul pour passer d'un plan à l'autre fera le reste ;)
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 :

Message par Le Soldat Inconnu »

Un autre code qui affiche un texte en rotation :

Code : Tout sélectionner

Structure Point3D
  x.f
  y.f
  z.f
EndStructure

Global Coord.Point3D

Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f)
  ; 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
  
  ; 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) - x3 * Sin(ay)
  Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
  ; y4 = y3
  ; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0
  End
EndIf

If OpenWindow(0, 0, 0, 500, 500, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Le Soldat Inconnu") = 0
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, 500, 500, 1, 0, 0) = 0
  End
EndIf

AngleX.f = 0
AngleY.f = 0
AngleZ.f = 0

FontID = LoadFont(0, "arial", 36, #PB_Font_HighQuality)

TexteAffiche.s = "Texte en rotation"

; On dessine le texte et on le convertit en point
Dim Texte(500, 200)
CreateSprite(0, 500, 200)
StartDrawing(SpriteOutput(0))
  Box(0, 0, 500, 100, $FFFFFF)
  DrawingFont(FontID)
  Locate((500 - TextLength(TexteAffiche)) / 2, 0)
  FrontColor(0, 0, 0)
  DrawText(TexteAffiche)
  
  For n = 0 To 500 - 1
    For nn = 0 To 100 - 1
      Texte(n, nn) = Point(n, nn)
    Next
  Next
  
StopDrawing()

Repeat

  ClearScreen(255, 255, 255)
  
  ; 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
  AngleY + 0.005
  AngleZ + 0.02
  
  StartDrawing(ScreenOutput())
    
    For n = 0 To 500 - 1
      For nn = 0 To 100 - 1
        If Texte(n, nn) = 0
          For z = 0 To 5 ; Epaisseur du texte
            XYFrom3D(n - 250, nn - 50, z, AngleX, AngleY, AngleZ) ; on affiche tous les points du texte
            Plot(250 +Coord\x, 250 + Coord\y, 200)
          Next
        EndIf
      Next
    Next
    
     
  StopDrawing()
  
  FlipBuffers()

  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
allez, bonne nuit :wink:
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

Message par Backup »

En Mieux et plus court !!!
(ça c'est de l'optimisation !!!) :lol:

Code : Tout sélectionner


; pour windows XP
Resultat = RunProgram("C:\WINDOWS\system32\sstext3D.scr","", "C:\WINDOWS\system32\" ,1) 

; pour window 98
;Resultat = RunProgram("C:\WINDOWS\system\Texte 3D.scr","", "C:\WINDOWS\system\" ,1) 
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

quelle blatte .... :mrgreen: tusors:

le même effet que le premier message mais sans image :

Code : Tout sélectionner

Structure InfoTexte
  Couleur.l
  z.f
EndStructure

Dim Texte.InfoTexte(500, 100)


Structure Point3D
  x.f
  y.f
  z.f
EndStructure

Global Coord.Point3D

Procedure XYFrom3D(x.f, y.f, z.f, ax.f, ay.f, az.f)
  ; 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
  
  ; 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) - x3 * Sin(ay)
  Coord\x = z3 * Sin(ay) + x2 * Cos(ay)
  ; y4 = y3
  ; Debug StrF(Coord\x) + " , " + StrF(Coord\y) + " , " + StrF(z3)
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0
  End
EndIf

If OpenWindow(0, 0, 0, 500, 500, #PB_Window_BorderLess | #PB_Window_ScreenCentered, "Le Soldat Inconnu") = 0
  End
EndIf

If OpenWindowedScreen(WindowID(), 0, 0, 500, 500, 1, 0, 0) = 0
  End
EndIf

AngleX.f = 0
AngleY.f = 0
AngleZ.f = 0

FontID = LoadFont(0, "arial", 25, #PB_Font_HighQuality)

TexteAffiche.s = "PureBasic, Puissance à l'état pure"

; On dessine le texte et on le convertit en point
CreateSprite(0, 500, 200)
StartDrawing(SpriteOutput(0))
  Box(0, 0, 500, 100, $FFFFFF)
  DrawingFont(FontID)
  Locate((500 - TextLength(TexteAffiche)) / 2, 0)
  FrontColor(0, 0, 0)
  DrawText(TexteAffiche)
  
  For n = 0 To 500 - 1
    For nn = 0 To 100 - 1
      Texte(n, nn)\Couleur = Point(n, nn)
      Texte(n, nn)\z = Random(51) - 25
    Next
  Next
  
StopDrawing()

Repeat

  ClearScreen(255, 255, 255)
  
  ; 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
  AngleY + 0.01
  AngleZ + 0.01
  
  StartDrawing(ScreenOutput())
    
    For n = 0 To 500 - 1
      For nn = 0 To 100 - 1
        If Texte(n, nn)\Couleur = 0
          XYFrom3D(n - 250, nn - 50, Texte(n, nn)\z, AngleX, AngleY, AngleZ) ; on affiche tous les points du texte
          Plot(250 +Coord\x, 250 + Coord\y, $DA8900)
        EndIf
      Next
    Next
    
     
  StopDrawing()
  
  FlipBuffers()

  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
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
Crystal Noir
Messages : 892
Inscription : mar. 27/janv./2004 10:07

Message par Crystal Noir »

c'est cool comme effet, mais pfff faut être matheux :(
filperj
Messages : 395
Inscription : jeu. 22/janv./2004 1:13

Message par filperj »

Héhé, joli... :wink:
Le chaos l'emporte toujours sur l'ordre
parcequ'il est mieux organisé.
(Ly Tin Wheedle)
Répondre