Page 1 sur 1

WaveFront Obj to Ogre Mesh (obj2OgreMesh)

Publié : mar. 27/août/2013 16:35
par falsam
[PB 5.20]
Objectif : Ouvrir un fichier WaveFront Obj contenant une description ASCII d'une modélisation 3D pour en faire un Mesh dans l'environnement Ogre 3D.

Pour plus d'information sur les fichier Wavefront Obj, vous pouvez consulter le lien suivant :
http://fr.wikipedia.org/wiki/Objet_3D_( ... e_fichier)

Je vous présente déjà la version 0.02 de mon projet car j'ai besoin d'aide.
Si Le mesh s'affiche bien, je bloque sur l'affichage de la texture.

:arrow: Touche + & - pour zoomer

Code : Tout sélectionner

;obj2OgreMesh V 0.04

;Description d'un fichier obj http://fr.wikipedia.org/wiki/Objet_3D_(format_de_fichier)

EnableExplicit

Enumeration
  #Mainform
  #File
  #Mesh
  #Texture
  #Material
  #Entity
EndEnumeration

Define.l Event

Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered
Global FileObj.s
Global Camera.i, CamX.f, CamY.f, CamZ.f

Structure sVertex
  X.f
  Y.f
  Z.f
EndStructure

Structure sFace
  A.i
  B.i
  C.i
EndStructure

Structure sVertexTexture
  U.f
  V.f
EndStructure

Structure sObj
  Name.s
  Level.i
  
  List Vertex.sVertex()
  List Face.sFace()
  List Normals.sVertex()
  List VertexTexture.sVertexTexture()
EndStructure
Global NewList Object.sObj()

Procedure ReadObj(ObjFile.s, List object.sObj())
  Protected.s Buffer.s, Type, Indice.s
  Protected.i Vertices.i, VertexNormals.i, TextureCoordinates.i, Faces.i

  If OpenFile(#File, ObjFile)
    While Eof(#File) = 0
      Buffer = ReadString(#File)
     
      Type = StringField(Buffer, 1, " ")
      
      Select Type
          
        Case "o" ;je ne sais pas si il faut traiter ce cas 
          ;Plusieurs objets peuvent cohabiter dans le même fichier. 
          ;La section définissant l'objet est définie de la maniére suivante : o [nom de l'objet]
          
        Case "g" 
          ;Plusieurs groupes de faces peuvent cohabiter dans le même objet
          ;La section définissant chaque groupe est définie de la maniére suivante : g [nom du groupe]
          AddElement(Object())
          object()\Name = StringField(Buffer, CountString(Buffer, " ") + 1, " ")
          object()\level = CountString(Buffer, " ") - 1
          
          Debug "Groupe " + object()\name
          
        Case "v" 
          ;Un sommet est défini de la manière suivante : v 1.0 0.0 0.0
          ;MeshVertexPosition() pour ajouter un sommet
          If ListSize(object()) = 0
            AddElement(object())
          EndIf
          
          AddElement(Object()\Vertex())
          Object()\Vertex()\X = ValF(StringField(Buffer, 2, " "))
          Object()\Vertex()\Y = ValF(StringField(Buffer, 3, " "))
          Object()\Vertex()\Z = ValF(StringField(Buffer, 4, " "))
          
          Vertices + 1
                    
        Case "vn" 
          ;Une normale est définie de la manière suivante : vn 0.0 1.0 0.0
          ;MeshVertexNormal() pour ajouter l'information concernant la 'normale' 
          ;du nouveau sommet précédemment ajouté avec MeshVertexPosition()
          AddElement(object()\normals())
          Object()\Normals()\X = ValF(StringField(Buffer, 2, " "))
          Object()\Normals()\Y = ValF(StringField(Buffer, 3, " "))
          Object()\Normals()\Z = ValF(StringField(Buffer, 4, " "))
          
          VertexNormals + 1
          
        Case "vt"
          ;Une coordonnée de texture est définie de la manière suivante : vt U V
          ;Exemple vt 1.00 0.00
          ;MeshVertexTextureCoordinate() pour ajouter l'information UV pour le nouveau sommet précédemment ajouté 
          AddElement(Object()\VertexTexture())
          Object()\VertexTexture()\U = ValF(StringField(Buffer, 2, " "))
          Object()\VertexTexture()\V = ValF(StringField(Buffer, 3, " "))
     
          TextureCoordinates + 1
          
        Case "f" 
          ;Chaque face est définie par un ensemble d'indices faisant référence aux
          ;coordonnées des points, de texture et des normales.
          ;Par exemple : f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
          ;MeshFace(Sommet1, Sommet2, Sommet3) pour ajouter une nouvelle face au mesh 
          AddElement(Object()\Face())
          
          Indice = StringField(Buffer, 2, " ")
          object()\face()\A = Val(StringField(Indice, 1, "/"))
          
          Indice = StringField(Buffer, 3, " ")
          object()\face()\B = Val(StringField(Indice, 1, "/"))
          
          Indice = StringField(Buffer, 4, " ")
          object()\face()\C = Val(StringField(Indice, 1, "/"))
          
          Faces + 1
      EndSelect
   
    Wend
    
    Debug Str(Vertices) +  " Vertices"
    Debug Str(TextureCoordinates) + " Texture Coordinates"
    Debug Str(VertexNormals) + " Vertex Normals"
    Debug Str(Faces) + " Faces"
    CloseFile(#File)
  EndIf
EndProcedure

Procedure RenderObj()
  Protected Texture.i, Material.i
  
  ; Dans cette version on ne load pas encore la texture
  ; Cette texture pourra être loader plus tard avec l'instruction LoadTexture()
  CreateTexture(#Texture, 512, 512)
  StartDrawing(TextureOutput(#Texture))
  Box(0,0,512,512,RGB(0, 0, 0))
  Box(1,1,510,510,RGB(255, 0, 0))
  StopDrawing()
  
  CreateMaterial(#Material, TextureID(#Texture))
  
  CreateMesh(#Mesh)
  
  ForEach(Object())
    
    ;MeshVertexPosition() pour ajouter un sommet au mesh précédement créer 
    ForEach object()\vertex()
      MeshVertexPosition(Object()\Vertex()\X, Object()\Vertex()\Y, Object()\Vertex()\Z)
    Next

    ;MeshVertexNormal() pour ajouter l'information concernant la 'normale' 
    ;du nouveau sommet précédemment ajouté avec MeshVertexPosition()
    ForEach Object()\Normals()
      MeshVertexNormal(Object()\Normals()\X, Object()\Normals()\Y, Object()\Normals()\Z)
    Next
    
    ;MeshVertexTextureCoordinate() pour ajouter l'information UV pour le nouveau sommet précédemment ajouté 
    ForEach Object()\VertexTexture()
      ;MeshVertexTextureCoordinate(Object()\VertexTexture()\U, Object()\VertexTexture()\V)
    Next
    
    ;MeshFace(Sommet1, Sommet2, Sommet3) pour ajouter une nouvelle face au mesh 
    ForEach object()\face()
      MeshFace(object()\face()\A - 1, object()\face()\B - 1, object()\face()\C - 1)
    Next
    
  Next
    
  FinishMesh(#True)
  NormalizeMesh(#Mesh)
  CreateEntity(#Entity, MeshID(#Mesh), MaterialID(#Material))
  
  CreateEntityBody(#Entity, #PB_Entity_StaticBody, 1, 1, 1)
EndProcedure


Procedure Start()
  InitEngine3D()
  InitKeyboard()
  InitSprite()
  InitMouse()
  ;
  ;Fenetre 3D
  OpenWindow(#Mainform,0,0,1024,768, "Obj2OgreMesh", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  OpenWindowedScreen(WindowID(#Mainform),0 ,0 ,1024, 768, 0, 0, 0)
  KeyboardMode(#PB_Keyboard_International)  
  
  WorldDebug(#PB_World_DebugBody)

  
  ;
  ;Lumiere et ombre
  AmbientColor(RGB(127, 127, 127))
  CreateLight(#PB_Any,RGB(151, 251, 151), -1.8, 50, 5)
  WorldShadows(#PB_Shadow_Additive)

  ;
  ; Camera 
  Camera = CreateCamera(#PB_Any,0,0,100,100)
  CameraBackColor(Camera, RGB(145, 182, 201))

  CamX = 10.0
  CamY = 5.0
  CamZ = 15.0

  ;
  ; Ouverture d'un fichier WaveFront   
  FileObj = OpenFileRequester("Ouvrir un fichier Wavefront Obj", "", "Wavefront (*.obj)|*.obj", 1)
  
  If FileObj <> ""
    ;Lecture du fichier WaveFront Obj
    ReadObj(FileObj, Object()) 
    
    ;Rendu sous la forme d'un mesh ogre
    RenderObj()  
        
  EndIf
  
EndProcedure

start()

While #True
  Event  = WindowEvent()
    
  If ExamineKeyboard()
    
    If KeyboardPushed (#PB_Key_Escape) Or Event = #PB_Event_CloseWindow
      Break
    EndIf
    
    If KeyboardPushed (#PB_Key_Add)
      CamX-1
    EndIf
    
    If KeyboardPushed (#PB_Key_Subtract)
      CamX+1
    EndIf
    
    If KeyboardPushed(#PB_Key_F2)
      WorldDebug(#PB_World_DebugEntity)
    EndIf
    
    If KeyboardPushed(#PB_Key_F3)
      WorldDebug(#PB_World_DebugBody)
    EndIf
    
    If KeyboardPushed(#PB_Key_F4)    
      WorldDebug(#PB_World_DebugNone)
    
    EndIf
    
  EndIf
  
  MoveCamera(Camera, CamX, CamY, CamZ, #PB_Absolute)  
  CameraLookAt(Camera, 0,0,0)

  ; Affiche le rendu de la scène
  ClearScreen(RGB(0, 0, 0))
  RenderWorld(80)
  FlipBuffers()  
  
Wend 
Vous pouvez télécharger un fichier obj test en cliquant sur le lien suivant
:arrow: cubeSphere.zip

j'ai du commenter cette portion de code car j'ai un Runtime Error du compilateur.

Code : Tout sélectionner

MeshVertexTextureCoordinate(Object()\VertexTexture()\U, Object()\VertexTexture()\V)
Je pense que la non exécution de cette ligne de code empêche aussi le code d'afficher la texture.

L'idée plus tard est de créer une lib qui permettra d'afficher un obj dans l'environnement Ogre sans passer par un convertisseur.

Re: WaveFront Obj to Ogre Mesh (obj2OgreMesh)

Publié : mar. 27/août/2013 20:36
par comtois
falsam a écrit :j'ai du commenter cette portion de code car j'ai un Runtime Error du compilateur.

Code : Tout sélectionner

MeshVertexTextureCoordinate(Object()\VertexTexture()\U, Object()\VertexTexture()\V)
Je pense que la non exécution de cette ligne de code empêche aussi le code d'afficher la texture.
si tu veux utiliser MeshVertexTextureCoordinate() , il faut le faire à la création du premier vertex.

Voir aussi ici

Re: WaveFront Obj to Ogre Mesh (obj2OgreMesh)

Publié : mar. 27/août/2013 22:42
par falsam
comtois a écrit :si tu veux utiliser MeshVertexTextureCoordinate() , il faut le faire à la création du premier vertex.
je ne veux pas forcement l'utiliser mes certains fichiers obj importés comportent des lignes type Texture Coordinates.

Je ne comprends pas bien comment construire un mesh à partir d'un fichier WaveFront.

Si j'ai un fichier qui comporte par exemple 8 lignes types vertices
# 8 Vertices
v -1.871668 -1.932886 2.040268
v 2.208869 -1.932886 2.040268
v -1.871668 2.147651 2.040268
v 2.208869 2.147651 2.040268
v 2.208869 -1.932886 -2.040268
v -1.871668 -1.932886 -2.040268
v 2.208869 2.147651 -2.040268
v -1.871668 2.147651 -2.040268
ainsi que 36 lignes types Texture Coordinates
# 36 Texture Coordinates
vt 1.0 0.0
vt 0.0 0.0
vt 0.0 1.0
vt 1.0 0.0
vt 0.0 0.0
vt 0.0 1.0
vt 1.0 0.0
vt 0.0 0.0
vt 0.0 1.0
vt 1.0 0.0
vt 0.0 0.0
vt 0.0 1.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
vt 0.0 1.0
vt 0.0 0.0
vt 1.0 0.0
Comment je dois initialiser ces 36 lignes ? Juste aprés la création du premier vertice ? (ça sent la question idiote)

Re: WaveFront Obj to Ogre Mesh (obj2OgreMesh)

Publié : mar. 27/août/2013 23:26
par falsam
Le code du premier message est mise à jour. Correction de quelques bugs et ajout d'information dans le debug.

Mais je ne suis toujours pas arriver à afficher une texture sur le mesh.

Re: WaveFront Obj to Ogre Mesh (obj2OgreMesh)

Publié : ven. 30/août/2013 12:18
par falsam
Toute une nuit sur ce code et je ne sais toujours pas afficher correctement une texture sur ces obj importés !!! C'est quand même dommage d'arriver à afficher la forme et de ne pas pouvoir appliquer le matériel.

J'aimerais bien un feedback sur l'importation de fichier WaveForm en provenance des différents logiciels standards modélisation comme Blender, 3ds studio, etc ...

Merci d'avance :)