Wavefront OBJ

This commit is contained in:
2024-05-06 08:23:01 -04:00
parent 9f1359aa3e
commit c4f4cffbdc
8 changed files with 119 additions and 68 deletions

View File

@@ -1,5 +1,10 @@
#pragma once
#include <vector>
#include <types/keyFrame.h>
#include <types/bone.h>
struct KeyFrame {
uint index;
Bone bone;
};
typedef std::vector<KeyFrame> Animation;

View File

@@ -14,6 +14,7 @@ public:
const Matrix4x4& getMatrix();
void setMatrix(const Matrix4x4& m);
void appendChild(const Bone& bone);
uint getDepth(); //The "depth" refers to how far in the bone is on the bonemap. For ex, the fingers would be deeper than the elbow.
Bone* getParent();
Bone* getChildByName(const std::string& bName);
Bone* getChildByNameRecursive(const std::string& bName);

View File

@@ -1,7 +1,2 @@
#pragma once
#include <types/bone.h>
struct KeyFrame {
uint index;
Bone bone;
};

View File

@@ -16,25 +16,32 @@ enum struct ModelType : uint8_t {
COLLADA = 3, //*Very* complicated.
};
struct FaceIndices {
unsigned int vertexIndex[3];
unsigned int texCoordIndex[3];
};
class SkeletalVertex : public Vertex {
int8_t joints[3]; //The index of 4 bones that can effect the vertex. 0 represents an empty slot. -1 represents the root bone.
Vector4 weights; //The 4 weights must total to 1.0
};
class Model {
private:
void loadOBJ(const std::string& filename);
void load(const std::string& file);
protected:
std::vector<Vertex> vertices;
std::vector<uint> indices;
std::vector<TextureInformation> textureInfo;
void load(const std::string& file);
void load(const std::string& file, const ModelType& type);
void mapFaces(const FaceIndices& facedata, const std::vector<Vector3>& positions, const std::vector<Vector2>& uvs);
public:
ModelType type;
const std::vector<Vertex>& getVertices();
const std::vector<uint>& getIndices();
const std::vector<TextureInformation>& getTextureInformation();
Model() = default;
Model(const std::string& file);
explicit Model(const std::string& file);
};
class SkeletalModel : public Model {

View File

@@ -3,6 +3,6 @@
#include <J3ML/LinearAlgebra.h>
struct TextureInformation {
std::string name;
std::string path;
std::vector<Vector2> textureCoordinates;
};

85
src/obj.cpp Normal file
View File

@@ -0,0 +1,85 @@
#include <iostream>
#include <types/model.h>
Vector3 ParseVertexCoordinatesFromOBJ(std::istringstream& stream) {
float x, y, z;
stream >> x >> y >> z;
return {x,y,z};
}
Vector2 ParseVertexTextureCoordinatesFromOBJ(std::istringstream& stream) {
float u, v;
stream >> u >> v;
return {u,v};
}
FaceIndices ParseFaceIndicesFromOBJ(std::istringstream& stream) {
FaceIndices face{};
char slash;
for (int i = 0; i < 3; ++i) {
unsigned int vI;
unsigned int tCI;
stream >> vI >> slash >> tCI;
face.vertexIndex[i] = vI;
face.texCoordIndex[i] = tCI;
// Shift vertexindex by 1
face.vertexIndex[i]--;
// shift texcoordindex by 1
face.texCoordIndex[i]--;
}
return face;
}
void Model::loadOBJ(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open())
std::cerr << filename << " not found." << std::endl;
std::vector<Vector3> positions;
std::vector<Vector2> uvs;
std::string line;
// First: We read every (unique) vertex entry and textureCoord entry from the file.
// Then: Use Face data to map the bulk data into correct locations.
// TODO: Check the assumption that we can **always** read all "v", "vt" etc. tokens first,
// allowing us to perform a second-pass to reconstruct faces?
while (std::getline(file, line)) {
std::istringstream stream(line);
std::string prefix;
stream >> prefix;
if (prefix == "v") {
auto result = ParseVertexCoordinatesFromOBJ(stream);
positions.emplace_back(result);
} else if (prefix == "vt") {
auto result = ParseVertexTextureCoordinatesFromOBJ(stream);
uvs.emplace_back(result);
} else if (prefix == "f") {
auto result = ParseFaceIndicesFromOBJ(stream);
mapFaces(result, positions, uvs);
}
}
file.close();
};
// map face of model to positions and texture coords
void Model::mapFaces(const FaceIndices& facedata, const std::vector<Vector3>& positions, const std::vector<Vector2>& uvs) {
TextureInformation tInfo{};
for (int i = 0; i < 3; ++i) {
Vector3 vertex;
Vector2 textureCoordinate;
vertex = positions[facedata.vertexIndex[i]];
textureCoordinate = uvs[facedata.texCoordIndex[i]];
vertices.push_back(vertex);
tInfo.path = "default"; //Placeholder
tInfo.textureCoordinates.push_back(textureCoordinate);
indices.push_back(static_cast<unsigned int>(indices.size()));
}
textureInfo.push_back(tInfo);
}

View File

@@ -53,3 +53,17 @@ Bone* Bone::getParent() {
return this;
return parent;
}
uint Bone::getDepth() {
if (isRootBone())
return 0;
Bone* b = parent;
uint depth = 1;
while (b != nullptr && !b->isRootBone()) {
b = b->getParent();
depth++;
}
return depth;
}

View File

@@ -1,64 +1,8 @@
#include <types/model.h>
struct FaceIndices {
unsigned int vertexIndex[3];
unsigned int texCoordIndex[3];
};
Vector3 ParseVertexCoordinatesFromOBJ(std::istringstream& stream) {
float x, y, z;
stream >> x >> y >> z;
return {x,y,z};
}
Vector2 ParseVertexTextureCoordinatesFromOBJ(std::istringstream& stream) {
float u, v;
stream >> u >> v;
return {u,v};
}
FaceIndices ParseFaceIndicesFromOBJ(std::istringstream& stream) {
FaceIndices face{};
char slash;
for (int i = 0; i < 3; ++i) {
unsigned int vI;
unsigned int tCI;
stream >> vI >> slash >> tCI;
face.vertexIndex[i] = vI;
face.texCoordIndex[i] = tCI;
// Shift vertexindex by 1
face.vertexIndex[i]--;
// shift texcoordindex by 1
face.texCoordIndex[i]--;
}
return face;
}
/*
// map face of model to positions and texture coords
void Model::mapfaces(const FaceIndices& facedata, const std::vector<Vector3>& positions, const std::vector<Vector2>& uvs) {
for (int i = 0; i < 3; ++i) {
Vector3 vertex;
Vector2 textureCoordinate;
vertex = positions[facedata.vertexIndex[i]];
textureCoordinate = uvs[facedata.texCoordIndex[i]];
vertices.push_back(vertex);
textureCoor.push_back(textureCoordinate);
indices.push_back(static_cast<unsigned int>(indices.size()));
}
}
*/
void Model::load(const std::string& file, const ModelType& modelType) {
//TODO: Call correct func.
}
void Model::load(const std::string& file) {
//TODO: Determine model type and call correct func.
if (file.ends_with(".obj"))
loadOBJ(file);
}
const std::vector<Vector3>& Model::getVertices() {