mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-09 20:08:57 +03:00
Added new component and panel + model loader
This commit is contained in:
79
Editor/src/ComponentsPanel/SkinnedModelPanel.h
Normal file
79
Editor/src/ComponentsPanel/SkinnedModelPanel.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
#include <src/Core/Core.h>
|
||||
#include "ComponentPanel.h"
|
||||
#include "ModelResourceInspector.h"
|
||||
|
||||
#include <src/Scene/Entities/ImGuiHelper.h>
|
||||
#include <src/Scene/Components/SkinnedModelComponent.h>
|
||||
|
||||
#include <src/Resource/ResourceLoader.h>
|
||||
#include <src/Core/String.h>
|
||||
|
||||
class SkinnedModelPanel : ComponentPanel
|
||||
{
|
||||
private:
|
||||
Scope<ModelResourceInspector> _modelInspector;
|
||||
bool _expanded = false;
|
||||
|
||||
public:
|
||||
SkinnedModelPanel()
|
||||
{
|
||||
CreateScope<ModelResourceInspector>();
|
||||
}
|
||||
|
||||
void Draw(Nuake::Entity entity) override
|
||||
{
|
||||
using namespace Nuake;
|
||||
if (!entity.HasComponent<SkinnedModelComponent>())
|
||||
return;
|
||||
|
||||
SkinnedModelComponent& component = entity.GetComponent<SkinnedModelComponent>();
|
||||
BeginComponentTable(SKINNED MESH, SkinnedModelComponent);
|
||||
{
|
||||
ImGui::Text("Model");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
std::string label = "None";
|
||||
|
||||
const bool isModelNone = component.ModelResource == nullptr;
|
||||
if (!isModelNone)
|
||||
{
|
||||
label = std::to_string(component.ModelResource->ID);
|
||||
}
|
||||
|
||||
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
|
||||
{
|
||||
}
|
||||
|
||||
if (_expanded)
|
||||
{
|
||||
_modelInspector->Draw();
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
|
||||
{
|
||||
char* file = (char*)payload->Data;
|
||||
std::string fullPath = std::string(file, 256);
|
||||
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
|
||||
|
||||
if (Nuake::String::EndsWith(fullPath, ".model"))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
component.ModelPath = fullPath;
|
||||
component.LoadModel();
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ComponentTableReset(component.ModelPath, "");
|
||||
}
|
||||
EndComponentTable();
|
||||
}
|
||||
};
|
||||
@@ -103,6 +103,7 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
|
||||
mParticleEmitterPanel.Draw(entity);
|
||||
mSpritePanel.Draw(entity);
|
||||
mMeshPanel.Draw(entity);
|
||||
mSkinnedModelPanel.Draw(entity);
|
||||
mQuakeMapPanel.Draw(entity);
|
||||
mCameraPanel.Draw(entity);
|
||||
mRigidbodyPanel.Draw(entity);
|
||||
@@ -131,6 +132,7 @@ void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity)
|
||||
MenuItemComponent("Camera", Nuake::CameraComponent)
|
||||
MenuItemComponent("Light", Nuake::LightComponent)
|
||||
MenuItemComponent("Model", Nuake::ModelComponent)
|
||||
MenuItemComponent("Skinned Model", Nuake::SkinnedModelComponent)
|
||||
MenuItemComponent("Sprite", Nuake::SpriteComponent)
|
||||
MenuItemComponent("Particle Emitter", Nuake::ParticleEmitterComponent)
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../ComponentsPanel/CharacterControllerPanel.h"
|
||||
#include "../ComponentsPanel/SpritePanel.h"
|
||||
#include "../ComponentsPanel/ParticleEmitterPanel.h"
|
||||
#include "../ComponentsPanel/SkinnedModelPanel.h"
|
||||
|
||||
|
||||
class EditorSelectionPanel
|
||||
@@ -29,6 +30,7 @@ private:
|
||||
LightPanel mLightPanel;
|
||||
ScriptPanel mScriptPanel;
|
||||
MeshPanel mMeshPanel;
|
||||
SkinnedModelPanel mSkinnedModelPanel;
|
||||
QuakeMapPanel mQuakeMapPanel;
|
||||
CameraPanel mCameraPanel;
|
||||
RigidbodyPanel mRigidbodyPanel;
|
||||
|
||||
@@ -8,6 +8,15 @@ namespace Nuake {
|
||||
Vector3 Min;
|
||||
Vector3 Max;
|
||||
|
||||
AABB() = default;
|
||||
~AABB() = default;
|
||||
|
||||
AABB(const Vector3& min, const Vector3& max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
// Transforms the bounding box and recalculate an axis aligned box
|
||||
void Transform(Matrix4 transform)
|
||||
{
|
||||
|
||||
197
Nuake/src/Rendering/Mesh/SkinnedMesh.cpp
Normal file
197
Nuake/src/Rendering/Mesh/SkinnedMesh.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "SkinnedMesh.h"
|
||||
|
||||
#include "src/Core/Maths.h"
|
||||
#include "src/Rendering/Textures/Material.h"
|
||||
#include "src/Rendering/Textures/MaterialManager.h"
|
||||
#include "src/Rendering/Renderer.h"
|
||||
#include "src/Rendering/Shaders/Shader.h"
|
||||
|
||||
#include "src/Rendering/Vertex.h"
|
||||
#include "src/Rendering/Buffers/VertexBuffer.h"
|
||||
#include "src/Rendering/Buffers/VertexArray.h"
|
||||
#include "src/Rendering/Buffers/VertexBufferLayout.h"
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
void SkinnedMesh::AddSurface(std::vector<SkinnedVertex> vertices, std::vector<uint32_t> indices, std::vector<Bone> bones)
|
||||
{
|
||||
m_Vertices = vertices;
|
||||
m_Indices = indices;
|
||||
m_Bones = bones;
|
||||
|
||||
SetupMesh();
|
||||
CalculateAABB();
|
||||
|
||||
if (m_Material == nullptr)
|
||||
{
|
||||
m_Material = MaterialManager::Get()->GetMaterial("default");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SkinnedVertex>& SkinnedMesh::GetVertices()
|
||||
{
|
||||
return m_Vertices;
|
||||
}
|
||||
|
||||
std::vector<uint32_t>& SkinnedMesh::GetIndices()
|
||||
{
|
||||
return m_Indices;
|
||||
}
|
||||
|
||||
Ref<Material> SkinnedMesh::GetMaterial() inline const
|
||||
{
|
||||
return m_Material;
|
||||
}
|
||||
|
||||
void SkinnedMesh::SetMaterial(Ref<Material> material)
|
||||
{
|
||||
m_Material = material;
|
||||
MaterialManager::Get()->RegisterMaterial(material);
|
||||
}
|
||||
|
||||
void SkinnedMesh::CalculateAABB()
|
||||
{
|
||||
float minX = 0.0f;
|
||||
float minY = 0.0f;
|
||||
float minZ = 0.0f;
|
||||
float maxX = 0.0f;
|
||||
float maxY = 0.0f;
|
||||
float maxZ = 0.0f;
|
||||
|
||||
for (const SkinnedVertex& v : m_Vertices)
|
||||
{
|
||||
minX = v.position.x < minX ? v.position.x : minX;
|
||||
minY = v.position.y < minY ? v.position.y : minY;
|
||||
minZ = v.position.z < minZ ? v.position.z : minZ;
|
||||
maxX = v.position.x > maxX ? v.position.x : maxX;
|
||||
maxY = v.position.y > maxY ? v.position.y : maxY;
|
||||
maxZ = v.position.z > maxZ ? v.position.z : maxZ;
|
||||
}
|
||||
|
||||
m_AABB = AABB(Vector3(minX, minY, minZ), Vector3(maxX, maxY, maxZ));
|
||||
}
|
||||
|
||||
void SkinnedMesh::SetupMesh()
|
||||
{
|
||||
m_VertexArray = CreateScope<VertexArray>();
|
||||
m_VertexArray->Bind();
|
||||
m_VertexBuffer = CreateScope<VertexBuffer>(m_Vertices.data(), m_Vertices.size() * sizeof(Vertex));
|
||||
m_ElementBuffer = CreateScope<VertexBuffer>(m_Indices.data(), m_Indices.size() * sizeof(unsigned int), RendererEnum::ELEMENT_ARRAY_BUFFER);
|
||||
|
||||
VertexBufferLayout bufferLayout = VertexBufferLayout();
|
||||
bufferLayout.Push<float>(3); // Position
|
||||
bufferLayout.Push<float>(2); // UV
|
||||
bufferLayout.Push<float>(3); // Normal
|
||||
bufferLayout.Push<float>(3); // Tangent
|
||||
bufferLayout.Push<float>(3); // Bitangent
|
||||
bufferLayout.Push<unsigned int>(4); // BoneIds
|
||||
bufferLayout.Push<float>(4); // Weights
|
||||
|
||||
m_VertexArray->AddBuffer(*m_VertexBuffer, bufferLayout);
|
||||
m_VertexArray->Unbind();
|
||||
}
|
||||
|
||||
void SkinnedMesh::Bind() const
|
||||
{
|
||||
m_VertexArray->Bind();
|
||||
}
|
||||
|
||||
void SkinnedMesh::Draw(Shader* shader, bool bindMaterial)
|
||||
{
|
||||
if (bindMaterial)
|
||||
m_Material->Bind(shader);
|
||||
|
||||
m_VertexArray->Bind();
|
||||
RenderCommand::DrawElements(RendererEnum::TRIANGLES, (int)m_Indices.size(), RendererEnum::UINT, 0);
|
||||
}
|
||||
|
||||
void SkinnedMesh::DebugDraw()
|
||||
{
|
||||
Renderer::m_DebugShader->Bind();
|
||||
Renderer::m_DebugShader->SetUniform4f("u_Color", 1.0f, 0.0f, 0.0f, 1.f);
|
||||
|
||||
m_VertexArray->Bind();
|
||||
RenderCommand::DrawElements(RendererEnum::TRIANGLES, (int)m_Indices.size(), RendererEnum::UINT, 0);
|
||||
}
|
||||
|
||||
json SkinnedMesh::Serialize()
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
|
||||
j["Material"] = m_Material->Serialize();
|
||||
j["Indices"] = m_Indices;
|
||||
|
||||
for (uint32_t i = 0; i < m_Bones.size(); i++)
|
||||
{
|
||||
//j["Bones"][i] = m_Bones[i];
|
||||
}
|
||||
json v;
|
||||
for (uint32_t i = 0; i < m_Vertices.size(); i++)
|
||||
{
|
||||
v["Position"]["x"] = m_Vertices[i].position.x;
|
||||
v["Position"]["y"] = m_Vertices[i].position.y;
|
||||
v["Position"]["z"] = m_Vertices[i].position.z;
|
||||
|
||||
v["UV"]["x"] = m_Vertices[i].uv.x;
|
||||
v["UV"]["y"] = m_Vertices[i].uv.y;
|
||||
|
||||
v["Normal"]["x"] = m_Vertices[i].normal.x;
|
||||
v["Normal"]["y"] = m_Vertices[i].normal.y;
|
||||
v["Normal"]["z"] = m_Vertices[i].normal.z;
|
||||
|
||||
v["Tangent"]["x"] = m_Vertices[i].tangent.x;
|
||||
v["Tangent"]["y"] = m_Vertices[i].tangent.y;
|
||||
v["Tangent"]["z"] = m_Vertices[i].tangent.z;
|
||||
|
||||
v["Bitangent"]["x"] = m_Vertices[i].bitangent.x;
|
||||
v["Bitangent"]["y"] = m_Vertices[i].bitangent.y;
|
||||
v["Bitangent"]["z"] = m_Vertices[i].bitangent.z;
|
||||
|
||||
j["Vertices"][i] = v;
|
||||
}
|
||||
|
||||
|
||||
END_SERIALIZE();
|
||||
}
|
||||
|
||||
bool SkinnedMesh::Deserialize(const json& j)
|
||||
{
|
||||
m_Material = CreateRef<Material>();
|
||||
m_Material->Deserialize(j["Material"]);
|
||||
|
||||
m_Indices.reserve(j["Indices"].size());
|
||||
for (auto& i : j["Indices"])
|
||||
{
|
||||
m_Indices.push_back(i);
|
||||
}
|
||||
|
||||
std::vector<SkinnedVertex> vertices;
|
||||
|
||||
std::async(std::launch::async, [&]()
|
||||
{
|
||||
for (auto& v : j["Vertices"])
|
||||
{
|
||||
SkinnedVertex vertex;
|
||||
try {
|
||||
DESERIALIZE_VEC2(v["UV"], vertex.uv)
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
vertex.uv = { 0.0, 0.0 };
|
||||
}
|
||||
DESERIALIZE_VEC3(v["Position"], vertex.position)
|
||||
DESERIALIZE_VEC3(v["Normal"], vertex.normal)
|
||||
DESERIALIZE_VEC3(v["Tangent"], vertex.tangent)
|
||||
DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent)
|
||||
vertices.push_back(vertex);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
m_Vertices = vertices;
|
||||
|
||||
SetupMesh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
67
Nuake/src/Rendering/Mesh/SkinnedMesh.h
Normal file
67
Nuake/src/Rendering/Mesh/SkinnedMesh.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "src/Core/Core.h"
|
||||
#include "src/Rendering/AABB.h"
|
||||
#include "src/Resource/Resource.h"
|
||||
#include "src/Resource/Serializable.h"
|
||||
#include "src/Rendering/Vertex.h"
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class VertexBuffer;
|
||||
class VertexArray;
|
||||
class Material;
|
||||
struct Vertex;
|
||||
class Shader;
|
||||
|
||||
struct BoneVertexWeight
|
||||
{
|
||||
uint32_t VertexID;
|
||||
float Weight;
|
||||
};
|
||||
|
||||
struct Bone
|
||||
{
|
||||
std::string Name;
|
||||
Matrix4 Offset;
|
||||
std::vector<BoneVertexWeight> VertexWeights;
|
||||
};
|
||||
|
||||
class SkinnedMesh : ISerializable, Resource
|
||||
{
|
||||
public:
|
||||
SkinnedMesh() = default;
|
||||
~SkinnedMesh() = default;
|
||||
|
||||
void AddSurface(std::vector<SkinnedVertex> vertices, std::vector<uint32_t> indices, std::vector<Bone> bones);
|
||||
std::vector<SkinnedVertex>& GetVertices();
|
||||
std::vector<uint32_t>& GetIndices();
|
||||
std::vector<Bone>& GetBones();
|
||||
|
||||
Ref<Material> GetMaterial() inline const;
|
||||
void SetMaterial(Ref<Material> material);
|
||||
|
||||
void Bind() const;
|
||||
void Draw(Shader* shader, bool bindMaterial = true);
|
||||
void DebugDraw();
|
||||
|
||||
inline AABB GetAABB() const { return m_AABB; }
|
||||
|
||||
json Serialize() override;
|
||||
bool Deserialize(const json& j) override;
|
||||
|
||||
private:
|
||||
Ref<Material> m_Material = nullptr;
|
||||
std::vector<uint32_t> m_Indices;
|
||||
std::vector<SkinnedVertex> m_Vertices;
|
||||
std::vector<Bone> m_Bones;
|
||||
|
||||
Scope<VertexBuffer> m_VertexBuffer;
|
||||
Scope<VertexArray> m_VertexArray;
|
||||
Scope<VertexBuffer> m_ElementBuffer;
|
||||
|
||||
void SetupMesh();
|
||||
|
||||
AABB m_AABB;
|
||||
void CalculateAABB();
|
||||
};
|
||||
}
|
||||
@@ -12,6 +12,20 @@ namespace Nuake
|
||||
Vector3 bitangent;
|
||||
};
|
||||
|
||||
const uint32_t MAX_BONE_INFLUENCE = 4;
|
||||
struct SkinnedVertex
|
||||
{
|
||||
Vector3 position;
|
||||
Vector2 uv;
|
||||
Vector3 normal;
|
||||
Vector3 tangent;
|
||||
Vector3 bitangent;
|
||||
|
||||
int boneIDs[MAX_BONE_INFLUENCE];
|
||||
//weights from each bone
|
||||
float weights[MAX_BONE_INFLUENCE];
|
||||
};
|
||||
|
||||
struct LineVertex
|
||||
{
|
||||
Vector3 position;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "src/Core/String.h"
|
||||
|
||||
#include "src/Resource/SkinnedModel.h"
|
||||
#include "src/Resource/Model.h"
|
||||
|
||||
|
||||
@@ -18,8 +19,8 @@ namespace Nuake
|
||||
m_Meshes.clear();
|
||||
Ref<Model> model = CreateRef<Model>(path);
|
||||
|
||||
Assimp::Importer import;
|
||||
import.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90);
|
||||
Assimp::Importer importer;
|
||||
importer.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90);
|
||||
|
||||
auto importFlags =
|
||||
aiProcess_Triangulate |
|
||||
@@ -29,10 +30,10 @@ namespace Nuake
|
||||
|
||||
modelDir = absolute ? path + "/../" : FileSystem::Root + path + "/../";
|
||||
const std::string filePath = absolute ? path : FileSystem::Root + path;
|
||||
const aiScene* scene = import.ReadFile(filePath, importFlags);
|
||||
const aiScene* scene = importer.ReadFile(filePath, importFlags);
|
||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
||||
{
|
||||
std::string assimpErrorMsg = std::string(import.GetErrorString());
|
||||
std::string assimpErrorMsg = std::string(importer.GetErrorString());
|
||||
std::string logMsg = "[Failed to load model] - " + assimpErrorMsg;
|
||||
Logger::Log(logMsg, "model", WARNING);
|
||||
|
||||
@@ -49,6 +50,42 @@ namespace Nuake
|
||||
return model;
|
||||
}
|
||||
|
||||
Ref<SkinnedModel> ModelLoader::LoadSkinnedModel(const std::string& path, bool absolute)
|
||||
{
|
||||
m_Meshes.clear();
|
||||
Ref<SkinnedModel> model = CreateRef<SkinnedModel>(path);
|
||||
|
||||
Assimp::Importer importer;
|
||||
importer.SetPropertyFloat("PP_GSN_MAX_SMOOTHING_ANGLE", 90);
|
||||
|
||||
auto importFlags =
|
||||
aiProcess_Triangulate |
|
||||
aiProcess_GenSmoothNormals |
|
||||
aiProcess_FixInfacingNormals |
|
||||
aiProcess_CalcTangentSpace;
|
||||
|
||||
modelDir = absolute ? path + "/../" : FileSystem::Root + path + "/../";
|
||||
const std::string filePath = absolute ? path : FileSystem::Root + path;
|
||||
const aiScene* scene = importer.ReadFile(filePath, importFlags);
|
||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
|
||||
{
|
||||
std::string assimpErrorMsg = std::string(importer.GetErrorString());
|
||||
std::string logMsg = "[Failed to load model] - " + assimpErrorMsg;
|
||||
Logger::Log(logMsg, "model", WARNING);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
ProcessNode(scene->mRootNode, scene);
|
||||
|
||||
for (const auto& mesh : m_SkinnedMeshes)
|
||||
{
|
||||
model->AddMesh(mesh);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
void ModelLoader::ProcessNode(aiNode* node, const aiScene* scene)
|
||||
{
|
||||
for (uint32_t i = 0; i < node->mNumMeshes; i++)
|
||||
@@ -63,12 +100,84 @@ namespace Nuake
|
||||
}
|
||||
}
|
||||
|
||||
void ModelLoader::ProcessSkinnedNode(aiNode* node, const aiScene* scene)
|
||||
{
|
||||
for (uint32_t i = 0; i < node->mNumMeshes; i++)
|
||||
{
|
||||
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
m_SkinnedMeshes.push_back(ProcessSkinnedMesh(mesh, scene));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->mNumChildren; i++)
|
||||
{
|
||||
ProcessSkinnedNode(node->mChildren[i], scene);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<SkinnedMesh> ModelLoader::ProcessSkinnedMesh(aiMesh* node, const aiScene* scene)
|
||||
{
|
||||
auto vertices = ProcessSkinnedVertices(node);
|
||||
auto indices = ProcessIndices(node);
|
||||
auto material = ProcessMaterials(scene, node);
|
||||
auto bones = std::vector<Bone>();
|
||||
if (node->HasBones())
|
||||
{
|
||||
for (uint32_t i = 0; i < node->mNumBones; i++)
|
||||
{
|
||||
aiBone* bone = node->mBones[i];
|
||||
const std::string& boneName = bone->mName.C_Str();
|
||||
const auto& boneMatrix = bone->mOffsetMatrix;
|
||||
|
||||
for (uint32_t j = 0; j < bone->mNumWeights; j++)
|
||||
{
|
||||
aiVertexWeight vertexWeight = bone->mWeights[j];
|
||||
|
||||
const float weigth = vertexWeight.mWeight;
|
||||
uint32_t vertexId = vertexWeight.mVertexId;
|
||||
|
||||
vertices[vertexId].boneIDs[j] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::Log("Using skinned mesh imported while the model has no bones!", "model loader", WARNING);
|
||||
}
|
||||
|
||||
// Fill in the bones in the vertices
|
||||
|
||||
|
||||
Ref<SkinnedMesh> mesh = CreateRef<SkinnedMesh>();
|
||||
mesh->AddSurface(vertices, indices, bones);
|
||||
mesh->SetMaterial(material);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Ref<Mesh> ModelLoader::ProcessMesh(aiMesh* node, const aiScene* scene)
|
||||
{
|
||||
auto vertices = ProcessVertices(node);
|
||||
auto indices = ProcessIndices(node);
|
||||
auto material = ProcessMaterials(scene, node);
|
||||
|
||||
if (node->HasBones())
|
||||
{
|
||||
for (uint32_t i = 0; i < node->mNumBones; i++)
|
||||
{
|
||||
aiBone* bone = node->mBones[i];
|
||||
const std::string& boneName = bone->mName.C_Str();
|
||||
const auto& boneMatrix = bone->mOffsetMatrix;
|
||||
|
||||
for (uint32_t j = 0; j < bone->mNumWeights; j++)
|
||||
{
|
||||
aiVertexWeight vertexWeight = bone->mWeights[j];
|
||||
|
||||
const float weigth = vertexWeight.mWeight;
|
||||
uint32_t vertexId = vertexWeight.mVertexId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Mesh> mesh = CreateRef<Mesh>();
|
||||
mesh->AddSurface(vertices, indices);
|
||||
mesh->SetMaterial(material);
|
||||
@@ -130,6 +239,62 @@ namespace Nuake
|
||||
return vertices;
|
||||
}
|
||||
|
||||
std::vector<SkinnedVertex> ModelLoader::ProcessSkinnedVertices(aiMesh* mesh)
|
||||
{
|
||||
auto vertices = std::vector<SkinnedVertex>();
|
||||
for (uint32_t i = 0; i < mesh->mNumVertices; i++)
|
||||
{
|
||||
SkinnedVertex vertex;
|
||||
|
||||
Vector3 current;
|
||||
|
||||
// Position
|
||||
current.x = mesh->mVertices[i].x;
|
||||
current.y = mesh->mVertices[i].y;
|
||||
current.z = mesh->mVertices[i].z;
|
||||
vertex.position = current;
|
||||
|
||||
// Normals
|
||||
current.x = mesh->mNormals[i].x;
|
||||
current.y = mesh->mNormals[i].y;
|
||||
current.z = mesh->mNormals[i].z;
|
||||
vertex.normal = current;
|
||||
|
||||
// Tangents
|
||||
if (mesh->mTangents)
|
||||
{
|
||||
current.x = mesh->mTangents[i].x;
|
||||
current.y = mesh->mTangents[i].y;
|
||||
current.z = mesh->mTangents[i].z;
|
||||
vertex.tangent = current;
|
||||
}
|
||||
|
||||
if (mesh->mBitangents)
|
||||
{
|
||||
current.x = mesh->mBitangents[i].x;
|
||||
current.y = mesh->mBitangents[i].y;
|
||||
current.z = mesh->mBitangents[i].z;
|
||||
vertex.bitangent = current;
|
||||
}
|
||||
|
||||
vertex.uv = glm::vec2(0.0f, 0.0f);
|
||||
|
||||
// Does it contain UVs?
|
||||
if (mesh->mTextureCoords[0])
|
||||
{
|
||||
float u = mesh->mTextureCoords[0][i].x;
|
||||
float v = mesh->mTextureCoords[0][i].y;
|
||||
vertex.uv = Vector2(u, v);
|
||||
}
|
||||
|
||||
// We are filling the bones later.
|
||||
|
||||
vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> ModelLoader::ProcessIndices(aiMesh* mesh)
|
||||
{
|
||||
auto indices = std::vector<uint32_t>();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "src/Core/Core.h"
|
||||
|
||||
#include "src/Rendering/Mesh/SkinnedMesh.h"
|
||||
#include "src/Rendering/Mesh/Mesh.h"
|
||||
#include "src/Rendering/Textures/Material.h"
|
||||
#include "src/Rendering/Textures/Texture.h"
|
||||
@@ -11,9 +12,13 @@
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
|
||||
#include "src/Rendering/Buffers/VertexArray.h"
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class Model;
|
||||
class SkinnedModel;
|
||||
|
||||
class ModelLoader
|
||||
{
|
||||
public:
|
||||
@@ -21,9 +26,12 @@ namespace Nuake
|
||||
~ModelLoader();
|
||||
|
||||
Ref<Model> LoadModel(const std::string& path, bool absolute = false);
|
||||
Ref<SkinnedModel> LoadSkinnedModel(const std::string& path, bool absolute = false);
|
||||
|
||||
private:
|
||||
std::string modelDir;
|
||||
std::vector<Ref<Mesh>> m_Meshes;
|
||||
std::vector<Ref<SkinnedMesh>> m_SkinnedMeshes;
|
||||
|
||||
void ProcessNode(aiNode* node, const aiScene* scene);
|
||||
Ref<Mesh> ProcessMesh(aiMesh* node, const aiScene* scene);
|
||||
@@ -32,5 +40,10 @@ namespace Nuake
|
||||
std::vector<uint32_t> ProcessIndices(aiMesh* mesh);
|
||||
Ref<Material> ProcessMaterials(const aiScene* scene, aiMesh* mesh);
|
||||
Ref<Texture> ProcessTextures(const aiScene* scene, const std::string& path);
|
||||
|
||||
// Skinned
|
||||
void ProcessSkinnedNode(aiNode* node, const aiScene* scene);
|
||||
Ref<SkinnedMesh> ProcessSkinnedMesh(aiMesh* node, const aiScene* scene);
|
||||
std::vector<SkinnedVertex> ProcessSkinnedVertices(aiMesh* mesh);
|
||||
};
|
||||
}
|
||||
73
Nuake/src/Resource/SkinnedModel.cpp
Normal file
73
Nuake/src/Resource/SkinnedModel.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "src/Resource/ModelLoader.h"
|
||||
|
||||
#include "src/Resource/SkinnedModel.h"
|
||||
#include "src/Core/FileSystem.h"
|
||||
#include "src/Core/Logger.h"
|
||||
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
SkinnedModel::SkinnedModel(const std::string path) : m_Meshes(std::vector<Ref<SkinnedMesh>>())
|
||||
{
|
||||
this->Path = path;
|
||||
}
|
||||
|
||||
SkinnedModel::SkinnedModel() : m_Meshes(std::vector<Ref<SkinnedMesh>>())
|
||||
{}
|
||||
|
||||
SkinnedModel::~SkinnedModel() {}
|
||||
|
||||
void SkinnedModel::AddMesh(Ref<SkinnedMesh> mesh)
|
||||
{
|
||||
m_Meshes.push_back(mesh);
|
||||
}
|
||||
|
||||
std::vector<Ref<SkinnedMesh>>& SkinnedModel::GetMeshes()
|
||||
{
|
||||
return m_Meshes;
|
||||
}
|
||||
|
||||
json SkinnedModel::Serialize()
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
|
||||
if (this->Path != "")
|
||||
{
|
||||
j["Path"] = this->Path;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < std::size(m_Meshes); i++)
|
||||
{
|
||||
j["Meshes"][i] = m_Meshes[i]->Serialize();
|
||||
}
|
||||
}
|
||||
END_SERIALIZE();
|
||||
}
|
||||
|
||||
bool SkinnedModel::Deserialize(const json& j)
|
||||
{
|
||||
if (j.contains("Path"))
|
||||
{
|
||||
this->IsEmbedded = true;
|
||||
|
||||
ModelLoader loader;
|
||||
auto otherModel = loader.LoadSkinnedModel(j["Path"], false);
|
||||
m_Meshes = otherModel->GetMeshes();
|
||||
|
||||
this->Path = j["Path"];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& m : j["Meshes"])
|
||||
{
|
||||
auto mesh = CreateRef<SkinnedMesh>();
|
||||
mesh->Deserialize(m);
|
||||
|
||||
m_Meshes.push_back(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
26
Nuake/src/Resource/SkinnedModel.h
Normal file
26
Nuake/src/Resource/SkinnedModel.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "src/Core/Core.h"
|
||||
#include "src/Rendering/Mesh/SkinnedMesh.h"
|
||||
#include "src/Resource/Resource.h"
|
||||
#include "src/Resource/Serializable.h"
|
||||
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class SkinnedModel : public Resource, ISerializable
|
||||
{
|
||||
private:
|
||||
std::vector<Ref<SkinnedMesh>> m_Meshes;
|
||||
|
||||
public:
|
||||
SkinnedModel();
|
||||
SkinnedModel(const std::string path);
|
||||
~SkinnedModel();
|
||||
|
||||
void AddMesh(Ref<SkinnedMesh> mesh);
|
||||
std::vector<Ref<SkinnedMesh>>& GetMeshes();
|
||||
|
||||
json Serialize() override;
|
||||
bool Deserialize(const json& j) override;
|
||||
};
|
||||
}
|
||||
16
Nuake/src/Scene/Components/SkinnedModelComponent.cpp
Normal file
16
Nuake/src/Scene/Components/SkinnedModelComponent.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include "SkinnedModelComponent.h"
|
||||
#include "src/Resource/ModelLoader.h"
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
SkinnedModelComponent::SkinnedModelComponent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SkinnedModelComponent::LoadModel()
|
||||
{
|
||||
auto loader = ModelLoader();
|
||||
this->ModelResource = loader.LoadSkinnedModel(ModelPath);
|
||||
}
|
||||
}
|
||||
45
Nuake/src/Scene/Components/SkinnedModelComponent.h
Normal file
45
Nuake/src/Scene/Components/SkinnedModelComponent.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
#include "src/Resource/Serializable.h"
|
||||
#include "src/Resource/SkinnedModel.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
struct SkinnedModelComponent
|
||||
{
|
||||
Ref<SkinnedModel> ModelResource;
|
||||
std::string ModelPath;
|
||||
|
||||
SkinnedModelComponent();
|
||||
|
||||
void LoadModel();
|
||||
|
||||
std::string directory;
|
||||
|
||||
json Serialize()
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
SERIALIZE_VAL(ModelPath);
|
||||
SERIALIZE_OBJECT(ModelResource);
|
||||
END_SERIALIZE();
|
||||
}
|
||||
|
||||
bool Deserialize(const json& j)
|
||||
{
|
||||
ModelPath = j["ModelPath"];
|
||||
ModelResource = CreateRef<SkinnedModel>();
|
||||
|
||||
if (j.contains("ModelResource"))
|
||||
{
|
||||
auto& res = j["ModelResource"];
|
||||
ModelResource->Deserialize(res);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user