Vecteur3D
Vecteur3D
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.
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.
Ç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
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
Merci Guimauve.
Pour moi , l'axe Y remplace le Z , je trouve cela "plus logique" , bref , c'est pas le problème
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 :
Pour moi , l'axe Y remplace le Z , je trouve cela "plus logique" , bref , c'est pas le problème

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

Je testerai à l'occasion.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
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
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
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)
Vais implementé cela maintenant

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.
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.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
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.
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.
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.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.
A+
Guimauve
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
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 :/
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
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
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.

à 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
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.