Fix rendering and parsing of OBJ models

Create a new surface for each 'usemtl' statement in the OBJ file, and fix memory errors caused by TriangulateQuad.

Calculate missing normals, and fix incorrect UV coordinates

Fix construction of vertex buffer for objects with multiple surfaces

Localize curMtl, curSurface, aggSurfFaceCount, and curSurfFaceCount to FOBJModel::Load(), since they are not used anywhere else.

Fix parsing of OBJs without UV references

Internally, I replaced hashtag line comments with C-style line comments, and I replaced each forward slash with newSideSep.

If no UV coordinates are available, add a default vector of (0,0).

Also, remove "this->" from ResolveIndex to make the code a bit cleaner, and fix a minor garbage issue I failed to notice earlier (normref would pick up garbage if there was no normal reference).

Ensure usemtl statements remain intact

It may be a bit inefficient, but I tried modifying the buffer directly, and I got memory corruption errors. In this case, it's a lot better to be safe than sorry.
This commit is contained in:
Kevin Caccamo 2018-06-03 04:11:38 -04:00 committed by Christoph Oelckers
commit bb8c66b3a0
2 changed files with 484 additions and 328 deletions

View file

@ -29,66 +29,59 @@
class FOBJModel : public FModel
{
private:
int mLumpNum;
int numMtls;
int mLumpNum;
const char *newSideSep = "$"; // OBJ side separator is /, which is parsed as a line comment by FScanner if two of them are next to each other.
enum class FaceElement
{
VertexIndex,
UVIndex,
VNormalIndex
};
enum class FaceElement
{
VertexIndex,
UVIndex,
VNormalIndex
};
struct OBJFaceSide
{
int vertref;
int normref;
int uvref;
};
struct OBJFace
{
int sideCount;
OBJFaceSide sides[4];
};
struct OBJTriangle
{
int vertref[3];
};
struct OBJSurface // 1 surface per 'usemtl'
{
int numTris; // Number of triangulated faces
int numFaces; // Number of faces
int faceStart; // Index of first face in faces array
OBJFace* tris; // Triangles
FTextureID skin;
OBJSurface(FTextureID skin): numTris(0), numFaces(0), faceStart(0), tris(nullptr), skin(skin) {}
};
struct OBJFaceSide
{
int vertref;
int normref;
int uvref;
};
struct OBJFace
{
int sideCount;
OBJFaceSide sides[4];
};
struct OBJSurface // 1 surface per 'usemtl'
{
unsigned int numTris; // Number of triangulated faces
unsigned int numFaces; // Number of faces
unsigned int vbStart; // First index in vertex buffer
unsigned int faceStart; // Index of first face in faces array
OBJFace* tris; // Triangles
FTextureID skin;
OBJSurface(FTextureID skin): numTris(0), numFaces(0), vbStart(0), faceStart(0), tris(nullptr), skin(skin) {}
};
TArray<FVector3> verts;
TArray<FVector3> norms;
TArray<FVector2> uvs;
TArray<OBJFace> faces;
TArray<OBJSurface> surfaces;
FTextureID curMtl;
OBJSurface* curSurface;
int aggSurfFaceCount;
int curSurfFaceCount;
FScanner sc;
TArray<FVector3> verts;
TArray<FVector3> norms;
TArray<FVector2> uvs;
TArray<OBJFace> faces;
TArray<OBJSurface> surfaces;
FScanner sc;
void ParseVector2(TArray<FVector2> &array);
void ParseVector3(TArray<FVector3> &array);
void ParseFaceSide(const FString &side, OBJFace &face, int sidx);
void ConstructSurfaceTris(OBJSurface *surf);
int ResolveIndex(int origIndex, FaceElement el);
void TriangulateQuad(const OBJFace &quad, OBJFace *tris);
void ParseVector2(TArray<FVector2> &array);
void ParseVector3(TArray<FVector3> &array);
void ParseFaceSide(const FString &side, OBJFace &face, int sidx);
void ConstructSurfaceTris(OBJSurface &surf);
int ResolveIndex(int origIndex, FaceElement el);
void TriangulateQuad(const OBJFace &quad, OBJFace *tris);
public:
FOBJModel(): curSurface(nullptr), aggSurfFaceCount(0), curSurfFaceCount(0) {}
~FOBJModel();
bool Load(const char* fn, int lumpnum, const char* buffer, int length) override;
int FindFrame(const char* name) override;
void RenderFrame(FModelRenderer* renderer, FTexture* skin, int frame, int frame2, double inter, int translation=0) override;
void BuildVertexBuffer(FModelRenderer* renderer) override;
void AddSkins(uint8_t* hitlist) override;
FOBJModel() {}
~FOBJModel();
bool Load(const char* fn, int lumpnum, const char* buffer, int length) override;
int FindFrame(const char* name) override;
void RenderFrame(FModelRenderer* renderer, FTexture* skin, int frame, int frame2, double inter, int translation=0) override;
void BuildVertexBuffer(FModelRenderer* renderer) override;
void AddSkins(uint8_t* hitlist) override;
};
#endif