Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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: http://i49.tinypic.com/302s02u.jpg

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 vertexs 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 so.

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

All The Files Used to make this work:

The .obj to .dat converter.

Main.java -> https://pastee.org/hatha FileBuilder -> https://pastee.org/xzdqf

Full Source: http://uppit.com/qi7eouhmedpb/OBJ_FILE_PARSER.zip

The directx visual studio 2010 testing files.

Main.cpp -> https://pastee.org/rztug CacheReader.cpp -> https://pastee.org/ckgey

Full Source: http://uppit.com/ixropebxtrgi/DxLibTutTesting.zip

share|improve this question

3 Answers 3

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

share|improve this answer
    
+1 Did not know that about obj indices. –  Stephan van den Heuvel Dec 31 '12 at 22:59
    
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. –  Jeremy Trifilo Dec 31 '12 at 23:10
    
If you're using counter-clockwise winding, try 0, 1, 2, 0, 2, 3. Otherwise, try 0, 2, 1, 0, 3, 2. –  Robert Rouhani Dec 31 '12 at 23:14
    
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. –  Jeremy Trifilo Dec 31 '12 at 23:29
    
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. –  Robert Rouhani Dec 31 '12 at 23:44

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]);
} 
share|improve this answer
up vote 0 down vote accepted

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.

In case anyone ever needs help getting DirectX .obj models working I'll post some of the source to aid anyone who comes along with similar issues I've had this past week in trying to figure out how to render 3D models.

GameUtilities.cpp -> http://pastie.org/5616892

Model.hpp -> http://pastie.org/5616896

ModelCache.cpp -> http://pastie.org/5616916

CacheReader.cpp -> http://pastie.org/5616919

Main.cpp -> http://pastie.org/5616922

The Main.cpp was a modified class from a tutorial website on -> http://www.directxtutorial.com/

I was merely using it as a base until I could edit + merge the other 4 files into my fully project. I prefer to do testing on blank projects just in case something goes wrong It'll be hopefully easier to figure out the problem. 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.

share|improve this answer
    
Why don't you read/write floats directly from the file? Something like this –  elFarto Jan 3 '13 at 16:18
    
Or better still this. I haven't tested those, but they shouldn't be too difficult to get working. –  elFarto Jan 3 '13 at 16:25
    
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. –  Jeremy Trifilo Jan 3 '13 at 17:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.