[Résolu] v4.30 beta4: MousePick ne fonctionne pas bien

Archive.
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

[Résolu] v4.30 beta4: MousePick ne fonctionne pas bien

Message par kelebrindae »

Bonjour à tous,

En testant la 4.30, j'observe ce qui me semble être un fonctionnement incorrect de la commande "MousePick". :(

Description:
Je créé dynamiquement un mesh (un cylindre) à l'aide d'une procédure de l'illustre Comtois, puis je créé un lot d'entités à partir de ce mesh.
Ensuite, avec MousePick, je tente de déterminer quelle entité se trouve sous le curseur de la souris.

Problème:
Plus le mesh a de facettes, plus le résultat de MousePick est faux.
On peut observer ça en modifiant le premier paramètre de l'appel à la procédure "CreateCylinderMesh":
- en mettant 4, c'est à peu près bon (quoique assez imprécis)
- en mettant 16 ou plus, c'est n'importe quoi

Pouvez-vous tester le code ci-dessous pour me confirmer le problème ?

Code : Tout sélectionner

; Author: Kelebrindae
; Date: October, 29, 2008
; PB version: v4.30 beta4
; OS: Windows XP

;- Initialization
Global FullScreen.b
If MessageRequester("Test MousePick","Full Screen ?",#PB_MessageRequester_YesNo) = 6      
  FullScreen=#True 
Else            
  FullScreen=#False
EndIf 

If InitEngine3D("D:\Programmation\PB430beta\Compilers\engine3d.dll") = 0
  MessageRequester( "Error" , "Can't initialize 3D, check if engine3D.dll is available" , 0 ) 
End 
ElseIf InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 
  MessageRequester( "Error" , "Can't find DirectX 7.0 or above" , 0 ) 
  End 
EndIf 

If Fullscreen  
  OpenScreen(800,600,32,"Test MousePick") 
Else 
  OpenWindow(0,0, 0, 800 , 600 ,"Test MousePick") 
  OpenWindowedScreen(WindowID(0),0,0, 800 , 600,0,0,0) 
EndIf 

Enumeration
  #CYLCAP_NONE
  #CYLCAP_BOTH
  #CYLCAP_TOP
  #CYLCAP_BOTTOM
EndEnumeration

#BOARDSIZE = 16

Structure Vertex 
  px.f 
  py.f 
  pz.f 
  nx.f 
  ny.f 
  nz.f 
  Couleur.l 
  U.f 
  V.f 
EndStructure 

Structure FaceTri 
  f1.w 
  f2.w 
  f3.w 
EndStructure 

Procedure.l CreateCylinderMesh(nbSides.l,height.f,radius.f,capped.b,coul.l)
  Protected *PtrV.Vertex,*vertexBuffer.l    ; vertices buffer in memory
  Protected *PtrF.FaceTri,*facetriBuffer.l  ; Faces buffer in memory
  Protected newmesh.l                       ; Procedure Result
  Protected i.l,nbVert.l,nbTri.l, numVertHaut.l,numVertBas.l
  Protected h2.f,theta.f
   
  If nbSides<3
    ProcedureReturn 0
  EndIf

  h2 = height / 2.0
  nbVert = 4*(nbSides+1)+2
  If capped = #CYLCAP_TOP Or capped = #CYLCAP_BOTTOM
    nbVert-1
  Else
    If capped = #CYLCAP_NONE
      nbVert-2
    EndIf
  EndIf   
  
  *vertexBuffer = AllocateMemory(SizeOf(Vertex)*nbVert)
  *PtrV = *vertexBuffer
   
  ;Sommet en bas du cylindre
  For i = 0 To nbSides
    theta =2*#PI*i/nbSides
     
    *PtrV\px = radius*Cos(theta)
    *PtrV\py = -h2
    *PtrV\pz = radius*Sin(theta)
    *PtrV\nx = Cos(theta)
    *PtrV\ny = 0
    *PtrV\nz = Sin(theta)
    *PtrV\couleur = Coul
    *PtrV\u = Theta / (2.0*#PI)
    *PtrV\v = 0
    *PtrV + SizeOf(Vertex)
  Next i

   
  ;Sommet en haut du cylindre
  For i = 0 To nbSides
    theta =2*#PI*i/nbSides
     
    *PtrV\px = radius*Cos(theta)
    *PtrV\py = h2
    *PtrV\pz = radius*Sin(theta)
    *PtrV\nx = Cos(theta)
    *PtrV\ny = 0
    *PtrV\nz = Sin(theta)
    *PtrV\couleur = Coul
    *PtrV\u = Theta / (2.0*#PI)
    *PtrV\v = 1
    *PtrV + SizeOf(Vertex)
  Next i

      
  ;Sommet face bas du cylindre
  For i = 0 To nbSides
    theta =2*#PI*i/nbSides
     
    *PtrV\px = radius*Cos(theta)
    *PtrV\py = -h2
    *PtrV\pz = radius*Sin(theta)
    *PtrV\nx = 0
    *PtrV\ny = -1
    *PtrV\nz = 0
    *PtrV\couleur = Coul
    *PtrV\u = Theta / (2.0*#PI)
    *PtrV\v = 1
    *PtrV + SizeOf(Vertex)
  Next i
               
  ;Sommet face haut du cylindre
  For i = 0 To nbSides
    theta =2*#PI*i/nbSides
     
    *PtrV\px = radius*Cos(theta)
    *PtrV\py = h2
    *PtrV\pz = radius*Sin(theta)
    *PtrV\nx = 0
    *PtrV\ny = 1
    *PtrV\nz = 0
    *PtrV\couleur = Coul
    *PtrV\u = Theta / (2.0*#PI)
    *PtrV\v = 1
    *PtrV + SizeOf(Vertex)
  Next i
   
  ;Centre bas
  If capped = #CYLCAP_BOTH Or capped = #CYLCAP_BOTTOM
    numVertBas = (*PtrV - *vertexBuffer) / SizeOf(Vertex)
    
    *PtrV\px = 0
    *PtrV\py = -h2
    *PtrV\pz = 0
    *PtrV\nx = 0
    *PtrV\ny = -1
    *PtrV\nz = 0
    *PtrV\couleur = Coul
    *PtrV\u = 0.5
    *PtrV\v = 0.5
    *PtrV + SizeOf(Vertex)
  EndIf
  
  ;Centre haut
  If capped = #CYLCAP_BOTH Or capped = #CYLCAP_TOP
    numVertHaut = (*PtrV - *vertexBuffer) / SizeOf(Vertex)
    
    *PtrV\px = 0
    *PtrV\py = h2
    *PtrV\pz = 0
    *PtrV\nx = 0
    *PtrV\ny = 1
    *PtrV\nz = 0
    *PtrV\couleur = Coul
    *PtrV\u = 0.5
    *PtrV\v = 0.5
  EndIf 
   
  ;Les facettes
  nbTri = 4*nbSides
  If capped = #CYLCAP_BOTTOM Or capped = #CYLCAP_TOP
    nbTri - nbSides
  Else
    If capped = #CYLCAP_NONE
      nbTri - (nbSides*2)
    EndIf
  EndIf
    
  *facetriBuffer=AllocateMemory(SizeOf(FaceTri)*nbTri)
  *PtrF=*facetriBuffer
  
  For i=0 To nbSides-1
      *PtrF\f3=i
      *PtrF\f2=i + 1
      *PtrF\f1=nbSides + i + 2
      *PtrF + SizeOf(FaceTri)
    
    
      *PtrF\f1=i 
      *PtrF\f3=nbSides + i + 2
      *PtrF\f2=nbSides + i + 1
      *PtrF + SizeOf(FaceTri)
  Next i
   
  
  ;Face bas
  If capped = #CYLCAP_BOTH Or capped = #CYLCAP_BOTTOM   
    For i=0 To nbSides-1
      *PtrF\f1= numVertBas
      *PtrF\f2= 2 * nbSides + 2 + i
      *PtrF\f3= 2 * nbSides + 3 + i
      *PtrF + SizeOf(FaceTri)
    Next i      
  EndIf 
  ;Face Haut
  If capped = #CYLCAP_BOTH Or capped = #CYLCAP_TOP  
    For i=0 To nbSides-1
      *PtrF\f1= numVertHaut
      *PtrF\f3= 3 * nbSides + 3 + i
      *PtrF\f2= 3 * nbSides + 4 + i
      *PtrF + SizeOf(FaceTri)
    Next i      
  EndIf
  
  ; Create mesh from stored infos
  newmesh = CreateMesh(#PB_Any,nbVert)
  If IsMesh(newmesh) 
    SetMeshData(newmesh,#PB_Mesh_Vertex | #PB_Mesh_Normal | #PB_Mesh_UVCoordinate | #PB_Mesh_Color,*vertexBuffer,nbVert) 
    SetMeshData(newmesh,#PB_Mesh_Face,*facetriBuffer,nbTri) 
    ; and don't forget to free memory
    FreeMemory(*vertexBuffer)
    FreeMemory(*facetriBuffer)
    ProcedureReturn newmesh 
  Else 
    ; even if "createMesh" has failed
    FreeMemory(*vertexBuffer)
    FreeMemory(*facetriBuffer)
    ProcedureReturn -1    
  EndIf 
   
EndProcedure  


;- Mesh creation
numMesh = CreateCylinderMesh(16,15,10,2,RGB(255,0,0))

;- Material
CreateImage(1,128,128)
StartDrawing(ImageOutput(1))
Box(0,0,127,127,$FFFFFF)
StopDrawing()
SaveImage(1,"temp.bmp")
FreeImage(1)

Add3DArchive(".", #PB_3DArchive_FileSystem)
LoadTexture(1,"temp.bmp")
CreateMaterial(1,TextureID(1))
MaterialAmbientColor(1, #PB_Material_AmbientColors)
CreateMaterial(2,TextureID(1))
DeleteFile("temp.bmp")

;- Entities
numobj=1
numMaterial = MaterialID(1)
For j=1 To #BOARDSIZE
  For i=1 To #BOARDSIZE
    ; The first entity is created, the others are copied
    If numobj=1
      CreateEntity(numobj,MeshID(numMesh),numMaterial)
    Else
      CopyEntity(1,numobj)
    EndIf
    
    EntityLocate(numobj,i*22,0,j*22)
    numobj+1      
  Next i
Next j

;- Camera
Global camdist.f,bearing.f,azimuth.f
Global camchanged.b
Global elementAtCenter = (#BOARDSIZE*#BOARDSIZE/2) - (#BOARDSIZE/2)
Global camcenterX=EntityX(elementAtCenter) + 10
Global camcenterY=EntityY(elementAtCenter)
Global camcenterZ=EntityZ(elementAtCenter) + 10

camdist=300:bearing=180:azimuth=45
camchanged=#True
CreateCamera(0, 0 , 0, 100 , 100)

;- Light
AmbientColor(RGB(105,105,105)) 
CreateLight(0,RGB(255,255,255),-40,100,-220)

;- Main loop
ShowCursor_(1)
numobj=0
Repeat
  If FullScreen = #False 
    While WindowEvent() : Wend 
  EndIf
  
  ; Get mouse moves
  If ExamineMouse()
    movex=MouseDeltaX():movey=MouseDeltaY():movez=MouseWheel()
    mousePosX+movex
    mousePosY+moveY
  Else
    movex=0:movey=0:movez=0
  EndIf

  ; Show 3D mouse
  InputEvent3D(mousePosX, mousePosY, 0, "")
  
  ; Mouse Pick
  numobj=MousePick(0,mousePosX,mousePosY)
  If numObj<>oldnumObj And oldnumObj > 0
    EntityMaterial(oldnumObj, MaterialID(1))
    oldnumObj=0
  EndIf
  If numObj > 0
     If numObj<>oldnumObj
       EntityMaterial(numobj, MaterialID(2))
       oldnumObj=numObj
     EndIf
  EndIf
  
  ; Right-click to move the camera
  If MouseButton(#PB_MouseButton_Right) And (movex<>0 Or movey<>0)
    bearing + movex      
    azimuth + movey
    If azimuth<0
      azimuth=0
    EndIf
    If azimuth>89
      azimuth=89
    EndIf    
    camchanged = #True
  EndIf
  ; Mouse-wheel to zoom
  If movez <> 0
    camdist-movez*5
    If camdist<100
      camdist=100
    EndIf
    If camdist>500
      camdist=500
    EndIf
    camchanged=#True 
  EndIf ; if movez <> 0...

  
  ; Calculate camera's new position
  If camchanged=#True
    CameraLocate(0,camcenterX,camcenterY,camcenterZ)
    CameraLookAt(0,camcenterX,camcenterY,camcenterZ+100)
    RotateCamera(0,azimuth,bearing,0)
    MoveCamera(0,0,0,-camdist)

    CameraLookAt(0,camcenterX,camcenterY,camcenterZ)
    camchanged = #False
  EndIf ; if camchanged=#true...
  
  ; show it all
  RenderWorld() 
     
  ; Flip buffers to avoid tearing  
  FlipBuffers()
  
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)

End
Dernière modification par kelebrindae le mer. 29/oct./2008 22:13, modifié 1 fois.
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

C'est un bug, mousepick() ne semble plus fonctionner, y compris avec l'exemple fourni dans l'archive Ogre1.6.
Il faudrait le signaler sur le forum anglais. Si tu veux je peux le faire.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Je n'ai pas la beta 4 sous la main pour tester, mais plusieurs remarques
ajoute un WorldDebug() au début de ton code pour visualiser la boite englobante des entités. mousepick() fonctionne avec la boite, et si elle est mal définie dans ton CreateMesh() alors ça merdouille :)

En parlant du CreateMEsh() justement, c'est là qu'il faut adapter ton code, le second paramètre correspond au rayon de la boite englobante, faudrait que je corrige la doc d'ailleurs à ce sujet :)

essaye avec

Code : Tout sélectionner

; Create mesh from stored infos
  newmesh = CreateMesh(#PB_Any,10)
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.
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

Message par kelebrindae »

@Comtois:
Merci! C'est exactement ça!
En mettant le rayon du cylindre comme taille pour la bounding box, le mousePick fonctionne parfaitement. :D

Question: si on passe "0" comme second paramètre du "CreateMesh", est-ce que ça désactive le mousePick ? (ça pourrait être utile pour optimiser le pick quand on a beaucoup d'entités à l'écran)

@Djes:
Merci, mais du coup ce ne sera pas nécessaire...
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Message par djes »

J'ai l'air d'un con :lol:
Non mais heureusement, il y a quand même un bug dans l'exemple mousepicking, je vais le signaler après vérification.

Pour le createmesh, il faudrait aussi le dire pour la doc anglaise.

Edit : Après vérification, y'a pas de bug! J'ai vraiment l'air d'un con 8)
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

kelebrindae a écrit :Question: si on passe "0" comme second paramètre du "CreateMesh", est-ce que ça désactive le mousePick ? (ça pourrait être utile pour optimiser le pick quand on a beaucoup d'entités à l'écran)
J'imagine que MousePick() n'est rien d'autre qu'un lancer de rayon, le moteur 3D doit tester la collision du rayon sur un octree pour déterminer l'entity détecter.
Tout ça pour dire que c'est au moteur d'optimiser le pick, tu n'as pas à t'en inquiéter.
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.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

bon je viens de tester chez moi avec la Beta4.

il y avait un comportement bizarre avec le MousePick(), un décalage dans la sélection !

J'ai jeté un oeil dans le code, et en corrigeant ceci , ça fonctionne très bien
Il faut donner les coordonnées réelles de la souris, je n'ai pas trop compris ce que tu cherchais à faire avec ton calcul.

Code : Tout sélectionner

  ; Show 3D mouse
  InputEvent3D(MouseX(), MouseY(), 0, "")
 
  ; Mouse Pick
  numobj=MousePick(0,MouseX(),MouseY())
Et si tu rajoutes

Code : Tout sélectionner

WorldDebug(#PB_World_DebugEntity)
juste avant le Repeat, tu verras les jolies boîtes.
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.
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

Message par kelebrindae »

Oui, j'avais remarqué ce bug: le décalage se produisait quant le curseur "virtuel" sortait de l'écran.

Ce que je voulais faire, je ne sais plus très bien; j'ai essayé pas mal de modifications pour comprendre ce qui n'allait pas, et ce calcul bizarre est un reste de mes tests...

Merci beaucoup de ton aide, en tout cas: je n'aurais jamais trouvé, pour le 2ème paramètre de "CreateMesh" (d'autant que la description de la commande qui apparait dans la barre d'état de l'IDE indique aussi que ce paramètre est le nombre de vertices du mesh)...
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Ah tiens , tu fais bien de parler de ça , j'allais l'oublier !!
Je vais ajouter un message sur le forum anglais
'MaximumVertex should be RadiusBoundingBox'

:wink:
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