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"]
path = external/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(ANIM animationController.cpp animationChannel.cpp animation.cpp animatable.h keyframeChannel.cpp driver.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(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})
set(TINYXML2_DIR external/tinyxml2)
set(GLFW_DIR external/glfw)
set(FREETYPE_DIR external/freetype)
set(ASSIMP_DIR external/assimp)
@@ -39,6 +40,11 @@ elseif(WIN32)
message("Building for Windows")
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})
set(GLFW_LIB_DIR build/${GLFW_DIR}/src)
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_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})
+4 -3
View File
@@ -17,8 +17,9 @@ namespace vb01{
void lookAt(Vector3, Vector3);
Vector3 getBoneSpaceRestPos(Bone*);
Vector3 getModelSpacePos();
inline Bone* getIkTarget(){return ikTarget;}
inline void setIkTarget(Bone *target){this->ikTarget = target;}
inline Skeleton* getSkeleton(){return skeleton;}
inline std::string getIkTarget(){return ikTarget;}
inline void setIkTarget(std::string target){this->ikTarget = target;}
inline int getIkChainLength(){return ikChainLength;}
inline void setIkChainLength(int ikChainLength){this->ikChainLength = ikChainLength;}
inline float getLength(){return length;}
@@ -39,7 +40,7 @@ namespace vb01{
virtual float getDriverValue(Driver::VariableType);
float length;
Bone *ikTarget = nullptr;
std::string ikTarget = "";
int ikChainLength = -1;
bool ikFromTail = true;
Skeleton *skeleton = nullptr;
Vendored Submodule
+1
Submodule external/tinyxml2 added at a977397684
+3 -1
View File
@@ -1,4 +1,5 @@
#include "ikSolver.h"
#include "skeleton.h"
#include "bone.h"
namespace vb01{
@@ -7,7 +8,8 @@ namespace vb01{
for(int i = 0; i < chainLength; i++)
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));
if(startPos.getDistanceFrom(targetPos) < sumLengths){
int numIterations = 500;
+1 -1
View File
@@ -27,7 +27,7 @@ namespace vb01{
boneD->lookAt(Vector3::VEC_K, Vector3::VEC_J);
boneD->setIkChainLength(chainLength);
boneD->setIkTarget(ikBone);
boneD->setIkTarget(ikBone->getName());
ikPos = new Vector3[chainLength];
boneChain = new Bone*[chainLength];
+4 -1
View File
@@ -8,6 +8,7 @@
#include "skeleton.h"
#include "animation.h"
#include "vbModelReader.h"
#include "xmlModelReader.h"
#include "assimpModelReader.h"
#include <vector>
@@ -25,7 +26,9 @@ namespace vb01{
string extension = path.substr(dotId + 1, string::npos);
ModelReader *modelReader = nullptr;
if(extension == "vb")
if(extension == "xml")
modelReader = new XmlModelReader(this, path);
else if(extension == "vb")
modelReader = new VbModelReader(this, path);
else
modelReader = new AssimpModelReader(this, path);
+4
View File
@@ -118,6 +118,10 @@ namespace vb01{
mesh->setNode(this);
}
void Node::addSkeleton(Skeleton *skeleton){
skeletons.push_back(skeleton);
}
void Node::attachParticleEmitter(ParticleEmitter *emitter){
emitters.push_back(emitter);
emitter->setNode(this);
+4
View File
@@ -16,11 +16,14 @@ namespace vb01{
class Light;
class ParticleEmitter;
class Text;
class Skeleton;
class AnimationController;
class Node : public Animatable{
public:
Node(Vector3 = Vector3::VEC_ZERO, Quaternion = Quaternion::QUAT_W, Vector3 = Vector3::VEC_IJK, std::string = "");
virtual ~Node();
void addSkeleton(Skeleton*);
void attachMesh(Mesh*);
void attachParticleEmitter(ParticleEmitter*);
virtual void update();
@@ -81,6 +84,7 @@ namespace vb01{
std::vector<Node*> children;
std::vector<Light*> lights;
std::vector<Text*> texts;
std::vector<Skeleton*> skeletons;
std::string name;
Node *parent = nullptr;
};
+10 -4
View File
@@ -5,7 +5,6 @@ rootTag = ET.Element('model')
def exportBone(armature, parentBone, parentTag, exportChildren = True):
head = parentBone.head
tail = parentBone.tail
xAxis = parentBone.x_axis
yAxis = parentBone.y_axis
ikTarget = None
@@ -16,9 +15,13 @@ def exportBone(armature, parentBone, parentTag, exportChildren = True):
boneTag.set('hx', str(head.x))
boneTag.set('hy', str(head.y))
boneTag.set('hz', str(head.z))
boneTag.set('tx', str(tail.x))
boneTag.set('ty', str(tail.y))
boneTag.set('tz', str(tail.z))
boneTag.set('length', str(parentBone.length))
boneTag.set('xaxisx', str(xAxis.x))
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
@@ -153,6 +156,9 @@ def export(node, parentTag):
numShapeKeys = len(mesh.shape_keys.key_blocks) - 1
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:
pos = vert.co
+3 -3
View File
@@ -21,7 +21,7 @@ namespace vb01{
void Skeleton::updateIk(){
for(Bone *b : bones){
if(b->getIkTarget()){
if(b->getIkTarget() != ""){
const int chainLength = b->getIkChainLength();
Bone **boneChain = getIkBoneChain(b);
for(int i = 0; i < chainLength; i++){
@@ -33,13 +33,13 @@ namespace vb01{
}
}
for(Bone *b : bones)
if(b->getIkTarget())
if(getBone(b->getIkTarget()))
solveIk(b);
}
void Skeleton::solveIk(Bone *ikBone){
const int chainLength = ikBone->getIkChainLength();
Bone *ikTarget = ikBone->getIkTarget();
Bone *ikTarget = getBone(ikBone->getIkTarget());
Bone *subBase = (Bone*)ikTarget->getParent();
Bone **boneChain = getIkBoneChain(ikBone);
+1 -1
View File
@@ -225,7 +225,7 @@ namespace vb01{
for(it = ikRelationships.begin(); it != ikRelationships.end(); it++){
string targetBoneName = it->first;
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