Texture coordinates from OBJ file for use in Android - opengl-es

I have this OBJ file for a cube with texture:
# Max2Obj Version 4.0 Mar 10th, 2001
#
mtllib cube2.mtl
g
# object Cube_1 to come ...
#
v -5.500000 0.000000 -1.000000
v -5.500000 0.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 2.000000 1.000001
v -7.500000 2.000000 1.000000
v -7.500000 2.000000 -1.000000
v -5.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 2.000000 1.000001
v -5.500000 0.000000 -1.000000
v -5.500000 2.000000 1.000001
v -5.500000 0.000000 1.000000
v -5.500000 0.000000 1.000000
v -5.500000 2.000000 1.000001
v -7.500000 2.000000 1.000000
v -5.500000 0.000000 1.000000
v -7.500000 2.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 2.000000 1.000000
v -7.500000 2.000000 -1.000000
v -7.500000 0.000000 1.000000
v -7.500000 2.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 0.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -7.500000 2.000000 -1.000000
# 32 vertices
vt 0.000500 0.999500 0.000500
vt 0.000500 0.000500 0.000500
vt 0.999501 0.000500 0.000500
vt 0.999501 0.999500 0.000500
vt 0.999500 0.999500 0.999501
vt 0.999500 0.000500 0.999501
vt 0.000499 0.000500 0.999501
vt 0.000499 0.999500 0.999501
vt 0.999500 0.000500 0.999500
vt 0.999500 0.999501 0.999500
vt 0.000500 0.999501 0.999500
vt 0.999500 0.000500 0.999500
vt 0.000500 0.999501 0.999500
vt 0.000500 0.000500 0.999500
vt 0.999500 0.000500 0.000500
vt 0.999500 0.999501 0.000500
vt 0.000499 0.999501 0.000500
vt 0.999500 0.000500 0.000500
vt 0.000499 0.999501 0.000500
vt 0.000499 0.000500 0.000500
vt 0.999500 0.000500 0.000499
vt 0.999500 0.999501 0.000499
vt 0.000500 0.999501 0.000499
vt 0.999500 0.000500 0.000499
vt 0.000500 0.999501 0.000499
vt 0.000500 0.000500 0.000499
vt 0.000500 0.999501 0.999500
vt 0.000500 0.000500 0.999500
vt 0.999501 0.000500 0.999500
vt 0.000500 0.999501 0.999500
vt 0.999501 0.000500 0.999500
vt 0.999501 0.999501 0.999500
vt 0.000500 0.999500 0.000500
vt 0.999501 0.000500 0.000500
vt 0.999500 0.999500 0.999501
vt 0.000499 0.000500 0.999501
# 36 texture vertices
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000000 -0.000000 1.000000
vn -0.000000 -0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
# 32 vertex normals
g Cube_1
usemtl 01_-_Default_1
s 0
f 1/33/1 2/2/2 3/34/3
f 1/1/1 3/3/3 4/4/4
f 5/35/5 8/8/8 7/36/7
f 5/5/5 7/7/7 6/6/6
f 9/9/9 10/10/10 11/11/11
f 12/12/12 13/13/13 14/14/14
f 15/15/15 16/16/16 17/17/17
f 18/18/18 19/19/19 20/20/20
f 21/21/21 22/22/22 23/23/23
f 24/24/24 25/25/25 26/26/26
f 27/27/27 28/28/28 29/29/29
f 30/30/30 31/31/31 32/32/32
# 12 faces
g
As you can see vt have 3 entries per row. Does this mean is it 3d texture and not 2d? Android supports only 2d textures. So does it mean above OBJ file will not work in Android?
I can parse OBJ and get float[] textcoordinates = [0.000500, 0.999500, 0.000500,0.000500, 0.000500, 0.000500, .....] Are these the correct first 2 tex coordinates that needs to be fed to OpenGL-ES? Or do I need to figure the texture coordinates from the f numbers in the OBJ file which AFAIK are indexes into texture coordinates to compute the correct tex coodinates. So I am not sure which is the right way. Somebody with experience with OpenGL-ES and OBJ file format can clear all this up.

This model is in fact using a 3d texture. The details of the obj file format are described at http://paulbourke.net/dataformats/obj/, here is the part about texture coordinates:
vt u v w
Vertex statement for both polygonal and free-form geometry.
Specifies a texture vertex and its coordinates. A 1D texture
requires only u texture coordinates, a 2D texture requires both u
and v texture coordinates, and a 3D texture requires all three
coordinates.
The vertex data from the obj file can not be passed directly to opengl. You have to setup your arrays so that the corresponding indices in each array belong to the same vertex. As an example, the first vertex of the first face in your model (1/33/1) consists of
the vertex coordinates from the first "v" line.
the texture coordinates from the 33. "vt" line.
the normal vector from the first "vn" line.
The easiest way to set this up for opengl would be to iterate over all faces, get the values for vertex, texture and normal and append these to new arrays.

Related

Odd-dim vs even-dim vectors allocated in Julia

Why do not odd dimensions seem to allocate extra memory when initializing Vectors? Example:
julia> for N in 1:10 #time a = [k for k in 1:N] end
0.000002 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 112 bytes)
0.000000 seconds (1 allocation: 112 bytes)
0.000000 seconds (1 allocation: 128 bytes)
0.000000 seconds (1 allocation: 128 bytes)
0.000000 seconds (1 allocation: 144 bytes)
The code deciding on array allocation has several branches. You can see it here. In general what you can see is byte-alignment of allocations, which is governed by two contestants defined here.
Now the code is more complicated than this but in your case for very small arrays alignment is 16 bytes, so since Int64 has 8 bytes every two consecutive sizes will have the same allocated size.
To read more about memory alignment see here.
We can check that if e.g. you allocate Int32 vector instead of Int64 vector every four values get the same allocation. Similarly for Int16 every eight values have the same allocation:
julia> for N in 1:12 #time a = Int32[k for k in 1:N] end
0.000004 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000001 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000001 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000001 seconds (1 allocation: 96 bytes)
0.000001 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 112 bytes)
0.000000 seconds (1 allocation: 112 bytes)
julia> for N in 1:20 #time a = Int16[k for k in 1:N] end
0.000003 seconds (1 allocation: 64 bytes)
0.000001 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 64 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 80 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000001 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 96 bytes)
0.000000 seconds (1 allocation: 96 bytes)
(remember that this is for small arrays, for lager arrays Julia uses different alignment, growing up to 64 bytes)

Does Three.js support more complex materials

I have a obj model with mtls of a cake I want to load to my webpage.
In Blend, the model I am using looks like this.
But in webpage it comes out as this.
I am using the Three.js OBJ and MTL loader to load the model, which works perfectly fine on less complex models. Now I am wondering if Three.js might not be able to display this complex materials.
newmtl Material
Ns 225.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd C:\xampp\htdocs\uploads\Jakob\CAKECOLOR.png
newmtl Material.002
Ns 572.940236
Ka 1.000000 1.000000 1.000000
Kd 0.031064 0.010178 0.002872
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl Material.003
Ns 900.000000
Ka 1.000000 1.000000 1.000000
Kd 0.023651 0.023651 0.023651
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 3
newmtl Material.004
Ns 900.000000
Ka 1.000000 1.000000 1.000000
Kd 0.057803 0.017225 0.006625
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl Material.005
Ns 900.000000
Ka 1.000000 1.000000 1.000000
Kd 1.000000 0.878900 0.685513
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2

Purpose of "subsd 0x0(%rip),%xmm0"

I'm trying to understand/debug a library I don't have source code for. In doing so, I came across the following function (and a bunch of other, more complicated, ones like it, e.g. [0]):
0000000000000000 <old_bern_poly_power02(double, double)>:
0: 66 0f 28 d0 movapd %xmm0,%xmm2
4: 66 0f 28 c1 movapd %xmm1,%xmm0
8: f2 0f 59 d1 mulsd %xmm1,%xmm2
c: f2 0f 5c 05 00 00 00 subsd 0x0(%rip),%xmm0 # 14 <old_bern_poly_power02(double, double)+0x14>
13: 00
14: f2 0f 59 c2 mulsd %xmm2,%xmm0
18: c3 retq
19: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
It's pretty obvious what the function does apart from the subsd instruction. However, I am confused about what the subsd instruction is doing. What does the value at the pointed to instruction, 0x0(%rip), have to do with this calculation?
So, this is my question: What is the purpose of the "subsd" instruction above? I assume the function was compiled with GCC. Why would GCC (or an assembly language programmer) include an instruction like this? [1]
[0] Here's another, similar example:
0000000000000020 <old_bern_poly_power03(double, double)>:
20: 66 0f 28 d0 movapd %xmm0,%xmm2
24: 66 0f 28 d8 movapd %xmm0,%xmm3
28: 66 0f 28 c1 movapd %xmm1,%xmm0
2c: f2 0f 59 15 00 00 00 mulsd 0x0(%rip),%xmm2 # 34 <old_bern_poly_power03(double, double)+0x14>
33: 00
34: f2 0f 5c 05 00 00 00 subsd 0x0(%rip),%xmm0 # 3c <old_bern_poly_power03(double, double)+0x1c>
3b: 00
3c: f2 0f 59 d9 mulsd %xmm1,%xmm3
40: f2 0f 59 c3 mulsd %xmm3,%xmm0
44: f2 0f 58 c2 addsd %xmm2,%xmm0
48: f2 0f 59 c3 mulsd %xmm3,%xmm0
4c: c3 retq
4d: 0f 1f 00 nopl (%rax)
[1] Note: Based on stepping through the function in gdb, the subsd instruction seems to have no practical effect when %xmm0 is away from 0.0, because 0x0(%rip) is tiny (I am not sure this is correct):
(gdb) x $rip
0x4004e2 <old_bern_poly_power02+12>: 0x00000000055c0ff2
(gdb) p (double)(void *)(0x00000000055c0ff2)
$22 = 4.4426122995515177e-316
To investigate the effect of the subsd instruction further, I made a version of the old_bern_poly_power02 function that does not include the subsd instruction, but is otherwise identical to the listing above. The following table compares the return values of each version of the function given a variety of inputs.
Indeed, the return values are identical except when the xmm1 argument is 0, in which case the result is -0 (0x8000000000000000) in the original and 0 (0x0) in the version without the subsd instruction.
xmm0 xmm1 ret_val_with_subsd (as hex) ret_val_without_subsd (as hex)
0.000000 0.000000 -0.0000000000 (8000000000000000) 0.0000000000 ( 0)
0.000000 1.000000 0.0000000000 ( 0) 0.0000000000 ( 0)
0.000000 2.000000 0.0000000000 ( 0) 0.0000000000 ( 0)
0.000000 3.000000 0.0000000000 ( 0) 0.0000000000 ( 0)
1.000000 0.000000 -0.0000000000 (8000000000000000) 0.0000000000 ( 0)
1.000000 1.000000 1.0000000000 (3ff0000000000000) 1.0000000000 (3ff0000000000000)
1.000000 2.000000 4.0000000000 (4010000000000000) 4.0000000000 (4010000000000000)
1.000000 3.000000 9.0000000000 (4022000000000000) 9.0000000000 (4022000000000000)
2.000000 0.000000 -0.0000000000 (8000000000000000) 0.0000000000 ( 0)
2.000000 1.000000 2.0000000000 (4000000000000000) 2.0000000000 (4000000000000000)
2.000000 2.000000 8.0000000000 (4020000000000000) 8.0000000000 (4020000000000000)
2.000000 3.000000 18.0000000000 (4032000000000000) 18.0000000000 (4032000000000000)
3.000000 0.000000 -0.0000000000 (8000000000000000) 0.0000000000 ( 0)
3.000000 1.000000 3.0000000000 (4008000000000000) 3.0000000000 (4008000000000000)
3.000000 2.000000 12.0000000000 (4028000000000000) 12.0000000000 (4028000000000000)
3.000000 3.000000 27.0000000000 (403b000000000000) 27.0000000000 (403b000000000000)
Edit 1: Per Harold and Ross's comments, I linked the library into a simple executable (the one that generated the above table) and disassembled the function in GDB, as follows:
$ gdb ./tmp
[snp]
(gdb) b old_bern_poly_power02
Breakpoint 1 at 0x400516
(gdb) r
Starting program: [...]/tmp
xmm0 xmm1 ret_val_with_subsd (as hex) ret_val_without_subsd (as hex)
Breakpoint 1, 0x0000000000400516 in old_bern_poly_power02 ()
(gdb) disassemble
Dump of assembler code for function old_bern_poly_power02:
=> 0x0000000000400516 <+0>: movapd %xmm0,%xmm2
0x000000000040051a <+4>: movapd %xmm1,%xmm0
0x000000000040051e <+8>: mulsd %xmm1,%xmm2
0x0000000000400522 <+12>: subsd 0x0(%rip),%xmm0 # 0x40052a <old_bern_poly_power02+20>
0x000000000040052a <+20>: mulsd %xmm2,%xmm0
0x000000000040052e <+24>: retq
0x000000000040052f <+25>: nopl (%rax)
End of assembler dump.
It seems to still have the same reference to 0-offset-to-%rip here, though it's definitely possible that I am still doing something wrong?
Edit 2: In the above listing, I was disassembling a version I'd copied and pasted from a disassembly of the unlinked static library, then assembled and linked into my test program above. When I disassemble the function from the original static library, as linked into my real program, the offsets are indeed filled in:
(gdb) disassemble old_bern_poly_power02
Dump of assembler code for function _Z21old_bern_poly_power02dd:
0x00007f65cf642a50 <+0>: movapd %xmm0,%xmm2
0x00007f65cf642a54 <+4>: movapd %xmm1,%xmm0
0x00007f65cf642a58 <+8>: mulsd %xmm1,%xmm2
0x00007f65cf642a5c <+12>: subsd 0x38cc(%rip),%xmm0 # 0x7f65cf646330
0x00007f65cf642a64 <+20>: mulsd %xmm2,%xmm0
0x00007f65cf642a68 <+24>: retq
End of assembler dump.
So I guess that the subsd instruction is just referencing a constant in a table here.

what parameters should I use when drawing this data using glDrawElements?

I am trying to load ply format which looks like this:
0.000000 0.000000 -1.543509 0.000000 0.000000 -1.000000 0.838731 0.300864 106 34 22
vertex pos/ normal dir/texture coords/ vertex color
and the face defines like this:
3 0 1 2
how much vertices per face/ which vertex for x/ which vertex for y/which vertex for z/
then I read them in to a vertex array,and a face array, draw them like this:
//bind buffer first of course)
glDrawElements(GL_TRIANGLE_FAN,vert_amount,GL_UNSIGNED_INT,faces);
I am using opengles 1.1 so I am stuck with TRIANGLE_FAN I guess,the result is messed up,so I guess the default ply face definition is not suitable for opengl right? how to reorganize faces if I want to use glDrawElements ?
here is the simple cube of ply model file:
1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000
1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000
-1.000000 -1.000000 -1.000000 0.000000 0.000000 -1.000000
1.000000 0.999999 1.000000 -0.000000 0.000000 1.000000
-1.000000 1.000000 1.000000 -0.000000 0.000000 1.000000
-1.000000 -1.000000 1.000000 -0.000000 0.000000 1.000000
1.000000 1.000000 -1.000000 1.000000 -0.000001 -0.000000
1.000000 0.999999 1.000000 1.000000 -0.000001 -0.000000
0.999999 -1.000001 1.000000 1.000000 -0.000001 -0.000000
1.000000 -1.000000 -1.000000 -0.000000 -1.000000 -0.000000
0.999999 -1.000001 1.000000 -0.000000 -1.000000 -0.000000
-1.000000 -1.000000 1.000000 -0.000000 -1.000000 -0.000000
-1.000000 -1.000000 -1.000000 -1.000000 0.000000 -0.000000
-1.000000 -1.000000 1.000000 -1.000000 0.000000 -0.000000
-1.000000 1.000000 1.000000 -1.000000 0.000000 -0.000000
1.000000 0.999999 1.000000 0.000000 1.000000 0.000000
1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000
-1.000000 1.000000 -1.000000 0.000000 1.000000 0.000000
-1.000000 1.000000 -1.000000 0.000000 0.000000 -1.000000
0.999999 -1.000001 1.000000 -0.000000 0.000000 1.000000
1.000000 -1.000000 -1.000000 1.000000 0.000000 0.000000
1.000000 1.000000 -1.000000 1.000000 0.000000 0.000000
0.999999 -1.000001 1.000000 1.000000 0.000000 0.000000
-1.000000 -1.000000 -1.000000 -0.000000 -1.000000 0.000000
-1.000000 1.000000 -1.000000 -1.000000 0.000000 -0.000000
-1.000000 1.000000 1.000000 0.000000 1.000000 0.000000
3 0 1 2
3 3 4 5
3 6 7 8
3 9 10 11
3 12 13 14
3 15 16 17
3 18 0 2
3 19 3 5
3 20 21 22
3 23 9 11
3 24 12 14
3 25 15 17
GL_TRIANGLE_FAN is the wrong primitive here - a triangle fan has one fixed vertex shared by all the triangles. If you only have triangles, GL_TRIANGLES is the better choice. If not, consider triangulating, or otherwise build triangle strips instead.

Why vertices/normals are duplicated in OBJ file?

OBJ files uses f lines that are index into vertices to represent data very efficiently.
But I notice many OBJ models out there have duplicated v lines. For example here is a sample cube OBJ content:
# Max2Obj Version 4.0 Mar 10th, 2001
#
mtllib ./Cube 2.mtl
g
# object Cube_1 to come ...
#
v -5.500000 0.000000 -1.000000
v -5.500000 0.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 2.000000 1.000001
v -7.500000 2.000000 1.000000
v -7.500000 2.000000 -1.000000
v -5.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 2.000000 1.000001
v -5.500000 0.000000 -1.000000
v -5.500000 2.000000 1.000001
v -5.500000 0.000000 1.000000
v -5.500000 0.000000 1.000000
v -5.500000 2.000000 1.000001
v -7.500000 2.000000 1.000000
v -5.500000 0.000000 1.000000
v -7.500000 2.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 0.000000 1.000000
v -7.500000 2.000000 1.000000
v -7.500000 2.000000 -1.000000
v -7.500000 0.000000 1.000000
v -7.500000 2.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -5.500000 0.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -5.500000 2.000000 -1.000000
v -7.500000 0.000000 -1.000000
v -7.500000 2.000000 -1.000000
# 32 vertices
vt 0.000500 0.999500 0.000500
vt 0.000500 0.000500 0.000500
vt 0.999501 0.000500 0.000500
vt 0.999501 0.999500 0.000500
vt 0.999500 0.999500 0.999501
vt 0.999500 0.000500 0.999501
vt 0.000499 0.000500 0.999501
vt 0.000499 0.999500 0.999501
vt 0.999500 0.000500 0.999500
vt 0.999500 0.999501 0.999500
vt 0.000500 0.999501 0.999500
vt 0.999500 0.000500 0.999500
vt 0.000500 0.999501 0.999500
vt 0.000500 0.000500 0.999500
vt 0.999500 0.000500 0.000500
vt 0.999500 0.999501 0.000500
vt 0.000499 0.999501 0.000500
vt 0.999500 0.000500 0.000500
vt 0.000499 0.999501 0.000500
vt 0.000499 0.000500 0.000500
vt 0.999500 0.000500 0.000499
vt 0.999500 0.999501 0.000499
vt 0.000500 0.999501 0.000499
vt 0.999500 0.000500 0.000499
vt 0.000500 0.999501 0.000499
vt 0.000500 0.000500 0.000499
vt 0.000500 0.999501 0.999500
vt 0.000500 0.000500 0.999500
vt 0.999501 0.000500 0.999500
vt 0.000500 0.999501 0.999500
vt 0.999501 0.000500 0.999500
vt 0.999501 0.999501 0.999500
vt 0.000500 0.999500 0.000500
vt 0.999501 0.000500 0.000500
vt 0.999500 0.999500 0.999501
vt 0.000499 0.000500 0.999501
# 36 texture vertices
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 -1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 0.000000 1.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn 1.000000 0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000000 -0.000000 1.000000
vn -0.000000 -0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn -1.000000 0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
# 32 vertex normals
g Cube_1
usemtl 01_-_Default_1
s 0
f 1/33/1 2/2/2 3/34/3
f 1/1/1 3/3/3 4/4/4
f 5/35/5 8/8/8 7/36/7
f 5/5/5 7/7/7 6/6/6
f 9/9/9 10/10/10 11/11/11
f 12/12/12 13/13/13 14/14/14
f 15/15/15 16/16/16 17/17/17
f 18/18/18 19/19/19 20/20/20
f 21/21/21 22/22/22 23/23/23
f 24/24/24 25/25/25 26/26/26
f 27/27/27 28/28/28 29/29/29
f 30/30/30 31/31/31 32/32/32
# 12 faces
g
This causes a lot problem when I import such a model into opengl es application using gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices, GL10.GL_UNSIGNED_SHORT, mIndicesBuffer)
method of drawing due to wrong shading which has something to do with normals. It seems opnegl-es expect that the vertices we give to it are not duplicated if we are using drawElement method and not DrawArrays.
The f lines makes it possible to eliminate any duplicate to produce very efficient data for processing in OpenGL-ES. But the OBJ files have duplicates which defeat the purpose of f lines.
It'll likely just be because it's quite common to keep data the same way that OpenGL's fixed pipeline does internally, and OBJ allows redundancy to be eliminated but doesn't require it. So as long as the software outputs something that is a valid OBJ file and describes the correct shape, its author was satisfied. You're correct to say that there's no need to duplicate any locations, normals or texture coordinates in an OBJ — the 'f' declarations provide a level of indirection so as to avoid that.
To display a general case OBJ that contains v vertices, n normals and t texture coordinates you therefore need to be ready to submit v*n*t vertices to OpenGL in the worst case. OpenGL doesn't know or care whether you duplicate vertices.

Resources