SimpleSpline : Démo

Généralités sur la programmation 3D
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

SimpleSpline : Démo

Message par comtois »

la suite logique de ce code, c'est de l'appliquer en 3D pour définir un chemin , alors voici une démo qu'il suffit d'enregistrer dans le répertoire Examples/3D de PureBasic.

Code : Tout sélectionner

; This source file is part of OGRE
;     (Object-oriented Graphics Rendering Engine)
; For the latest info, see http://www.ogre3d.org/
; 
; Copyright (c) 2000-2009 Torus Knot Software Ltd

;An example of using SimpleSpline To make an Entity smoothly 
;follow a predefined path With spline interpolation.

IncludeFile "Screen3DRequester.pb"

Structure Vector3
  x.f
  y.f
  z.f
EndStructure

Structure Spline
  NbPoint.i
  Array mPoints.Vector3(0)
  Array mTangents.Vector3(0)
  pos.Vector3
EndStructure

Macro CopyVector3(a, b)
  a\x = b\x
  a\y = b\y
  a\z = b\z
EndMacro

Global Dim mCoeffs.f(3,3)
Declare recalcTangents(*Spline.Spline)
Declare interpolate2(*Spline.Spline, fromIndex, t.f) 

; Set up matrix
; Hermite polynomial
mCoeffs(0,0) = 2
mCoeffs(0,1) = -2
mCoeffs(0,2) = 1
mCoeffs(0,3) = 1

mCoeffs(1,0) = -3
mCoeffs(1,1) = 3
mCoeffs(1,2) = -2
mCoeffs(1,3) = -1

mCoeffs(2,0) = 0
mCoeffs(2,1) = 0
mCoeffs(2,2) = 1
mCoeffs(2,3) = 0

mCoeffs(3,0) = 1
mCoeffs(3,1) = 0
mCoeffs(3,2) = 0
mCoeffs(3,3) = 0

Procedure CreateSpline()
  *mem = AllocateMemory(SizeOf(Spline))
  InitializeStructure(*mem, Spline)
  ProcedureReturn *mem
EndProcedure

Procedure concatenate(Array r.f(2), Array m.f(2), Array m2.f(2))
  r(0,0) = m(0,0) * m2(0,0) + m(0,1) * m2(1,0) + m(0,2) * m2(2,0) + m(0,3) * m2(3,0);
  r(0,1) = m(0,0) * m2(0,1) + m(0,1) * m2(1,1) + m(0,2) * m2(2,1) + m(0,3) * m2(3,1);
  r(0,2) = m(0,0) * m2(0,2) + m(0,1) * m2(1,2) + m(0,2) * m2(2,2) + m(0,3) * m2(3,2);
  r(0,3) = m(0,0) * m2(0,3) + m(0,1) * m2(1,3) + m(0,2) * m2(2,3) + m(0,3) * m2(3,3);
  
  r(1,0) = m(1,0) * m2(0,0) + m(1,1) * m2(1,0) + m(1,2) * m2(2,0) + m(1,3) * m2(3,0);
  r(1,1) = m(1,0) * m2(0,1) + m(1,1) * m2(1,1) + m(1,2) * m2(2,1) + m(1,3) * m2(3,1);
  r(1,2) = m(1,0) * m2(0,2) + m(1,1) * m2(1,2) + m(1,2) * m2(2,2) + m(1,3) * m2(3,2);
  r(1,3) = m(1,0) * m2(0,3) + m(1,1) * m2(1,3) + m(1,2) * m2(2,3) + m(1,3) * m2(3,3);
  
  r(2,0) = m(2,0) * m2(0,0) + m(2,1) * m2(1,0) + m(2,2) * m2(2,0) + m(2,3) * m2(3,0);
  r(2,1) = m(2,0) * m2(0,1) + m(2,1) * m2(1,1) + m(2,2) * m2(2,1) + m(2,3) * m2(3,1);
  r(2,2) = m(2,0) * m2(0,2) + m(2,1) * m2(1,2) + m(2,2) * m2(2,2) + m(2,3) * m2(3,2);
  r(2,3) = m(2,0) * m2(0,3) + m(2,1) * m2(1,3) + m(2,2) * m2(2,3) + m(2,3) * m2(3,3);
  
  r(3,0) = m(3,0) * m2(0,0) + m(3,1) * m2(1,0) + m(3,2) * m2(2,0) + m(3,3) * m2(3,0);
  r(3,1) = m(3,0) * m2(0,1) + m(3,1) * m2(1,1) + m(3,2) * m2(2,1) + m(3,3) * m2(3,1);
  r(3,2) = m(3,0) * m2(0,2) + m(3,1) * m2(1,2) + m(3,2) * m2(2,2) + m(3,3) * m2(3,2);
  r(3,3) = m(3,0) * m2(0,3) + m(3,1) * m2(1,3) + m(3,2) * m2(2,3) + m(3,3) * m2(3,3);
EndProcedure 

Procedure Multiplication(Array r.f(1), Array v.f(1), Array m.f(2))
  r(0) = m(0,0) * v(0) + m(1,0) * v(1) + m(2,0) * v(2) + m(3,0) * v(3)
  r(1) = m(0,1) * v(0) + m(1,1) * v(1) + m(2,1) * v(2) + m(3,1) * v(3)
  r(2) = m(0,2) * v(0) + m(1,2) * v(1) + m(2,2) * v(2) + m(3,2) * v(3)
  r(3) = m(0,3) * v(0) + m(1,3) * v(1) + m(2,3) * v(2) + m(3,3) * v(3)
EndProcedure

Procedure AddPointSpline(*Spline.Spline, x.f, y.f, z.f)
  Protected Index.s
  *Spline\mPoints(*Spline\NbPoint)\x = x
  *Spline\mPoints(*Spline\NbPoint)\y = y
  *Spline\mPoints(*Spline\NbPoint)\z = z
  *Spline\NbPoint + 1
  ReDim *spline\mPoints.Vector3(*Spline\NbPoint)
  recalcTangents(*Spline)
EndProcedure

Procedure interpolateSpline(*Spline.Spline, t.f) 
  
  ;Currently assumes points are evenly spaced, will cause velocity
  ;change where this is Not the Case
  ;TODO: base on arclength?
  
  ; Work out which segment this is in
  fSeg.f = t * (*spline\NbPoint - 1)
  segIdx = Int(fSeg)
  ; Apportion t 
  t = fSeg - segIdx
  interpolate2(*Spline, segIdx, t)
  
EndProcedure

Procedure interpolate2(*Spline.Spline, fromIndex, t.f) 
  
  ;// Bounds check
  If *spline\NbPoint=0
    ProcedureReturn
  EndIf 
  
  If (fromIndex + 1) = *spline\NbPoint
    
    ;// Duff request, cannot blend To nothing
    ;// Just Return source
    CopyVector3(*Spline\pos, *Spline\mPoints(fromIndex))
    ProcedureReturn 
    
  EndIf
  
  ;// Fast special cases
  If t = 0.0
    
    CopyVector3(*Spline\pos, *Spline\mPoints(fromIndex))
    ProcedureReturn
    
  ElseIf t = 1.0
    CopyVector3(*Spline\pos, *Spline\mPoints(fromIndex + 1))
    ProcedureReturn
  EndIf
  
  ;// Real interpolation
  ;// Form a vector of powers of t
  Define.f t2, t3
  t2 = t * t
  t3 = t2 * t
  Dim powers.f(3)
  powers(0) = t3
  powers(1) = t2
  powers(2) = t
  powers(3) = 1
  
  ;// Algorithm is ret = powers * mCoeffs * Matrix4(point1, point2, tangent1, tangent2)
  Define.Vector3 point1, point2, tan1, tan2
  CopyVector3(point1, *Spline\mPoints(fromIndex))
  CopyVector3(point2, *Spline\mPoints(fromIndex+1))
  CopyVector3(tan1  , *Spline\mTangents(fromIndex))
  CopyVector3(tan2  , *Spline\mTangents(fromIndex+1))
  
  Dim pt.f(3,3)
  
  pt(0,0) = point1\x
  pt(0,1) = point1\y
  pt(0,2) = point1\z
  pt(0,3) = 1.0
  
  pt(1,0) = point2\x
  pt(1,1) = point2\y
  pt(1,2) = point2\z
  pt(1,3) = 1.0
  
  pt(2,0) = tan1\x
  pt(2,1) = tan1\y
  pt(2,2) = tan1\z
  pt(2,3) = 1.0
  
  pt(3,0) = tan2\x
  pt(3,1) = tan2\y
  pt(3,2) = tan2\z
  pt(3,3) = 1.0
  
  Dim ret.f(3)
  Dim r.f(3,3)
  ;ret = powers * mCoeffs * pt;
  concatenate(r(), mCoeffs(), pt())
  Multiplication(ret(), powers(), r())
  
  *Spline\pos\x = ret(0)   
  *Spline\pos\y = ret(1)  
  *Spline\pos\z = ret(2)  
  
EndProcedure

Procedure recalcTangents(*Spline.Spline)
  
  ;         // Catmull-Rom approach
  ;         // 
  ;         // tangent[i] = 0.5 * (point[i+1] - point[i-1])
  ;         //
  ;         // Assume endpoint tangents are parallel With line With neighbour
  
  Define.i i, numPoints, isClosed
  
  numPoints = *spline\NbPoint
  If numPoints < 2
    
    ; Can't do anything yet
    ProcedureReturn
  EndIf
  
  ; Closed Or open?
  
  If *Spline\mPoints(0) = *Spline\mPoints(numPoints-1)
    
    isClosed = #True
    
  Else
    
    isClosed = #False
  EndIf
  
  ReDim *Spline\mTangents.Vector3(numPoints)
  
  For i = 0 To numPoints-1
    
    If i =0
      
      ; Special Case start
      If isClosed
        ; Use numPoints-2 since numPoints-1 is the last point And == [0]
        *spline\mTangents(i)\x = 0.5 * (*spline\mPoints(1)\x - *spline\mPoints(numPoints-2)\x)
        *spline\mTangents(i)\y = 0.5 * (*spline\mPoints(1)\y - *spline\mPoints(numPoints-2)\y)
        *spline\mTangents(i)\z = 0.5 * (*spline\mPoints(1)\z - *spline\mPoints(numPoints-2)\z)
      Else
        
        *spline\mTangents(i)\x = 0.5 * (*spline\mPoints(1)\x - *spline\mPoints(0)\x)
        *spline\mTangents(i)\y = 0.5 * (*spline\mPoints(1)\y - *spline\mPoints(0)\y)
        *spline\mTangents(i)\z = 0.5 * (*spline\mPoints(1)\z - *spline\mPoints(0)\z)
      EndIf
      
    ElseIf i = numPoints-1
      
      ; Special Case End
      If isClosed
        
        ; Use same tangent As already calculated For [0]
        *spline\mTangents(i)\x = *spline\mTangents(0)\x
        *spline\mTangents(i)\y = *spline\mTangents(0)\y
        *spline\mTangents(i)\z = *spline\mTangents(0)\z
        
      Else
        
        *spline\mTangents(i)\x = 0.5 * (*spline\mPoints(i)\x - *spline\mPoints(i-1)\x)
        *spline\mTangents(i)\y = 0.5 * (*spline\mPoints(i)\y - *spline\mPoints(i-1)\y)
        *spline\mTangents(i)\z = 0.5 * (*spline\mPoints(i)\z - *spline\mPoints(i-1)\z)
      EndIf
      
    Else
      *spline\mTangents(i)\x = 0.5 * (*spline\mPoints(i+1)\x - *spline\mPoints(i-1)\x)
      *spline\mTangents(i)\y = 0.5 * (*spline\mPoints(i+1)\y - *spline\mPoints(i-1)\y)
      *spline\mTangents(i)\z = 0.5 * (*spline\mPoints(i+1)\z - *spline\mPoints(i-1)\z)
    EndIf
    
  Next
  
EndProcedure

Define.f Time, pas = 1, x, y, z

If InitEngine3D()
  
  InitSprite()
  InitKeyboard()
  InitMouse()
  
  If Screen3DRequester()
    Add3DArchive("Data/"                , #PB_3DArchive_FileSystem)    
    Add3DArchive("Data/Textures"        , #PB_3DArchive_FileSystem)
    Add3DArchive("Data/Models"          , #PB_3DArchive_FileSystem)
    Add3DArchive("Data/Scripts"         , #PB_3DArchive_FileSystem)
    Add3DArchive("Data/Packs/skybox.zip", #PB_3DArchive_Zip)
    Parse3DScripts()
    
    WorldShadows(#PB_Shadow_Modulative)
    
    ;- Ground
    CreateMaterial(0, LoadTexture(0, "Dirt.jpg"))
    CreatePlane(0, 1200, 1200, 1, 1, 5, 5)
    CreateEntity(0, MeshID(0), MaterialID(0), 500, 0, -500)
    
    ;- Cylinder - check point
    CreateCylinder(3, 10, 100)
    CreateEntity(4, MeshID(3), #PB_Material_None, 50,  0,   50)
    CreateEntity(5, MeshID(3), #PB_Material_None, 50,  0, -950)
    CreateEntity(6, MeshID(3), #PB_Material_None, 950, 0, -950)
    CreateEntity(7, MeshID(3), #PB_Material_None, 950, 0,   50)
    CreateEntity(8, MeshID(3), #PB_Material_None, 450, 0, -450)
    
    ;- Robot
    ;
    LoadMesh(1, "robot.mesh")
    CreateEntity(1, MeshID(1), #PB_Material_None, 0, 0, 0)
    ScaleEntity(1, 3, 3, 3)
    AnimateEntity(1, "Walk")
    
    ;- Camera
    ;
    CreateCamera(0, 0, 0, 100, 100)
    CameraLocate(0, 500, 1500, 1450)
    CameraFOV(0, 25)
    CameraBackColor(0,$846748)
    CameraLookAt(0, 500, 0, -500)
    
    ;- Light
    ;
    AmbientColor(RGB(25, 25, 25))
    CreateLight(0, RGB(200, 200, 200), -750, 750, -750)
    
    ;- Spline
    ;
    *spline.Spline = CreateSpline()
    AddPointSpline(*spline, EntityX(4), 0, EntityZ(4))
    AddPointSpline(*spline, EntityX(8), 0, EntityZ(8))
    AddPointSpline(*spline, EntityX(5), 0, EntityZ(5))
    AddPointSpline(*spline, EntityX(6), 0, EntityZ(6))
    AddPointSpline(*spline, EntityX(8), 0, EntityZ(8))
    AddPointSpline(*spline, EntityX(7), 0, EntityZ(7)) 
    AddPointSpline(*spline, EntityX(4), 0, EntityZ(4))
    
    Repeat
      Screen3DEvents()
      
      ExamineKeyboard()
      
      InterpolateSpline(*Spline, time)
      
      EntityLookAt(1, *Spline\pos\x, EntityY(1), *Spline\pos\z)
      EntityLocate(1, *Spline\pos\x, *Spline\pos\y, *Spline\pos\z)
      
      time + pas * 0.017 / 35
      
      If time > 1
        Time = 1
        pas = - pas
      ElseIf time < 0
        Time = 0
        pas = - pas
      EndIf  
      
      RenderWorld()
      
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape)   
    
    End 
    
  EndIf 
Else
  MessageRequester("Error","Can't initialize engine3D")
EndIf 

FreeMemory(*Spline)
Dernière modification par comtois le mer. 25/juil./2012 22:18, modifié 1 fois.
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.
Avatar de l’utilisateur
Ar-S
Messages : 9478
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: SimpleSpline : Démo

Message par Ar-S »

Merci comtois, sympa le shinobi.
Reste à régler l'orientation du mesh selon sa direction.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: SimpleSpline : Démo

Message par comtois »

oups !

Je me suis trompé de code , c'est le robot qui est orienté correctement. Je mets à jour le code tout de suite ...

Et effectivement la fonction EntityLookAt() devra être modifiée pour prendre en compte l'orientation de n'importe quelle entity.
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.
Avatar de l’utilisateur
Ar-S
Messages : 9478
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: SimpleSpline : Démo

Message par Ar-S »

Ah ba c'est bien mieux comme ça ;)
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: SimpleSpline : Démo

Message par blendman »

salut

Chouette exemple
Ça marche super avec la 4.61, mais ça ne marche plus aussi bien avec la 4.70 beta ;)
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: SimpleSpline : Démo

Message par comtois »

Faudra que je teste, mais j'imagine que tu parles de l'orientation du robot ? C'est normal j'ai modifié EntityLookAt() pour la 4.70 ! Je n'en dis pas plus pour l'instant, j'attends de voir ce que Fred va intégrer et comment.

Par contre tu peux essayer avec le ninja, il est correctement orienté.
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.
Répondre