...Me voici de retour de mon excursion dans le monde merveilleux des quaternions.
Voici une nouvelle version du même code, qui fait la même chose qu'avant, mais avec des quaternions.
- Je dois ajouter 90° dans mon RotateEntity, car "l'avant" du mon entité ne correspondait pas à l'axe Z du vecteur de translation (peut-être à cause de l'ordre des vertices dans les meshdata? Qu'est-ce qui définit l'orientation par défaut d'une entité?)
! AAAAAARGH ! Quand que je mets 90° de roulis, les modifications d'azimuth et d'inclinaison provoquent les mêmes mouvements de l'entity.
Code : Tout sélectionner
; Moving_an_entity_quaternion
; Author: Comtois, modified by Kelebrindae to add pitch control
; Date: 11 mars 2008
; PB version: v4.00
; OS: Windows XP
; Demo: Yes
EnableExplicit
InitEngine3D()
InitSprite()
InitKeyboard()
ExamineDesktops()
OpenScreen(DesktopWidth(0), DesktopHeight(0), DesktopDepth(0), "Moving an entity - 2 axis")
;- Structure et variables globales
Enumeration
#VueDessus
#VueArriere
#VueCote
#VueAvant
#VueFixe
EndEnumeration
Structure quaternion
x.f
y.f
z.f
w.f
EndStructure
Structure vector3
x.f
y.f
z.f
EndStructure
Global norm.f
Global cQuat.quaternion
Global pResultVector.vector3
Global azimuth.f,inclinaison.f,roulis.f
Global Vitesse.f
Define.l Options, ModeCamera, i
Vitesse = 1
ModeCamera = #VueArriere
;- Declaration des procédures
Declare.f CurveValue(actuelle.f, Cible.f, P.f)
Declare GestionCamera(Mode.l)
Declare.f wrapValueF(angle.f)
Declare EulerAnglesToQuat(x.f,y.f,z.f)
Declare QuaternionTransform(x.f,y.f,z.f)
;- Macros
Macro NEW_X(x, Angle, Distance)
((x) + Cos((Angle) * 0.0174533) * (Distance))
EndMacro
Macro NEW_Z(z, Angle, Distance)
((z) - Sin((Angle) * 0.0174533) * (Distance))
EndMacro
Macro AFFICHE_AIDE()
StartDrawing(ScreenOutput())
DrawText(0,0,"Touches [F1] - [F2] - [F3] - [F4] - [F5] pour changer la vue de la caméra ", $FF0000, $00FFFF)
DrawText(0,18,"Touches du curseur pour modifier l'orientation, S/X pour avancer/reculer", $FF0000, $00FFFF)
DrawText(0,40,"Azimuth, inclinaison, roulis: " + StrF(azimuth,2) + "," + StrF(inclinaison,2) + "," + StrF(roulis,2), $FF0000, $00FFFF)
StopDrawing()
EndMacro
;-Mesh
#Mesh = 0
CreateMesh(#Mesh, 100)
Options = #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_Color | #PB_Mesh_UVCoordinate
SetMeshData(#Mesh, Options , ?Sommets, 24)
SetMeshData(#Mesh, #PB_Mesh_Face, ?Triangles, 12)
;-Textures
#Texture = 0
CreateTexture(#Texture, 64, 64)
;Remplissage de la texture du cube avec une couleur par face pour mieux situer l'orientation de l'objet
StartDrawing(TextureOutput(#Texture))
Box(0, 0, TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $FF00FF)
Box(TextureWidth(#Texture)/3, 0,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $FF0000)
Box(2*TextureWidth(#Texture)/3, 0,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $00FF00)
Box(0, TextureHeight(#Texture)/2, TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $0000FF)
Box(TextureWidth(#Texture)/3, TextureWidth(#Texture)/2,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $FFFF00)
Box(2*TextureWidth(#Texture)/3, TextureHeight(#Texture)/2,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, $00FFFF)
DrawingMode(#PB_2DDrawing_Outlined) ; Pour tracer le contour
Box(0, 0, TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
Box(TextureWidth(#Texture)/3, 0,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
Box(2*TextureWidth(#Texture)/3, 0,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
Box(0, TextureHeight(#Texture)/2, TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
Box(TextureWidth(#Texture)/3, TextureWidth(#Texture)/2,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
Box(2*TextureWidth(#Texture)/3, TextureHeight(#Texture)/2,TextureWidth(#Texture)/3, TextureHeight(#Texture)/2, 0)
StopDrawing()
#TextureSol = 1
CreateTexture(#TextureSol, 128, 128)
;Remplissage de la texture du sol en blanc
StartDrawing(TextureOutput(#TextureSol))
Box(0, 0, TextureWidth(#TextureSol), TextureHeight(#TextureSol), $007700)
For i = 0 To 127 Step 10
Line(i, 0, 0, TextureHeight(#TextureSol), $00FF00)
Line(0, i, TextureWidth(#TextureSol), 0, $00FF00)
Next i
DrawingMode(#PB_2DDrawing_Outlined) ; Pour tracer le contour
Box(0, 0, TextureWidth(#TextureSol), TextureHeight(#TextureSol), $000088)
StopDrawing()
;-Matière
#Matiere = 0
CreateMaterial(#Matiere, TextureID(#Texture))
#MatiereSol = 1
CreateMaterial(#MatiereSol, TextureID(#TextureSol))
;-Entity
#Entity = 0
CreateEntity(#Entity, MeshID(#Mesh), MaterialID(#Matiere))
ScaleEntity(#Entity, 10, 10, 10) ; Agrandir l'entity
EntityLocate(#Entity, 500, 5, 500)
#EntitySol = 1
CreateEntity(#EntitySol, MeshID(#Mesh), MaterialID(#MatiereSol))
ScaleEntity(#EntitySol, 1000, 2, 1000) ; Agrandir l'entity
EntityLocate(#EntitySol, 500, -1, 500)
EntityRenderMode(#EntitySol,#PB_Entity_Solid)
;-Camera
#Camera = 0
CreateCamera(#Camera, 0, 0, 100, 100)
;-Light
AmbientColor(RGB(100,100,100)) ; Réduit la lumière ambiante pour mieux voir les lumières
CreateLight(0,RGB(255, 255, 255), 0, 500, 0)
;-Shadows
WorldShadows(#PB_Shadow_Modulative) ; Commenter cette ligne si le frame rate est trop lent
RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
Repeat
If ExamineKeyboard()
;Change la vue de la caméra
If KeyboardReleased(#PB_Key_F1)
ModeCamera = #VueDessus
ElseIf KeyboardReleased(#PB_Key_F2)
ModeCamera = #VueArriere
ElseIf KeyboardReleased(#PB_Key_F3)
ModeCamera = #VueCote
ElseIf KeyboardReleased(#PB_Key_F4)
ModeCamera = #VueAvant
ElseIf KeyboardReleased(#PB_Key_F5)
ModeCamera = #VueFixe
EndIf
; Azimuth
If KeyboardPushed(#PB_Key_Left)
azimuth = wrapValueF( azimuth + 1 )
RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
ElseIf KeyboardPushed(#PB_Key_Right)
azimuth = wrapValueF( azimuth - 1 )
RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
EndIf
; Inclinaison
If KeyboardPushed(#PB_Key_Down)
inclinaison = wrapValueF( inclinaison + 1 )
RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
ElseIf KeyboardPushed(#PB_Key_Up)
inclinaison = wrapValueF( inclinaison - 1 )
RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
EndIf
; Roulis (désactivé pour l'instant)
; If KeyboardPushed(#PB_Key_A)
; roulis = wrapValueF( roulis + 1 )
;
; RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
; ElseIf KeyboardPushed(#PB_Key_D)
; roulis = wrapValueF( roulis - 1 )
;
; RotateEntity(#Entity, azimuth+90, roulis, inclinaison)
; EndIf
If KeyboardPushed(#PB_Key_S)
EulerAnglesToQuat(inclinaison * 0.0174533,azimuth * 0.0174533,roulis * 0.0174533 )
QuaternionTransform(0,0,-vitesse)
MoveEntity(#Entity, pResultVector\x,pResultVector\y,pResultVector\z)
ElseIf KeyboardPushed(#PB_Key_X)
EulerAnglesToQuat(inclinaison * 0.0174533,azimuth * 0.0174533,roulis * 0.0174533 )
QuaternionTransform(0,0,vitesse)
MoveEntity(#Entity, pResultVector\x,pResultVector\y,pResultVector\z)
EndIf
EndIf
GestionCamera(ModeCamera)
RenderWorld()
AFFICHE_AIDE()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Procedure.f CurveValue(actuelle.f, Cible.f, P.f)
;Calcule une valeur progressive allant de la valeur actuelle à la valeur cible
Define.f Delta
Delta = Cible - actuelle
If P > 1000.0 : P = 1000.0 : EndIf
ProcedureReturn (actuelle + ( Delta * P / 1000.0))
EndProcedure
Procedure GestionCamera(Mode.l)
Define.f Px, Py, Pz, Pv
Static AngleCamera.f
Pv = 25
Select Mode
Case #VueDessus
AngleCamera = CurveValue(AngleCamera, azimuth + 180, Pv)
Px = CurveValue(CameraX(#Camera), NEW_X(EntityX(#Entity), AngleCamera, 40), Pv)
Py = CurveValue(CameraY(#Camera), EntityY(#Entity) + 140, Pv)
Pz = CurveValue(CameraZ(#Camera), NEW_Z(EntityZ(#Entity), AngleCamera, 40), Pv)
Case #VueArriere
AngleCamera = CurveValue(AngleCamera, azimuth + 180, Pv)
Px = CurveValue(CameraX(#Camera), NEW_X(EntityX(#Entity), AngleCamera, 80), Pv)
Py = CurveValue(CameraY(#Camera), EntityY(#Entity) + 40, Pv)
Pz = CurveValue(CameraZ(#Camera), NEW_Z(EntityZ(#Entity), AngleCamera, 80), Pv)
Case #VueCote
AngleCamera = CurveValue(AngleCamera, azimuth + 120, Pv)
Px = CurveValue(CameraX(#Camera), NEW_X(EntityX(#Entity), AngleCamera, 80), Pv)
Py = CurveValue(CameraY(#Camera), EntityY(#Entity) + 40, Pv)
Pz = CurveValue(CameraZ(#Camera), NEW_Z(EntityZ(#Entity), AngleCamera, 80), Pv)
Case #VueAvant
AngleCamera = CurveValue(AngleCamera, azimuth, Pv)
Px = CurveValue(CameraX(#Camera), NEW_X(EntityX(#Entity), AngleCamera, 80), Pv)
Py = CurveValue(CameraY(#Camera), EntityY(#Entity) + 40, Pv)
Pz = CurveValue(CameraZ(#Camera), NEW_Z(EntityZ(#Entity), AngleCamera, 80), Pv)
EndSelect
If Mode <> #VueFixe
CameraLocate(#Camera, Px, Py, Pz)
EndIf
CameraLookAt(#Camera, EntityX(#Entity), EntityY(#Entity), EntityZ(#Entity))
EndProcedure
Procedure.f wrapValueF(angle.f)
If angle < 0
ProcedureReturn angle+360
Else
If angle >= 360
ProcedureReturn angle-360
EndIf
EndIf
ProcedureReturn angle
EndProcedure
Procedure EulerAnglesToQuat(x.f,y.f,z.f)
Protected roll.f,pitch.f,yaw.f
Protected cyaw.f, cpitch.f, croll.f, syaw.f, spitch.f, sroll.f
Protected cyawcpitch.f, syawspitch.f, cyawspitch.f, syawcpitch.f
roll = x
pitch= y
yaw = z
cyaw = Cos(0.5 * yaw)
cpitch = Cos(0.5 * pitch)
croll = Cos(0.5 * roll)
syaw = Sin(0.5 * yaw)
spitch = Sin(0.5 * pitch)
sroll = Sin(0.5 * roll)
cyawcpitch = cyaw*cpitch
syawspitch = syaw*spitch
cyawspitch = cyaw*spitch
syawcpitch = syaw*cpitch
norm = (cyawcpitch * croll + syawspitch * sroll)
cQuat\x = (cyawcpitch * sroll - syawspitch * croll)
cQuat\y = (cyawspitch * croll + syawcpitch * sroll)
cQuat\z = (syawcpitch * croll - cyawspitch * sroll)
cQuat\w = norm
EndProcedure
Procedure QuaternionTransform(x.f,y.f,z.f)
pResultVector\x = cQuat\w*cQuat\w*x + 2*cQuat\y*cQuat\w*z - 2*cQuat\z*cQuat\w*y + cQuat\x*cQuat\x*x + 2*cQuat\y*cQuat\x*y + 2*cQuat\z*cQuat\x*z - cQuat\z*cQuat\z*x - cQuat\y*cQuat\y*x
pResultVector\y = 2*cQuat\x*cQuat\y*x + cQuat\y*cQuat\y*y + 2*cQuat\z*cQuat\y*z + 2*cQuat\w*cQuat\z*x - cQuat\z*cQuat\z*y + cQuat\w*cQuat\w*y - 2*cQuat\x*cQuat\w*z - cQuat\x*cQuat\x*y;
pResultVector\z = 2*cQuat\x*cQuat\z*x + 2*cQuat\y*cQuat\z*y + cQuat\z*cQuat\z*z - 2*cQuat\w*cQuat\y*x - cQuat\y*cQuat\y*z + 2*cQuat\w*cQuat\x*y - cQuat\x*cQuat\x*z + cQuat\w*cQuat\w*z;
EndProcedure
;{ Définition du cube
DataSection
Sommets:
;Dessus 0 à 3
Data.f -0.5,0.5,-0.5
Data.f 0,1,0
Data.l 0
Data.f 0,0
Data.f 0.5,0.5,-0.5
Data.f 0,1,0
Data.l 0
Data.f 0,0.5
Data.f 0.5,0.5,0.5
Data.f 0,1,0
Data.l 0
Data.f 0.333,0.5
Data.f -0.5,0.5,0.5
Data.f 0,1,0
Data.l 0
Data.f 0.333,0
;Dessous 4 à 7
Data.f -0.5,-0.5,0.5
Data.f 0,-1,0
Data.l 0
Data.f 0.333,0
Data.f 0.5,-0.5,0.5
Data.f 0,-1,0
Data.l 0
Data.f 0.333,0.5
Data.f 0.5,-0.5,-0.5
Data.f 0,-1,0
Data.l 0
Data.f 0.666,0.5
Data.f -0.5,-0.5,-0.5
Data.f 0,-1,0
Data.l 0
Data.f 0.666,0
;Devant 8 à 11
Data.f -0.5,0.5,0.5
Data.f 0,0,1
Data.l 0
Data.f 0.666,0
Data.f 0.5,0.5,0.5
Data.f 0,0,1
Data.l 0
Data.f 0.666,0.5
Data.f 0.5,-0.5,0.5
Data.f 0,0,1
Data.l 0
Data.f 1,0.5
Data.f -0.5,-0.5,0.5
Data.f 0,0,1
Data.l 0
Data.f 1,0
;Derrière 12 à 15
Data.f 0.5,0.5,-0.5
Data.f 0,0,-1
Data.l 0
Data.f 0,0.5
Data.f -0.5,0.5,-0.5
Data.f 0,0,-1
Data.l 0
Data.f 0,1
Data.f -0.5,-0.5,-0.5
Data.f 0,0,-1
Data.l 0
Data.f 0.333,1
Data.f 0.5,-0.5,-0.5
Data.f 0,0,-1
Data.l 0
Data.f 0.333,0.5
;Cote gauche 16 à 19
Data.f -0.5,0.5,-0.5
Data.f -1,0,0
Data.l 0
Data.f 0.333,0.5
Data.f -0.5,0.5,0.5
Data.f -1,0,0
Data.l 0
Data.f 0.333,1
Data.f -0.5,-0.5,0.5
Data.f -1,0,0
Data.l 0
Data.f 0.666,1
Data.f -0.5,-0.5,-0.5
Data.f -1,0,0
Data.l 0
Data.f 0.666,0.5
;Cote droit 20 à 23
Data.f 0.5,0.5,0.5
Data.f 1,0,0
Data.l 0
Data.f 0.666,0.5
Data.f 0.5,0.5,-0.5
Data.f 1,0,0
Data.l 0
Data.f 0.666,1
Data.f 0.5,-0.5,-0.5
Data.f 1,0,0
Data.l 0
Data.f 1,1
Data.f 0.5,-0.5,0.5
Data.f 1,0,0
Data.l 0
Data.f 1,0.5
Triangles:
;Face en Haut
Data.w 2,1,0
Data.w 0,3,2
;Face en Bas
Data.w 6,5,4
Data.w 4,7,6
;Face Avant
Data.w 10,9,8
Data.w 8,11,10
;Face Arrière
Data.w 14,13,12
Data.w 12,15,14
;Face Gauche
Data.w 18,17,16
Data.w 16,19,18
;Face Droite
Data.w 22,21,20
Data.w 20,23,22
EndDataSection
;}
Ah oui, j'oubliais: merci à Tmyke pour la procedure "EulerAnglesToQuat" trouvée à cette adresse:
C'est toujours ça de moins à réécrire...