Who's Online:

  • [Bot]
Now online:
  • 3 guests
  • 1 robot

 

DBPRO CODE - LOAD AN OBJ FILE IN DBPRO

  Hi,

The OBJ file format is a simple data-format that represents 3D geometry. It is commonly used by various 3D modeling apps. One such app that I like and use is Sculptris. Found at:
http://www.zbrushcentral.com/showthread.php?t=090617

This program reads in the obj text file and stores each line in a dynamic array of strings. During that process, it retrieves the obj 3D data. This site is where I got obj info to help me extract the data I wanted:
http://en.wikipedia.org/wiki/Obj

The only data it currently extracts is the vertex positions, texture coords, normals and face info. It only extracts 3 point triangle faces. The obj can hold 4 point quad face polygons and more( If you need help for me to add at least quad face polygons support, just ask and supply me with an obj file that uses quads ). I'm not sure if the normals data extraction is correct or not. As I made this for obj files created by Scupltris, Scupltris doesn't supply normals when exporting for me( mabie I just don't know how to export normals correctly ). So, I'm unable to test the normal stuff currently.

After extracting the needed data, it creates a glob of polygons needed for building the obj object with. Basically, it starts by creating a triangle object, make a mesh of that object, add then add the needed amount of triangle polygons by adding the mesh triangle to the original object as a limbs. After that, make a new mesh from the object with all the limbs. Then make the final object from the mesh. This is so the object is made out of only 1 mesh of triangles. No limbs.

This is what the code looks like:

        MAKE OBJECT TRIANGLE ObjectID,0,0,0,1,1,0,2,0,0 ` here: triangle coordinates don't matter
        MAKE MESH FROM OBJECT 1, ObjectID
        FOR local_index=1 TO gNumberOfFaces-1
                ADD LIMB ObjectID,local_index,1
        NEXT
        DELETE MESH 1
        MAKE MESH FROM OBJECT 1, ObjectID
        DELETE OBJECT ObjectID
        MAKE OBJECT ObjectID,1,ImageID
        DELETE MESH 1

 

After creating an object with the needed amount of polygons, it will then manipulate the object's data by reading in the stored obj data and applying it using the DBPro's VertexData Commands.

Note: To render an obj object in a DirectX based program, I had to reverse order the obj's triangle vertices and also reverse the V texture coordinate to display texturing right. Again, note that if you try to load an obj file with normal data, it may not work right.

If you have any problems with this, please let me know. Thanks.

Full Example:

  • NOTE: You will need to supply your own obj file and image file to run it
  • Press W/S to go Forward/Backwards
  • Right Mouse Click to rotate camera view
  • Press Esc to escape

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
rem ###################################################################
rem Load Object - By: Todd Riggins - ExoDev.Com - Dec. 8, 2010
rem 3D Object Format Info: http://en.wikipedia.org/wiki/Obj
rem ###################################################################
 
 
rem ###################################################################
rem GLOBALS
rem ###################################################################
 
GLOBAL global_CamID as INTEGER
 
DIM array_string(0) AS STRING
 
TYPE TYPE_VERTEX
    x AS FLOAT
    y AS FLOAT
    z AS FLOAT
ENDTYPE
DIM array_vertex(0) AS TYPE_VERTEX
 
TYPE TYPE_TEXCOORD
    u AS FLOAT
    v AS FLOAT
ENDTYPE
DIM array_texcoord(0) AS TYPE_TEXCOORD
 
TYPE TYPE_NORMAL
    x AS FLOAT
    y AS FLOAT
    z AS FLOAT
ENDTYPE
DIM array_normal(0) AS TYPE_NORMAL
 
TYPE TYPE_FACE
    V1Vertex AS INTEGER
    V1TexCoord AS INTEGER
    V1Normal AS INTEGER
    V2Vertex AS INTEGER
    V2TexCoord AS INTEGER
    V2Normal AS INTEGER
    V3Vertex AS INTEGER
    V3TexCoord AS INTEGER
    V3Normal AS INTEGER
ENDTYPE
DIM array_face(0) AS TYPE_FACE
 
GLOBAL gThisStringPosition AS INTEGER
GLOBAL gIndiceStep AS INTEGER
GLOBAL gNumberOfVertices,gNumberOfFaces AS INTEGER
 
GLOBAL Global_CamID AS INTEGER
GLOBAL Global_RightMouseClick AS INTEGER
 
 
rem ###################################################################
rem Start Main Loop
rem ###################################################################
 
Main()
END
 
rem ###################################################################
rem Main Loop
rem ###################################################################
 
FUNCTION Main()
    LOCAL local_ObjectID AS INTEGER
    LOCAL local_SpaceHelm2Image AS INTEGER
   
    rem Initialize Display Setup
    InitDisplaySetup()
   
    rem Retrieve image used by obj 3d object
    local_SpaceHelm2Image = GetNewImageID()
    LOAD IMAGE "BadGuy1.png",local_SpaceHelm2Image,0
   
    rem Load the obj 3d file
    local_ObjectID = GetNewObjectID()
    LoadObj("BadGuy1.obj",local_ObjectID,local_SpaceHelm2Image)
 
    rem Don't know if Sculptris can save out normals in it's obj export
    rem so I manually create smoothing normals for it here
    SET OBJECT NORMALS local_ObjectID
    SET OBJECT SMOOTHING local_ObjectID,100
   
    rem Rotate the object to face the camera
    ROTATE OBJECT local_ObjectID,0,180,0
 
    rem Main loop
    REPEAT
        UserControls()
 
 
        TEXT 10,30,"Faces:"+str$(gNumberOfFaces)
        TEXT 1,1,"FPS:"+STR$(SCREEN FPS())
        SYNC
    UNTIL ESCAPEKEY()=1
ENDFUNCTION
 
 
rem ###################################################################
rem FUNCTIONS
rem ###################################################################
 
 
rem Setup Display and Camera
FUNCTION InitDisplaySetup()
    SYNC ON
    SYNC RATE 30
 
    SET WINDOW POSITION 0,0
    SET WINDOW LAYOUT 0,0,0
    MAXIMIZE WINDOW
 
    SET DISPLAY MODE DESKTOP WIDTH(),DESKTOP HEIGHT(),0, 0 
    SET WINDOW OFF
 
    rem create camera
    global_CamID = 1
    MAKE CAMERA global_CamID
    POSITION CAMERA global_CamID,0,2,-1000
    COLOR BACKDROP global_CamID, RGB(16,16,16)
    SET CAMERA FOV global_CamID,45
    SET CAMERA RANGE global_CamID,1,10000
   
    HIDE LIGHT 0
 
    rem create light to follow camera  
    MAKE LIGHT 1
    SET LIGHT RANGE 1,7000
    POSITION LIGHT 1,CAMERA POSITION X(global_CamID),CAMERA POSITION Y(global_CamID),CAMERA POSITION Z(global_CamID)
   
    DISABLE ESCAPEKEY
ENDFUNCTION
 
 
Function UserControls()
    LOCAL local_CameraAngleX as FLOAT
    LOCAL local_CameraAngleY as FLOAT
    LOCAL local_mmovex as INTEGER
    LOCAL local_mmovex as INTEGER
   
    local_mmovex = mousemovex()
    local_mmovey = mousemovey()
 
    ` Camera Control:
    ` Move Camera Position
    `W=17
    if (keystate(17)=1)
        Move Camera global_CamID,10.0
    endif
    `S=31
    if (keystate(31)=1)
        Move Camera global_CamID,-10.0
    endif
    `A=30
    if (keystate(30)=1)
        `
    endif
    `D=32
    if (keystate(32)=1)
        `
    endif
 
 
    ` Rotate camera on right click
    if mouseclick()=2
        if Global_RightMouseClick = 0
            Global_RightMouseClick = 1
            hide mouse
        endif
        ` keep mouse centered when rotating camera
        position mouse screen width()/2, screen height()/2
        ` Get Current Anlges
        local_CameraAngleX = Camera Angle X(global_CamID)
        local_CameraAngleY = Camera Angle Y(global_CamID)
        ` create a rotation axis based on controller movement
        local_CameraAngleX = WrapValue ( local_CameraAngleX + (local_mmovey) )
        local_CameraAngleY = WrapValue ( local_CameraAngleY + (local_mmovex) )
        ` rotate camera and lock x-axis between 0 and 90
        if ((( local_CameraAngleX >= 0 ) and ( local_CameraAngleX <= 90 )) or (( local_CameraAngleX >= 270 ) and ( local_CameraAngleX < 360 )))
            XRotate Camera global_CamID, local_CameraAngleX
        endif
       
        YRotate Camera global_CamID, local_CameraAngleY
    else
        if mouseclick()=0 and Global_RightMouseClick = 1
            Global_RightMouseClick = 0
            position mouse screen width()/2, screen height()/2             
            show mouse
        endif
    endif
   
    rem keep light at current camera position
    POSITION LIGHT 1,CAMERA POSITION X(global_CamID),CAMERA POSITION Y(global_CamID),CAMERA POSITION Z(global_CamID)   
EndFunction
 
 
rem Load in a .obj 3d file
FUNCTION LoadObj(Filename$,ObjectID,ImageID)
    LOCAL local_index,local_index2 AS INTEGER
    LOCAL local_count AS INTEGER
    LOCAL vertex_index AS INTEGER
    LOCAL indice_index AS INTEGER
    LOCAL local_vi AS INTEGER
    LOCAL local_tci AS INTEGER
    LOCAL local_ni AS INTEGER
    LOCAL local_vx AS FLOAT
    LOCAL local_vy AS FLOAT
    LOCAL local_vz AS FLOAT
    LOCAL local_u AS FLOAT
    LOCAL local_v AS FLOAT
    LOCAL local_nx AS FLOAT
    LOCAL local_ny AS FLOAT
    LOCAL local_nz AS FLOAT
 
    rem store file in memory/array of strings
    OPEN TO READ 1,Filename$
    IF FILE OPEN(1)=1
   
        REPEAT
            READ STRING 1,thisLine$
           
            IF thisLine$<>""
                ADD TO STACK array_string(0)
                local_index = ARRAY COUNT(array_string(0))
                array_string(local_index)=thisLine$
            ENDIF
       
        UNTIL FILE END(1)=1
    ENDIF
    CLOSE FILE 1
   
    local_count = ARRAY COUNT(array_string(0))
   
    FOR local_index=1 TO local_count
        IF UPPER$(LEFT$(array_string(local_index),2))="V "
            ADD TO STACK array_vertex(0)
            local_index2 = ARRAY COUNT(array_vertex(0))
            array_vertex(local_index2).x=GetFloatFromString(array_string(local_index),2)
            array_vertex(local_index2).y=GetFloatFromString(array_string(local_index),gThisStringPosition)
            array_vertex(local_index2).z=GetFloatFromString(array_string(local_index),gThisStringPosition)
        ENDIF
        IF UPPER$(LEFT$(array_string(local_index),3))="VT "
            ADD TO STACK array_texcoord(0)
            local_index2 = ARRAY COUNT(array_texcoord(0))
            array_texcoord(local_index2).u=GetFloatFromString(array_string(local_index),3)
            array_texcoord(local_index2).v=GetFloatFromString(array_string(local_index),gThisStringPosition)
        ENDIF
        IF UPPER$(LEFT$(array_string(local_index),3))="VN "
            ADD TO STACK array_normal(0)
            local_index2 = ARRAY COUNT(array_normal(0))
            array_normal(local_index2).x=GetFloatFromString(array_string(local_index),3)
            array_normal(local_index2).y=GetFloatFromString(array_string(local_index),gThisStringPosition)
            array_normal(local_index2).z=GetFloatFromString(array_string(local_index),gThisStringPosition)
        ENDIF
        IF UPPER$(LEFT$(array_string(local_index),2))="F "
            ADD TO STACK array_face(0)
            local_index2 = ARRAY COUNT(array_face(0))
            gIndiceStep=1 : array_face(local_index2).V1Vertex=GetIntegerFromString(array_string(local_index),2)
            gIndiceStep=2 : array_face(local_index2).V1TexCoord=GetIntegerFromString(array_string(local_index),gThisStringPosition)
            gIndiceStep=3 : array_face(local_index2).V1Normal=GetIntegerFromString(array_string(local_index),gThisStringPosition)
           
            gIndiceStep=1 : array_face(local_index2).V2Vertex=GetIntegerFromString(array_string(local_index),gThisStringPosition)
            gIndiceStep=2 : array_face(local_index2).V2TexCoord=GetIntegerFromString(array_string(local_index),gThisStringPosition)
            gIndiceStep=3 : array_face(local_index2).V2Normal=GetIntegerFromString(array_string(local_index),gThisStringPosition)
 
            gIndiceStep=1 : array_face(local_index2).V3Vertex=GetIntegerFromString(array_string(local_index),gThisStringPosition)
            gIndiceStep=2 : array_face(local_index2).V3TexCoord=GetIntegerFromString(array_string(local_index),gThisStringPosition)
            gIndiceStep=3 : array_face(local_index2).V3Normal=GetIntegerFromString(array_string(local_index),gThisStringPosition)
           
        ENDIF
    NEXT
   
    gNumberOfVertices=ARRAY COUNT(array_vertex(0))
    gNumberOfFaces=ARRAY COUNT(array_face(0))
 
   
    rem Build Obj Mesh
    MAKE OBJECT TRIANGLE ObjectID,0,0,0,1,1,0,2,0,0 ` here: triangle coordinates don't matter
    MAKE MESH FROM OBJECT 1, ObjectID
    FOR local_index=1 TO gNumberOfFaces-1
        ADD LIMB ObjectID,local_index,1
    NEXT
    DELETE MESH 1
    MAKE MESH FROM OBJECT 1, ObjectID
    DELETE OBJECT ObjectID
    MAKE OBJECT ObjectID,1,ImageID
    DELETE MESH 1
 
    indice_index=0
    vertex_index=0
    LOCK VERTEXDATA FOR LIMB ObjectID, 0
        FOR local_index=1 TO gNumberOfFaces
 
            local_vi=array_face(local_index).V1Vertex
            local_vx=array_vertex(local_vi).x
            local_vy=array_vertex(local_vi).y
            local_vz=array_vertex(local_vi).z
            SET VERTEXDATA POSITION vertex_index,local_vx,local_vy,local_vz
            local_tci=array_face(local_index).V1TexCoord
            IF local_tci>0
                local_u = array_texcoord(local_tci).u
                local_v = array_texcoord(local_tci).v
                SET VERTEXDATA UV vertex_index,0,local_u,-local_v
            ELSE
                SET VERTEXDATA UV vertex_index,0,0 
            ENDIF
            local_ni=array_face(local_index).V1Normal
            IF local_tci>0
                local_nx=array_normal(local_ni).x
                local_ny=array_normal(local_ni).y
                local_nz=array_normal(local_ni).z
                SET VERTEXDATA NORMALS vertex_index,local_nx,local_ny,local_nz
            ELSE
                SET VERTEXDATA NORMALS vertex_index,0,0,0
            ENDIF
            SET INDEXDATA indice_index,vertex_index
            INC vertex_index : INC indice_index
                       
            local_vi=array_face(local_index).V2Vertex
            local_vx=array_vertex(local_vi).x
            local_vy=array_vertex(local_vi).y
            local_vz=array_vertex(local_vi).z
            SET VERTEXDATA POSITION vertex_index,local_vx,local_vy,local_vz    
            local_tci=array_face(local_index).V2TexCoord
            IF local_tci>0
                local_u = array_texcoord(local_tci).u
                local_v = array_texcoord(local_tci).v
                SET VERTEXDATA UV vertex_index,0,local_u,-local_v
            ELSE
                SET VERTEXDATA UV vertex_index,0,0                 
            ENDIF
            local_ni=array_face(local_index).V2Normal
            IF local_tci>0
                local_nx=array_normal(local_ni).x
                local_ny=array_normal(local_ni).y
                local_nz=array_normal(local_ni).z
                SET VERTEXDATA NORMALS vertex_index,local_nx,local_ny,local_nz
            ELSE
                SET VERTEXDATA NORMALS vertex_index,0,0,0              
            ENDIF
            SET INDEXDATA indice_index,vertex_index
            INC vertex_index : INC indice_index
                                               
            local_vi=array_face(local_index).V3Vertex
            local_vx=array_vertex(local_vi).x
            local_vy=array_vertex(local_vi).y
            local_vz=array_vertex(local_vi).z
            SET VERTEXDATA POSITION vertex_index,local_vx,local_vy,local_vz
            local_tci=array_face(local_index).V3TexCoord
            IF local_tci>0
                local_u = array_texcoord(local_tci).u
                local_v = array_texcoord(local_tci).v
                SET VERTEXDATA UV vertex_index,0,local_u,-local_v
            ELSE
                SET VERTEXDATA UV vertex_index,0,0                 
            ENDIF
            local_ni=array_face(local_index).V3Normal
            IF local_tci>0
                local_nx=array_normal(local_ni).x
                local_ny=array_normal(local_ni).y
                local_nz=array_normal(local_ni).z
                SET VERTEXDATA NORMALS vertex_index,local_nx,local_ny,local_nz
            ELSE
                SET VERTEXDATA NORMALS vertex_index,0,0,0              
            ENDIF
            SET INDEXDATA indice_index,vertex_index
            INC vertex_index : INC indice_index    
           
 
        NEXT
    UNLOCK VERTEXDATA
 
    CALCULATE OBJECT BOUNDS ObjectID
ENDFUNCTION
 
 
rem used to parse a float out of the obj file
FUNCTION GetFloatFromString(thisString$,Position)
    LOCAL local_length AS INTEGER
    LOCAL local_index AS INTEGER
    LOCAL local_done AS INTEGER
    LOCAL local_string AS STRING
    LOCAL local_float AS FLOAT
   
    local_string=""
    local_done=0
    local_length=LEN(thisString$)
    REPEAT
        Position=Position+1
        IF MID$(thisString$,Position)<>" "
            local_string=local_string+MID$(thisString$,Position)
        ELSE
            gThisStringPosition=Position
            local_done=1
        ENDIF
    UNTIL (Position=local_length) OR (local_done=1)
   
    local_float=VAL(local_string)
   
ENDFUNCTION local_float
 
rem used to parse an integer out of the obj file
FUNCTION GetIntegerFromString(thisString$,Position)
    LOCAL local_length AS INTEGER
    LOCAL local_index AS INTEGER
    LOCAL local_string AS STRING
    LOCAL local_int AS INTEGER
   
    local_string=""
    local_done=0
    local_length=LEN(thisString$)
 
    rem In case of "f v1/vt1 v2/vt2 v3/vt3 ...", return 0 for normal indice
    IF (gIndiceStep=3)
        IF (Position>=local_length)
            EXITFUNCTION 0
        ELSE
            IF (MID$(thisString$,Position)=" ")
                EXITFUNCTION 0
            ENDIF
        ENDIF
    ENDIF
   
    rem In case of "f v1 v2 v3 v4 ..."
    IF (gIndiceStep=2) AND (MID$(thisString$,Position)=" ")
        gThisStringPosition=Position
        EXITFUNCTION 0
    ENDIF
   
    rem In case of  "f v1//vn1 v2//vn2 v3//vn3 ...", return 0 for texture coordinates indice
    IF (gIndiceStep=2) AND (MID$(thisString$,Position)="/") AND (MID$(thisString$,Position+1)="/")
        gThisStringPosition=Position+1
        EXITFUNCTION 0
    ENDIF
   
    rem if string position > string length then nothing left to process
    IF (Position>=local_length) THEN EXITFUNCTION 0
       
    REPEAT
        Position=Position+1
        IF (MID$(thisString$,Position)<>" ") AND (MID$(thisString$,Position)<>"/")
            local_string=local_string+MID$(thisString$,Position)
        ELSE
            gThisStringPosition=Position
            local_int=VAL(local_string)
            EXITFUNCTION local_int
        ENDIF
    UNTIL Position>=local_length
    gThisStringPosition=Position
    local_int=VAL(local_string)
   
ENDFUNCTION local_int
 
rem find unused object ID
Function GetNewObjectID()
    ObjectID=0
    repeat
        inc ObjectID
    until object exist(ObjectID)=0
EndFunction ObjectID
 
rem find unused image ID
Function GetNewImageID()
    imageID=0
    repeat
        inc imageID
    until image exist(imageID)=0
EndFunction imageID