Skip to content

Commit

Permalink
Load vertex weight
Browse files Browse the repository at this point in the history
  • Loading branch information
vadimvinokurov committed Sep 1, 2022
1 parent 1ed0893 commit e060aba
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 64 deletions.
204 changes: 161 additions & 43 deletions Sources/AssetImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,180 @@
#include "AssetImporter.h"
#include "span.h"
#include "SkeletalMeshModel.h"
#include "SkeletalMeshSection.h"
#include <sstream>

AssetImporter::AssetImporter(const char *path)
{
pScene = Importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs |
aiProcess_JoinIdenticalVertices);
if (!pScene)
{
spdlog::error("Can't open asset file.");
std::exit(1);
}
boneIndexing();
}

bool AssetImporter::good()
void AssetImporter::boneIndexing()
{
return pScene;
int32 index = 0;
boneIndexingByNode(pScene->mRootNode, index);
}

std::vector<StaticMesh> AssetImporter::loadMeshes()
void AssetImporter::boneIndexingByNode(aiNode *node, int32 &index)
{
if(!good()) {
spdlog::error("Mesh can't load");
std::exit(1);
boneIndexMap[node->mName.C_Str()] = index++;
for (uint32 i = 0; i < node->mNumChildren; ++i)
{
boneIndexingByNode(node->mChildren[i], index);
}
}

SkeletalMeshModel AssetImporter::getSkeletalMesh()
{
SkeletalMeshModel skeletalMeshModel;
tcb::span<aiMesh *> meshes(pScene->mMeshes, pScene->mNumMeshes);
for (const auto &mesh : meshes)
{
SkeletalMeshSection skeletalMeshSection;
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
for (uint32 i = 0; i < mesh->mNumVertices; ++i)
{
const aiVector3D *pPos = &(mesh->mVertices[i]);
const aiVector3D *pNormal = &(mesh->mNormals[i]);
const aiVector3D *pTexCoord = mesh->HasTextureCoords(0) ? &(mesh->mTextureCoords[0][i]) : &Zero3D;
skeletalMeshSection.vertices.emplace_back(pPos->x, pPos->y, pPos->z);
skeletalMeshSection.normals.emplace_back(pNormal->x, pNormal->y, pNormal->z);
skeletalMeshSection.textureCoordinates.emplace_back(pTexCoord->x, pTexCoord->y);
}

for (uint32 i = 0; i < mesh->mNumFaces; ++i)
{
const aiFace &Face = mesh->mFaces[i];
assert(Face.mNumIndices == 3);
skeletalMeshSection.indices.push_back(Face.mIndices[0]);
skeletalMeshSection.indices.push_back(Face.mIndices[1]);
skeletalMeshSection.indices.push_back(Face.mIndices[2]);
}

skeletalMeshSection.influenceBones.resize(skeletalMeshSection.vertices.size(), IVector4(INVALID_BODE_ID));
skeletalMeshSection.influenceWeights.resize(skeletalMeshSection.vertices.size(), Vector4(0.0f));

VertexWeights vertexWeights = getMeshVertexWeights(mesh);

for (const auto &weights : vertexWeights)
{
uint32 vertex = weights.first;
auto [bonesVector, weightsVector] = weightsToEngineType(weights.second);
skeletalMeshSection.influenceBones.at(vertex) = bonesVector;
skeletalMeshSection.influenceWeights.at(vertex) = weightsVector;
}

skeletalMeshModel.addSkeletalMeshSection(skeletalMeshSection);
}
return skeletalMeshModel;
}

VertexWeights AssetImporter::getMeshVertexWeights(const aiMesh *mesh)
{
VertexWeights vertexWeights;
tcb::span<aiBone *> meshBones(mesh->mBones, mesh->mNumBones);
for (const auto &bone : meshBones)
{
int32 boneId = boneIndexMap[bone->mName.C_Str()];
tcb::span<aiVertexWeight> weights(bone->mWeights, bone->mNumWeights);
for (const auto &weight : weights)
{
vertexWeights[weight.mVertexId][boneId] = weight.mWeight;
}
}
return vertexWeights;
}

std::pair<IVector4, Vector4> AssetImporter::weightsToEngineType(const Weights &weights)
{
std::multimap<float, uint32, std::greater<float>> sortedWeights;
for (const auto &weight : weights)
{
if (weight.first == INVALID_BODE_ID || weight.second == 0.0f)
{
continue;
}
sortedWeights.emplace(weight.second, weight.first);
}

Vector4 weightsVector(0.0f);
IVector4 bonesVector(INVALID_BODE_ID);

uint32 index = 0;
for (const auto &sortedWeight : sortedWeights)
{
if (index >= 4)
{
break;
}
weightsVector.v[index] = sortedWeight.first;
bonesVector.v[index] = sortedWeight.second;
++index;
}

float totalWeight = weightsVector.v[0] + weightsVector.v[1] + weightsVector.v[2] + weightsVector.v[3];

if (totalWeight < 0.8f || totalWeight > 1.1f)
{
assert(false && "Incorrect weight. VEngine support only 4 bone per vertex.");
spdlog::warn("Incorrect weight : {}", totalWeight);
std::stringstream s;
for (const auto &swb : sortedWeights)
{
s << "b" << swb.second << " w" << swb.first;
}
s << std::endl;
spdlog::warn(" {}", s.str());
}

return {bonesVector, weightsVector};
}

Transform AssetImporter::getTransform(const aiMatrix4x4 &m)
{
aiVector3D aiscale;
aiVector3D aiposition;
aiQuaternion airotation;
m.Decompose(aiscale, airotation, aiposition);
Transform transform;
transform.scale = Vector3(aiscale.x, aiscale.y, aiscale.z);
transform.position = Vector3(aiposition.x, aiposition.y, aiposition.z);
transform.rotation = Quaternion(airotation.x, airotation.y, airotation.z, airotation.w);
return transform;
}

Skeleton AssetImporter::getSkeleton()
{
std::vector<Bone> bones(boneIndexMap.size());
loadBones(bones, pScene->mRootNode, INVALID_BODE_ID);
return Skeleton(bones);
}

void AssetImporter::loadBones(std::vector<Bone> &bones, aiNode *node, int32 parentId)
{
int32 boneId = boneIndexMap[std::string(node->mName.C_Str())];
bones[boneId].transform = getTransform(node->mTransformation);
bones[boneId].parentId = parentId;

for (uint32 i = 0; i < node->mNumChildren; ++i)
{
loadBones(bones, node->mChildren[i], boneId);
}
}

std::vector<StaticMesh> AssetImporter::loadMeshes()
{
std::vector<StaticMesh> meshes;
spdlog::warn("Mesh count: {}", pScene->mNumMeshes);
tcb::span<aiMesh *> meshesInFile(pScene->mMeshes,pScene->mNumMeshes);
for(const auto& paiMesh: meshesInFile) {
// spdlog::warn("Mesh count: {}", pScene->mNumMeshes);
tcb::span<aiMesh *> meshesInFile(pScene->mMeshes, pScene->mNumMeshes);
for (const auto &paiMesh : meshesInFile)
{
meshes.emplace_back();
StaticMesh &mesh = meshes.back();
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
Expand All @@ -52,36 +203,3 @@ std::vector<StaticMesh> AssetImporter::loadMeshes()
}
return meshes;
}
SkeletalMeshModel AssetImporter::loadSkeletalMesh()
{

SkeletalMeshModel skeletalMeshModel;
tcb::span<aiMesh *> meshesInFile(pScene->mMeshes,pScene->mNumMeshes);
int32 clk = 0;
for(const auto& paiMesh: meshesInFile) {
spdlog::warn("{} - {}", clk, pScene->mMaterials[paiMesh->mMaterialIndex]->GetName().C_Str());
clk++;
SkeletalMeshSection skeletalMeshSection;
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
for (uint32 i = 0; i < paiMesh->mNumVertices; ++i)
{
const aiVector3D *pPos = &(paiMesh->mVertices[i]);
const aiVector3D *pNormal = &(paiMesh->mNormals[i]);
const aiVector3D *pTexCoord = paiMesh->HasTextureCoords(0) ? &(paiMesh->mTextureCoords[0][i]) : &Zero3D;
skeletalMeshSection.vertices.emplace_back(pPos->x, pPos->y, pPos->z);
skeletalMeshSection.normals.emplace_back(pNormal->x, pNormal->y, pNormal->z);
skeletalMeshSection.textureCoordinates.emplace_back(pTexCoord->x, pTexCoord->y);
}

for (uint32 i = 0; i < paiMesh->mNumFaces; ++i)
{
const aiFace &Face = paiMesh->mFaces[i];
assert(Face.mNumIndices == 3);
skeletalMeshSection.indices.push_back(Face.mIndices[0]);
skeletalMeshSection.indices.push_back(Face.mIndices[1]);
skeletalMeshSection.indices.push_back(Face.mIndices[2]);
}
skeletalMeshModel.addSkeletalMeshSection(skeletalMeshSection);
}
return skeletalMeshModel;
}
24 changes: 19 additions & 5 deletions Sources/AssetImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,39 @@
#define VENGINE3D_ASSETIMPORTER_H

#include <string>
#include <map>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>

#include "Transform.h"
#include "Bone.h"
#include "Skeleton.h"
#include "StaticMesh.h"
#include <memory>

using Weights = std::map<int32, float>;
using VertexWeights = std::map<uint32, Weights>;

class StaticMesh;
class SkeletalMeshModel;

class AssetImporter {
public:
AssetImporter(const char* path);
bool good();
std::vector<StaticMesh> loadMeshes();


SkeletalMeshModel loadSkeletalMesh();
SkeletalMeshModel getSkeletalMesh();
Skeleton getSkeleton();
private:
void boneIndexing();
void boneIndexingByNode(aiNode* node, int32& index);
VertexWeights getMeshVertexWeights(const aiMesh *mesh);
std::pair<IVector4, Vector4> weightsToEngineType(const Weights& weights);

void loadBones(std::vector<Bone>& bones, aiNode* node, int32 parentId);
static Transform getTransform(const aiMatrix4x4& m);
const aiScene* pScene = nullptr;
Assimp::Importer Importer;
std::unordered_map<std::string, int32> boneIndexMap;
};


Expand Down
1 change: 0 additions & 1 deletion Sources/Bone.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
static constexpr int32 INVALID_BODE_ID = -1;

struct Bone{
int32 id;
int32 parentId;
Transform transform;
};
Expand Down
4 changes: 4 additions & 0 deletions Sources/Math/Vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ struct TVector4
{
}

TVector4(T fillValue) : x(fillValue), y(fillValue), z(fillValue), w(fillValue)
{
}

TVector4(const T *fv) : x(fv[0]), y(fv[1]), z(fv[2]), w(fv[3])
{
}
Expand Down
15 changes: 13 additions & 2 deletions Sources/SkeletalMeshSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,26 @@

#include <vector>
#include "Math/Vector.h"
#include "Bone.h"

struct SkeletalMeshSection
{
void addBoneInfluence(uint32 vertexIndex, int32 boneId, float weight){
for(int32 i = 0; i < 4; ++i) {
if(influenceBones[vertexIndex].v[i] == INVALID_BODE_ID) {
influenceBones[vertexIndex].v[i] = boneId;
influenceWeights[vertexIndex].v[i] = weight;
return;
}
}
//assert(0);
}
std::vector<Vector3> vertices;
std::vector<Vector3> normals;
std::vector<Vector2> textureCoordinates;
std::vector<uint32> indices;
std::vector<IVector4> influenceBoneIndices;
std::vector<Vector4> influenceBoneWeight;
std::vector<IVector4> influenceBones;
std::vector<Vector4> influenceWeights;
};

#endif // VENGINE3D_SKELETALMESHDATA_H
8 changes: 4 additions & 4 deletions Sources/SkeletalMeshSectionRenderData.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct SkeletalMeshSectionRenderData
normals.set(skeletalMesh.normals);
textureCoordinate.set(skeletalMesh.textureCoordinates);
indices.set(skeletalMesh.indices);
influenceBoneIndices.set(skeletalMesh.influenceBoneIndices);
influenceBoneWeight.set(skeletalMesh.influenceBoneWeight);
influenceBones.set(skeletalMesh.influenceBones);
influenceWeights.set(skeletalMesh.influenceWeights);
}

void use()
Expand All @@ -34,8 +34,8 @@ struct SkeletalMeshSectionRenderData
Render::ObjectBuffer<Vector3> normals;
Render::ObjectBuffer<Vector2> textureCoordinate;
Render::IndexBuffer indices;
Render::ObjectBuffer<IVector4> influenceBoneIndices;
Render::ObjectBuffer<Vector4> influenceBoneWeight;
Render::ObjectBuffer<IVector4> influenceBones;
Render::ObjectBuffer<Vector4> influenceWeights;
};

#endif // VENGINE3D_SKELETALMESHSECTIONRENDERDATA_H
36 changes: 36 additions & 0 deletions Sources/Skeleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,39 @@
//

#include "Skeleton.h"
Skeleton::Skeleton(const std::vector<Bone> &bones) : bones_(bones)
{
}

Transform Skeleton::getGlobalTransform(int32 boneId) const
{
Transform result = bones_[boneId].transform;
while (bones_[boneId].parentId != INVALID_BODE_ID)
{
boneId = bones_[boneId].parentId;
result = bones_[boneId].transform * result;
}

return result;
}

std::vector<Matrix4> Skeleton::getMatrixPalette() const
{
std::vector<Matrix4> result(bones_.size());

for (int32 boneId = 0; boneId < bones_.size(); ++boneId)
{
result[boneId] = getGlobalTransform(boneId).toMatrix();
}
return result;
}

Transform &Skeleton::operator[](int32 boneId)
{
return bones_[boneId].transform;
}

const Transform &Skeleton::operator[](int32 boneId) const
{
return bones_[boneId].transform;
}
9 changes: 9 additions & 0 deletions Sources/Skeleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@

class Skeleton
{
public:
explicit Skeleton(const std::vector<Bone> &bones);
Transform& operator[](int32 boneId);
const Transform& operator[](int32 boneId) const;
Transform getGlobalTransform(int32 boneId) const;
std::vector<Matrix4> getMatrixPalette() const;

private:
std::vector<Bone> bones_;
};

#endif // VENGINE3D_SKELETON_H
Loading

0 comments on commit e060aba

Please sign in to comment.