Page 1 sur 2

Vecteur3D

Publié : mer. 24/sept./2008 22:22
par Anonyme
Voilà j'ai un petit soucis mathématique.
Je voudrais agrémenté ma gestion de caméra & d'entité , pour cela j'ai besoin d'aligner ( comme lookat() ) deux entités , comme il n'y a pas de fct° toute faite , je passe par les vecteurs.

A.Vector3
B.Vector3

A&B sont les vecteurs position des mes entités.

A=0,0,0
B=1000,1000,1000

Pour connaitre le vecteur direction , je normalize les 2 vecteurs par leur norme. puis je soustraits le vecteur B au vecteur A ( B - A )
se qui me donne le vecteur Direction :

Direction.Vector3 = 1,1,1

une fois cela obtenu , je voudrais pouvoir convertir tout cela en degrés , mais le hic , je ne vois pas comment m'y prendre.

Publié : jeu. 25/sept./2008 0:35
par Guimauve
Ça c'est facile, ton problème est que tu souhaite passer d'un système de coordonnées rectangulaires vers un système de coordonnées sphériques.

Important les explications qui suivent sont valides pour les hypothèses suivante :

1. L'axe Z+ est verticale vers le haut
2. L'angle Phi est l'angle entre l'axe Z et le vecteur.
3. L'axe X et l'axe Y sont sur le "Sol"
4. L'angle Thêta est l'angle entre l'axe X et le vecteur.
5. Le vecteur est défini comme suit : [i,j,k]

Rhô = Sqr(i²+j²+k²)
Thêta = ArcTan(j/i)
Phi = ArcTan(sqr(i²+j²)/k)

Remarque : Il faut vérifier le quadrant dans le quel on se trouve pour les angles Thêta et Phi.

A+
Guimauve

Publié : jeu. 25/sept./2008 12:47
par Anonyme
Merci Guimauve.
Pour moi , l'axe Y remplace le Z , je trouve cela "plus logique" , bref , c'est pas le problème :D

dans ton explication , le vecteur I,J,K , il sort d'ou ?
C'est le vecteur direction entre deux vecteurs ? ( Fct° lookat dans le code plus bas ? )

je me base la dessus pour le moment :

Code : Tout sélectionner

Structure VECTOR3
  x.f
  y.f
  z.f
EndStructure

Macro SetVector3(V,_x,_y,_z)
V\x=_x
V\y=_y
V\z=_z
EndMacro

Macro VectorLength(V)
(V\x*V\x + V\y*V\y + V\z*V\z)
EndMacro

Macro Normalize(V)
			l.f = VectorLength(V)
			If (l <> 0) 
  			l =  Sqr(l)
  			V\x / l
  			V\y / l
  			V\z / l
			EndIf 
EndMacro
;//////////////////////////////////////////////////////////
;Retourne un nouveau vecteur qui contient le resultat
;//////////////////////////////////////////////////////////
Procedure Vector3_LookAT(*A.VECTOR3,*B.VECTOR3)
Normalize(*A) : Normalize(*B)
*R.Vector3 = AllocateMemory(SizeOf(VECTOR3))
*R\x= *A\x - *B\x
*R\y= *A\y - *B\y
*R\z= *A\z - *B\z
ProcedureReturn *R
EndProcedure

Procedure.f DotProduct(*A.VECTOR3,*B.VECTOR3)
ProcedureReturn *A\X * *B\X + *A\Y * *B\Y + *A\Z * *B\Z
EndProcedure

Publié : jeu. 25/sept./2008 13:10
par comtois
Cool je voulais bosser le sujet, tu as pris de l'avance, Je n'ai plus qu'à pomper le résultat :)

Je testerai à l'occasion.

Publié : jeu. 25/sept./2008 13:11
par Guimauve
Le vecteur [i, j, k] c'est juste une notation mathématique. Pour la plupart d'entre vous un vecteur c'est [x, y, z] et pour moi ce n'est pas un vecteur 3D mais un point en 3D.

C'est ici que vous aller pouvoir faire le lien ;

La composante i du vecteur est sur l'axe X
La composante j du vecteur est sur l'axe Y
La composante k du vecteur est sur l'axe Z

Et pour l'axe Y+ verticale vers le haut c'est aussi ma convention. C'est juste que la convention d'où j'ai tiré la démonstration mathématique est différente. En comprenant la différence, il est alors facile de l'adapter.

J'espère que c'est plus claire à présent.

A+
Guimauve

Publié : jeu. 25/sept./2008 13:15
par Anonyme

Code : Tout sélectionner

Structure VECTOR3
  x.f
  y.f
  z.f
EndStructure


Macro SetVector3(V,_x,_y,_z)
V\x=_x
V\y=_y
V\z=_z
EndMacro

Macro VectorLength(V)
(V\x*V\x + V\y*V\y + V\z*V\z)
EndMacro

Macro Normalize(V)
			l.f = VectorLength(V)
			If (l <> 0) 
  			l =  Sqr(l)
  			V\x / l
  			V\y / l
  			V\z / l
			EndIf 
EndMacro
;//////////////////////////////////////////////////////////
;Retourne un nouveau vecteur qui contient le resultat
;//////////////////////////////////////////////////////////
Procedure Vector3_LookAT(*A.VECTOR3,*B.VECTOR3)
Normalize(*A) : Normalize(*B)
  *R.Vector3 = AllocateMemory(SizeOf(VECTOR3))
  *R\x= *B\x - *A\x
  *R\y= *B\y - *A\y
  *R\z= *B\z - *A\z
  
  Rho.f   = Sqr(*R\x**R\x+*R\y**R\y+*R\z**R\z)
  Phi.f   = ATan(*R\z/*R\x) ; REMPLACE Z PAR Y
  Theta.f = ATan(Sqr( *R\x * *R\x + *R\z * *R\z)/ *R\y)  ; IDEM IC
  
    Debug Rho
    Debug Phi*180/#PI
    Debug Theta*180/#PI
    
    
ProcedureReturn *R
EndProcedure

Procedure.f DotProduct(*A.VECTOR3,*B.VECTOR3)
ProcedureReturn *A\X * *B\X + *A\Y * *B\Y + *A\Z * *B\Z
EndProcedure



A.VECTOR3 : SetVector3(A,0,0,0)
B.VECTOR3 : SetVector3(B,-10,-10,0)

Vector3_LookAT(A,B)
C'est bien se qui me semblait , merci guimauve.
Vais implementé cela maintenant :D

Publié : jeu. 25/sept./2008 13:24
par comtois
je n'ai pas encore testé , mais pour moi le premier vecteur doit correspondre à l'orientation d'une des entités, celle qui devra regarder l'autre.et le second vecteur est calculé entre les positions des deux entités.

ce qui te fait bien deux vecteurs, le premier correspond à l'orientation initiale de l'entité A , et le second à l'orientation entre l'entité A et l'entité B, ou un point B.

Je ferai peut-être quelques tests ce soir.

Publié : jeu. 25/sept./2008 13:46
par Anonyme
Comtois , ca marche impec ,


A.VECTOR3 : SetVector3(A,0,0,0)
B.VECTOR3 : SetVector3(B,10,10,10)


A c'est la Position de l'entité qui va être dirigé vers l'entité B


ensuite , tu ne normalize pas les vecteur !! , le code n'est donc pas bon.

Vector3_LookAT(A,B)


Rho , c'est la distance , on s'en fou ,
tu colles Rho , Phi & theta dans le vecteur resultant
et tu orientes ton entité.
Attention au changement de signe aussi , si l'objet pointé et < tu auras des soucis , je vais regler le prob et posté un joli code ici après.

Publié : jeu. 25/sept./2008 13:52
par Guimauve
comtois a écrit :je n'ai pas encore testé , mais pour moi le premier vecteur doit correspondre à l'orientation d'une des entités, celle qui devra regarder l'autre.et le second vecteur est calculé entre les positions des deux entités.

ce qui te fait bien deux vecteurs, le premier correspond à l'orientation initiale de l'entité A , et le second à l'orientation entre l'entité A et l'entité B, ou un point B.

Je ferai peut-être quelques tests ce soir.
En fait non. C'est le vecteur entre deux positions. La position A (Celle de la caméra) et la position B (Celle de l'entité vers laquelle on veut tourner la caméra). En trouvant le vecteur entre les 2 positions (B-A) et en calculant les angles on se retrouve avec les angles par rapport au référentiel fixe de la scène et non les angles relatives par rapport à l'orientation actuelle de la caméra. Pour ça des calculs supplémentaires sont nécessaires.

A+
Guimauve

Publié : jeu. 25/sept./2008 13:57
par Anonyme

Code : Tout sélectionner

Procedure Vector3_LookAT(*A.VECTOR3,*B.VECTOR3)
;Normalize(*A) : Normalize(*B)
  *R.Vector3 = AllocateMemory(SizeOf(VECTOR3))
  *R\x= *B\x - *A\x
  *R\y= *B\y - *A\y
  *R\z= *B\z - *A\z
  
  Rho.f   = Sqr(*R\x**R\x+*R\y**R\y+*R\z**R\z)
  Phi.f   = ATan(*R\y/*R\x) 
  Theta.f = ATan(Sqr( *R\x * *R\x + *R\y * *R\y)/ *R\z)  
  
  *R\x=Rho
  *R\y=Phi*180/#PI
  *R\z=Theta*180/#PI
    
    
ProcedureReturn *R
EndProcedure
Avec cela ca fonctionne , y a plus qu'a orienté l'entité ou la caméra

Pitch = *R\y
Yaw = *R\z

mais ca merde quand l'objet visé est plus petit ( le vecteur ).
je verrais demain , là j'ai plus le temps :/

Publié : jeu. 25/sept./2008 13:57
par Guimauve
Cpl.Bator a écrit : Rho , c'est la distance , on s'en fou ,
Pas nécessairement, c'est peut-être pas intéressant pour la fonction LookAt()
mais ça peut-être utile pour autre chose.

A+
Guimauve

Publié : jeu. 25/sept./2008 21:57
par Anonyme
a prioris , j'ai toujours le soucis de l'entité visé qui a une position plus petite sur l'axe des x ou z , la caméra s'inverse , j'ai beau faire des tests de positions pour incrémenté la valeur finale de phi&theta , mais a prioris l'angle renvoyer va de -90 a 90 , soit un arc de 180.
yé comprend pô :D

Publié : jeu. 25/sept./2008 23:11
par Guimauve
Il est possible que l'on doivent ajouter le complément à l'angle en fonction de l'octant dans lequel le vecteur pointe.

Exemple dans le 1er octant les angles calculer sont les bons, dans le 2e octant il faut ajouter 180º. Je vais méditer là dessus ce soir et demain.

[Edit]
En passant, le calcul de normalisation sur les vecteurs A et B sont inutiles.
La normalisation du vecteur résultant (B-A) est suffisant. Ça fait moins de calculs en bout de ligne. (Optimisation)
[/Edit]

A+
Guimauve

Publié : ven. 26/sept./2008 11:24
par comtois
en fait je n'avais pas besoin d'un lookat complet, du coup j'ai repris ce qu'on fait en 2D pour orienter un sprite, ça suffit à mon besoin :)
à mettre dans le dossier demo3D pour ceux qui ont téléchargé mon pack.
Les médias utilisés se trouvent dedans.

Il est possible de changer le point de vue de la caméra, pressez F1.

Il me reste à améliorer l'arrêt quand le personnage arrive au point cible.

Code : Tout sélectionner

#Deg2Rad = #PI/180
#Rad2Deg = 180/#PI
 
IncludeFile "Screen3DRequester.pb"

If InitEngine3D()

  InitSprite()
  InitKeyboard()
  InitMouse()
  Add3DArchive("GUI\", #PB_3DArchive_FileSystem)
  Add3DArchive("GUI\schemes", #PB_3DArchive_FileSystem)
  Add3DArchive("GUI\imagesets", #PB_3DArchive_FileSystem)
  Add3DArchive("GUI\fonts", #PB_3DArchive_FileSystem)
  Add3DArchive("GUI\looknfeel", #PB_3DArchive_FileSystem)
  Add3DArchive("GUI\layouts", #PB_3DArchive_FileSystem)
  Add3DArchive("Data\"          , #PB_3DArchive_FileSystem)
  Add3DArchive("Jaiqua\", #PB_3DArchive_FileSystem)
  Add3DArchive("Cube\", #PB_3DArchive_FileSystem)
  Add3DArchive("Data\Skybox.zip", #PB_3DArchive_Zip)
 
  If Screen3DRequester()
    
    Structure Vecteur
      x.f
      y.f
    EndStructure

    Declare Norme(*V.Vecteur)
    Declare.f atan2f(y.f,x.f)
    Declare.f CurveValue(actuelle.f, Cible.f, P.f)
    Declare.f WrapValue(angle.f)
    Declare.f CurveAngle( Actuelle.f , Cible.f , P.f)
    
    ;-Déclaration des variables
    Define AngleY.f, Angle, AngleC.f, dist, Mode,Vitesse.f = 0.7, pas.f=0.2
    Define.Vecteur Direction, Sprite, Destination  
    Define.f KeyX, KeyY, MouseX, MouseY, AngleCamera,Px,Py,Pz,Pv=50
    #Speed = 4
  
    Macro DISTANCE(p1, p2)
      Sqr((p1\x - p2\x) * (p1\x - p2\x) + (p1\y - p2\y) * (p1\y - p2\y))
    EndMacro

    Macro NEW_X(x, Angle, Distance)
      ((x) + Cos((Angle) * #Deg2Rad) * (Distance))
    EndMacro
    
    Macro NEW_Z(z, Angle, Distance)
      ((z) - Sin((Angle) * #Deg2Rad) * (Distance))
    EndMacro

    WorldShadows(#PB_Shadow_Additive) ; Set the shadow mode for the world
   
    ; Create a plan, manually
    ;
    CreateMesh(1,100)
    SetMeshData(1, #PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_UVCoordinate, ?PlanVertices, 4)
    SetMeshData(1, #PB_Mesh_Face, ?PlanFaces, 2)
    CreateMaterial(1, LoadTexture(1, "Background.png"))
    CreateEntity (10, MeshID(1), MaterialID(1))
    
    EntityRenderMode(1, 0) ; Disable shadow casting for this entity as it's our plan
    
    ScaleEntity(10, 1000, 1, 1000)
    MoveEntity(10, -500, -5, -500)
    DisableMaterialLighting(1, #False)
    ;-Entité A
    LoadMesh   (0, "jaiqua.mesh")
    CreateMaterial(0, LoadTexture(0, "blue_jaiqua.jpg"))
    CreateEntity(0,MeshID(0),MaterialID(0))
    ScaleEntity(0,4,4,4)
    AnimateEntity(0, "Walk")
     
    ;-Entité B
    LoadMesh(2,"cube.mesh")
    CreateMaterial(2,LoadTexture(2,"clouds.jpg"))
    CreateEntity(2,MeshID(2), MaterialID(2),400,0,400)
    ScaleEntity(2,0.1,0.1,0.1)  
    
    ;-Camera
    CreateCamera(0, 0, 0, 100, 100)
    CameraLocate(0, 500, 190, 700)
    CameraLookAt(0,EntityX(0),EntityY(0),EntityZ(0))
    
    ;-Light
    AmbientColor(RGB(138,138,138))
    CreateLight(0, RGB(255,255,255),  100, 400, 0)
    
    ;-Skybox
    SkyBox("stevecube.jpg")
    
    ;-Window3D
    OpenWindow3D(0,0,0,300,100,"Poursuite")
    TextGadget3D(0,20,50,200,40,"Push 'F1'")
    ShowGUI(128,1)
    
    Repeat
      If ExamineKeyboard()
      
        If KeyboardReleased(#PB_Key_F1)
          Mode = 1 - Mode
          If Mode 
          T$="use cursor or 'F1'"
          Else
          T$="Camera auto or 'F1'"
          EndIf
          SetGadgetText3D(0,T$)
        EndIf
        If Mode 
          If KeyboardPushed(#PB_Key_Left)
            KeyX = -#Speed
          ElseIf KeyboardPushed(#PB_Key_Right)
            KeyX = #Speed
          Else
            KeyX = 0
          EndIf
          
          If KeyboardPushed(#PB_Key_Up)
            KeyY = -#Speed
          ElseIf KeyboardPushed(#PB_Key_Down)
            KeyY = #Speed
          Else
            KeyY = 0
          EndIf
          
          If KeyboardPushed(#PB_Key_PageUp)
            RollZ = 3
          Else
            RollZ = 0
          EndIf
          RotateCamera(0, MouseY, MouseX, RollZ,1)
          MoveCamera  (0, KeyX, 0, KeyY)
        Else
          AngleCamera = Curveangle(AngleCamera, AngleY-90, Pv)
          Px = CurveValue(CameraX(0), NEW_X(EntityX(0), AngleCamera, 160), Pv)
          Py = CurveValue(CameraY(0), EntityY(0) + 90, Pv)
          Pz = CurveValue(CameraZ(0), NEW_Z(EntityZ(0), AngleCamera, 160), Pv)

          CameraLocate(0, Px, Py, Pz)
          CameraLookAt(0, EntityX(0), EntityY(0)+30, EntityZ(0))
        
        EndIf          
      
      EndIf
      
      If ExamineMouse()
        MouseX = -MouseDeltaX()/10 
        MouseY = -MouseDeltaY()/10
      EndIf
     
      EntityLocate(2,Cos(AngleC*#Deg2Rad)*400,0,Sin(AngleC*#Deg2Rad)*400)
      AngleC+pas
      Destination\x = EntityX(2)
      Destination\y = EntityZ(2)
      
      ;Direction
      Direction\x = Destination\x - Sprite\x 
      Direction\y = Destination\y - Sprite\y
      Angle=-atan2f(Direction\y, Direction\x) / #Deg2Rad
      Norme(@Direction)
      
      ;Deplacement sprite
      dist = DISTANCE(Destination, Sprite)
      
      If dist < Vitesse
          Sprite\x + Direction\x * dist
          Sprite\y + Direction\y * dist   
      Else 
          Sprite\x + Direction\x * Vitesse
          Sprite\y + Direction\y * Vitesse
      EndIf
      
    	EntityLocate(0, Sprite\x, 0, Sprite\y)
     	AngleY=CurveAngle(AngleY,Angle-90,40)
     	RotateEntity(0,0,AngleY,0)

      RenderWorld()
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  EndIf
   
Else
  MessageRequester("Error", "The 3D Engine can't be initialized",0)
EndIf

Procedure.f WrapValue(angle.f); <- wraps a value into [0,360) fringe
  ;Psychophanta : http://purebasic.fr/english/viewtopic.php?t=18635  
  !fild dword[@f] ; <- now i have 360 into st0
  !fld dword[p.v_angle]
  !fprem
  !fadd st1,st0
  !fldz
  !fcomip st1
  !fcmovnbe st0,st1
  !fstp st1
  ProcedureReturn
  !@@:dd 360
EndProcedure 

Procedure.f EcartAngle( Angle1.f , Angle2.f )
  Delta.f=Angle2-Angle1
  If Delta>180
    ProcedureReturn Delta-360
  ElseIf Delta<=-180
    ProcedureReturn Delta+360
  Else
    ProcedureReturn Delta
  EndIf   
EndProcedure
Procedure.f CurveAngle( Actuelle.f , Cible.f , P.f )
  ;Calcule un angle progressif allant de la valeur actuelle à la valeur cible
  Delta.f = EcartAngle( Actuelle , Cible )
  If P > 1000 : P = 1000 : EndIf
  Valeur.f = Actuelle + ( Delta * P / 1000 )
  ProcedureReturn WrapValue( Valeur )
EndProcedure 

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 Norme(*V.Vecteur)
    Define.f Norme
    
    Norme.f = Sqr(*V\x * *V\x + *V\y * *V\y)
    If Norme 
     	*V\x / Norme
      *V\y / Norme
    EndIf
EndProcedure 
Procedure.f atan2f(y.f, x.f)
  !fld dword[p.v_y]
  !fld dword[p.v_x]
  !fpatan
  ProcedureReturn
EndProcedure

DataSection

  PlanVertices:
    
    ; Note normals are important component to allow correct light support (and therefore shadow)
    ;
    Data.f 0, 0, 0    ; Vertex 0
    Data.f 1, 1, 1    ; Normals (perpendicular to the plan)
    Data.f 0   , 0.33 ; UVCoordinate
    
    Data.f 1, 0, 0    ; Vertex 1
    Data.f 1,1,1      ; Normals
    Data.f 0.33, 0.33 ; UVCoordinate
    
    Data.f 1, 0, 1    ; Vertex 2
    Data.f 1,1,1      ; Normals
    Data.f 0.33, 0    ; UVCoordinate
    
    Data.f 0, 0, 1    ; Vertex 3
    Data.f 1,1,1      ; Normals
    Data.f 0,    0    ; UVCoordinate

  PlanFaces:
    Data.w 2, 1, 0 ; bottom face (clockwise as it's reversed...)
    Data.w 0, 3, 2 

EndDataSection

Publié : sam. 27/sept./2008 11:17
par Anonyme
Guimauve , ta pu voir pour c'est histoire de quadrant ?
D'apres mes test ici

en faisant un cercle complet , j'obtients se genre de suite :

0 90
180 270
90 180
270 360