4
\$\begingroup\$

Well I can clearly tell that what rendered is close to what I wanted, but there seems to be a few problems.

The .obj files contained values like "f", "v", "vt".

Image Of Problem:

As you can see it renders very close to what it's suppose to be, but there's a few problems. I can provide more examples/code if needed. The top two are what I'm rendering, the bottom two are while it's loaded in Blender.

Example below of each:

v 0.025487 1.194620 0.121091
v -0.025487 1.194620 0.121091
v 0.025487 1.143731 0.118145
v -0.025487 1.143731 0.118145

vt 0.032776 0.559649
vt 0.041251 0.559656
vt 0.041210 0.563958
vt 0.035813 0.563927

f 47/1 46/2 35/3 36/4
f 51/5 50/6 39/7 40/8
f 51/5 40/8 44/9 55/10
f 45/11 33/12 41/13 53/14

Going by simple things in Math Vertex,Edge,Face The "v" must be corners and "f" must be the quads or the jointed triangular faces. So then each of the "f"'s must build 6 indices?

So what I did was

Firstly I wrote the size of the vertices and quads.

content.writeInt(vertexs.size());
content.writeInt(quads.size());

I wrote to a separate file all the "v" values.

for (Vector3f vector : vertexs)
    content.writeVector(vector);

So they are in order that they were loaded out of the .obj file.

Then I figured every line for the faces would be 6 indexes. So from what I found in some tutorials you're suppose to do it clockwise so for a 1 side of a quad 1,2,3 then 2,4,3. So What I did was load the first part of each "f" so let's say we had "f 11/5 12/6 13/7 14/8" I'd store the values 11,12,13, and 14. Then I'll write them out like the following:

11,12,13, 12,14,13

So basically what I have below.

for (Quad qv : quads)
{
    content.writeShort(qv.indices[0] - 1);
    content.writeShort(qv.indices[1] - 1);
    content.writeShort(qv.indices[2] - 1);
    content.writeShort(qv.indices[1] - 1);
    content.writeShort(qv.indices[3] - 1);
    content.writeShort(qv.indices[2] - 1);
}

So now I can load these into DirectX like this:

LOAD MODEL METHOD

CacheReader::open("model.dat"); //For now it just files no indexing yet.
CacheReader *reader = CacheReader::readFully();

vert_size = reader->readUnsignedInt();

int faces = reader->readUnsignedInt();

int index_capacity = faces * 6;
index_size = faces * 2;

CUSTOMVERTEX *verts = new CUSTOMVERTEX[vert_size];
short *indices = new short[index_capacity];

for (int i = 0; i < vert_size; ++i)
{
    verts[i].X = reader->readFloat();
    verts[i].Y = reader->readFloat();
    verts[i].Z = reader->readFloat();
    verts[i].COLOR = D3DCOLOR_XRGB(255, 255, 255);
}

int n = 0;

for (int i = 0; i < faces; ++i)
{
    indices[n++] = reader->readUnsignedShort();
    indices[n++] = reader->readUnsignedShort();
    indices[n++] = reader->readUnsignedShort();
    indices[n++] = reader->readUnsignedShort();
    indices[n++] = reader->readUnsignedShort();
    indices[n++] = reader->readUnsignedShort();
}

VOID* pVoid;

d3ddev->CreateVertexBuffer(vert_size * sizeof(CUSTOMVERTEX),
    0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, verts, vert_size * sizeof(CUSTOMVERTEX));
v_buffer->Unlock();

d3ddev->CreateIndexBuffer(index_capacity * sizeof(short), 0, 
    D3DFMT_INDEX16, D3DPOOL_MANAGED, &i_buffer, NULL);
i_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, indices, index_capacity * sizeof(short));
i_buffer->Unlock();

D3DXMATRIX matView;
D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3 (0.0f, 0.0f, -5.0f),
    &D3DXVECTOR3 (0.0f, 0.0f, 0.0f), &D3DXVECTOR3 (0.0f, 1.0f, 0.0f));
d3ddev->SetTransform(D3DTS_VIEW, &matView);

D3DXMATRIX matProjection;
D3DXMatrixPerspectiveFovLH(&matProjection, D3DXToRadian(45),
    (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 1.0f, 100.0f);
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection);

RENDER METHOD:

d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);

D3DXMATRIX matRotateY;
static float index = 0.0f; index+=0.05f;
D3DXMatrixRotationY(&matRotateY, index);
d3ddev->SetTransform(D3DTS_WORLD, &matRotateY);

d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetIndices(i_buffer);
d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vert_size, 0, index_size);

d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);

INITALIZE METHOD

d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;

ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
d3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
d3ddev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
d3ddev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
d3ddev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);

load_model();

Here's what the first quad shows in the .obj file.

These are the vertex's

47:  v 0.104867 0.547076 -0.142017
46:  v 0.113943 0.548103 -0.144205
35:  v 0.113968 0.543585 -0.146221
36:  v 0.108210 0.542732 -0.144383

This is the first face.

f 47/1 46/2 35/3 36/4
\$\endgroup\$

3 Answers 3

2
\$\begingroup\$

The issue is that indices in a .obj file start at 1, while when rendering, they start at 0. Pretty much everyone who writes a .obj parser will run into this issue at some point.

The solution is to subtract each index by 1 when loading it:

for (Quad qv : quads)
{
    content.writeShort(qv.indices[0] - 1);
    content.writeShort(qv.indices[1] - 1);
    content.writeShort(qv.indices[2] - 1);
    content.writeShort(qv.indices[1] - 1);
    content.writeShort(qv.indices[3] - 1);
    content.writeShort(qv.indices[2] - 1);
}

Additionally, the other answer is correct about index ordering, and you're going to run into another issue when you want to apply a texture. The order of the vertices (v) and vertex texture coordinates (vt) don't match up, which is why f defines two indices for every vertex. What you want to do is create a new vertex buffer and copy the vertices into it as the indices specify.

This is necessary because the .obj format does not guarantee unique sets of vertex data, so you'll run into issues if you try and sort the texture coordinates alone, because they are sometimes used with more than one vertex.

Link to obj specification

\$\endgroup\$
9
  • \$\begingroup\$ Actually I was editing the way I loaded them and forgot to add the -1 part again, but it still does the same thing as in the picture those were taken prior the the modifications. I've been trying different values for the 0,1,2,1,3,2, but it doesn't seem to get rid of those extra chunks. Thanks for the comment though. I'm wondering if it's just the way I'm rendering them through DirectX because it seems like it's pretty much loaded just fine, but there's like an extra bulk of triangles around it. \$\endgroup\$
    – user24629
    Dec 31, 2012 at 23:10
  • \$\begingroup\$ If you're using counter-clockwise winding, try 0, 1, 2, 0, 2, 3. Otherwise, try 0, 2, 1, 0, 3, 2. \$\endgroup\$ Dec 31, 2012 at 23:14
  • \$\begingroup\$ I'm thinking that stuff is working correctly, but it must be something else that I'm just not seeing. I'm a bit new to models in 3D, but when I tried rendering small objects they didn't seem to have any problems. I noticed I only got these issues when the "f" values had more than 1 type. E.g. if it was only "f 1 2 3 4" that works fine, but when it's "f 1/10 2/11 3/12 4/12" I'm parsing it correctly since I've tested it, but I haven't done anything with the texture or normals yet. I'm wondering if that's the cause? I also provided the first quads information at the end of the original post. \$\endgroup\$
    – user24629
    Dec 31, 2012 at 23:29
  • \$\begingroup\$ Make sure you aren't accidentally including texture coordinates or vertex normals in your vertex buffer. The model loading code isn't for the .obj format, so I'm assuming you're converting it to your own format first. \$\endgroup\$ Dec 31, 2012 at 23:44
  • \$\begingroup\$ Hmm, It seems valid I had it print out everything and front what I was willing to compare it looked okay. There's a few extra thing I noticed. At the very bottom of the .obj is the following which I ignored. f 5570 10142 I'm not sure what the 5570 means, but 10142 is the total vertexs. Then there's a few other things. usemtl BlackCloth -> So that must be the texture. Then right before the faces are read in this is there. usemtl man and s 1 \$\endgroup\$
    – user24629
    Jan 1, 2013 at 0:14
0
\$\begingroup\$

I don't know if you are triangulating your quads correctly.

for (Quad qv : quads)
{
    content.writeShort(qv.indices[0]);
    content.writeShort(qv.indices[1]);
    content.writeShort(qv.indices[2]);
    content.writeShort(qv.indices[1]);
    content.writeShort(qv.indices[3]);
    content.writeShort(qv.indices[2]);
}

Would make the triangles

-----|
\    | 
 \   |
  \  |
   \ |
    \|

and

     /|
    / |
   /  |
  /___|

which dont represent the quad. You can change the second triangle to match the first one, like so:

for (Quad qv : quads)
{
    content.writeShort(qv.indices[0]);
    content.writeShort(qv.indices[1]);
    content.writeShort(qv.indices[2]);
    content.writeShort(qv.indices[2]);
    content.writeShort(qv.indices[3]);
    content.writeShort(qv.indices[0]);
} 
\$\endgroup\$
0
\$\begingroup\$

Yeah, the problem this whole time was that my method of storing floats in order to speed up load time had a few minor errors with some values. Thus only a couple floats or coordinates were screwed up. I've converted it to read as ASCII code, but this is horribly slow and I'll be trying to figure out a better alternative that's still fully portable.

Thank's for all the help guys. Sorry that the issue was something so simplistic when it felt like something much more. Seem's I've spent 3 days trying to figure out an error that was merely my own fault for trying to optimize the floats, but my tests showed it worked, which led me to think it was a good system.

I'll have to start verifying every class is working from the easiest to the hardest. So I don't run into a really easy glitch again.

\$\endgroup\$
3
  • \$\begingroup\$ Why don't you read/write floats directly from the file? Something like this \$\endgroup\$
    – elFarto
    Jan 3, 2013 at 16:18
  • \$\begingroup\$ Or better still this. I haven't tested those, but they shouldn't be too difficult to get working. \$\endgroup\$
    – elFarto
    Jan 3, 2013 at 16:25
  • \$\begingroup\$ I don't think that's completely portable? I'd like it so I can have other computers use this. Worst case I can make separate downloads, but I'd rather not have to. Thank's for the suggestion I'll look more into it. \$\endgroup\$
    – user24629
    Jan 3, 2013 at 17:19

You must log in to answer this question.