Problème avec les Submesh

Généralités sur la programmation 3D
kelebrindae
Messages : 579
Inscription : ven. 11/mai/2007 15:21

Problème avec les Submesh

Message par kelebrindae »

Bonjour,

Je rencontre un bug, et je n'arrive pas à déterminer s'il vient de PB ou de moi. :?

Mon but est de construire un mesh complexe avec plusieurs submeshes dotés chacun de leur propre material.
Pour cela, je duplique les "meshDatas" d'un cube standard et je les recopie plein de fois en changeant juste les x,y,z des vertex. Et quand je veux passer au material suivant, j'ajoute un submesh.

Or, dès que je dépasse 3 submeshes (cf. ligne 164 dans le code), je me tape une erreur "invalide memory access" sur le "finishMesh". J'obtiens le même résultat en DirectX et en OpenGL, et sur deux PC différents. :(

Quelqu'un pourrait me dire ce que je fais mal, s'il vous plaît ?

Code : Tout sélectionner

; Window size
#SCREENWIDTH = 800
#SCREENHEIGHT = 500

; Camera
#CAMERA = 0
#CAMERASPEED = 0.2

Structure meshInfo_struct
  maxVertIndex.i
  maxFaceIndex.i
  Array vertInfos.PB_MeshVertex(0)
  Array faceInfos.PB_MeshFace(0)
EndStructure 
Global Dim meshInfo.meshInfo_struct(64)

Global mouseX.f, mouseY.f
Global timer.i, oldTimer.i, loopTime.f

EnableExplicit
;************************************************************************************
;-                                 ---- Procedures ----
;************************************************************************************
; Ici, je récupère les meshDatas d'un cube purebasic standard
Procedure initializeCubeMesh()
  Protected cubeMesh.i,i.i
  
  cubeMesh = CreateCube(#PB_Any,1)
   
  BuildMeshShadowVolume(cubeMesh)
  BuildMeshTangents(cubeMesh)
  
  i=0
  meshInfo(i)\maxVertIndex = MeshVertexCount(cubeMesh) - 1
  meshInfo(i)\maxFaceIndex = MeshIndexCount(cubeMesh) - 1
  GetMeshData(cubeMesh,0,meshInfo(i)\vertInfos(),#PB_Mesh_Vertex|#PB_Mesh_Normal|#PB_Mesh_UVCoordinate,0,meshInfo(i)\maxVertIndex )
  GetMeshData(cubeMesh,0,meshInfo(i)\faceInfos(),#PB_Mesh_Face,0,meshInfo(i)\maxFaceIndex )   
  
  FreeMesh(cubeMesh)
  
EndProcedure

; Juste pour faire joli
Procedure initializeMaterials()
  Protected Dim couleur.i(7)
  Protected i.i,j.i,x.i,y.i
  
  couleur(0) = $0000FF
  couleur(1) = $0077FF
  couleur(2) = $00FFFF
  couleur(3) = $00FF00
  couleur(4) = $FF0000
  couleur(5) = $FF0077
  couleur(6) = $FF00FF
  couleur(7) = $FFFFFF
  
  For i = 0 To 7
    CreateTexture(i,64,64)
    StartDrawing(TextureOutput(i))
    Box(0,0,64,64,couleur(i))
    For j=0 To Random(10)
      x = Random(64): y = Random(64)
      Box(x,y,4,4,RGB( Red(couleur(i)) / 2,Green(couleur(i)) / 2,Blue(couleur(i)) / 2 ) )
    Next j
    StopDrawing()
    
    CreateMaterial(i,TextureID(i))  
  Next i
  
EndProcedure

; Ici, je crée le gros mesh en dupliquant plein de fois les meshDatas du cube
Procedure.i buildComplexMesh(size.i)
  Protected x.i,y.i,z.i
  Protected i.i
  Protected index.i, numSubMesh.i, numMesh.i
  
  numMesh = CreateMesh(#PB_Any)
  
  ; Le mesh mesurera size*size
  For y = 0 To size-1
    ; Quand je change de material, j'assigne le material au submesh précédent et j'en ajoute un autre
    If y > 0
      Debug "Submesh " + Str(numSubMesh) + " : material = " + Str( (size - y)%8 )
      SetMeshMaterial(numMesh,MaterialID( (size - y)%8 ),numSubMesh)
      AddSubMesh()
      numSubMesh+1
      index = 0
    EndIf
        
    For x = 0 To size - y - 1
      For z = 0 To size - y - 1
        
        ; Add the vertices
        For i = 0 To meshInfo(0)\maxVertIndex
          MeshVertexPosition((meshInfo(0)\vertInfos(i)\x ) + x,
                             (meshInfo(0)\vertInfos(i)\y ) + y,
                             (meshInfo(0)\vertInfos(i)\z ) + z)
          
          MeshVertexNormal(meshInfo(0)\vertInfos(i)\NormalX,
                           meshInfo(0)\vertInfos(i)\NormalY,
                           meshInfo(0)\vertInfos(i)\NormalZ)
          
          MeshVertexTextureCoordinate(meshInfo(0)\vertInfos(i)\u,
                                      meshInfo(0)\vertInfos(i)\v )
        Next i
                    
        For i = 0 To meshInfo(0)\maxFaceIndex Step 3
          MeshFace(meshInfo(0)\faceInfos(i)\Index + index,meshInfo(0)\faceInfos(i+1)\Index + index,meshInfo(0)\faceInfos(i+2)\Index + index)
        Next i
        
        index + meshInfo(0)\maxVertIndex + 1   
        
      Next z
    Next x
    
  Next y
  
  FinishMesh(#True)
  SetMeshMaterial(numMesh,MaterialID( (size - y)%8 ),numSubMesh)
  Debug "Submesh " + Str(numSubMesh) + " - material = " + Str( (size - y)%8 )
  
  ProcedureReturn numMesh
  
EndProcedure
DisableExplicit

;************************************************************************************
;-                                 ---- Main program ----
;************************************************************************************

;- Initialization
InitEngine3D()
InitSprite()
InitKeyboard()
InitMouse()
UsePNGImageDecoder()
UsePNGImageEncoder()

;- Window
OpenWindow(Wmain,0, 0, #SCREENWIDTH,#SCREENHEIGHT ,"Test submesh",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(Wmain), 0, 0, #SCREENWIDTH,#SCREENHEIGHT, 0, 0, 0,#PB_Screen_NoSynchronization)


;- Camera
CreateCamera(#CAMERA, 0, 0, 100, 100)
CameraBackColor(#CAMERA,$222222)
MoveCamera(#CAMERA,20,30,20)
CameraLookAt(#CAMERA,0,0,0)

;-Light
CreateLight(1,$FFFFFF,CameraX(#CAMERA),CameraY(#CAMERA),CameraZ(#CAMERA))
WorldShadows(#PB_Shadow_None)

;- Initialize the mesh datas
initializeCubeMesh()

;- Initialize the materials
initializeMaterials()

;- Build a mesh with many submeshes
;- BUG ICI !
numMesh = buildComplexMesh(15)  ; Le bug se produit dès que je dépasse 3


;- Create the entity

;CreateStaticGeometry(0, 100,100,100, #False)
chunkEntity = CreateEntity(#PB_Any,MeshID(numMesh),#PB_Material_None)
;AddStaticGeometryEntity(0, EntityID(chunkEntity),0,0,0)
;FreeEntity(chunkEntity)
;BuildStaticGeometry(numGroup)

;- Main Loop
oldTimer = ElapsedMilliseconds()
KeyboardMode(#PB_Keyboard_International)
Repeat
  Delay(1)
  
  ; Windows events
  WaitWindowEvent(1)

  ExamineKeyboard()
  
  ; Activate wireframe render
  If KeyboardReleased(#PB_Key_W)
    wireframe = 1-wireframe
    If wireframe = #True
      CameraRenderMode(#CAMERA,#PB_Camera_Wireframe)
    Else
      CameraRenderMode(#CAMERA,#PB_Camera_Textured)
    EndIf
  EndIf
  
  ;- Movements (mouse + arrows)
  timer = ElapsedMilliseconds()
  loopTime = 1 + (timer - oldtimer)
  If looptime > 32
    looptime = 32
  EndIf
  oldtimer = timer
  
  ; Look around    
  If ExamineMouse()
    MouseX = -(MouseDeltaX()/10)
    MouseY = -(MouseDeltaY()/10)
  EndIf
 
  RotateCamera(#CAMERA, MouseY, MouseX,0, #PB_Relative)
  If ExamineKeyboard()
    If KeyboardPushed(#PB_Key_Up)
      MoveCamera (#CAMERA, 0, 0, -#CAMERASPEED/looptime)
    EndIf
    If KeyboardPushed(#PB_Key_Down)
      MoveCamera  (#CAMERA, 0, 0, #CAMERASPEED/looptime)
    EndIf
     If KeyboardPushed(#PB_Key_Left)
      MoveCamera  (#CAMERA, -#CAMERASPEED/looptime,0, 0)
    EndIf
    If KeyboardPushed(#PB_Key_Right)
      MoveCamera  (#CAMERA, #CAMERASPEED/looptime,0, 0)
    EndIf
  EndIf
  
  
  ;- Render
  RenderWorld()
  
  ;- Display FPS
  ;DISPLAY_FPS(timer)        
  
  FlipBuffers()

Until KeyboardPushed(#PB_Key_Escape)

End

;************************************************************************************
;-                                 ---- Datas ----
;************************************************************************************

;- Meshes datas
DataSection
  meshTopDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f -0.5,0.5,-0.5
  Data.f 0,1,0
  Data.f 0,0
  Data.f 0.5,0.5,-0.5
  Data.f 0,1,0
  Data.f 1,0
  Data.f 0.5,0.5,0.5
  Data.f 0,1,0
  Data.f 1,1
  Data.f -0.5,0.5,0.5
  Data.f 0,1,0
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2
  
MeshBottomDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f -0.50,-0.50,0.50
  Data.f 0.00,-1.00,0.00
  Data.f 0,0
  Data.f 0.50,-0.50,0.50
  Data.f 0.00,-1.00,0.00
  Data.f 1,0
  Data.f 0.50,-0.50,-0.50
  Data.f 0.00,-1.00,0.00
  Data.f 1,1
  Data.f -0.50,-0.50,-0.50
  Data.f 0.00,-1.00,0.00
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2

MeshLeftDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f -0.50,0.50,-0.50
  Data.f -1.00,0.00,0.00
  Data.f 0,0
  Data.f -0.50,0.50,0.50
  Data.f -1.00,0.00,0.00
  Data.f 1,0
  Data.f -0.50,-0.50,0.50
  Data.f -1.00,0.00,0.00
  Data.f 1,1
  Data.f -0.50,-0.50,-0.50
  Data.f -1.00,0.00,0.00
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2

MeshRightDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f 0.50,0.50,0.50
  Data.f 1.00,0.00,0.00
  Data.f 0,0
  Data.f 0.50,0.50,-0.50
  Data.f 1.00,0.00,0.00
  Data.f 1,0
  Data.f 0.50,-0.50,-0.50
  Data.f 1.00,0.00,0.00
  Data.f 1,1
  Data.f 0.50,-0.50,0.50
  Data.f 1.00,0.00,0.00
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2

MeshFrontDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f -0.50,0.50,0.50
  Data.f 0.00,0.00,1.00
  Data.f 0,0
  Data.f 0.50,0.50,0.50
  Data.f 0.00,0.00,1.00
  Data.f 1,0
  Data.f 0.50,-0.50,0.50
  Data.f 0.00,0.00,1.00
  Data.f 1,1
  Data.f -0.50,-0.50,0.50
  Data.f 0.00,0.00,1.00
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2

MeshBackDatas:
  ; Nb vertices, nb triangles
  Data.i 4,2
  ; Vertices: pos / normals / uv
  Data.f 0.50,0.50,-0.50
  Data.f 0.00,0.00,-1.00
  Data.f 0,0
  Data.f -0.50,0.50,-0.50
  Data.f 0.00,0.00,-1.00
  Data.f 1,0
  Data.f -0.50,-0.50,-0.50
  Data.f 0.00,0.00,-1.00
  Data.f 1,1
  Data.f 0.50,-0.50,-0.50
  Data.f 0.00,0.00,-1.00
  Data.f 0,1
  ; Faces
  Data.i 2,1,0
  Data.i 0,3,2
  
EndDataSection
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Problème avec les Submesh

Message par comtois »

Il semblerait que ça ne soit pas une bonne idée de créer autant de submesh

vu ici
Batching
You may be using too many individual objects/submeshes. Graphics cards (GPU) like to have rendering queued into a relatively small number of large batches to operate at peak efficiency. If you use lots of small movable objects, especially if they are composed of multiple submeshes (each of which is its own render operation), the GPU underperforms because too much time is being spent in the overhead of setting up the individual rendering operations. This enqueueing process is done in the driver, which is constrained by the speed of the CPU, not the GPU. This presentation(external link) explains that 25000 batches per second will saturate (completely, on its own) a 1Ghz CPU. That means to maintain 60 FPS on a 1Ghz CPU you cannot issue more than about 416 batches per frame, where a batch is one instance of a submesh (for example). Of course, other factors may limit your performance earlier. You can improve batching by grouping static objects together in a StaticGeometry object, or by reducing the number of submeshes you use per mesh (do you really need that many different materials per mesh?).
Chez moi ton code fonctionne jusqu'à 5

[EDIT]
oups, je me trompe, tu n'as pas beaucoup de submesh puisque la taille que tu demandes correspond au nombre de submesh, alors du coup je ne sais pas pourquoi ça plante.
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

Re: Problème avec les Submesh

Message par kelebrindae »

@Comtois:
Ceci dit, ces infos à propos des impacts du nombre de submeshes sur les perfs sont très intéressantes; Je le note. :)

Pour en revenir à mon bug: j'ai l'impression que si les submeshes ont le même nombre de vertex / faces, ça ne plante plus. Exemple: dans mon code, si aux lignes 91 et 92 vous enlevez le " - y " de façon à ce que tous les submeshes soient identiques, ça marche.

=> N'y aurait-il pas un petit souci au niveau des index au moment de la construction du mesh dans PB (genre, on passe le nombre de vertex du submesh précédent ou suivant au lieu du bon) ?
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
comtois
Messages : 5172
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: Problème avec les Submesh

Message par comtois »

Il y a en effet un souci dans le calcul de l'index ici

Code : Tout sélectionner

        index + meshInfo(0)\maxVertIndex + 1 
ça devrait plutôt s'écrire comme ça

Code : Tout sélectionner

  index + meshInfo(0)\maxFaceIndex + 1 
à noter que les fonctions MeshFace() et MeshIndex() renvoient le nombre d'index en cours. Idem pour les fonctions sur les vertices, elles renvoient le nombre de vertices en cours.

Par conséquent ton code pourrait s"écrire ainsi

Code : Tout sélectionner

    For i = 0 To meshInfo(0)\maxFaceIndex Step 3
         index2 = MeshFace(meshInfo(0)\faceInfos(i)\Index + index,meshInfo(0)\faceInfos(i+1)\Index + index,meshInfo(0)\faceInfos(i+2)\Index + index)
        Next i

index = index2
une autre façon de faire

Code : Tout sélectionner

        For i = 0 To meshInfo(0)\maxFaceIndex
          
          index2 =  MeshIndex(meshInfo(0)\faceInfos(i)\Index + index)
        Next i
     
        index = index2

Mais ça ne change rien à ton problème :?

[EDIT]

:oops: j'ai écrit une connerie hier soir :oops:

Ton calcul de l'index est juste. tant pis je laisse ce message, il y a quand même l'info que les fonctions renvoient un truc contrairement à ce qu'indique l'aide (à voir avec Fred si c'est volontaire ou un oubli ?)
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 :

Re: Problème avec les Submesh

Message par comtois »

Finalement je viens d'ouvrir mon c++ pour analyser ce qui se passe dans le source, c'est effectivement un bug de la fonction FinishMesh().
En isolant une partie du code de cette fonction, ton code fonctionne correctement et tous les cubes sont affichés.

Il me reste à examiner la partie fautive.
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 :

Re: Problème avec les Submesh

Message par comtois »

C'est corrigé. C'était la fonction UpdateMeshBoundingBox() qui merdait. FinishMesh() appelle cette fonction après la conversion des datas en mesh.
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

Re: Problème avec les Submesh

Message par kelebrindae »

Super! Merci beaucoup de cette correction rapide, comtois! :D
Les idées sont le souvenir de choses qui ne se sont pas encore produites.
Répondre