Load OBJ wavefront

Everything related to 3D programming
User avatar
minimy
Enthusiast
Enthusiast
Posts: 619
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Load OBJ wavefront

Post by minimy »

This is my first attempt to upload an OBJ file to PB.
result a mesh with UV mapped.
If someone can help improve it, it is appreciated.

The program create a OBJ file for test (cube cuboPB.obj).

Code: Select all

Global.b sal
Global objsize.Vector3
Global normal.Vector3
Structure caras
  verXY.i
  verUV.i
EndStructure

Procedure   CalculateTriangleNormal(x1.f, y1.f, z1.f, x2.f, y2.f, z2.f, x3.f, y3.f, z3.f)
  ;devuelve la normal del triangulo
  Protected.f ABx, ABy, ABz, ACx, ACy, ACz
  ABx = x2 - x1
  ABy = y2 - y1
  ABz = z2 - z1
  ACx = x3 - x1
  ACy = y3 - y1
  ACz = z3 - z1

  ; Calcula el producto cruz de AB y AC
;   Protected.f Nx, Ny, Nz
  normal\x = ABy * ACz - ABz * ACy
  normal\y = ABz * ACx - ABx * ACz
  normal\z = ABx * ACy - ABy * ACx

  ; Normaliza el vector resultante
  Protected.f length
  length = Sqr(normal\x * normal\x + normal\y * normal\y + normal\z * normal\z)
  If length <> 0
    normal\x = normal\x / length
    normal\y = normal\y / length
    normal\z = normal\z / length
  EndIf

EndProcedure
Procedure   CalculateNormalVector4(x1.f, y1.f, z1.f, x2.f, y2.f, z2.f, x3.f, y3.f, z3.f, x4.f, y4.f, z4.f)
  ;devuelve las normales de los dos triángulos formados por los vértices
  Protected.f n1.Vector3, n2.Vector3
  CalculateTriangleNormal(x1, y1, z1, x2, y2, z2, x3, y3, z3)
  n1\x= normal\x
  n1\y= normal\y
  n1\z= normal\z
  
  CalculateTriangleNormal(x1, y1, z1, x3, y3, z3, x4, y4, z4)
  n2\x= normal\x
  n2\y= normal\y
  n2\z= normal\z

  ; Promedia las normales de los triángulos para obtener la normal del plano
  Protected.f NormalX, NormalY, NormalZ
  normal\x = (n1\x + n2\x) / 2
  normal\y = (n1\y + n2\y) / 2
  normal\z = (n1\z + n2\z) / 2

  ; Devuelve el vector normal
;   Result NormalX, NormalY, NormalZ
EndProcedure
Procedure   loadOBJmesh(file.s,s.f=1)
  Protected.s l,a, name
  Protected   Dim verXY.Vector3(2000)
  Protected   Dim verUV.Vector3(2000)
  Protected   Dim faces.caras(2000,4)
  Protected   vposXY,vposUV,carast
  Protected.b ncaras
  Protected   p,n
  Protected   tx3d,ma,e
  Protected.f no,su,es,oe,ar,ab
  If ReadFile(0,file)
    While Eof(0)=0
      l= ReadString(0)
      a= StringField(l,1," ")
      Select a
        Case "g"
          name= StringField(l,2," ")
        Case "v"
          vposXY+1
          verXY(vposXY)\x= ValF(StringField(l,2," ")) * s
          verXY(vposXY)\y= ValF(StringField(l,3," ")) * s
          verXY(vposXY)\z= ValF(StringField(l,4," ")) * s
          If verXY(vposXY)\x>0 : If verXY(vposXY)\x>es : es=verXY(vposXY)\x:EndIf : Else: If verXY(vposXY)\x<oe:oe=verXY(vposXY)\x : EndIf : EndIf
          If verXY(vposXY)\y>0 : If verXY(vposXY)\y>ar : ar=verXY(vposXY)\y:EndIf : Else: If verXY(vposXY)\y<ab:ab=verXY(vposXY)\y : EndIf : EndIf
          If verXY(vposXY)\z>0 : If verXY(vposXY)\y>no : no=verXY(vposXY)\z:EndIf : Else: If verXY(vposXY)\z<su:su=verXY(vposXY)\z : EndIf : EndIf
        Case "vt"
          vposUV+1
          verUV(vposUV)\x= ValF(StringField(l,2," "))
          verUV(vposUV)\y= 1-ValF(StringField(l,3," "))
        Case "f"
          carast+1
          ncaras= CountString(l," ")-1
          faces(carast,0)\verXY= ncaras
          For n= 1 To ncaras
            faces(carast,n)\verXY= ValF(StringField(StringField(l,n+1," "),1,"/"))
            faces(carast,n)\verUV= ValF(StringField(StringField(l,n+1," "),2,"/"))
          Next n
      EndSelect
    Wend
    CloseFile(0)
    
    objsize\x= Abs(oe)+es
    objsize\y= Abs(ab)+ar
    objsize\z= Abs(su)+no
    
      Debug "Objeto: "+name
      Debug "vertices: "+vposXY
      Debug "verti.UV: "+vposUV
      Debug "Caras: "+carast
      Debug "NCaras: "+ncaras
      Debug "Tamño: "+Str(objsize\x)+" , "+Str(objsize\y)+" , "+Str(objsize\z)+"  escalado: "+StrF(s,3)
    
    vr= 0
    m= CreateMesh(#PB_Any)
    For p= 1 To carast
      If faces(p,0)= 3
        CalculateTriangleNormal(verXY(faces(p,1)\verXY)\x, verXY(faces(p,1)\verXY)\y, verXY(faces(p,1)\verXY)\z,
                                verXY(faces(p,2)\verXY)\x, verXY(faces(p,2)\verXY)\y, verXY(faces(p,2)\verXY)\z,
                                verXY(faces(p,3)\verXY)\x, verXY(faces(p,3)\verXY)\y, verXY(faces(p,3)\verXY)\z)
      Else
        CalculateNormalVector4( verXY(faces(p,1)\verXY)\x, verXY(faces(p,1)\verXY)\y, verXY(faces(p,1)\verXY)\z,
                                verXY(faces(p,2)\verXY)\x, verXY(faces(p,2)\verXY)\y, verXY(faces(p,2)\verXY)\z,
                                verXY(faces(p,3)\verXY)\x, verXY(faces(p,3)\verXY)\y, verXY(faces(p,3)\verXY)\z,
                                verXY(faces(p,4)\verXY)\x, verXY(faces(p,4)\verXY)\y, verXY(faces(p,4)\verXY)\z)
      EndIf
      For n= 1 To faces(p,0)\verXY
        MeshVertex( verXY(faces(p,n)\verXY)\x, verXY(faces(p,n)\verXY)\y, verXY(faces(p,n)\verXY)\z,
                    verUV(faces(p,n)\verUV)\x, verUV(faces(p,n)\verUV)\y, $ffffff, normal\x, normal\y, normal\z)
        faces(p,n)\verXY= vr
        vr +1
      Next n
    Next p
    For p= 1 To carast
      If faces(p,0)\verXY= 3
        MeshFace(faces(p,1)\verXY,faces(p,2)\verXY,faces(p,3)\verXY)
      Else
        MeshFace(faces(p,1)\verXY,faces(p,2)\verXY,faces(p,3)\verXY,faces(p,4)\verXY)
      EndIf
    Next p
    FinishMesh(#True)
    
    FreeArray(verXY())
    FreeArray(verUV())
    FreeArray(faces())
  EndIf
  ProcedureReturn m
EndProcedure

Procedure   grabaOBJtest(file.s="cuboPB.obj")
  If CreateFile(0,file)  
    WriteStringN(0,"# WaveFront *.obj file (generada con purebasic)")
    WriteStringN(0,"g Cubo")
    WriteStringN(0,"usemtl Mat_1")
    WriteStringN(0,"v -100 -100 100")
    WriteStringN(0,"v -100 100 100")
    WriteStringN(0,"v 100 -100 100")
    WriteStringN(0,"v 100 100 100")
    WriteStringN(0,"v 100 -100 -100")
    WriteStringN(0,"v 100 100 -100")
    WriteStringN(0,"v -100 -100 -100")
    WriteStringN(0,"v -100 100 -100")
    WriteStringN(0,"")
    WriteStringN(0,"vt 0.511675 0.32555 0")
    WriteStringN(0,"vt 0.988325 0.341117 0")
    WriteStringN(0,"vt 0.011675 0.67445 0")
    WriteStringN(0,"vt 0.011675 0.007784 0")
    WriteStringN(0,"vt 0.988325 0.658883 0")
    WriteStringN(0,"vt 0.011675 0.992216 0")
    WriteStringN(0,"vt 0.988325 0.32555 0")
    WriteStringN(0,"vt 0.511675 0.67445 0")
    WriteStringN(0,"vt 0.488325 0.67445 0")
    WriteStringN(0,"vt 0.488325 0.007784 0")
    WriteStringN(0,"vt 0.511675 0.992216 0")
    WriteStringN(0,"vt 0.488325 0.992216 0")
    WriteStringN(0,"vt 0.988325 0.007784 0")
    WriteStringN(0,"vt 0.011675 0.341117 0")
    WriteStringN(0,"vt 0.988325 0.67445 0")
    WriteStringN(0,"vt 0.488325 0.32555 0")
    WriteStringN(0,"vt 0.011675 0.658883 0")
    WriteStringN(0,"vt 0.988325 0.992216 0")
    WriteStringN(0,"vt 0.511675 0.007784 0")
    WriteStringN(0,"vt 0.511675 0.341117 0")
    WriteStringN(0,"vt 0.488325 0.341117 0")
    WriteStringN(0,"vt 0.011675 0.32555 0")
    WriteStringN(0,"vt 0.511675 0.658883 0")
    WriteStringN(0,"vt 0.488325 0.658883 0")
    WriteStringN(0,"")
    WriteStringN(0,"f 3/9 4/12 2/6 1/3 ")
    WriteStringN(0,"f 5/15 6/18 4/11 3/8 ")
    WriteStringN(0,"f 7/21 8/24 6/17 5/14 ")
    WriteStringN(0,"f 1/2 2/5 8/23 7/20 ")
    WriteStringN(0,"f 4/10 6/16 8/22 2/4 ")
    WriteStringN(0,"f 5/13 3/7 1/1 7/19 ")
    CloseFile(0)
  EndIf
EndProcedure


Procedure   eventos3D(camara, speed.f=1, mouseSpd.f=0.05)
  Protected.f KeyX,KeyY, MouseX,MouseY
  If KeyboardPushed(#PB_Key_A)
    KeyX= -speed
  ElseIf KeyboardPushed(#PB_Key_D)
    KeyX= speed
  Else
    KeyX= 0
  EndIf
  
  If KeyboardPushed(#PB_Key_W)
    KeyY= -speed
  ElseIf KeyboardPushed(#PB_Key_S)
    KeyY= speed
  Else
    KeyY= 0
  EndIf
  
  If KeyboardPushed(#PB_Key_LeftShift)
    keyY * 10
    keyX * 10
  EndIf

  MouseX = -MouseDeltaX() * mouseSpd
  MouseY = -MouseDeltaY() * mouseSpd
  
  RotateCamera(camara, MouseY, MouseX, 0, #PB_Relative)
  MoveCamera (camara, KeyX, 0, KeyY)
EndProcedure

InitEngine3D(): InitSprite(): InitKeyboard(): InitMouse()
ExamineDesktops():width=DesktopWidth(0):height=DesktopHeight(0)
OpenWindow(0, 0, 0, width, height, "PB OBJ wavefront", #PB_Window_BorderLess)
SetWindowColor(0,$444444)
OpenWindowedScreen(WindowID(0), 0, 0, width,height,0,0,0,#PB_Screen_NoSynchronization)

grabaOBJtest()
m=  loadOBJmesh("cuboPB.obj",0.04)
ma= CreateMaterial(#PB_Any,#Null,$ff0000)
e=  CreateEntity(#PB_Any,MeshID(m),MaterialID(ma))



CreateLine3D(0,-objsize\x*2,0,0,$00ffff, objsize\x*2,0,0,$0000ff)
CreateLine3D(1,0,0,-objsize\y*2,$ffff00, 0,0,objsize\y*2,$ff0000)
CreateLine3D(2,0,-objsize\z*2,0,$00ff44, 0,objsize\z*2,0,$009900)

luz=          CreateLight(#PB_Any,$ffffff,objsize\x*2,objsize\y*2,-objsize\z*2,#PB_Light_Point)

camara=       CreateCamera(#PB_Any,0,0,100,100)
              MoveCamera(camara,objsize\x*2,objsize\y*2,objsize\z*2)
              CameraLookAt(camara,0,0,0)
              CameraRange(camara, 0.1, (objsize\x+objsize\y+objsize\z)*4)
              
Repeat
  Repeat : event= WindowEvent() : Until event= 0
  ExamineKeyboard() : ExamineMouse()
  eventos3D(camara, 0.1)
  
  If KeyboardPushed(#PB_Key_Escape) : sal= 1: EndIf
  ElapsedTime = RenderWorld()
  
  FlipBuffers()
  Delay(1)
Until sal=1




If translation=Error: reply="Sorry, Im Spanish": Endif
miso
Enthusiast
Enthusiast
Posts: 466
Joined: Sat Oct 21, 2023 4:06 pm
Location: Hungary

Re: Load OBJ wavefront

Post by miso »

I wanted to make something similar, but never get to do it. So I'm glad for this snippet, I will take a better look at it on the weekend. Thanks for sharing.

PS: I will never get used to the spanish variable names, though it's fewer than usual. ;)
User avatar
minimy
Enthusiast
Enthusiast
Posts: 619
Joined: Mon Jul 08, 2013 8:43 pm
Location: off world

Re: Load OBJ wavefront

Post by minimy »

Thanks miso, i hope you like.
OBJ format is a little weird because put many UV to one vertex, and is hard to get the logic of it, at least for me.
If translation=Error: reply="Sorry, Im Spanish": Endif
SMaag
Enthusiast
Enthusiast
Posts: 325
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Load OBJ wavefront

Post by SMaag »

welcome in parsing 3D grafic files.
Post Reply