Faulty 3DS file?

Started by
7 comments, last by rick_appleton 19 years, 9 months ago
I'm having trouble with a certain 3DS file. You can download the 3d Studio Max file, with the .3ds file I created from the scene here If I load this model, the scene comes up screwed: If I attach everything to a single mesh in 3dstudiomax then export, then everything works fine. In 3dstudio max the scene looks as it should of course. Anyone have any ideas what the problem could be?
Advertisement
Quote:Original post by rick_appleton
If I attach everything to a single mesh in 3dstudiomax then export, then everything works fine. In 3dstudio max the scene looks as it should of course.


sounds like your .3DS parser isn't properly handling cases where there are multiple objects in the scene. basically whenever you hit an Object chunk you need to start a new model/model-component & make sure you reset all the position, rotation, etc values or whatever relevant fields your local model format has. not knowing your local model format or how your .3DS parser works makes this question very difficult to answer.

-me
I see what you mean, but I'm positive that's not it, since I don't read any position/rotation information from the 3ds file, and all the mesh parts are currently loaded into a single model (which can have multiple meshes, but only a single transform matrix), so I'm pretty sure that the data in the 3ds file is incorrect.

However, that begs the question: why does 3dstudiomax r6 export incorrectly to .3ds files? For which I have no answer, and I also wouldn't expect this to happen.

But my loader is straight forward:
#include "loader3DS.h"#include <vector>// Define 3DS chunk;// ===================================================//------ Primary chunk#define MAIN3DS       0x4D4D//------ Main Chunks#define EDIT3DS       0x3D3D  // this is the start of the editor config#define KEYF3DS       0xB000  // this is the start of the keyframer config//------ sub defines of EDIT3DS#define EDIT_MATERIAL 0xAFFF#define EDIT_OBJECT   0x4000//------ sub defines of EDIT_OBJECT#define OBJ_TRIMESH   0x4100#define OBJ_LIGHT     0x4600#define OBJ_CAMERA    0x4700//------ sub defines of OBJ_LIGHT#define LIT_OFF       0x4620#define LIT_SPOT      0x4610#define LIT_UNKNWN01  0x465A//------ sub defines of OBJ_TRIMESH#define TRI_VERTEXL   0x4110#define TRI_FACES     0x4120#define TRI_UVW       0x4140#define TRI_FACEL2    0x4111 #define TRI_FACEL1    0x4120#define TRI_SMOOTH    0x4150#define TRI_LOCAL     0x4160#define TRI_VISIBLE   0x4165short int GetString( BufferReader &file, char *buffer ){  short int nofRead=0;  file.Read(&buffer[0], 1);  while (buffer[nofRead])  {    ++nofRead;    file.Read(&buffer[nofRead], 1);  }  return (nofRead+1);}short int ReadChunkID( BufferReader &file ){  unsigned short int id;  if (file.Read(&id, 2))    return id;  else    return -1;}unsigned long ReadChunkNextPosition( BufferReader &file ){  unsigned long pos;  file.Read(&pos, 4);  return (pos-6);}unsigned long LoadFaces( BufferReader &file, CGeometryChunk &gc ){  unsigned long chunkLength = ReadChunkNextPosition(file);  unsigned short nofFaces;  file.Read(&nofFaces, 2);  gc.mNofFaces = nofFaces;  unsigned short tmp;  gc.mpIndicesArray = new unsigned short[nofFaces*3];  for (int i=0; i<gc.mNofFaces; ++i)  {    file.Read(&gc.mpIndicesArray[3*i], 3*2);    file.Read(&tmp,2);  }  return chunkLength;}unsigned long LoadUVCoords( BufferReader &file, CGeometryChunk &gc ){  unsigned long chunkLength = ReadChunkNextPosition(file);  unsigned short nofVerts;  file.Read(&nofVerts, 2);  if (gc.mNofVertices!=nofVerts)  {    // ERROR    return 0;  }  for (int i=0; i<gc.mNofVertices; ++i)    file.Read(&gc.mpDataArray.texCoords[0], 2*sizeof(float));  return chunkLength;}unsigned long LoadVertices( BufferReader &file, CGeometryChunk &gc ){  unsigned long chunkLength = ReadChunkNextPosition(file);  unsigned short nofVerts;  file.Read(&nofVerts, 2);  gc.mNofVertices = nofVerts;  gc.mpDataArray = new CDataVertex[gc.mNofVertices];  for (int i=0; i<gc.mNofVertices; ++i)    file.Read(&gc.mpDataArray.vertex.x, 3*sizeof(float));  return chunkLength;}unsigned long LoadMeshObject( BufferReader &file, CGeometryChunk &gc ){  short id = 0;  unsigned long chunkLength = ReadChunkNextPosition(file);  unsigned long position = 6;  unsigned long length;  while (position<chunkLength)  {    id = ReadChunkID(file);    switch(id)    {      case TRI_VERTEXL: position+=LoadVertices(file, gc);                        break;      case TRI_UVW:     position+=LoadUVCoords(file, gc);                        break;      case TRI_FACES:   position+=LoadFaces(file, gc);                        break;      default:          length = ReadChunkNextPosition(file);                        position+=length;                        file.Seek(length);                        break;    }  }  return chunkLength;}unsigned long LoadEditObject( BufferReader &file, CGeometryChunk &gc ){  short id = 0;  unsigned long chunkLength = ReadChunkNextPosition(file);  unsigned long position = 6;  unsigned long length;  char data[512];  position+=GetString(file, &data[0]);  while (position<chunkLength)  {    id = ReadChunkID(file);    switch(id)    {      case OBJ_TRIMESH: position+=LoadMeshObject(file, gc);                        break;      case OBJ_LIGHT:   length = ReadChunkNextPosition(file);                        position+=length;                        file.Seek(length);                        break;      case OBJ_CAMERA:  length = ReadChunkNextPosition(file);                        position+=length;                        file.Seek(length);                        break;      default:          length = ReadChunkNextPosition(file);                        position+=length;                        file.Seek(length);                        break;    }  }  return chunkLength;}IResource* Load3DS( BufferReader &file ){  short id;  id = ReadChunkID(file);  if (id==MAIN3DS)  {    unsigned long mainChunkLength=ReadChunkNextPosition(file);    unsigned long mainPosition=6;    unsigned long mainLength;    std::vector<CGeometryChunk*> gcList;    while (mainPosition<mainChunkLength)    {      id = ReadChunkID(file);      mainPosition+=2;      switch(id)      {      case EDIT3DS:        {          unsigned long chunkLength=ReadChunkNextPosition(file);          mainPosition+=4;          unsigned long position=6;          unsigned long length;                    while (position<chunkLength)          {            id = ReadChunkID(file);            mainPosition+=2;            switch (id)            {              case EDIT_MATERIAL: length = ReadChunkNextPosition(file);                                  mainPosition+=length;                                  position+=length;                                  file.Seek(length);                                  break;              case EDIT_OBJECT:                   {                 CGeometryChunk* gc = new CGeometryChunk;                                  gcList.push_back(gc);                                  length = LoadEditObject(file, *gc);                                  mainPosition+=(length+4); // Add 4 for the length info                                  position+=length;                                  break;                }              default:            length = ReadChunkNextPosition(file);                                  mainPosition+=length;                                  position+=length;                                  file.Seek(length);                                  break;            }          }        }        break;      case KEYF3DS:     mainLength = ReadChunkNextPosition(file);                        mainPosition+=(mainLength+4);                        file.Seek(mainLength);                        break;      default:          mainLength = ReadChunkNextPosition(file);                        mainPosition+=mainLength;                        file.Seek(mainLength);                        break;      }    }    CMesh *mesh = new CMesh;    mesh->nofChunks = gcList.size();    mesh->pMeshChunks = new CGeometryChunk[mesh->nofChunks];    for (int i=0; i<mesh->nofChunks; ++i)      mesh->pMeshChunks = *gcList;	  return mesh;  }  else    return 0;}


Incidentally, I've also tried loading the .3ds file with the 3dsloader from www.gametutorials.com and it shows the same problems. So I'm really leaning toward the 3dsmax problem.
The trimesh chunk can have a subchunk for a local coordinate system which you don't seem to be checking for in your LoadMeshObject() function.

-------------------------------------------------------------------
Chunk # : 0x4160
Name : Local coordinate system
Level : 4
Size : 48
Father : 0x4100 (Triangular mesh)
Format :

vector X1
vector X2
vector X3
vector O

X1, X2 and X3 represent the axes, O the origin.

-------------------------------------------------------------------

Could that be it?

Dan

That could be it. I had a quick look, but it doens't seem to help matters though.

I found the block, and I'm reading 4 vectors from it (each contains 3 floats). However, the X1, X2, X3 vectors are not unit length. I tried to only translate the verts of each block by its origin vector, but that didn't help any, the model is now even more screwed up.

I'm presuming I need to normalize the other vectors before I create a rotation matrix with them? Unless there's already a scaling in them already, and I should just use them as is?

Edit: I tried them as is using the full four vectors, and now nothing is anywhere near where it should be!

Edit2: Tried a different, simpler test-case, and that seems to work out find. So is the 3DS file just borked?
Is it set to anything though?

I believe the 3ds format will normally leave out any chunks that are not used, so the presence of them should indicate that somehing may be going on. If it is set anything other than <1, 0, 0> <0, 1, 0> <0, 0, 1> <0, 0, 0> (or whatever the 'normal' orientation and origin is) then it should indicate that it is causing problems.

Dan

Dan

Yes it is set. A quick grab:

v1: (-0.0531, -0.00596, 0.0845)

I've checked the local origin, and that does seem to correspond with what 3dsmax says. So I'm currently assuming only the rotations are going wrong. But I'm still stumped as to what is going wrong.

I've tried normalizing vector 1,2,3 before making the transformation matrix, but that didn't help much. It did seem a bit better, but the axis where totally screwed still.

I am skipping over a number of chunks, but I'm not sure if they're important. The docs I downloaded from wotsit.org weren't all too good. Maybe you hae a better one?

edit: I found the document you quoted from. Now the funny thing is that the loader that comes with the document is also unable to correctly load my file. The results it produces are even worse than my own. However, 3d studio max can correctly import the model again, so the file is somehow correct. I'm going to search for some more loaders, and see if they can load the model correctly.

edit2: Deep Exploration can also load the model correctly. So it's definately me :(. Just a quick check, I need to multiply the verts with the matrix created from the vectors right? not with the inverse of that matrix?

[Edited by - rick_appleton on August 11, 2004 5:41:14 PM]
bump, anyone any ideas?
well, after messing around a lot more, I finally found the problem. The local matrix included in the 3ds file is not the normal right-handed (?) coordinate system, but the other one, the one not used by OpenGL.

Still need to figure out how to fix it, and if this occurs with all the parts of the object, but there is is. :(

Edit: after some more work

Conclusions:
- 3dsmax stores the meshes in worldcoordinates, not in local coordinates. So if all parts have the same handedness you need not read the local transforms
- a 3ds chunk does not contain any info on the handedness of the coordinate system, nor does it guarentee that all parts have the same handedness.

In order to correctly process ALL files you have to read the local coordinate system from the chunk, and then calculate for yourself if this is a right-handed or left-handed coordinate system. If it is the incorrect one, take the inverse of the local transform, so the verts are transformed back into local objectspace, invert one of the coordinates of all the parts (in this case I had to invert the x-coord, not sure if this is always the case, doubtfull), then transform back into worldspace using the same localtransform.

This, and only this gave me the correct results.

[Edited by - rick_appleton on August 18, 2004 1:13:33 PM]

This topic is closed to new replies.

Advertisement