Trying to deform a skeletal model in code has me confused DirectX
Posted: September 20th, 2022, 2:43 am
DirectX: One thing is when I find a tutorial on skeletal models they always teach in terms of bones and weights per vertex. I want things in vertices and weights per bone. This I because I want to be able to know where my vertices actually are. When I have this, I could convert it to GPU code. My code is quite disorganized, and I haven't finished it:
this is my Skinned Mesh class
this is my Skinned Model class
This is a Transformation class
It would be nice If someone could help me with this or even organize it.
Thanks
this is my Skinned Mesh class
Code: Select all
#pragma once
#include "Vertex.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "ConstantBuffer.h"
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include "Texture.h"
//#include <vector>
struct BoneMatrix
{
aiMatrix4x4 offset_matrix;
aiMatrix4x4 final_world_transform;
//glm::mat4 offset_matrix;
//glm::mat4 final_world_transform;
};
struct pasvars {
std::vector<Vertex> vertices;
std::vector<DWORD> indices;
};
class SkinMesh
{
public:
SkinMesh(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex>& vertices, std::vector<DWORD>& indices, std::vector<Texture>& textures, const DirectX::XMMATRIX& transformMatrix);
SkinMesh(const SkinMesh& mesh);
void Draw();
const DirectX::XMMATRIX& GetTransformMatrix();
pasvars getVars();
private:
std::vector<Vertex> vertices;
VertexBuffer<Vertex> vertexbuffer;
std::vector<DWORD> inducies;
IndexBuffer indexbuffer;
ID3D11DeviceContext* deviceContext;
std::vector<Texture> textures;
DirectX::XMMATRIX transformMatrix;
Code: Select all
#include "SkinMesh.h"
SkinMesh::SkinMesh(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex>& vertices, std::vector<DWORD>& indices, std::vector<Texture>& textures, const DirectX::XMMATRIX& transformMatrix)
{
this->deviceContext = deviceContext;
this->textures = textures;
this->transformMatrix = transformMatrix;
this->vertices = vertices;
this->inducies = indices;
//HRESULT hr = this->vertexbuffer.Initialize(device, vertices.data(), vertices.size());
//COM_ERROR_IF_FAILED(hr, "Failed to initialize vertex buffer for SkinMesh.");
//
//hr = this->indexbuffer.Initialize(device, indices.data(), indices.size());
//COM_ERROR_IF_FAILED(hr, "Failed to initialize index buffer for SkinMesh.");
}
SkinMesh::SkinMesh(const SkinMesh& SkinMesh)
{
this->deviceContext = SkinMesh.deviceContext;
this->inducies = SkinMesh.inducies;
this->vertices = SkinMesh.vertices;
this->textures = SkinMesh.textures;
this->transformMatrix = SkinMesh.transformMatrix;
}
void SkinMesh::Draw()
{
UINT offset = 0;
for (int i = 0; i < textures.size(); i++)
{
if (textures[i].GetType() == aiTextureType::aiTextureType_DIFFUSE)
{
this->deviceContext->PSSetShaderResources(0, 1, textures[i].GetTextureResourceViewAddress());
break;
}
}
this->deviceContext->IASetVertexBuffers(0, 1, this->vertexbuffer.GetAddressOf(), this->vertexbuffer.StridePtr(), &offset);
this->deviceContext->IASetIndexBuffer(this->indexbuffer.Get(), DXGI_FORMAT::DXGI_FORMAT_R32_UINT, 0);
this->deviceContext->DrawIndexed(this->indexbuffer.IndexCount(), 0, 0);
}
const DirectX::XMMATRIX& SkinMesh::GetTransformMatrix()
{
return this->transformMatrix;
}
pasvars SkinMesh::getVars() {
pasvars ret;
ret.indices = this->inducies;
ret.vertices = this->vertices;
return ret;
}
Code: Select all
#pragma once
#include "VertexBoneData.h"
#include <DirectXMath.h>
#include "SkinMesh.h"
#include <string>
#include <map>
using namespace std;
using namespace DirectX;
class SkinModel
{
public:
bool Initialize(const std::string& filePath, ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader);
void Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix);
private:
map<string, UINT> m_bone_mapping;
std::vector<SkinMesh> meshes;
bool LoadModel(const std::string& filePath);
void ProcessNode(aiNode* node, const aiScene* scene, const XMMATRIX& parentTransformMatrix);
SkinMesh ProcessMesh(aiMesh* mesh, const aiScene* scene, const XMMATRIX& transformMatrix);
TextureStorageType DetermineTextureStorageType(const aiScene* pScene, aiMaterial* pMat, unsigned int index, aiTextureType textureType);
std::vector<Texture> LoadMaterialTextures(aiMaterial* pMaterial, aiTextureType textureType, const aiScene* pScene);
int GetTextureIndex(aiString* pStr);
vector<UINT> meshinfo;
ID3D11Device* device = nullptr;
ID3D11DeviceContext* deviceContext = nullptr;
ConstantBuffer<CB_VS_vertexshader>* cb_vs_vertexshader = nullptr;
std::string directory = "";
UINT m_num_bones = 0;
UINT previdx = 0;
vector<UINT> indexes;
vector<VertexBoneData> bones_id_weights;
vector<XMMATRIX> m_bone_matrices;
};
Code: Select all
#include "SkinModel.h"
bool SkinModel::Initialize(const std::string& filePath, ID3D11Device* device, ID3D11DeviceContext* deviceContext, ConstantBuffer<CB_VS_vertexshader>& cb_vs_vertexshader)
{
this->device = device;
this->deviceContext = deviceContext;
this->cb_vs_vertexshader = &cb_vs_vertexshader;
try
{
if (!this->LoadModel(filePath))
return false;
}
catch (COMException& exception)
{
ErrorLogger::Log(exception);
return false;
}
return true;
}
void SkinModel::Draw(const XMMATRIX& worldMatrix, const XMMATRIX& viewProjectionMatrix)
{
this->deviceContext->VSSetConstantBuffers(0, 1, this->cb_vs_vertexshader->GetAddressOf());
for (int i = 0; i < meshes.size(); i++)
{
//Update Constant buffer with WVP Matrix
this->cb_vs_vertexshader->data.mat = meshes[i].GetTransformMatrix() * worldMatrix * viewProjectionMatrix; //Calculate World-View-Projection Matrix
this->cb_vs_vertexshader->data.mat = XMMatrixTranspose(this->cb_vs_vertexshader->data.mat);
this->cb_vs_vertexshader->ApplyChanges();
meshes[i].Draw();
}
}
bool SkinModel::LoadModel(const std::string& filePath)
{
this->directory = StringHelper::GetDirectoryFromPath(filePath);
Assimp::Importer importer;
const aiScene* pScene = importer.ReadFile(filePath,
aiProcess_Triangulate |
aiProcess_ConvertToLeftHanded);
if (pScene == nullptr)
return false;
this->ProcessNode(pScene->mRootNode, pScene, DirectX::XMMatrixIdentity());
return true;
}
void SkinModel::ProcessNode(aiNode* node, const aiScene* scene, const XMMATRIX& parentTransformMatrix)
{
vector<VertexBoneData> bones_id_weights;
XMMATRIX nodeTransformMatrix = XMMatrixTranspose(XMMATRIX(&node->mTransformation.a1)) * parentTransformMatrix;
for (UINT i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(this->ProcessMesh(mesh, scene, nodeTransformMatrix));
}
for (UINT i = 0; i < node->mNumChildren; i++)
{
this->ProcessNode(node->mChildren[i], scene, nodeTransformMatrix);
}
}
SkinMesh SkinModel::ProcessMesh(aiMesh* mesh, const aiScene* scene, const XMMATRIX& transformMatrix)
{
// Data to fill
std::vector<Vertex> vertices;
std::vector<DWORD> indices;
//Get vertices
for (UINT i = 0; i < mesh->mNumVertices; i++)
{
Vertex vertex;
vertex.pos.x = mesh->mVertices[i].x;
vertex.pos.y = mesh->mVertices[i].y;
vertex.pos.z = mesh->mVertices[i].z;
if (mesh->mTextureCoords[0])
{
vertex.texCoord.x = (float)mesh->mTextureCoords[0][i].x;
vertex.texCoord.y = (float)mesh->mTextureCoords[0][i].y;
}
vertices.push_back(vertex);
}
//Get indices
for (UINT i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (UINT j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
bones_id_weights.resize(mesh->mNumVertices);
for (UINT i = 0; i < mesh->mNumBones; i++)
{
UINT bone_index = 0;
string bone_name(mesh->mBones[i]->mName.data);
if (m_bone_mapping.find(bone_name) == m_bone_mapping.end())
{
// Allocate an index for a new bone
bone_index = m_num_bones;
m_num_bones++;
XMMATRIX bi;
m_bone_matrices.push_back(bi);
m_bone_matrices[bone_index] = XMMatrixTranspose(XMMATRIX(&mesh->mBones[i]->mOffsetMatrix.a1));
m_bone_mapping[bone_name] = bone_index;
}
else
{
bone_index = m_bone_mapping[bone_name];
}
for (UINT j = 0; j < mesh->mBones[i]->mNumWeights; j++)
{
UINT vertex_id = previdx + mesh->mBones[i]->mWeights[j].mVertexId;
float weight = mesh->mBones[i]->mWeights[j].mWeight;
bones_id_weights[vertex_id].add(vertex_id, weight);
}
}
indexes.push_back(previdx);
previdx += mesh->mNumVertices;
std::vector<Texture> textures;
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
std::vector<Texture> diffuseTextures = LoadMaterialTextures(material, aiTextureType::aiTextureType_DIFFUSE, scene);
textures.insert(textures.end(), diffuseTextures.begin(), diffuseTextures.end());
return SkinMesh(this->device, this->deviceContext, vertices, indices, textures, transformMatrix);
}
TextureStorageType SkinModel::DetermineTextureStorageType(const aiScene* pScene, aiMaterial* pMat, unsigned int index, aiTextureType textureType)
{
if (pMat->GetTextureCount(textureType) == 0)
return TextureStorageType::None;
aiString path;
pMat->GetTexture(textureType, index, &path);
std::string texturePath = path.C_Str();
//Check if texture is an embedded indexed texture by seeing if the file path is an index #
if (texturePath[0] == '*')
{
if (pScene->mTextures[0]->mHeight == 0)
{
return TextureStorageType::EmbeddedIndexCompressed;
}
else
{
assert("SUPPORT DOES NOT EXIST YET FOR INDEXED NON COMPRESSED TEXTURES!" && 0);
return TextureStorageType::EmbeddedIndexNonCompressed;
}
}
//Check if texture is an embedded texture but not indexed (path will be the texture's name instead of #)
if (auto pTex = pScene->GetEmbeddedTexture(texturePath.c_str()))
{
if (pTex->mHeight == 0)
{
return TextureStorageType::EmbeddedCompressed;
}
else
{
assert("SUPPORT DOES NOT EXIST YET FOR EMBEDDED NON COMPRESSED TEXTURES!" && 0);
return TextureStorageType::EmbeddedNonCompressed;
}
}
//Lastly check if texture is a filepath by checking for period before extension name
if (texturePath.find('.') != std::string::npos)
{
return TextureStorageType::Disk;
}
return TextureStorageType::None; // No texture exists
}
std::vector<Texture> SkinModel::LoadMaterialTextures(aiMaterial* pMaterial, aiTextureType textureType, const aiScene* pScene)
{
std::vector<Texture> materialTextures;
TextureStorageType storetype = TextureStorageType::Invalid;
unsigned int textureCount = pMaterial->GetTextureCount(textureType);
if (textureCount == 0) //If there are no textures
{
storetype = TextureStorageType::None;
aiColor3D aiColor(0.0f, 0.0f, 0.0f);
switch (textureType)
{
case aiTextureType_DIFFUSE:
pMaterial->Get(AI_MATKEY_COLOR_DIFFUSE, aiColor);
if (aiColor.IsBlack()) //If color = black, just use grey
{
materialTextures.push_back(Texture(this->device, Colors::UnloadedTextureColor, textureType));
return materialTextures;
}
materialTextures.push_back(Texture(this->device, Color(aiColor.r * 255, aiColor.g * 255, aiColor.b * 255), textureType));
return materialTextures;
}
}
else
{
for (UINT i = 0; i < textureCount; i++)
{
aiString path;
pMaterial->GetTexture(textureType, i, &path);
TextureStorageType storetype = DetermineTextureStorageType(pScene, pMaterial, i, textureType);
switch (storetype)
{
case TextureStorageType::EmbeddedIndexCompressed:
{
int index = GetTextureIndex(&path);
Texture embeddedIndexedTexture(this->device,
reinterpret_cast<uint8_t*>(pScene->mTextures[index]->pcData),
pScene->mTextures[index]->mWidth,
textureType);
materialTextures.push_back(embeddedIndexedTexture);
break;
}
case TextureStorageType::EmbeddedCompressed:
{
const aiTexture* pTexture = pScene->GetEmbeddedTexture(path.C_Str());
Texture embeddedTexture(this->device,
reinterpret_cast<uint8_t*>(pTexture->pcData),
pTexture->mWidth,
textureType);
materialTextures.push_back(embeddedTexture);
break;
}
case TextureStorageType::Disk:
{
std::string filename = this->directory + '\\' + path.C_Str();
Texture diskTexture(this->device, filename, textureType);
materialTextures.push_back(diskTexture);
break;
}
}
}
}
if (materialTextures.size() == 0)
{
materialTextures.push_back(Texture(this->device, Colors::UnhandledTextureColor, aiTextureType::aiTextureType_DIFFUSE));
}
return materialTextures;
}
int SkinModel::GetTextureIndex(aiString* pStr)
{
assert(pStr->length >= 2);
return atoi(&pStr->C_Str()[1]);
}
Code: Select all
#pragma once
#include "Vertex.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "ConstantBuffer.h"
#include "Texture.h"
class Transformed {
public:
void initialize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex> vertices, std::vector<DWORD> inducies, std::vector<Texture> textures);
void deform(DirectX::XMMATRIX *bonepos);
void draw();
private:
VertexBuffer<Vertex> vertexbuffer;
std::vector<Vertex> vertices;
IndexBuffer indexbuffer;
ID3D11DeviceContext* deviceContext;
std::vector<Texture> textures;
ID3D11Device* device,
};
Code: Select all
#include "Transformed.h"
void Transformed::initialize(ID3D11Device* device, ID3D11DeviceContext* deviceContext, std::vector<Vertex> vertices, std::vector<DWORD> indices, std::vector<Texture> textures) {
this->deviceContext = deviceContext;
this->vertices = vertices;
this->textures = textures;
this->device = device;
HRESULT hr = this->indexbuffer.Initialize(device, indices.data(), indices.size());
COM_ERROR_IF_FAILED(hr, "Failed to initialize index buffer for mesh.");
}
void Transformed::deform(DirectX::XMMATRIX* bonepos) {
std::vector<Vertex> outverts;
}
void Transformed::draw() {
UINT offset = 0;
for (int i = 0; i < textures.size(); i++)
{
if (textures[i].GetType() == aiTextureType::aiTextureType_DIFFUSE)
{
this->deviceContext->PSSetShaderResources(0, 1, textures[i].GetTextureResourceViewAddress());
break;
}
}
this->deviceContext->IASetVertexBuffers(0, 1, this->vertexbuffer.GetAddressOf(), this->vertexbuffer.StridePtr(), &offset);
this->deviceContext->IASetIndexBuffer(this->indexbuffer.Get(), DXGI_FORMAT::DXGI_FORMAT_R32_UINT, 0);
this->deviceContext->DrawIndexed(this->indexbuffer.IndexCount(), 0, 0);
}
Thanks