basic 3D zombie model

This commit is contained in:
2026-01-03 23:33:26 +01:00
parent 19ebe7b64f
commit 45c9e5180f
9 changed files with 1887 additions and 8 deletions

1721
assets/zombie.fbx Normal file

File diff suppressed because it is too large Load Diff

BIN
assets/zombie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

View File

@@ -1,10 +1,11 @@
#pragma once
#include <memory>
#include <td/misc/SlotGuard.h>
#include <td/render/Camera.h>
#include <td/render/loader/FbxLoader.h>
#include <td/render/loader/GLLoader.h>
#include <td/render/shader/CameraShaderProgram.h>
#include <td/misc/SlotGuard.h>
namespace td {
namespace render {
@@ -15,6 +16,7 @@ class BasicRenderer {
virtual ~BasicRenderer() {}
void Render(const GL::VertexArray& a_Vao);
void Render(const Model& a_Model);
};
template <typename TShader>
@@ -66,7 +68,7 @@ class RenderPipeline {
template <typename TShader>
Renderer<TShader>::Renderer(Camera& a_Camera) : m_Shader(std::make_unique<TShader>()), m_Camera(a_Camera) {
Connect(a_Camera.OnPerspectiveChange, [this](){
Connect(a_Camera.OnPerspectiveChange, [this]() {
m_Shader->Start();
m_Shader->SetProjectionMatrix(m_Camera.GetProjectionMatrix());
});

View File

@@ -0,0 +1,19 @@
#pragma once
#include <td/render/loader/GLLoader.h>
#include <memory>
#include <string>
#include <vector>
namespace td {
struct Model {
std::vector<std::unique_ptr<GL::VertexArray>> m_Vaos;
};
namespace ModelLoader {
Model LoadModel(const std::string& fileName);
}
}

View File

@@ -1,5 +1,6 @@
#pragma once
#include <td/render/loader/FbxLoader.h>
#include <td/render/Renderer.h>
#include <td/render/shader/EntityShader.h>
#include <td/game/World.h>
@@ -10,7 +11,7 @@ namespace render {
class EntityRenderer : public Renderer<shader::EntityShader> {
private:
game::WorldPtr m_World;
std::unique_ptr<GL::VertexArray> m_EntityVao;
Model m_EntityModel;
public:
EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World);

View File

@@ -8,10 +8,17 @@ namespace render {
void BasicRenderer::Render(const GL::VertexArray& a_Vao) {
a_Vao.Bind();
glDrawArrays(GL_TRIANGLES, 0, a_Vao.GetVertexCount());
// glDrawElements(GL_TRIANGLES, a_Vao.GetVertexCount(), GL_UNSIGNED_INT, nullptr);
a_Vao.Unbind();
}
void BasicRenderer::Render(const Model& a_Model) {
for (const auto& vao : a_Model.m_Vaos) {
vao->Bind();
glDrawElements(GL_TRIANGLES, vao->GetVertexCount(), GL_UNSIGNED_INT, nullptr);
vao->Unbind();
}
}
RenderPipeline::RenderPipeline() {
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);

View File

@@ -0,0 +1,128 @@
#include <td/render/loader/FbxLoader.h>
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/postprocess.h> // Post processing flags
#include <assimp/scene.h> // Output data structure
#include <iostream>
#include <memory>
#include <sp/common/DataBuffer.h>
#include <td/render/loader/GLLoader.h>
#include <vector>
#define VERTEX_SIZE 3
#define UV_SIZE 2
#define VERTEX_POSITION_INDEX 0
#define VERTEX_UV_INDEX 1
#define VERTEX_NORMAL_INDEX 2
namespace td {
namespace ModelLoader {
static std::unique_ptr<GL::VertexArray> ProcessMesh(aiMesh* mesh, const aiScene* scene, const aiMatrix4x4& transform) {
std::vector<float> positions;
std::vector<float> textureCoords;
std::vector<float> normals;
std::vector<unsigned int> indicies;
aiFace* faces = mesh->mFaces;
std::size_t faceNumber = mesh->mNumFaces;
for (std::size_t j = 0; j < faceNumber; j++) {
std::size_t offset = indicies.size();
std::size_t numIndices = faces[j].mNumIndices;
indicies.resize(indicies.size() + numIndices);
std::memcpy(indicies.data() + offset, faces[j].mIndices, numIndices * sizeof(unsigned int));
}
std::size_t vertNumber = mesh->mNumVertices;
aiVector3D* vertecies = mesh->mVertices;
for (std::size_t j = 0; j < vertNumber; j++) {
aiVector3D vertex = transform * vertecies[j];
positions.push_back(vertex.x);
positions.push_back(vertex.y);
positions.push_back(vertex.z);
}
if (mesh->HasNormals()) {
aiVector3D* vertexNormals = mesh->mNormals;
for (std::size_t j = 0; j < vertNumber; j++) {
aiVector3D normal = transform * vertexNormals[j];
normals.push_back(normal.x);
normals.push_back(normal.y);
normals.push_back(normal.z);
}
}
aiVector3D** vertexTexture = mesh->mTextureCoords;
for (std::size_t j = 0; j < vertNumber; j++) {
textureCoords.push_back(vertexTexture[0][j].x);
textureCoords.push_back(vertexTexture[0][j].y);
}
GL::VertexBuffer positionVBO(positions, VERTEX_SIZE);
positionVBO.AddVertexAttribPointer(VERTEX_POSITION_INDEX, VERTEX_SIZE, 0);
GL::VertexBuffer textureVBO(textureCoords, UV_SIZE);
textureVBO.AddVertexAttribPointer(VERTEX_UV_INDEX, UV_SIZE, 0);
GL::VertexBuffer normalVBO(normals, VERTEX_SIZE);
normalVBO.AddVertexAttribPointer(VERTEX_NORMAL_INDEX, VERTEX_SIZE, 0);
auto Vao = std::make_unique<GL::VertexArray>(GL::ElementBuffer{indicies});
Vao->Bind();
Vao->BindVertexBuffer(std::move(positionVBO));
Vao->BindVertexBuffer(std::move(textureVBO));
Vao->BindVertexBuffer(std::move(normalVBO));
Vao->Unbind();
return Vao;
}
static void ProcessNode(
aiNode* node, const aiScene* scene, std::vector<std::unique_ptr<GL::VertexArray>>& meshes, const aiMatrix4x4& transform) {
// recursive
for (unsigned int i = 0; i < node->mNumChildren; i++) {
ProcessNode(node->mChildren[i], scene, meshes, transform * node->mTransformation);
}
for (unsigned int i = 0; i < node->mNumMeshes; i++) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(ProcessMesh(mesh, scene, transform * node->mTransformation));
}
}
Model LoadModel(const std::string& fileName) {
// DataBuffer fileData = utils::AssetsManager::GetAsset(fileName);
sp::DataBuffer fileData;
fileData.ReadFile(fileName);
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(fileName, aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_SortByPType |
aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_GlobalScale);
if (!scene) {
std::cerr << "[ModelLoader] Failed to load model !\n";
return {};
}
// utils::LOGD(utils::Format("[ModelLoader]\tModel nodes : %i", scene->mRootNode->mNumMeshes));
Model model;
ProcessNode(scene->mRootNode, scene, model.m_Vaos, {});
std::cout << "Loaded " << model.m_Vaos.size() << " vaos !\n";
return model;
}
} // namespace ModelLoader
} // namespace td

View File

@@ -1,3 +1,4 @@
#include "td/render/Renderer.h"
#include <td/render/renderer/EntityRenderer.h>
#include <td/render/loader/WorldLoader.h>
@@ -6,7 +7,7 @@ namespace td {
namespace render {
EntityRenderer::EntityRenderer(Camera& a_Camera, const game::WorldPtr& a_World) : Renderer(a_Camera), m_World(a_World) {
m_EntityVao = std::make_unique<GL::VertexArray>(WorldLoader::LoadMobModel());
m_EntityModel = ModelLoader::LoadModel("assets/zombie.fbx");
m_Shader->Start();
m_Shader->SetColorEffect({1, 0, 1});
}
@@ -23,7 +24,7 @@ void EntityRenderer::Render(float a_Lerp) {
float z = Lerp<game::Mob>(*mob, a_Lerp, [](const game::Mob& a_Mob) { return static_cast<float>(a_Mob.m_Position.y); });
m_Shader->SetModelPos({x, .001, z});
Renderer::Render(*m_EntityVao);
Renderer::Render(m_EntityModel);
}
}

View File

@@ -3,7 +3,7 @@ add_rules("mode.debug", "mode.release")
add_repositories("persson-repo https://git.ale-pri.com/Persson-dev/xmake-repo.git")
add_requires("imgui 1.92.0", {configs = {sdl3 = true, opengl3 = true}})
add_requires("libsdl3 3.2.16", "splib 2.3.2", "zlib", "glew", "fpm", "enet6")
add_requires("libsdl3 3.2.16", "splib 2.3.2", "zlib", "glew", "fpm", "enet6", "assimp")
set_languages("c++20")
@@ -21,7 +21,7 @@ target("Tower-Defense2")
add_includedirs("include", {public = true})
set_kind("binary")
add_files("src/**.cpp")
add_packages("libsdl3", "imgui", "glew", "splib", "zlib", "fpm", "enet6", {public = true})
add_packages("libsdl3", "imgui", "glew", "splib", "zlib", "fpm", "assimp", "enet6", {public = true})
set_rundir(".")
add_defines("TD_GL_LOADER_GLEW")