mirror of
https://github.com/devZoGok/vb01.git
synced 2026-08-26 19:43:30 +00:00
506 lines
14 KiB
C++
Executable File
506 lines
14 KiB
C++
Executable File
#include"model.h"
|
|
#include"mesh.h"
|
|
#include"material.h"
|
|
#include"vector.h"
|
|
#include"util.h"
|
|
#include"bone.h"
|
|
#include"root.h"
|
|
#include"skeleton.h"
|
|
#include"animation.h"
|
|
|
|
#include<vector>
|
|
#include<iostream>
|
|
#include<Importer.hpp>
|
|
#include<scene.h>
|
|
#include<postprocess.h>
|
|
#include<fstream>
|
|
|
|
using namespace std;
|
|
using namespace Assimp;
|
|
|
|
namespace vb01{
|
|
void Model::processNode(aiNode *node, const aiScene *scene, Node *currentNode){
|
|
for(int i=0;i<node->mNumMeshes;i++){
|
|
aiMesh *mesh=scene->mMeshes[node->mMeshes[i]];
|
|
processMesh(mesh,scene,currentNode);
|
|
}
|
|
for(int i=0;i<node->mNumChildren;i++){
|
|
Node *childNode=new Node();
|
|
currentNode->attachChild(childNode);
|
|
processNode(node->mChildren[i],scene,childNode);
|
|
}
|
|
}
|
|
|
|
void Model::processMesh(aiMesh *mesh, const aiScene *scene, Node *currentNode){
|
|
const int numTris=mesh->mNumFaces;
|
|
Mesh::Vertex *vertices=new Mesh::Vertex[3*numTris];
|
|
u32 *indices=new u32[3*numTris];
|
|
for(int i=0;i<3*numTris;i++){
|
|
Mesh::Vertex v;
|
|
v.pos.x=mesh->mVertices[i].x;
|
|
v.pos.y=mesh->mVertices[i].y;
|
|
v.pos.z=mesh->mVertices[i].z;
|
|
|
|
v.norm.x=mesh->mNormals[i].x;
|
|
v.norm.y=mesh->mNormals[i].y;
|
|
v.norm.z=mesh->mNormals[i].z;
|
|
|
|
v.tan.x=mesh->mTangents[i].x;
|
|
v.tan.y=mesh->mTangents[i].y;
|
|
v.tan.z=mesh->mTangents[i].z;
|
|
|
|
v.biTan.x=mesh->mBitangents[i].x;
|
|
v.biTan.y=mesh->mBitangents[i].y;
|
|
v.biTan.z=mesh->mBitangents[i].z;
|
|
|
|
if(mesh->mTextureCoords[0]){
|
|
v.uv.x=mesh->mTextureCoords[0][i].x;
|
|
v.uv.y=mesh->mTextureCoords[0][i].y;
|
|
}
|
|
else
|
|
v.uv=Vector2::VEC_ZERO;
|
|
vertices[i]=v;
|
|
}
|
|
for(int i=0;i<numTris;i++){
|
|
int numFaceIndices=mesh->mFaces[i].mNumIndices;
|
|
for(int j=0;j<numFaceIndices;j++){
|
|
indices[numFaceIndices*i+j]=mesh->mFaces[i].mIndices[j];
|
|
}
|
|
}
|
|
//if(mesh->mMaterialIndex>=0){
|
|
// aiMaterial *material=scene->mMaterial[mesh->mMaterialIndex];
|
|
//}
|
|
currentNode->attachMesh(new Mesh(vertices,indices,numTris));
|
|
}
|
|
|
|
Model::Model(string path,bool b) : Node(){
|
|
Node *rootNode=Root::getSingleton()->getRootNode();
|
|
if(b){
|
|
Importer importer;
|
|
const aiScene *scene=importer.ReadFile(path,aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_CalcTangentSpace);
|
|
if(!scene||scene->mFlags&AI_SCENE_FLAGS_INCOMPLETE||!scene->mRootNode){
|
|
cout<<"Failed to load model:"<<importer.GetErrorString()<<endl;
|
|
exit(-1);
|
|
}
|
|
processNode(scene->mRootNode,scene,this);
|
|
}
|
|
else{
|
|
enum Stage{ARMATURE,MESH};
|
|
|
|
Stage stage;
|
|
ifstream in(path);
|
|
string l,name="";
|
|
Vector3 localPos=Vector3::VEC_ZERO,localScale=Vector3::VEC_IJK;
|
|
Quaternion localRot=Quaternion::QUAT_W;
|
|
vector<string> childrenChain;
|
|
vector<Skeleton*> skeletons;
|
|
vector<Mesh*> meshes;
|
|
vector<Light*> lights;
|
|
vector<Node*> nodes;
|
|
|
|
Skeleton *skeleton=nullptr;
|
|
string animName="";
|
|
Bone *animBone=nullptr;
|
|
|
|
const int numVertsPerFace=3;
|
|
int numFaces=0,vertId=0,faceId=0,groupId=0,groupVertId=0,numGroups=0,numShapeKeys=0;
|
|
Mesh::Vertex *vertices;
|
|
u32 *indices;
|
|
vector<Vector3> vertPos,vertNorm;
|
|
vector<float> vertWeights;
|
|
string *groups=nullptr,*shapeKeys=nullptr;
|
|
|
|
while(getline(in,l)){
|
|
int colonId=-1;
|
|
for(int i=0;i<l.length();i++)
|
|
if(l[i]==':'){
|
|
colonId=i;
|
|
break;
|
|
}
|
|
|
|
string preColon=l.substr(0,colonId);
|
|
string postColon=l.length()==colonId+1?"":l.substr(colonId+2,string::npos);
|
|
|
|
if(preColon=="ARMATURE"){
|
|
stage=ARMATURE;
|
|
skeleton=new Skeleton(postColon);
|
|
name=postColon;
|
|
continue;
|
|
}
|
|
else if(preColon=="MESH"){
|
|
stage=MESH;
|
|
name=postColon;
|
|
continue;
|
|
}
|
|
else if(preColon=="pos"){
|
|
continue;
|
|
}
|
|
else if(preColon=="rot"){
|
|
continue;
|
|
}
|
|
else if(preColon=="scale"){
|
|
continue;
|
|
}
|
|
else if(preColon=="parent"){
|
|
childrenChain.push_back(name+" "+postColon);
|
|
continue;
|
|
}
|
|
|
|
if(stage==ARMATURE){
|
|
enum ArmatureStage{BONES,ANIMATIONS};
|
|
|
|
ArmatureStage armatureStage;
|
|
int numBones=0;
|
|
|
|
if(preColon=="bones"){
|
|
numBones=atoi(postColon.c_str());
|
|
armatureStage=BONES;
|
|
continue;
|
|
}
|
|
else if(preColon=="animations"){
|
|
armatureStage=ANIMATIONS;
|
|
continue;
|
|
}
|
|
|
|
switch(armatureStage){
|
|
case BONES:
|
|
{
|
|
int numData=11;
|
|
string data[numData];
|
|
getLineData(postColon,data,numData);
|
|
|
|
float length=atof(data[0].c_str());
|
|
Vector3 pos=Vector3(atof(data[2].c_str()),atof(data[3].c_str()),atof(data[4].c_str()));
|
|
Vector3 xAxis=Vector3(atof(data[5].c_str()),atof(data[6].c_str()),atof(data[6].c_str()));
|
|
Vector3 yAxis=Vector3(atof(data[8].c_str()),atof(data[9].c_str()),atof(data[10].c_str()));
|
|
Vector3 zAxis=xAxis.cross(yAxis);
|
|
|
|
string parName=string(data[0].c_str());
|
|
Node *parent=skeleton->getBone(parName);
|
|
if(!parent){
|
|
parent=this;
|
|
swap(xAxis.y,xAxis.z);
|
|
xAxis.z=-xAxis.z;
|
|
swap(yAxis.y,yAxis.z);
|
|
yAxis.z=-yAxis.z;
|
|
swap(zAxis.y,zAxis.z);
|
|
zAxis.z=-zAxis.z;
|
|
}
|
|
|
|
Vector3 parAxis[]={
|
|
parent->getLocalAxis(0),
|
|
parent->getLocalAxis(1),
|
|
parent->getLocalAxis(2)
|
|
};
|
|
Vector3 boneAxis[3]={
|
|
(parAxis[0]*xAxis.x+parAxis[1]*xAxis.y+parAxis[2]*xAxis.z).norm(),
|
|
(parAxis[0]*yAxis.x+parAxis[1]*yAxis.y+parAxis[2]*yAxis.z).norm(),
|
|
(parAxis[0]*zAxis.x+parAxis[1]*zAxis.y+parAxis[2]*zAxis.z).norm()
|
|
};
|
|
Bone *bone=new Bone(preColon,boneAxis,pos);
|
|
skeleton->addBone(bone,parent);
|
|
bone->lookAt(boneAxis[1],boneAxis[2],parent);
|
|
|
|
break;
|
|
}
|
|
case ANIMATIONS:
|
|
{
|
|
if(preColon=="animationName"){
|
|
animName=postColon;
|
|
skeleton->addAnimation(new Animation(animName));
|
|
continue;
|
|
}
|
|
Bone *b=skeleton->getBone(preColon);
|
|
if(b){
|
|
animBone=b;
|
|
Animation *anim=skeleton->getAnimation(animName);
|
|
Animation::KeyframeGroup *group=anim->getKeyframeGroup(animBone);
|
|
if(!group){
|
|
Animation::KeyframeGroup kg;
|
|
kg.bone=animBone;
|
|
anim->addKeyframeGroup(kg);
|
|
}
|
|
continue;
|
|
}
|
|
else{
|
|
Animation::KeyframeGroup::Keyframe::Type type;
|
|
Animation::KeyframeGroup::Keyframe::Interpolation interp;
|
|
if(preColon=="pos_x")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::POS_X;
|
|
else if(preColon=="pos_y")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::POS_Y;
|
|
else if(preColon=="pos_z")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::POS_Z;
|
|
else if(preColon=="rot_w")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::ROT_W;
|
|
else if(preColon=="rot_x")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::ROT_X;
|
|
else if(preColon=="rot_y")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::ROT_Y;
|
|
else if(preColon=="rot_z")
|
|
type=Animation::KeyframeGroup::Keyframe::Type::ROT_Z;
|
|
else if(l==""){
|
|
skeletons.push_back(skeleton);
|
|
break;
|
|
}
|
|
else{
|
|
int numData=3;
|
|
string data[numData];
|
|
|
|
getLineData(l,data,numData);
|
|
|
|
float value=atof(data[0].c_str()),frame=atoi(data[1].c_str());
|
|
interp=(Animation::KeyframeGroup::Keyframe::Interpolation)atoi(data[2].c_str());
|
|
|
|
Animation::KeyframeGroup::Keyframe keyframe;
|
|
keyframe.type=type;
|
|
keyframe.interpolation=interp;
|
|
keyframe.value=value;
|
|
keyframe.frame=frame;
|
|
skeleton->getAnimation(animName)->getKeyframeGroup(animBone)->keyframes.push_back(keyframe);
|
|
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
enum MeshStage{VERTICES,FACES,GROUPS,SHAPE_KEYS};
|
|
|
|
MeshStage meshStage;
|
|
|
|
if(preColon=="vertices"){
|
|
const int numData=4;
|
|
string data[numData];
|
|
getLineData(postColon,data,numData);
|
|
numFaces=atoi(data[1].c_str());
|
|
numGroups=atoi(data[2].c_str());
|
|
vertices=new Mesh::Vertex[numFaces*numVertsPerFace];
|
|
indices=new u32[numFaces*numVertsPerFace];
|
|
meshStage=VERTICES;
|
|
continue;
|
|
}
|
|
else if(preColon=="faces"){
|
|
meshStage=FACES;
|
|
continue;
|
|
}
|
|
else if(preColon=="groups"){
|
|
groups=new string[numGroups];
|
|
meshStage=GROUPS;
|
|
continue;
|
|
}
|
|
else if(preColon=="shapeKeys"){
|
|
meshStage=SHAPE_KEYS;
|
|
continue;
|
|
}
|
|
switch(meshStage){
|
|
{
|
|
case VERTICES:
|
|
int numData=10;
|
|
string data[numData];
|
|
getLineData(l,data,numData);
|
|
Vector3 vPos=Vector3(atof(data[0].c_str()),atof(data[2].c_str()),-atof(data[1].c_str()));
|
|
Vector3 vNorm=Vector3(atof(data[3].c_str()),atof(data[5].c_str()),-atof(data[4].c_str()));
|
|
float vWeights[]{
|
|
atof(data[6].c_str()),
|
|
atof(data[7].c_str()),
|
|
atof(data[8].c_str()),
|
|
atof(data[9].c_str())
|
|
};
|
|
vertPos.push_back(vPos);
|
|
vertNorm.push_back(vNorm);
|
|
for(int i=0;i<4;i++)
|
|
vertWeights.push_back(vWeights[i]);
|
|
/*
|
|
Vector2 vertUv=Vector2(atof(data[5].c_str()),atof(data[6].c_str()));
|
|
Vector3 vertTan=Vector3(atof(data[7].c_str()),atof(data[9].c_str()),-atof(data[10].c_str()));
|
|
Vector3 vertBitan=Vector3(atof(data[11].c_str()),atof(data[13].c_str()),-atof(data[12].c_str()));
|
|
*/
|
|
/*
|
|
Mesh::Vertex vert;
|
|
vert.pos=vertPos;
|
|
vert.norm=vertNorm;
|
|
vert.uv=vertUv;
|
|
vert.tan=vertTan;
|
|
vert.biTan=vertBitan;
|
|
*/
|
|
//vertices[vertId]=vert;
|
|
break;
|
|
}
|
|
{
|
|
case FACES:
|
|
int numData=9;
|
|
string data[numData];
|
|
getLineData(l,data,numData);
|
|
int index=atoi(data[0].c_str());
|
|
Vector2 uv=Vector2(atof(data[1].c_str()),atof(data[2].c_str()));
|
|
Vector3 tan=Vector3(atof(data[3].c_str()),atof(data[5].c_str()),-atof(data[4].c_str()));
|
|
Vector3 biTan=Vector3(atof(data[6].c_str()),atof(data[8].c_str()),-atof(data[7].c_str()));
|
|
|
|
Mesh::Vertex vert;
|
|
vert.pos=vertPos[index];
|
|
vert.norm=vertNorm[index];
|
|
vert.tan=tan;
|
|
vert.biTan=biTan;
|
|
vert.uv=uv;
|
|
vert.weights[0]=vertWeights[index*4+0];
|
|
vert.weights[1]=vertWeights[index*4+1];
|
|
vert.weights[2]=vertWeights[index*4+2];
|
|
vert.weights[3]=vertWeights[index*4+3];
|
|
for(int i=0;i<numVertsPerFace;i++){
|
|
}
|
|
indices[vertId]=vertId;
|
|
vertices[vertId]=vert;
|
|
|
|
vertId++;
|
|
break;
|
|
}
|
|
{
|
|
case GROUPS:
|
|
if(l==""){
|
|
meshes.push_back(new Mesh(vertices,indices,numFaces,groups,numGroups,shapeKeys,numShapeKeys,name));
|
|
break;
|
|
}
|
|
else{
|
|
groups[groupId]=l;
|
|
groupId++;
|
|
}
|
|
break;
|
|
}
|
|
{
|
|
case SHAPE_KEYS:
|
|
if(l==""){
|
|
meshes.push_back(new Mesh(vertices,indices,numFaces,groups,numGroups,shapeKeys,numShapeKeys,name));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for(Mesh *mesh : meshes){
|
|
Node *meshNode=new Node(localPos,localRot,localScale);
|
|
meshNode->attachMesh(mesh);
|
|
nodes.push_back(meshNode);
|
|
for(string line : childrenChain){
|
|
int spaceId=-1;
|
|
for(int i=0;i<line.length();i++)
|
|
if(line[i]==' ')
|
|
spaceId=i;
|
|
string childName=line.substr(0,spaceId),parentName=line.substr(spaceId+1,string::npos);
|
|
if(mesh->getName()==childName){
|
|
for(Skeleton *sk : skeletons){
|
|
if(sk->getName()==parentName)
|
|
mesh->setSkeleton(sk);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for(Light *light : lights){
|
|
Node *lightNode=new Node(localPos,localRot,localScale);
|
|
lightNode->addLight(light);
|
|
nodes.push_back(lightNode);
|
|
}
|
|
for(string line : childrenChain){
|
|
int spaceId=-1;
|
|
for(int i=0;i<line.length();i++)
|
|
if(line[i]==' ')
|
|
spaceId=i;
|
|
string childName=line.substr(0,spaceId),parentName=line.substr(spaceId+1,string::npos);
|
|
Node *childNode=nullptr,*parentNode=this;
|
|
for(int i=0;i<nodes.size();i++){
|
|
Mesh *m0=nodes[i]->getMesh(0);
|
|
Skeleton *sk0=m0->getSkeleton();
|
|
if(m0->getName()==childName||(sk0&&sk0->getName()==childName)){
|
|
childNode=nodes[i];
|
|
for(int j=0;j<nodes.size();j++){
|
|
Mesh *m1=nodes[j]->getMesh(0);
|
|
Skeleton *sk1=m1->getSkeleton();
|
|
if(m1->getName()==parentName||(sk1&&sk1->getName()==parentName))
|
|
parentNode=nodes[j];
|
|
}
|
|
}
|
|
}
|
|
if(childNode!=parentNode)
|
|
parentNode->attachChild(childNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
Model::~Model(){
|
|
delete children[0]->getMesh(0)->getMaterial();
|
|
|
|
vector<Node*> descendants;
|
|
getDescendants(this,descendants);
|
|
for(Node *node : descendants)
|
|
for(Mesh *mesh : node->getMeshes())
|
|
mesh->setMaterial(nullptr);
|
|
|
|
while(!children.empty()){
|
|
Node *c=children[children.size()-1];
|
|
dettachChild(c);
|
|
delete c;
|
|
}
|
|
}
|
|
|
|
void Model::update(){
|
|
Node::update();
|
|
}
|
|
|
|
void Model::getLineData(string &line,string data[],int numData,int offset){
|
|
int offsetComma=0,c1=0;
|
|
for(int i=0;i<line.length()&&offsetComma<offset;i++)
|
|
if(line.c_str()[i]==' '){
|
|
c1=i+1;
|
|
offsetComma++;
|
|
}
|
|
int c2=c1;
|
|
for(int i=0;i<numData;i++){
|
|
for(int j=c1;j<line.length();j++)
|
|
if(line.c_str()[j]==' '){
|
|
c2=j;
|
|
break;
|
|
}
|
|
data[i]=line.substr(c1,c2-c1);
|
|
c2++;
|
|
c1=c2;
|
|
}
|
|
}
|
|
|
|
void Model::setMaterial(Material *mat){
|
|
vector<Node*> descendants;
|
|
getDescendants(this,descendants);
|
|
for(Node *node : descendants)
|
|
for(Mesh *mesh : node->getMeshes())
|
|
mesh->setMaterial(mat);
|
|
}
|
|
|
|
void Model::setCastShadow(bool castShadow){
|
|
vector<Node*> descendants;
|
|
getDescendants(this,descendants);
|
|
for(Node *node : descendants)
|
|
for(Mesh *mesh : node->getMeshes())
|
|
mesh->setCastShadow(castShadow);
|
|
this->castShadow=castShadow;
|
|
}
|
|
|
|
void Model::setReflect(bool reflect){
|
|
vector<Node*> descendants;
|
|
getDescendants(this,descendants);
|
|
for(Node *node : descendants)
|
|
for(Mesh *mesh : node->getMeshes())
|
|
mesh->setReflect(reflect);
|
|
this->reflect=reflect;
|
|
}
|
|
|
|
void Model::setWireframe(bool wirefame){
|
|
vector<Node*> descendants;
|
|
getDescendants(this,descendants);
|
|
for(Node *node : descendants)
|
|
for(Mesh *mesh : node->getMeshes())
|
|
mesh->setWireframe(wirefame);
|
|
this->wireframe=wireframe;
|
|
}
|
|
}
|