Dans cette version les angles de la caméra peuvent changer , pour en faire la démontration , la caméra suit un petit cube , et on peut l'élever ou le baisser avec les touches pageUp ou PageDown, la caméra change d'angle pour suivre le cube , et il est toujours possible de sélectionner un autre cube rester au sol. Autrement dit , les projections 3D--> tiennent compte de l'angle de la caméra et de sa position. Bon il me reste à faire le contraire , la projection de la souris dans la scène 3D.
Placez la souris sur le gros cube pour vérifier le calcul de la projection 3D-->2D.
Le code est en chantier...
Code : Tout sélectionner
;Comtois le 25/06/06
;Cette fois ci le calcul tient compte de la résolution de l'écran et de la focale de la caméra.
;Evidemment cet exemple ne fonctionne plus si un angle de la caméra change.
;Malgré tout ça peut répondre à certains besoins.
#Souris = 0
#CameraSpeed = 10
#Focale = 50
;-Mesh
Enumeration
#Plan
#Cube
#Caisse
EndEnumeration
Macro NORME(V)
(Sqr(V\x * V\x + V\y * V\y + V\z * V\z))
EndMacro
Macro PRODUIT_VECTORIEL(N, V1, V2)
N\x = ((V1\y * V2\z) - (V1\z * V2\y))
N\y = ((V1\z * V2\x) - (V1\x * V2\z))
N\z = ((V1\x * V2\y) - (V1\y * V2\x))
EndMacro
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
Structure Screen
Width.l
Height.l
Width_2.l
Height_2.l
d.f
EndStructure
Structure Cube
Width.f
Height.f
Depth.f
Width_2.f
Height_2.f
Depth_2.f
EndStructure
Structure s_Vecteur
x.f
y.f
z.f
EndStructure
Global Screen.Screen
Screen\Width = 800
Screen\Width_2 = Screen\Width / 2
Screen\Height = 600
Screen\Height_2 = Screen\Height / 2
;Calcul de l'angle pour les projections
Angle.f = (#Focale * 0.0174533) / 2.0
Screen\d = (Screen\Height / (2 * Tan(Angle)))
Declare Erreur(Message.s, Quit.l)
Declare CalculMatriceCamera(No.l)
If InitEngine3D() = 0
Erreur("Impossible d'initialiser la 3D , vérifiez la présence de engine3D.dll" , #True)
ElseIf InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or InitSound() = 0
Erreur("Impossible d'initialiser DirectX 7 Ou plus" , #True)
ElseIf OpenScreen(Screen\Width, Screen\Height, 32, "3D") = 0
Erreur("Impossible d'ouvrir l'écran ", #True)
EndIf
UsePNGImageDecoder()
Define.f KeyX, KeyY, MouseX, MouseY
Global NbVertex, CouleurRegion
Global EAngleX.f
Global Dim Region.Point(7)
Dim VerticesCube.Point(7)
Global Dim MatriceCamera.f(2, 2)
Global Dim Ct(7)
Global NewList PolygoneConvexe.Point()
Global Cube.Cube
Cube\Width = 300
Cube\Width_2 = Cube\Width / 2
Cube\Height = 200
Cube\Height_2 = Cube\Height / 2
Cube\Depth = 300
Cube\Depth_2 = Cube\Depth / 2
Add3DArchive("Data\", #PB_3DArchive_FileSystem)
;-Sprite
LoadSprite(#SOuris,"Data\Souris.PNG")
LoadMesh (#plan, "plan.mesh")
LoadMesh (#cube, "cube.mesh")
;-Textures
LoadTexture(#Plan, "wood02.jpg")
LoadTexture(#Cube, "wall12.jpg")
;-Material
CreateMaterial(#Plan,TextureID(#Plan))
CreateMaterial(#Cube,TextureID(#Cube))
;-Entity
CreateEntity (#Plan, MeshID(#Plan), MaterialID(#Plan))
CreateEntity (#cube, MeshID(#Cube), MaterialID(#Cube),600, 50, 200)
CreateEntity (#caisse, MeshID(#Cube), MaterialID(#Cube),300, Cube\Height_2, 300)
ScaleEntity(#Plan, 10, 1, 10)
;ScaleEntity(#Cube, 2, 4, 2)
ScaleEntity(#Caisse, 3, 2, 3)
;-Light
AmbientColor(RGB(128,128,128))
CreateLight(0, RGB(255,255,255))
;-Camera
CreateCamera(0, 0, 0, 100, 100)
CameraLocate(0, 1000, 1700, 1000)
CameraFOV(0, #Focale * 0.0174533)
;-Procedures
Procedure Erreur(Message.s, Quit.l)
MessageRequester("Erreur", Message, #PB_MessageRequester_Ok)
If Quit
End
EndIf
EndProcedure
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)
Define.f Delta
Delta=Angle2-Angle1
If Delta>180
ProcedureReturn Delta-360
ElseIf Delta<=-180
ProcedureReturn Delta+360
Else
ProcedureReturn Delta
EndIf
EndProcedure
Procedure.f CurveValue(actuelle.f, Cible.f, P.f)
Define.f Delta, Valeur
Delta = Cible - actuelle
If P > 1000 : P = 1000 : EndIf
Valeur = actuelle + ( Delta * P / 1000)
ProcedureReturn Valeur
EndProcedure
Procedure GestionCamera()
Define.f d
d = 700
PosXCamera.f = CurveValue(CameraX(0) , NEW_X(EntityX(#Cube) , EAngleX + 180 , d) , 280)
;PosYCamera.f = CurveValue(CameraY(0) , EntityY(#Cube) + Camera\CameraHaut , 30)
PosYCamera.f = 550
PosZCamera.f = CurveValue(CameraZ(0) , NEW_Z(EntityZ(#Cube) , EAngleX + 180 , d) , 280)
CameraLocate(0 , PosXCamera , PosYCamera , PosZCamera)
CameraLookAt(0 , EntityX(#Cube) , EntityY(#Cube), EntityZ(#Cube))
EndProcedure
Procedure CherchePolygoneConvexe(ListePoints.Point(1))
Define.POINT *Min, *p0, *pi, *pc
;Trouve le point le plus bas dans la liste des points
*Min = @ListePoints(0)
For i = 0 To 7
*p0 = @ListePoints(i)
;Mémorise le point le plus bas , ou le plus à gauche s'il y a égalité
If (*p0\y < *Min\y) Or ((*p0\y = *Min\y) And (*p0\x < *Min\x))
*Min = *p0
EndIf
Next
;Initialise la liste pour le contour convexe
NbVertex = -1
;Effectue la progression de Jarvis pour calculer le contour
*p0 = *Min
Repeat
;Insertion du nouveau p0 dans le contour convexe
NbVertex + 1
Region(NbVertex)\x = *p0\x
Region(NbVertex)\y = *p0\y
;Trouve le point pc dans le sens des aiguilles d'une montre
*pc = #Null
For i = 0 To 7
*pi = @ListePoints(i)
;Saute p0
If *pi = *p0
Continue
EndIf
;Sélectionne le premier point
If *pc = #Null
*pc = @ListePoints(i)
Continue
EndIf
;Teste si pi est dans le sens des aiguilles d'une montre par rapport à pc
z=(((*pi\x - *p0\x) * (*pc\y - *p0\y)) - ((*pi\y - *p0\y) * (*pc\x - *p0\x)))
If z > 0
;pi est dans le sens des aiguilles d'une montre par rapport à pc
*pc = *pi
ElseIf z = 0
;Si pi et pc sont colinéaires , on choisit le plus éloigné de p0
longueurpi = (*pi\x - *p0\x)*(*pi\x - *p0\x) + (*pi\y - *p0\y)*(*pi\y - *p0\y)
longueurpc = (*pc\x - *p0\x)*(*pc\x - *p0\x) + (*pc\y - *p0\y)*(*pc\y - *p0\y)
If longueurpi > longueurpc
*pc = *pi
EndIf
EndIf
Next
;Cherche le point suivant
*p0 = *pc
Until *p0 = *Min Or NbVertex > 6
EndProcedure
Procedure P3D_P2D(X.f, Y.f, Z.f, *P2D.POINT)
Define.s_Vecteur p
Define.f X1,Y1,Z1
;Position du point dans le repère de la caméra
p\x = X - CameraX(0)
p\y = Y - CameraY(0)
p\z = Z - CameraZ(0)
X1 = (MatriceCamera(0,0) * p\x) + (MatriceCamera(0,1) * p\y) + (MatriceCamera(0,2) * p\z)
Y1 = (MatriceCamera(1,0) * p\x) + (MatriceCamera(1,1) * p\y) + (MatriceCamera(1,2) * p\z)
Z1 = (MatriceCamera(2,0) * p\x) + (MatriceCamera(2,1) * p\y) + (MatriceCamera(2,2) * p\z)
; Transformation 3D --> 2D
*P2D\x = (X1 / Z1 * Screen\d) + Screen\Width_2
*P2D\y = (Y1 / Z1 * Screen\d) + Screen\Height_2
EndProcedure
Procedure Normalise(*N.s_Vecteur)
Define.f NormeVecteur
NormeVecteur = NORME(*N)
If NormeVecteur <> 0.0
*N\x / NormeVecteur
*N\y / NormeVecteur
*N\z / NormeVecteur
EndIf
EndProcedure
Procedure CalculMatriceCamera(No.l)
Define.s_Vecteur x, y, z, p, SceneY
SceneY\x = 0
SceneY\y = 1
SceneY\z = 0
;La camera est toujours orientée ver l'entity #Cube
;il est aussi possible de lancer un rayon sur un plan imaginaire pour
;déterminer un point de la scène se trouvant dans la direction de la caméra, pour cela
;il faudrait avoir un retour sur les angles de la caméra ou les gérer soi même :(
;Calcule l'axe z de la caméra ( la caméra pointe vers l'entity)
z\x = EntityX(No) - CameraX(0)
z\y = EntityY(No) - CameraY(0)
z\z = EntityZ(No) - CameraZ(0)
Normalise(@z)
;Calcul l'axe x de la caméra de façon à ce qu'il soit perpendulaire aux axes z et Y de la Scène
PRODUIT_VECTORIEL(x, z, SceneY)
Normalise(@x)
;Calcule l'axe Y de la caméra de façon à ce qu'il soit perpendiculaire aux axes z et x
PRODUIT_VECTORIEL(y, z, x)
Normalise(@y)
;Ligne Colonne
MatriceCamera(0,0) = x\x
MatriceCamera(0,1) = x\y
MatriceCamera(0,2) = x\z
MatriceCamera(1,0) = y\x
MatriceCamera(1,1) = y\y
MatriceCamera(1,2) = y\z
MatriceCamera(2,0) = z\x
MatriceCamera(2,1) = z\y
MatriceCamera(2,2) = z\z
EndProcedure
Procedure Cube3D_Cube2D(X.f, Y.f, Z.f, ListeVertices.Point(1))
CalculMatriceCamera(#Cube)
P3D_P2D(X - Cube\Width_2, Y + Cube\Height_2, Z + Cube\Depth_2, ListeVertices(0))
P3D_P2D(X + Cube\Width_2, Y + Cube\Height_2, Z + Cube\Depth_2, ListeVertices(1))
P3D_P2D(X - Cube\Width_2, Y - Cube\Height_2, Z + Cube\Depth_2, ListeVertices(2))
P3D_P2D(X + Cube\Width_2, Y - Cube\Height_2, Z + Cube\Depth_2, ListeVertices(3))
P3D_P2D(X - Cube\Width_2, Y + Cube\Height_2, Z - Cube\Depth_2, ListeVertices(4))
P3D_P2D(X + Cube\Width_2, Y + Cube\Height_2, Z - Cube\Depth_2, ListeVertices(5))
P3D_P2D(X - Cube\Width_2, Y - Cube\Height_2, Z - Cube\Depth_2, ListeVertices(6))
P3D_P2D(X + Cube\Width_2, Y - Cube\Height_2, Z - Cube\Depth_2, ListeVertices(7))
EndProcedure
Macro INFOS
StartDrawing(ScreenOutput())
For i = 0 To 7
Ct(i) = (VerticesCube(i)\x>-1 And VerticesCube(i)\x<Screen\Width And VerticesCube(i)\y>-1 And VerticesCube(i)\y<Screen\Height)
Next i
If (ct(0) Or ct(1) Or ct(2) Or ct(3) Or ct(4) Or ct(5) Or ct(6) Or ct(7))
DrawText(0,20,"Le cube est visible", $00FF00,0)
If CouleurRegion
For i = 1 To NbVertex
LineXY(Region(i-1)\x, Region(i-1)\y, Region(i)\x, Region(i)\y, CouleurRegion)
Next i
LineXY(Region(0)\x, Region(0)\y, Region(i-1)\x, Region(i-1)\y, CouleurRegion)
EndIf
Else
DrawText(0,20,"Le cube n'est plus visible",$FF,0)
EndIf
StopDrawing()
EndMacro
MouseLocate(400,300)
V = 6
Repeat
ClearScreen(0)
If ExamineKeyboard()
If KeyboardPushed(#PB_Key_PageUp)
EntityLocate(#Cube, EntityX(#Cube), EntityY(#Cube) + 3, EntityZ(#Cube))
ElseIf KeyboardPushed(#PB_Key_PageDown) And EntityY(#Cube)> 50
EntityLocate(#Cube, EntityX(#Cube), EntityY(#Cube) - 3, EntityZ(#Cube))
EndIf
If KeyboardPushed(#PB_Key_Up)
EntityLocate(#Cube, NEW_X(EntityX(#Cube),EAngleX, V), EntityY(#Cube), NEW_Z(EntityZ(#Cube),EAngleX, V))
ElseIf KeyboardPushed(#PB_Key_Down)
EntityLocate(#Cube, NEW_X(EntityX(#Cube),EAngleX, -V), EntityY(#Cube), NEW_Z(EntityZ(#Cube),EAngleX, -V))
EndIf
If KeyboardPushed(#PB_Key_Left)
EAngleX + 1
RotateEntity(#Cube, EAngleX, 0,0)
ElseIf KeyboardPushed(#PB_Key_Right)
EAngleX - 1
RotateEntity(#Cube, EAngleX, 0,0)
EndIf
EndIf
GestionCamera()
Cube3D_Cube2D(EntityX(#caisse), EntityY(#caisse), EntityZ(#caisse), VerticesCube())
CherchePolygoneConvexe(VerticesCube())
If ExamineMouse()
;Teste la souris sur le cube
Hrgn = CreatePolygonRgn_(@Region(), NbVertex + 1, #WINDING)
If PtInRegion_(Hrgn,MouseX(), MouseY())
CouleurRegion = $00FF00
Else
CouleurRegion = 0
EndIf
DeleteObject_(Hrgn)
EndIf
RenderWorld()
DisplayTransparentSprite(#SOuris,MouseX(),MouseY())
INFOS
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)