Add better model loading, add test models

This commit is contained in:
bailwillharr 2022-11-21 17:14:31 +00:00
parent 6c50c37825
commit d91def268a
21 changed files with 2938 additions and 43 deletions

1
.gitignore vendored
View File

@ -10,6 +10,5 @@ MinSizeRel/
CMakeSettings.json CMakeSettings.json
compile_commands.json compile_commands.json
runme runme
res
*.log *.log

View File

@ -30,6 +30,8 @@ set(SRC_FILES
"src/resources/texture.cpp" "src/resources/texture.cpp"
"src/resources/font.cpp" "src/resources/font.cpp"
"src/util/model_loader.cpp"
"src/resource_manager.cpp" "src/resource_manager.cpp"
"src/gfx_device_vulkan.cpp" "src/gfx_device_vulkan.cpp"
@ -70,6 +72,8 @@ set(INCLUDE_FILES
"include/resources/texture.hpp" "include/resources/texture.hpp"
"include/resources/font.hpp" "include/resources/font.hpp"
"include/util/model_loader.hpp"
"include/resource_manager.hpp" "include/resource_manager.hpp"
"include/gfx.hpp" "include/gfx.hpp"
@ -214,6 +218,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE dependencies/stb)
# assimp # assimp
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE)
set(ASSIMP_BUILD_TESTS OFF CACHE INTERNAL "" FORCE) set(ASSIMP_BUILD_TESTS OFF CACHE INTERNAL "" FORCE)
set(ASSIMP_NO_EXPORT OFF CACHE INTERNAL "" FORCE)
set(ASSIMP_INSTALL OFF CACHE INTERNAL "" FORCE) set(ASSIMP_INSTALL OFF CACHE INTERNAL "" FORCE)
add_subdirectory(dependencies/assimp) add_subdirectory(dependencies/assimp)
target_include_directories(${PROJECT_NAME} PRIVATE dependencies/assimp/include) target_include_directories(${PROJECT_NAME} PRIVATE dependencies/assimp/include)

View File

@ -29,9 +29,6 @@ public:
std::shared_ptr<resources::Mesh> m_mesh = nullptr; std::shared_ptr<resources::Mesh> m_mesh = nullptr;
std::shared_ptr<resources::Texture> m_texture; std::shared_ptr<resources::Texture> m_texture;
glm::vec3 m_color = { 1.0f, 1.0f, 1.0f };
glm::vec3 m_emission = { 0.0f, 0.0f, 0.0f };
private: private:
std::shared_ptr<resources::Shader> m_shader; std::shared_ptr<resources::Shader> m_shader;

View File

@ -23,7 +23,6 @@ public:
struct UniformBuffer { struct UniformBuffer {
glm::mat4 p; glm::mat4 p;
glm::vec4 color;
}; };
gfx::Pipeline* getPipeline() gfx::Pipeline* getPipeline()

View File

@ -0,0 +1,11 @@
#pragma once
#include "object.hpp"
#include <string>
namespace engine::util {
Object* loadAssimpMeshFromFile(Object* parent, const std::string& path);
}

View File

@ -17,7 +17,7 @@ namespace engine::components {
Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER) Renderer::Renderer(Object* parent) : Component(parent, TypeEnum::RENDERER)
{ {
m_shader = this->parent.res.get<resources::Shader>("shader.glsl"); m_shader = this->parent.res.get<resources::Shader>("shader.glsl");
m_texture = this->parent.res.get<resources::Texture>("textures/missing.png"); m_texture = this->parent.res.get<resources::Texture>("textures/white.png");
} }
Renderer::~Renderer() Renderer::~Renderer()
@ -28,8 +28,6 @@ Renderer::~Renderer()
void Renderer::render(glm::mat4 transform, glm::mat4 view) void Renderer::render(glm::mat4 transform, glm::mat4 view)
{ {
resources::Shader::UniformBuffer uniformData{}; resources::Shader::UniformBuffer uniformData{};
uniformData.color = glm::vec4{ m_color.r, m_color.g, m_color.b, 1.0 };
gfxdev->updateUniformBuffer(m_shader->getPipeline(), &uniformData.color, sizeof(uniformData.color), offsetof(resources::Shader::UniformBuffer, color));
glm::mat4 pushConsts[] = { transform, view }; glm::mat4 pushConsts[] = { transform, view };
gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_indices.size(), pushConsts, sizeof(glm::mat4) * 2, m_texture->getHandle()); gfxdev->draw(m_shader->getPipeline(), m_mesh->vb, m_mesh->ib, m_mesh->m_indices.size(), pushConsts, sizeof(glm::mat4) * 2, m_texture->getHandle());

View File

@ -12,12 +12,9 @@ struct MeshFileHeader {
int32_t material; int32_t material;
}; };
static void loadMeshFromFile(const std::filesystem::path& path, std::vector<Vertex>* vertices, std::vector<uint32_t>* indices) static void loadCustomMeshFromFile(const std::filesystem::path& path, std::vector<Vertex>* vertices, std::vector<uint32_t>* indices)
{ {
// TODO
// Replace this aberation with something that's readable and doesn't use FILE*
struct MeshFileHeader header{}; struct MeshFileHeader header{};
FILE* fp = fopen(path.string().c_str(), "rb"); FILE* fp = fopen(path.string().c_str(), "rb");
@ -62,7 +59,13 @@ Mesh::Mesh(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& ind
// To be used with the resource manager // To be used with the resource manager
Mesh::Mesh(const std::filesystem::path& resPath) : Resource(resPath, "mesh") Mesh::Mesh(const std::filesystem::path& resPath) : Resource(resPath, "mesh")
{ {
loadMeshFromFile(resPath, &m_vertices, &m_indices); if (resPath.extension() == ".mesh") {
loadCustomMeshFromFile(resPath, &m_vertices, &m_indices);
}
else {
throw std::runtime_error("Mesh load error, unknown file type");
}
initMesh(); initMesh();
} }

213
src/util/model_loader.cpp Normal file
View File

@ -0,0 +1,213 @@
#include "util/model_loader.hpp"
#include "log.hpp"
#include "resources/texture.hpp"
#include "resources/mesh.hpp"
#include "components/mesh_renderer.hpp"
#include <assimp/Importer.hpp>
#include <assimp/LogStream.hpp>
#include <assimp/Logger.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/postprocess.h>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <glm/gtc/quaternion.hpp>
#include <map>
namespace engine::util {
static void buildGraph(
const std::map<int, std::shared_ptr<resources::Texture>>& textures,
const std::vector<std::shared_ptr<resources::Mesh>>& meshes,
const std::vector<unsigned int>& meshTextureIndices,
aiNode* parentNode, Object* parentObj)
{
// convert to glm column major
glm::mat4 transform;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
transform[i][j] = parentNode->mTransformation[j][i];
}
}
// get position
glm::vec3 position{ transform[3][0], transform[3][1], transform[3][2] };
// remove position from matrix
transform[3][0] = 0.0f;
transform[3][1] = 0.0f;
transform[3][2] = 0.0f;
// get scale
glm::vec3 scale{};
scale.x = sqrt(transform[0][0] * transform[0][0] + transform[0][1] * transform[0][1] + transform[0][2] * transform[0][2]);
scale.y = sqrt(transform[1][0] * transform[1][0] + transform[1][1] * transform[1][1] + transform[1][2] * transform[1][2]);
scale.z = sqrt(transform[2][0] * transform[2][0] + transform[2][1] * transform[2][1] + transform[2][2] * transform[2][2]);
// remove scaling from matrix
for (int row = 0; row < 3; row++) {
transform[0][row] /= scale.x;
transform[1][row] /= scale.y;
transform[2][row] /= scale.z;
}
// get rotation
glm::quat rotation = glm::quat_cast(transform);
// update position, scale, rotation
parentObj->transform.position = position;
parentObj->transform.scale = scale;
parentObj->transform.rotation = rotation;
for (int i = 0; i < parentNode->mNumMeshes; i++) {
// create child node for each mesh
auto child = parentObj->createChild("_mesh" + std::to_string(i));
auto childRenderer = child->createComponent<components::Renderer>();
childRenderer->m_mesh = meshes[parentNode->mMeshes[i]];
if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) {
childRenderer->m_texture = textures.at(meshTextureIndices[parentNode->mMeshes[i]]);
}
}
for (int i = 0; i < parentNode->mNumChildren; i++) {
buildGraph(textures, meshes, meshTextureIndices, parentNode->mChildren[i], parentObj->createChild("child" + std::to_string(i)));
}
}
Object* loadAssimpMeshFromFile(Object* parent, const std::string& path)
{
Assimp::Importer importer;
class myStream : public Assimp::LogStream {
public:
void write(const char* message) override {
DEBUG("ASSIMP: {}", message);
}
};
const unsigned int severity = Assimp::Logger::Debugging | Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
Assimp::DefaultLogger::get()->attachStream(new myStream, severity);
// remove everything but texcoords, normals, meshes, materials
importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
aiComponent_ANIMATIONS |
aiComponent_BONEWEIGHTS |
aiComponent_CAMERAS |
aiComponent_COLORS |
aiComponent_LIGHTS |
aiComponent_TANGENTS_AND_BITANGENTS |
aiComponent_TEXTURES |
0
);
importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,
aiPrimitiveType_POINT |
aiPrimitiveType_LINE |
aiPrimitiveType_POLYGON
);
const aiScene* scene = importer.ReadFile(path,
aiProcess_JoinIdenticalVertices |
aiProcess_Triangulate |
aiProcess_SortByPType |
aiProcess_RemoveComponent |
aiProcess_SplitLargeMeshes | // leave at default maximum
aiProcess_ValidateDataStructure | // make sure to log the output
aiProcess_ImproveCacheLocality |
aiProcess_RemoveRedundantMaterials |
aiProcess_FindInvalidData |
aiProcess_GenSmoothNormals |
aiProcess_GenUVCoords |
aiProcess_TransformUVCoords |
aiProcess_FlipUVs | // Maybe?
0
);
const char* errString = importer.GetErrorString();
if (errString[0] != '\0' || scene == nullptr) {
throw std::runtime_error(errString);
}
if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
throw std::runtime_error(errString);
}
assert(scene->HasAnimations() == false);
assert(scene->HasCameras() == false);
assert(scene->HasLights() == false);
assert(scene->hasSkeletons() == false);
INFO("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes);
std::map<int, std::shared_ptr<resources::Texture>> textures{};
for (int i = 0; i < scene->mNumMaterials; i++) {
const aiMaterial* m = scene->mMaterials[i];
INFO("Material {}:", i);
INFO(" Name: {}", m->GetName().C_Str());
for (int j = 0; j < m->mNumProperties; j++) {
const aiMaterialProperty* p = m->mProperties[j];
INFO(" prop {}, key: {}", j, p->mKey.C_Str());
}
if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) {
aiString texPath{};
aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath);
INFO(" Diffuse tex: {}", texPath.C_Str());
std::filesystem::path absPath = path;
absPath = absPath.parent_path();
absPath /= texPath.C_Str();
textures[i] = std::make_shared<resources::Texture>(absPath);
}
}
std::vector<std::shared_ptr<resources::Mesh>> meshes{};
std::vector<unsigned int> meshMaterialIndices{};
for (int i = 0; i < scene->mNumMeshes; i++) {
const aiMesh* m = scene->mMeshes[i];
meshMaterialIndices.push_back(m->mMaterialIndex);
std::vector<Vertex> vertices(m->mNumVertices);
std::vector<uint32_t> indices(m->mNumFaces * 3);
INFO("Mesh {}: vertex count {}", i, vertices.size());
INFO("Mesh {}: index count {}", i, indices.size());
for (int j = 0; j < vertices.size(); j++) {
Vertex v{};
v.pos.x = m->mVertices[j].x;
v.pos.y = m->mVertices[j].y;
v.pos.z = m->mVertices[j].z;
v.norm.x = m->mNormals[j].x;
v.norm.y = m->mNormals[j].y;
v.norm.z = m->mNormals[j].z;
vertices[j] = v;
}
if (m->mNumUVComponents[0] >= 2) {
for (int j = 0; j < vertices.size(); j++) {
vertices[j].uv.x = m->mTextureCoords[0][j].x;
vertices[j].uv.y = m->mTextureCoords[0][j].y;
}
}
for (int j = 0; j < indices.size() / 3; j++) {
indices[j * 3 + 0] = m->mFaces[j].mIndices[0];
indices[j * 3 + 1] = m->mFaces[j].mIndices[1];
indices[j * 3 + 2] = m->mFaces[j].mIndices[2];
}
meshes.push_back(std::make_shared<resources::Mesh>(vertices, indices));
}
Object* obj = parent->createChild(scene->GetShortFilename(path.c_str()));
buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, obj);
Assimp::DefaultLogger::kill();
return obj;
}
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,6 @@ layout(location = 0) in vec3 fragPos;
layout(location = 1) in vec3 fragNorm; layout(location = 1) in vec3 fragNorm;
layout(location = 2) in vec2 fragUV; layout(location = 2) in vec2 fragUV;
layout(location = 3) in vec3 fragLightPos; layout(location = 3) in vec3 fragLightPos;
layout(location = 4) in vec3 fragColor;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;

View File

@ -2,7 +2,6 @@
layout(binding = 0) uniform UBO { layout(binding = 0) uniform UBO {
mat4 proj; mat4 proj;
vec4 color;
} ubo; } ubo;
layout( push_constant ) uniform Constants { layout( push_constant ) uniform Constants {
@ -18,7 +17,6 @@ layout(location = 0) out vec3 fragPos;
layout(location = 1) out vec3 fragNorm; layout(location = 1) out vec3 fragNorm;
layout(location = 2) out vec2 fragUV; layout(location = 2) out vec2 fragUV;
layout(location = 3) out vec3 fragLightPos; layout(location = 3) out vec3 fragLightPos;
layout(location = 4) out vec3 fragColor;
void main() { void main() {
gl_Position = ubo.proj * constants.view * constants.model * vec4(inPosition, 1.0); gl_Position = ubo.proj * constants.view * constants.model * vec4(inPosition, 1.0);
@ -27,6 +25,5 @@ void main() {
fragUV = inUV; fragUV = inUV;
vec3 lightPos = vec3(-5.0, 20.0, 5.0); vec3 lightPos = vec3(-5.0, 20.0, 5.0);
fragLightPos = vec3(constants.view * vec4(lightPos, 1.0)); fragLightPos = vec3(constants.view * vec4(lightPos, 1.0));
fragColor = ubo.color.rgb;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

View File

@ -12,6 +12,8 @@
#include "resource_manager.hpp" #include "resource_manager.hpp"
#include "resources/texture.hpp" #include "resources/texture.hpp"
#include "util/model_loader.hpp"
#include "camera_controller.hpp" #include "camera_controller.hpp"
#include "meshgen.hpp" #include "meshgen.hpp"
@ -68,7 +70,6 @@ void playGame()
auto gunRenderer = gun->createComponent<engine::components::Renderer>(); auto gunRenderer = gun->createComponent<engine::components::Renderer>();
gunRenderer->setMesh("meshes/gun.mesh"); gunRenderer->setMesh("meshes/gun.mesh");
gunRenderer->setTexture("textures/gun.png"); gunRenderer->setTexture("textures/gun.png");
gunRenderer->m_color = { 0.2f, 0.3f, 0.2f };
// FLOOR // FLOOR
@ -86,12 +87,10 @@ void playGame()
{ { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } } { { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } }
}); });
floor->transform.scale = { 100.0f, 1.0f, 100.0f }; floor->transform.scale = { 100.0f, 1.0f, 100.0f };
floorRenderer->m_color = { 0.1f, 0.9f, 0.1f };
auto cube = app.scene()->createChild("cube"); auto cube = app.scene()->createChild("cube");
auto cubeRen = cube->createComponent<engine::components::Renderer>(); auto cubeRen = cube->createComponent<engine::components::Renderer>();
cubeRen->setMesh("meshes/cube.mesh"); cubeRen->setMesh("meshes/cube.mesh");
cubeRen->m_color = { 0.8f, 0.2f, 0.05f };
cube->transform.position = glm::vec3{ -5.0f, 1.0f, 0.0f }; cube->transform.position = glm::vec3{ -5.0f, 1.0f, 0.0f };
class Spin : public engine::components::CustomComponent { class Spin : public engine::components::CustomComponent {
@ -112,6 +111,14 @@ void playGame()
yawQuat.z = 0.0f; yawQuat.z = 0.0f;
yawQuat.w = glm::cos(halfYaw); yawQuat.w = glm::cos(halfYaw);
parent.transform.rotation = yawQuat; parent.transform.rotation = yawQuat;
constexpr float halfPitch = -glm::half_pi<float>() / 2.0f;
glm::quat pitchQuat{};
pitchQuat.x = glm::sin(halfPitch);
pitchQuat.y = 0.0f;
pitchQuat.z = 0.0f;
pitchQuat.w = glm::cos(halfPitch);
parent.transform.rotation *= pitchQuat;
} }
private: private:
@ -128,35 +135,26 @@ void playGame()
sphereRenderer->m_mesh = genSphereMesh(5.0f, 100, false); sphereRenderer->m_mesh = genSphereMesh(5.0f, 100, false);
sphereRenderer->setTexture("textures/cobble_stone.png"); sphereRenderer->setTexture("textures/cobble_stone.png");
/* castle */
auto castle = app.scene()->createChild("castle");
castle->transform.scale = { 0.01f, 0.01f, 0.01f };
std::vector<engine::Object*> castleParts(6);
for (int i = 0; i < castleParts.size(); i++) {
if (i == 2) continue;
castleParts[i] = castle->createChild(std::to_string(i));
auto ren = castleParts[i]->createComponent<engine::components::Renderer>();
ren->setMesh("meshes/castle_" + std::to_string(i) + ".mesh");
ren->setTexture("textures/rock.jpg");
if (i == 5) {
ren->setTexture("textures/metal.jpg");
}
if (i == 4) {
ren->setTexture("textures/door.jpg");
}
}
// boundary // boundary
auto bounds = app.scene()->createChild("bounds"); auto bounds = app.scene()->createChild("bounds");
auto boundsRen = bounds->createComponent<engine::components::Renderer>(); auto boundsRen = bounds->createComponent<engine::components::Renderer>();
boundsRen->m_mesh = genSphereMesh(100.0f, 100, true); boundsRen->m_mesh = genSphereMesh(100.0f, 100, true);
boundsRen->setTexture("textures/metal.jpg"); boundsRen->setTexture("textures/metal.jpg");
auto pyramid = app.scene()->createChild("pyramid"); auto myModel = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/pyramid/pyramid.dae").string());
auto pyramidRen = pyramid->createComponent<engine::components::Renderer>();
pyramidRen->setMesh("meshes/pyramid.mesh"); auto myRoom = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/room/room.dae").string());
pyramidRen->setTexture("textures/pyramid.png");
auto astronaut = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/astronaut/astronaut.dae").string());
astronaut->transform.position.z += 5.0f;
astronaut->createComponent<Spin>();
auto plane = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/plane/plane.dae").string());
plane->transform.position = { -30.0f, 2.0f, 10.0f };
// END TESTING
app.scene()->printTree();
app.gameLoop(); app.gameLoop();
} }