beginning of XML model reader

This commit is contained in:
devZoGok
2022-03-02 20:29:22 +02:00
parent 1a020addfd
commit dae9cd08d7
14 changed files with 273 additions and 16 deletions
+3
View File
@@ -10,3 +10,6 @@
[submodule "external/assimp"] [submodule "external/assimp"]
path = external/assimp path = external/assimp
url = https://github.com/assimp/assimp url = https://github.com/assimp/assimp
[submodule "external/tinyxml2"]
path = external/tinyxml2
url = https://github.com/leethomason/tinyxml2
+8 -2
View File
@@ -17,7 +17,7 @@ set(MATH quaternion.cpp vector.cpp matrix.cpp ray.cpp)
set(RENDER lineRenderer.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp) set(RENDER lineRenderer.cpp particleEmitter.cpp camera.cpp light.cpp material.cpp mesh.cpp model.cpp node.cpp quad.cpp box.cpp root.cpp shader.cpp texture.cpp)
set(ANIM animationController.cpp animationChannel.cpp animation.cpp animatable.h keyframeChannel.cpp driver.cpp) set(ANIM animationController.cpp animationChannel.cpp animation.cpp animatable.h keyframeChannel.cpp driver.cpp)
set(ARMATURE skeleton.cpp bone.cpp ikSolver.cpp) set(ARMATURE skeleton.cpp bone.cpp ikSolver.cpp)
set(ASSET_READERS abstractAssetReader.cpp imageReader.cpp fontReader.cpp modelReader.cpp assimpModelReader.cpp vbModelReader.cpp) set(ASSET_READERS abstractAssetReader.cpp imageReader.cpp fontReader.cpp modelReader.cpp assimpModelReader.cpp vbModelReader.cpp xmlModelReader.cpp)
set(ASSET_MANAGER assetManager.cpp textAsset.h imageAsset.h modelAsset.h fontAsset.h) set(ASSET_MANAGER assetManager.cpp textAsset.h imageAsset.h modelAsset.h fontAsset.h)
set(LIB_SRC ${RENDER} ${MATH} ${UTILS} ${GUI} ${ARMATURE} ${ASSET_MANAGER} ${ASSET_READERS} ${ANIM}) set(LIB_SRC ${RENDER} ${MATH} ${UTILS} ${GUI} ${ARMATURE} ${ASSET_MANAGER} ${ASSET_READERS} ${ANIM})
@@ -28,6 +28,7 @@ include_directories(external/stb)
add_library(${LIB_NAME} SHARED external/glad/glad.c ${LIB_SRC}) add_library(${LIB_NAME} SHARED external/glad/glad.c ${LIB_SRC})
set(TINYXML2_DIR external/tinyxml2)
set(GLFW_DIR external/glfw) set(GLFW_DIR external/glfw)
set(FREETYPE_DIR external/freetype) set(FREETYPE_DIR external/freetype)
set(ASSIMP_DIR external/assimp) set(ASSIMP_DIR external/assimp)
@@ -39,6 +40,11 @@ elseif(WIN32)
message("Building for Windows") message("Building for Windows")
endif() endif()
add_subdirectory(${TINYXML2_DIR})
set(TINYXML2_LIB_DIR build/${TINYXML2_DIR})
target_include_directories(${LIB_NAME} PUBLIC ${TINYXML2_DIR})
target_link_directories(${LIB_NAME} PUBLIC ${TINYXML2_LIB_DIR})
add_subdirectory(${GLFW_DIR}) add_subdirectory(${GLFW_DIR})
set(GLFW_LIB_DIR build/${GLFW_DIR}/src) set(GLFW_LIB_DIR build/${GLFW_DIR}/src)
target_include_directories(${LIB_NAME} PUBLIC ${GLFW_DIR}/include/GLFW) target_include_directories(${LIB_NAME} PUBLIC ${GLFW_DIR}/include/GLFW)
@@ -54,7 +60,7 @@ add_subdirectory(${FREETYPE_DIR})
target_include_directories(${LIB_NAME} PUBLIC ${FREETYPE_DIR}/include) target_include_directories(${LIB_NAME} PUBLIC ${FREETYPE_DIR}/include)
target_link_directories(${LIB_NAME} PUBLIC ${FREETYPE_LIB_DIR}) target_link_directories(${LIB_NAME} PUBLIC ${FREETYPE_LIB_DIR})
set(DEPS glfw assimp freetype ${CMAKE_DL_LIBS}) set(DEPS glfw assimp freetype ${CMAKE_DL_LIBS} tinyxml2)
target_link_libraries(${LIB_NAME} ${DEPS}) target_link_libraries(${LIB_NAME} ${DEPS})
+4 -3
View File
@@ -17,8 +17,9 @@ namespace vb01{
void lookAt(Vector3, Vector3); void lookAt(Vector3, Vector3);
Vector3 getBoneSpaceRestPos(Bone*); Vector3 getBoneSpaceRestPos(Bone*);
Vector3 getModelSpacePos(); Vector3 getModelSpacePos();
inline Bone* getIkTarget(){return ikTarget;} inline Skeleton* getSkeleton(){return skeleton;}
inline void setIkTarget(Bone *target){this->ikTarget = target;} inline std::string getIkTarget(){return ikTarget;}
inline void setIkTarget(std::string target){this->ikTarget = target;}
inline int getIkChainLength(){return ikChainLength;} inline int getIkChainLength(){return ikChainLength;}
inline void setIkChainLength(int ikChainLength){this->ikChainLength = ikChainLength;} inline void setIkChainLength(int ikChainLength){this->ikChainLength = ikChainLength;}
inline float getLength(){return length;} inline float getLength(){return length;}
@@ -39,7 +40,7 @@ namespace vb01{
virtual float getDriverValue(Driver::VariableType); virtual float getDriverValue(Driver::VariableType);
float length; float length;
Bone *ikTarget = nullptr; std::string ikTarget = "";
int ikChainLength = -1; int ikChainLength = -1;
bool ikFromTail = true; bool ikFromTail = true;
Skeleton *skeleton = nullptr; Skeleton *skeleton = nullptr;
Vendored Submodule
+1
Submodule external/tinyxml2 added at a977397684
+3 -1
View File
@@ -1,4 +1,5 @@
#include "ikSolver.h" #include "ikSolver.h"
#include "skeleton.h"
#include "bone.h" #include "bone.h"
namespace vb01{ namespace vb01{
@@ -7,7 +8,8 @@ namespace vb01{
for(int i = 0; i < chainLength; i++) for(int i = 0; i < chainLength; i++)
sumLengths += boneChain[i]->getLength(); sumLengths += boneChain[i]->getLength();
Bone *subBase = (Bone*)boneChain[0]->getIkTarget()->getParent(); Skeleton *skeleton = boneChain[0]->getSkeleton();
Bone *subBase = (Bone*)skeleton->getBone(boneChain[0]->getIkTarget())->getParent();
Vector3 startPos = subBase->globalToLocalPosition(boneChain[chainLength - 1]->localToGlobalPosition(Vector3::VEC_ZERO)); Vector3 startPos = subBase->globalToLocalPosition(boneChain[chainLength - 1]->localToGlobalPosition(Vector3::VEC_ZERO));
if(startPos.getDistanceFrom(targetPos) < sumLengths){ if(startPos.getDistanceFrom(targetPos) < sumLengths){
int numIterations = 500; int numIterations = 500;
+1 -1
View File
@@ -27,7 +27,7 @@ namespace vb01{
boneD->lookAt(Vector3::VEC_K, Vector3::VEC_J); boneD->lookAt(Vector3::VEC_K, Vector3::VEC_J);
boneD->setIkChainLength(chainLength); boneD->setIkChainLength(chainLength);
boneD->setIkTarget(ikBone); boneD->setIkTarget(ikBone->getName());
ikPos = new Vector3[chainLength]; ikPos = new Vector3[chainLength];
boneChain = new Bone*[chainLength]; boneChain = new Bone*[chainLength];
+4 -1
View File
@@ -8,6 +8,7 @@
#include "skeleton.h" #include "skeleton.h"
#include "animation.h" #include "animation.h"
#include "vbModelReader.h" #include "vbModelReader.h"
#include "xmlModelReader.h"
#include "assimpModelReader.h" #include "assimpModelReader.h"
#include <vector> #include <vector>
@@ -25,7 +26,9 @@ namespace vb01{
string extension = path.substr(dotId + 1, string::npos); string extension = path.substr(dotId + 1, string::npos);
ModelReader *modelReader = nullptr; ModelReader *modelReader = nullptr;
if(extension == "vb") if(extension == "xml")
modelReader = new XmlModelReader(this, path);
else if(extension == "vb")
modelReader = new VbModelReader(this, path); modelReader = new VbModelReader(this, path);
else else
modelReader = new AssimpModelReader(this, path); modelReader = new AssimpModelReader(this, path);
+4
View File
@@ -118,6 +118,10 @@ namespace vb01{
mesh->setNode(this); mesh->setNode(this);
} }
void Node::addSkeleton(Skeleton *skeleton){
skeletons.push_back(skeleton);
}
void Node::attachParticleEmitter(ParticleEmitter *emitter){ void Node::attachParticleEmitter(ParticleEmitter *emitter){
emitters.push_back(emitter); emitters.push_back(emitter);
emitter->setNode(this); emitter->setNode(this);
+4
View File
@@ -16,11 +16,14 @@ namespace vb01{
class Light; class Light;
class ParticleEmitter; class ParticleEmitter;
class Text; class Text;
class Skeleton;
class AnimationController;
class Node : public Animatable{ class Node : public Animatable{
public: public:
Node(Vector3 = Vector3::VEC_ZERO, Quaternion = Quaternion::QUAT_W, Vector3 = Vector3::VEC_IJK, std::string = ""); Node(Vector3 = Vector3::VEC_ZERO, Quaternion = Quaternion::QUAT_W, Vector3 = Vector3::VEC_IJK, std::string = "");
virtual ~Node(); virtual ~Node();
void addSkeleton(Skeleton*);
void attachMesh(Mesh*); void attachMesh(Mesh*);
void attachParticleEmitter(ParticleEmitter*); void attachParticleEmitter(ParticleEmitter*);
virtual void update(); virtual void update();
@@ -81,6 +84,7 @@ namespace vb01{
std::vector<Node*> children; std::vector<Node*> children;
std::vector<Light*> lights; std::vector<Light*> lights;
std::vector<Text*> texts; std::vector<Text*> texts;
std::vector<Skeleton*> skeletons;
std::string name; std::string name;
Node *parent = nullptr; Node *parent = nullptr;
}; };
+10 -4
View File
@@ -5,7 +5,6 @@ rootTag = ET.Element('model')
def exportBone(armature, parentBone, parentTag, exportChildren = True): def exportBone(armature, parentBone, parentTag, exportChildren = True):
head = parentBone.head head = parentBone.head
tail = parentBone.tail
xAxis = parentBone.x_axis xAxis = parentBone.x_axis
yAxis = parentBone.y_axis yAxis = parentBone.y_axis
ikTarget = None ikTarget = None
@@ -16,9 +15,13 @@ def exportBone(armature, parentBone, parentTag, exportChildren = True):
boneTag.set('hx', str(head.x)) boneTag.set('hx', str(head.x))
boneTag.set('hy', str(head.y)) boneTag.set('hy', str(head.y))
boneTag.set('hz', str(head.z)) boneTag.set('hz', str(head.z))
boneTag.set('tx', str(tail.x)) boneTag.set('length', str(parentBone.length))
boneTag.set('ty', str(tail.y)) boneTag.set('xaxisx', str(xAxis.x))
boneTag.set('tz', str(tail.z)) boneTag.set('xaxisy', str(xAxis.y))
boneTag.set('xaxisz', str(xAxis.z))
boneTag.set('yaxisx', str(yAxis.x))
boneTag.set('yaxisy', str(yAxis.y))
boneTag.set('yaxisz', str(yAxis.z))
ikConstraint = None ikConstraint = None
@@ -153,6 +156,9 @@ def export(node, parentTag):
numShapeKeys = len(mesh.shape_keys.key_blocks) - 1 numShapeKeys = len(mesh.shape_keys.key_blocks) - 1
meshTag = ET.SubElement(nodeTag, 'mesh') meshTag = ET.SubElement(nodeTag, 'mesh')
meshTag.set('num_faces', str(numFaces))
meshTag.set('num_vertex_groups', str(numGroups))
meshTag.set('num_shape_keys', str(numShapeKeys))
for vert in mesh.vertices: for vert in mesh.vertices:
pos = vert.co pos = vert.co
+3 -3
View File
@@ -21,7 +21,7 @@ namespace vb01{
void Skeleton::updateIk(){ void Skeleton::updateIk(){
for(Bone *b : bones){ for(Bone *b : bones){
if(b->getIkTarget()){ if(b->getIkTarget() != ""){
const int chainLength = b->getIkChainLength(); const int chainLength = b->getIkChainLength();
Bone **boneChain = getIkBoneChain(b); Bone **boneChain = getIkBoneChain(b);
for(int i = 0; i < chainLength; i++){ for(int i = 0; i < chainLength; i++){
@@ -33,13 +33,13 @@ namespace vb01{
} }
} }
for(Bone *b : bones) for(Bone *b : bones)
if(b->getIkTarget()) if(getBone(b->getIkTarget()))
solveIk(b); solveIk(b);
} }
void Skeleton::solveIk(Bone *ikBone){ void Skeleton::solveIk(Bone *ikBone){
const int chainLength = ikBone->getIkChainLength(); const int chainLength = ikBone->getIkChainLength();
Bone *ikTarget = ikBone->getIkTarget(); Bone *ikTarget = getBone(ikBone->getIkTarget());
Bone *subBase = (Bone*)ikTarget->getParent(); Bone *subBase = (Bone*)ikTarget->getParent();
Bone **boneChain = getIkBoneChain(ikBone); Bone **boneChain = getIkBoneChain(ikBone);
+1 -1
View File
@@ -225,7 +225,7 @@ namespace vb01{
for(it = ikRelationships.begin(); it != ikRelationships.end(); it++){ for(it = ikRelationships.begin(); it != ikRelationships.end(); it++){
string targetBoneName = it->first; string targetBoneName = it->first;
string ikTargetBoneName = ikRelationships[targetBoneName]; string ikTargetBoneName = ikRelationships[targetBoneName];
skeleton->getBone(targetBoneName)->setIkTarget(skeleton->getBone(ikTargetBoneName)); skeleton->getBone(targetBoneName)->setIkTarget(ikTargetBoneName);
} }
} }
+201
View File
@@ -0,0 +1,201 @@
#include "xmlModelReader.h"
#include "mesh.h"
#include "skeleton.h"
#include "bone.h"
#include "vector.h"
#include <vector>
#include <tinyxml2.h>
using namespace std;
using namespace tinyxml2;
namespace vb01{
XmlModelReader::XmlModelReader(Model *model, string path) : ModelReader(model, path){
XMLDocument *doc = new XMLDocument();
doc->LoadFile(path.c_str());
XMLNode *root = doc->FirstChild();
model->attachChild(processNode(model, (XMLElement*)root));
}
Mesh* XmlModelReader::processMesh(XMLElement *meshEl){
vector<Vector3> vertPos, vertNorm;
vector<float> weights;
const char *tagName = "vertdata";
for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement()){
float posX = atof(vertEl->Attribute("px"));
float posY = atof(vertEl->Attribute("py"));
float posZ = atof(vertEl->Attribute("pz"));
vertPos.push_back(Vector3(posX, posY, posZ));
float normX = atof(vertEl->Attribute("nx"));
float normY = atof(vertEl->Attribute("ny"));
float normZ = atof(vertEl->Attribute("nz"));
vertNorm.push_back(Vector3(normX, normY, normZ));
for(XMLElement *weightEl = vertEl->FirstChildElement("weight"); weightEl; weightEl = weightEl->NextSiblingElement())
weights.push_back(atof(weightEl->Attribute("value")));
}
int numVertexGroups = atoi(meshEl->Attribute("num_vertex_groups"));
string *vertexGroups = new string[numVertexGroups];
tagName = "vertexgroup";
int i = 0;
for(XMLElement *vertGroupEl = meshEl->FirstChildElement(tagName); vertGroupEl && strcmp(vertGroupEl->Name(), tagName) == 0; vertGroupEl = vertGroupEl->NextSiblingElement(), i++)
vertexGroups[i] = (vertGroupEl->Attribute("name"));
i = 0;
int numVertices = 3 * atoi(meshEl->Attribute("num_faces"));
int numBones;
Mesh::Vertex *vertices = new Mesh::Vertex[numVertices];
tagName = "vert";
vector<u32> vertIds;
u32 *indices = new u32[numVertices];
for(XMLElement *vertEl = meshEl->FirstChildElement(tagName); vertEl && strcmp(vertEl->Name(), tagName) == 0; vertEl = vertEl->NextSiblingElement(), i++){
int id = atoi(vertEl->Attribute("id"));
vertIds.push_back(id);
float uvX = atof(vertEl->Attribute("uvx"));
float uvY = atof(vertEl->Attribute("uvy"));
Vector2 uv = Vector2(uvX, uvY);
float tanX = atof(vertEl->Attribute("tx"));
float tanY = atof(vertEl->Attribute("ty"));
float tanZ = atof(vertEl->Attribute("tz"));
Vector3 tan = Vector3(tanX, tanY, tanZ);
float biTanX = atof(vertEl->Attribute("bx"));
float biTanY = atof(vertEl->Attribute("by"));
float biTanZ = atof(vertEl->Attribute("bz"));
Vector3 biTan = Vector3(biTanX, biTanY, biTanZ);
Mesh::Vertex vertex;
vertex.pos = vertPos[id];
vertex.norm = vertNorm[id];
vertex.uv = uv;
vertex.tan = tan;
vertex.biTan = biTan;
for(int j = 0, boneIndex = 0; j < numBones; j++){
if(weights[id * numBones + j] > 0){
vertex.boneIndices[boneIndex] = j;
vertex.weights[boneIndex] = weights[id * numBones + j];
boneIndex++;
}
}
indices[i] = i;
vertices[i] = vertex;
}
vertNorm.clear();
tagName = "shapekey";
i = 0;
int numShapeKeys = atoi(meshEl->Attribute("num_shape_keys"));
Mesh::ShapeKey *shapeKeys = new Mesh::ShapeKey[numShapeKeys];
for(XMLElement *shapeKeyEl = meshEl->FirstChildElement(tagName); shapeKeyEl && strcmp(shapeKeyEl->Name(), tagName) == 0; shapeKeyEl = shapeKeyEl->NextSiblingElement(), i++){
shapeKeys[i].name = shapeKeyEl->Attribute("name");
shapeKeys[i].minValue = atof(shapeKeyEl->Attribute("min"));
shapeKeys[i].maxValue = atof(shapeKeyEl->Attribute("max"));
XMLElement *driverEl = shapeKeyEl->FirstChildElement("driver");
vector<Vector3> shapeKeyPos;
for(XMLElement *vertEl = shapeKeyEl->FirstChildElement(tagName); vertEl; vertEl = vertEl->NextSiblingElement()){
float posX = atof(vertEl->Attribute("px"));
float posY = atof(vertEl->Attribute("py"));
float posZ = atof(vertEl->Attribute("pz"));
shapeKeyPos.push_back(Vector3(posX, posY, posZ));
for(int j = 0; j < numVertices; j++)
vertices[j].shapeKeyOffsets[i] = shapeKeyPos[vertIds[j]] - vertPos[vertIds[j]];
}
}
Mesh *mesh = new Mesh(vertices, indices, numVertices / 3, vertexGroups, numBones, shapeKeys, numShapeKeys);
return mesh;
}
Skeleton* XmlModelReader::processSkeleton(Node *root, XMLElement *skeletonEl){
XMLElement *rootBoneEl = skeletonEl->FirstChildElement("bone");
Skeleton *skeleton = new Skeleton(nullptr);
skeleton->addBone((Bone*)processNode(root, rootBoneEl, true), (Bone*)root);
return skeleton;
}
Node* XmlModelReader::processNode(Node *parent, XMLElement *xmlEl, bool bone){
Node *node = nullptr;
if(bone){
float headX = atof(xmlEl->Attribute("hx"));
float headY = atof(xmlEl->Attribute("hy"));
float headZ = atof(xmlEl->Attribute("hz"));
Vector3 head = Vector3(headX, headY, headZ);
float xAxisX = atof(xmlEl->Attribute("xaxisx"));
float xAxisY = atof(xmlEl->Attribute("xaxisy"));
float xAxisZ = atof(xmlEl->Attribute("xaxisz"));
Vector3 xAxis = Vector3(xAxisX, xAxisY, xAxisZ);
float yAxisX = atof(xmlEl->Attribute("yaxisx"));
float yAxisY = atof(xmlEl->Attribute("yaxisy"));
float yAxisZ = atof(xmlEl->Attribute("yaxisz"));
Vector3 yAxis = Vector3(yAxisX, yAxisY, yAxisZ);
string name = xmlEl->Attribute("name");
float length = atof(xmlEl->Attribute("length"));
Vector3 zAxis = xAxis.cross(yAxis).norm();
Vector3 pos = head;
/*
if(!parent){
parent = model;
swap(pos.y, pos.z);
pos.z = -pos.z;
swap(yAxis.y, yAxis.z);
yAxis.z = -yAxis.z;
swap(zAxis.y, zAxis.z);
zAxis.z = -zAxis.z;
}
else
*/
pos = pos + Vector3(0, ((Bone*)parent)->getLength(), 0);
node = new Bone(name, length, pos, Quaternion::QUAT_W, Vector3::VEC_IJK);
node->lookAt(zAxis, yAxis);
const char *ikTarget = xmlEl->Attribute("iktarget");
if(ikTarget != nullptr){
((Bone*)node)->setIkTarget(ikTarget);
int ikChainLength = atoi(xmlEl->Attribute("chainlength"));
((Bone*)node)->setIkChainLength(ikChainLength);
}
}
XMLElement *skeletonTag = xmlEl->FirstChildElement("skeleton");
if(skeletonTag)
processSkeleton(node, skeletonTag);
XMLElement *meshTag = xmlEl->FirstChildElement("mesh");
if(meshTag)
processMesh(meshTag);
XMLElement *lightTag = xmlEl->FirstChildElement("light");
for(XMLElement *el = xmlEl->FirstChildElement("node"); el; el = el->NextSiblingElement())
parent->attachChild(processNode(parent, el, bone));
return node;
}
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef XML_MODEL_READER_H
#define XML_MODEL_READER_H
#include "modelReader.h"
namespace tinyxml2{
class XMLElement;
}
namespace vb01{
class Node;
class Mesh;
class Skeleton;
class Bone;
class XmlModelReader : public ModelReader{
public:
XmlModelReader(Model*, std::string);
private:
Node* processNode(Node*, tinyxml2::XMLElement*, bool = false);
Mesh* processMesh(tinyxml2::XMLElement*);
Skeleton* processSkeleton(Node*, tinyxml2::XMLElement*);
};
}
#endif