mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
try getting normal maps to work
This commit is contained in:
parent
53804696b3
commit
b58d343c8d
@ -199,7 +199,7 @@ target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/glm)
|
|||||||
|
|
||||||
# spdlog
|
# spdlog
|
||||||
set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE)
|
set(SPDLOG_BUILD_SHARED OFF CACHE INTERNAL "" FORCE)
|
||||||
|
set(SPDLOG_SYSTEM_INCLUDES ON CACHE INTERNAL "" FORCE)
|
||||||
set(BUILD_SHARED_LIBS OFF)
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
add_subdirectory(dependencies/spdlog)
|
add_subdirectory(dependencies/spdlog) # automatically calls target_include_directories
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog)
|
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog)
|
||||||
target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC dependencies/spdlog/include)
|
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
struct MeshRenderableComponent {
|
struct MeshRenderableComponent {
|
||||||
std::shared_ptr<resources::Mesh> mesh;
|
std::shared_ptr<Mesh> mesh;
|
||||||
std::shared_ptr<resources::Material> material;
|
std::shared_ptr<Material> material;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
@ -33,7 +33,7 @@ class Renderer {
|
|||||||
void PreRender(bool window_is_resized, glm::mat4 camera_transform);
|
void PreRender(bool window_is_resized, glm::mat4 camera_transform);
|
||||||
|
|
||||||
// staticList can be nullptr to render nothing
|
// staticList can be nullptr to render nothing
|
||||||
void Render(const RenderList& static_list, const RenderList& dynamic_list);
|
void Render(const RenderList* static_list, const RenderList* dynamic_list);
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
|
|
||||||
@ -78,7 +78,10 @@ class Renderer {
|
|||||||
*/
|
*/
|
||||||
// ALL fragment shaders must begin with:
|
// ALL fragment shaders must begin with:
|
||||||
/*
|
/*
|
||||||
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
|
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
|
||||||
|
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler;
|
||||||
|
layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// in vertex shader
|
// in vertex shader
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include <stb_truetype.h>
|
#include <stb_truetype.h>
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
namespace resources {
|
|
||||||
|
|
||||||
class Font {
|
class Font {
|
||||||
public:
|
public:
|
||||||
@ -31,7 +30,6 @@ class Font {
|
|||||||
int GetGlyphIndex(int unicode_codepoint);
|
int GetGlyphIndex(int unicode_codepoint);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resources
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -6,26 +6,37 @@
|
|||||||
#include "resources/shader.h"
|
#include "resources/shader.h"
|
||||||
#include "resources/texture.h"
|
#include "resources/texture.h"
|
||||||
|
|
||||||
|
// a material is just a shader with assigned textures/parameters
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
namespace resources {
|
|
||||||
|
|
||||||
// copyable
|
// copyable
|
||||||
class Material {
|
class Material {
|
||||||
public:
|
public:
|
||||||
Material(std::shared_ptr<Shader> shader);
|
Material(Renderer* renderer, std::shared_ptr<engine::Shader> shader);
|
||||||
~Material() = default;
|
~Material();
|
||||||
Material(const Material&);
|
Material& operator=(const Material&) = delete;
|
||||||
Material& operator=(const Material&) = delete;
|
|
||||||
|
|
||||||
auto GetShader() { return shader_.get(); }
|
void SetAlbedoTexture(std::shared_ptr<Texture> texture);
|
||||||
|
void SetNormalTexture(std::shared_ptr<Texture> texture);
|
||||||
|
void SetOcclusionTexture(std::shared_ptr<Texture> texture);
|
||||||
|
void SetMetallicRoughnessTexture(std::shared_ptr<Texture> texture);
|
||||||
|
|
||||||
std::shared_ptr<Texture> texture_;
|
const gfx::DescriptorSet* GetDescriptorSet() { return material_set_; }
|
||||||
|
Shader* GetShader() { return shader_.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::shared_ptr<Shader> shader_;
|
const std::shared_ptr<Shader> shader_;
|
||||||
|
std::shared_ptr<Texture> texture_albedo_;
|
||||||
|
std::shared_ptr<Texture> texture_normal_;
|
||||||
|
std::shared_ptr<Texture> texture_occlusion_;
|
||||||
|
std::shared_ptr<Texture> texture_metallic_roughness_;
|
||||||
|
|
||||||
|
const gfx::DescriptorSet* material_set_ = nullptr;
|
||||||
|
|
||||||
|
Renderer* const renderer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resources
|
} // namespace engine
|
||||||
} // namespace engine
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
#include <glm/vec3.hpp>
|
#include <glm/vec3.hpp>
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
@ -13,13 +14,13 @@ namespace engine {
|
|||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec3 pos;
|
glm::vec3 pos;
|
||||||
glm::vec3 norm;
|
glm::vec3 norm;
|
||||||
|
glm::vec4 tangent; // w component flips binormal if -1. w should be 1 or -1
|
||||||
glm::vec2 uv;
|
glm::vec2 uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
namespace resources {
|
|
||||||
|
|
||||||
class Mesh {
|
class Mesh {
|
||||||
public:
|
public:
|
||||||
@ -48,7 +49,6 @@ class Mesh {
|
|||||||
const std::vector<uint32_t>& indices);
|
const std::vector<uint32_t>& indices);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resources
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,12 +1,10 @@
|
|||||||
#ifndef ENGINE_INCLUDE_RESOURCES_SHADER_H_
|
#pragma once
|
||||||
#define ENGINE_INCLUDE_RESOURCES_SHADER_H_
|
|
||||||
|
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "gfx_device.h"
|
#include "gfx_device.h"
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
namespace resources {
|
|
||||||
|
|
||||||
class Shader {
|
class Shader {
|
||||||
public:
|
public:
|
||||||
@ -43,7 +41,4 @@ class Shader {
|
|||||||
const int render_order_;
|
const int render_order_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resources
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
|
@ -7,36 +7,33 @@
|
|||||||
#include "gfx_device.h"
|
#include "gfx_device.h"
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
namespace resources {
|
|
||||||
|
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
enum class Filtering {
|
enum class Filtering {
|
||||||
kOff,
|
kOff,
|
||||||
kBilinear,
|
kBilinear,
|
||||||
kTrilinear,
|
kTrilinear,
|
||||||
kAnisotropic,
|
kAnisotropic,
|
||||||
};
|
};
|
||||||
|
|
||||||
Texture(Renderer* renderer, const std::string& path,
|
Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height, Filtering filtering);
|
||||||
Filtering filtering);
|
|
||||||
Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height,
|
|
||||||
Filtering filtering);
|
|
||||||
|
|
||||||
~Texture();
|
~Texture();
|
||||||
Texture(const Texture&) = delete;
|
Texture(const Texture&) = delete;
|
||||||
Texture& operator=(const Texture&) = delete;
|
Texture& operator=(const Texture&) = delete;
|
||||||
|
|
||||||
const gfx::Image* GetImage() { return image_; }
|
const gfx::Image* GetImage() { return image_; }
|
||||||
const gfx::DescriptorSet* GetDescriptorSet() { return descriptor_set_; }
|
const gfx::Sampler* GetSampler() { return sampler_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GFXDevice* gfx_;
|
GFXDevice* gfx_;
|
||||||
const gfx::Image* image_;
|
const gfx::Image* image_;
|
||||||
const gfx::DescriptorSet* descriptor_set_;
|
const gfx::Sampler* sampler_; // not owned by Texture, owned by Renderer
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resources
|
std::unique_ptr<Texture> LoadTextureFromFile(const std::string& path, Texture::Filtering filtering, Renderer* renderer);
|
||||||
} // namespace engine
|
|
||||||
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -12,26 +12,50 @@ namespace engine {
|
|||||||
class Application;
|
class Application;
|
||||||
|
|
||||||
class SceneManager {
|
class SceneManager {
|
||||||
public:
|
public:
|
||||||
SceneManager(Application* app);
|
SceneManager(Application* app);
|
||||||
~SceneManager();
|
~SceneManager();
|
||||||
SceneManager(const SceneManager&) = delete;
|
SceneManager(const SceneManager&) = delete;
|
||||||
SceneManager& operator=(const SceneManager&) = delete;
|
SceneManager& operator=(const SceneManager&) = delete;
|
||||||
|
|
||||||
// creates an empty scene and sets it as active
|
// creates an empty scene and sets it as active
|
||||||
Scene* CreateEmptyScene();
|
Scene* CreateEmptyScene();
|
||||||
|
|
||||||
// returns active scene, nullptr if no scene active
|
// nullptr deactivates the active scene
|
||||||
Scene* UpdateActiveScene(float ts);
|
void SetActiveScene(Scene* scene)
|
||||||
Scene* GetActiveScene() { return scenes_.at(active_scene_index_).get(); }
|
{
|
||||||
|
if (scene == nullptr) {
|
||||||
|
active_scene_index_ = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// linear search for scene
|
||||||
|
int index = 0;
|
||||||
|
for (const auto& unique_scene : scenes_) {
|
||||||
|
if (unique_scene.get() == scene) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
if (index >= scenes_.size()) {
|
||||||
|
throw std::runtime_error("Failed to find active scene!");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
active_scene_index_ = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
// returns active scene, nullptr if no scene active
|
||||||
Application* const app_;
|
Scene* UpdateActiveScene(float ts);
|
||||||
|
Scene* GetActiveScene() { return scenes_.at(active_scene_index_).get(); }
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Scene>> scenes_;
|
private:
|
||||||
int active_scene_index_ = -1;
|
Application* const app_;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Scene>> scenes_;
|
||||||
|
int active_scene_index_ = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,5 +1,4 @@
|
|||||||
#ifndef ENGINE_INCLUDE_SYSTEMS_MESH_RENDER_SYSTEM_H_
|
#pragma once
|
||||||
#define ENGINE_INCLUDE_SYSTEMS_MESH_RENDER_SYSTEM_H_
|
|
||||||
|
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ struct RenderListEntry {
|
|||||||
const gfx::Pipeline* pipeline;
|
const gfx::Pipeline* pipeline;
|
||||||
const gfx::Buffer* vertex_buffer;
|
const gfx::Buffer* vertex_buffer;
|
||||||
const gfx::Buffer* index_buffer;
|
const gfx::Buffer* index_buffer;
|
||||||
const gfx::DescriptorSet* base_colour_texture;
|
const gfx::DescriptorSet* material_set;
|
||||||
glm::mat4 model_matrix;
|
glm::mat4 model_matrix;
|
||||||
uint32_t index_count;
|
uint32_t index_count;
|
||||||
};
|
};
|
||||||
@ -44,5 +43,3 @@ class MeshRenderSystem : public System {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
|
||||||
#endif
|
|
@ -14,7 +14,7 @@ std::unique_ptr<std::vector<uint8_t>> ReadBinaryFile(const std::string& path);
|
|||||||
// Read an image file into a vector byte buffer. PNG and JPG support at a
|
// Read an image file into a vector byte buffer. PNG and JPG support at a
|
||||||
// minimum. Output format is R8G8B8A8_UINT
|
// minimum. Output format is R8G8B8A8_UINT
|
||||||
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
|
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
|
||||||
int* width, int* height);
|
int& width, int& height);
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
42
res/engine/shaders/fancy.frag
Normal file
42
res/engine/shaders/fancy.frag
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
|
||||||
|
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler;
|
||||||
|
layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragPos;
|
||||||
|
layout(location = 1) in vec3 fragNorm;
|
||||||
|
layout(location = 2) in vec2 fragUV;
|
||||||
|
layout(location = 3) in vec3 fragViewPos;
|
||||||
|
layout(location = 4) in vec3 fragLightPos;
|
||||||
|
layout(location = 5) in mat3 fragTBN;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
|
||||||
|
// constants
|
||||||
|
vec3 lightColor = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 ambientColor = vec3(1.0, 1.0, 1.0);
|
||||||
|
float ambientStrength = 0.05;
|
||||||
|
vec3 emission = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
vec3 baseColor = vec3(texture(materialSetAlbedoSampler, fragUV));
|
||||||
|
|
||||||
|
vec3 norm = vec3(texture(materialSetNormalSampler, fragUV));
|
||||||
|
norm = normalize(norm * 2.0 - 1.0);
|
||||||
|
|
||||||
|
vec3 lightDir = fragTBN * normalize(fragLightPos - fragPos);
|
||||||
|
vec3 viewDir = fragTBN * normalize(fragViewPos - fragPos);
|
||||||
|
|
||||||
|
vec3 diffuse = max(dot(norm, lightDir), 0.0) * lightColor;
|
||||||
|
vec3 ambient = ambientColor * ambientStrength;
|
||||||
|
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||||
|
float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
|
||||||
|
vec3 specular = spec * lightColor;
|
||||||
|
|
||||||
|
vec3 lighting = min(diffuse + ambient + specular, 1.0);
|
||||||
|
outColor = min( ( vec4(baseColor, 1.0) ) * vec4(lighting + emission, 1.0), vec4(1.0));
|
||||||
|
}
|
||||||
|
|
43
res/engine/shaders/fancy.vert
Normal file
43
res/engine/shaders/fancy.vert
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer {
|
||||||
|
mat4 proj;
|
||||||
|
} globalSetUniformBuffer;
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform FrameSetUniformBuffer {
|
||||||
|
mat4 view;
|
||||||
|
} frameSetUniformBuffer;
|
||||||
|
|
||||||
|
layout( push_constant ) uniform Constants {
|
||||||
|
mat4 model;
|
||||||
|
} constants;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
layout(location = 1) in vec3 inNorm;
|
||||||
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragPos;
|
||||||
|
layout(location = 1) out vec3 fragNorm;
|
||||||
|
layout(location = 2) out vec2 fragUV;
|
||||||
|
layout(location = 3) out vec3 fragViewPos;
|
||||||
|
layout(location = 4) out vec3 fragLightPos;
|
||||||
|
layout(location = 5) out mat3 fragTBN;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = globalSetUniformBuffer.proj * frameSetUniformBuffer.view * constants.model * vec4(inPosition, 1.0);
|
||||||
|
|
||||||
|
mat3 normalMatrix = mat3(transpose(inverse(constants.model)));
|
||||||
|
|
||||||
|
fragPos = vec3(constants.model * vec4(inPosition, 1.0));
|
||||||
|
fragNorm = normalize(normalMatrix * inNorm);
|
||||||
|
fragUV = inUV;
|
||||||
|
fragViewPos = vec3(inverse(frameSetUniformBuffer.view) * vec4(0.0, 0.0, 0.0, 1.0));
|
||||||
|
fragLightPos = vec3(2000.0, -2000.0, 2000.0);
|
||||||
|
|
||||||
|
vec3 T = normalize(normalMatrix * inTangent.xyz);
|
||||||
|
vec3 B = cross(fragNorm, T) * inTangent.w; // from unity docs, w flips the binormal
|
||||||
|
fragTBN = transpose(mat3(T, B, fragNorm));
|
||||||
|
|
||||||
|
gl_Position.y *= -1.0;
|
||||||
|
}
|
@ -14,7 +14,8 @@ layout( push_constant ) uniform Constants {
|
|||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inNorm;
|
layout(location = 1) in vec3 inNorm;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec2 fragUV;
|
layout(location = 0) out vec2 fragUV;
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ layout(set = 0, binding = 0) uniform SetZeroBuffer {
|
|||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inNorm;
|
layout(location = 1) in vec3 inNorm;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragNorm;
|
layout(location = 0) out vec3 fragNorm;
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ layout(set = 0, binding = 0) uniform SetZeroBuffer {
|
|||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inNorm;
|
layout(location = 1) in vec3 inNorm;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec2 fragUV;
|
layout(location = 0) out vec2 fragUV;
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
|
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
|
||||||
|
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler;
|
||||||
|
layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler;
|
||||||
|
|
||||||
layout(location = 0) in vec2 fragUV;
|
layout(location = 0) in vec2 fragUV;
|
||||||
|
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = texture(materialSetSampler, fragUV);
|
outColor = texture(materialSetAlbedoSampler, fragUV);
|
||||||
}
|
}
|
@ -13,7 +13,9 @@ layout( push_constant ) uniform Constants {
|
|||||||
} constants;
|
} constants;
|
||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 1) in vec3 inNorm;
|
||||||
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec2 fragUV;
|
layout(location = 0) out vec2 fragUV;
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
|
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
|
||||||
|
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
|
||||||
|
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler;
|
||||||
|
layout(set = 2, binding = 3) uniform sampler2D materialSetMetallicRoughnessSampler;
|
||||||
|
|
||||||
layout(location = 0) in vec3 fragPos;
|
layout(location = 0) in vec3 fragPos;
|
||||||
layout(location = 1) in vec3 fragNorm;
|
layout(location = 1) in vec3 fragNorm;
|
||||||
@ -15,7 +18,7 @@ void main() {
|
|||||||
vec3 lightColor = vec3(1.0, 1.0, 1.0);
|
vec3 lightColor = vec3(1.0, 1.0, 1.0);
|
||||||
vec3 ambientColor = vec3(1.0, 1.0, 1.0);
|
vec3 ambientColor = vec3(1.0, 1.0, 1.0);
|
||||||
float ambientStrength = 0.05;
|
float ambientStrength = 0.05;
|
||||||
vec3 baseColor = vec3(texture(materialSetSampler, fragUV));
|
vec3 baseColor = vec3(texture(materialSetAlbedoSampler, fragUV));
|
||||||
vec3 emission = vec3(0.0, 0.0, 0.0);
|
vec3 emission = vec3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
// code
|
// code
|
||||||
|
@ -14,7 +14,8 @@ layout( push_constant ) uniform Constants {
|
|||||||
|
|
||||||
layout(location = 0) in vec3 inPosition;
|
layout(location = 0) in vec3 inPosition;
|
||||||
layout(location = 1) in vec3 inNorm;
|
layout(location = 1) in vec3 inNorm;
|
||||||
layout(location = 2) in vec2 inUV;
|
layout(location = 2) in vec4 inTangent;
|
||||||
|
layout(location = 3) in vec2 inUV;
|
||||||
|
|
||||||
layout(location = 0) out vec3 fragPos;
|
layout(location = 0) out vec3 fragPos;
|
||||||
layout(location = 1) out vec3 fragNorm;
|
layout(location = 1) out vec3 fragNorm;
|
||||||
|
@ -83,11 +83,11 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
|
|||||||
resources_path_ = getResourcesPath();
|
resources_path_ = getResourcesPath();
|
||||||
|
|
||||||
// register resource managers
|
// register resource managers
|
||||||
RegisterResourceManager<resources::Mesh>();
|
RegisterResourceManager<Mesh>();
|
||||||
RegisterResourceManager<resources::Material>();
|
RegisterResourceManager<Material>();
|
||||||
RegisterResourceManager<resources::Texture>();
|
RegisterResourceManager<Texture>();
|
||||||
RegisterResourceManager<resources::Shader>();
|
RegisterResourceManager<Shader>();
|
||||||
RegisterResourceManager<resources::Font>();
|
RegisterResourceManager<Font>();
|
||||||
|
|
||||||
im_gui_things.context = ImGui::CreateContext();
|
im_gui_things.context = ImGui::CreateContext();
|
||||||
// ImGuiIO& io = ImGui::GetIO()
|
// ImGuiIO& io = ImGui::GetIO()
|
||||||
@ -97,58 +97,78 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
|
|||||||
|
|
||||||
/* default fonts */
|
/* default fonts */
|
||||||
{
|
{
|
||||||
auto monoFont = std::make_unique<resources::Font>(GetResourcePath("engine/fonts/mono.ttf"));
|
auto monoFont = std::make_unique<Font>(GetResourcePath("engine/fonts/mono.ttf"));
|
||||||
GetResourceManager<resources::Font>()->AddPersistent("builtin.mono", std::move(monoFont));
|
GetResourceManager<Font>()->AddPersistent("builtin.mono", std::move(monoFont));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* default shaders */
|
/* default shaders */
|
||||||
{
|
{
|
||||||
resources::Shader::VertexParams vertParams{};
|
Shader::VertexParams vertParams{};
|
||||||
vertParams.has_normal = true;
|
vertParams.has_normal = true;
|
||||||
|
vertParams.has_tangent = true;
|
||||||
vertParams.has_uv0 = true;
|
vertParams.has_uv0 = true;
|
||||||
resources::Shader::ShaderSettings shaderSettings{};
|
Shader::ShaderSettings shaderSettings{};
|
||||||
shaderSettings.vertexParams = vertParams;
|
shaderSettings.vertexParams = vertParams;
|
||||||
shaderSettings.alpha_blending = false;
|
shaderSettings.alpha_blending = false;
|
||||||
shaderSettings.cull_backface = true;
|
shaderSettings.cull_backface = true;
|
||||||
shaderSettings.write_z = true;
|
shaderSettings.write_z = true;
|
||||||
shaderSettings.render_order = 0;
|
shaderSettings.render_order = 0;
|
||||||
auto texturedShader = std::make_unique<resources::Shader>(renderer(), GetResourcePath("engine/shaders/standard.vert").c_str(),
|
auto texturedShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/standard.vert").c_str(),
|
||||||
GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings);
|
GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings);
|
||||||
GetResourceManager<resources::Shader>()->AddPersistent("builtin.standard", std::move(texturedShader));
|
GetResourceManager<Shader>()->AddPersistent("builtin.standard", std::move(texturedShader));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
resources::Shader::VertexParams vertParams{};
|
Shader::VertexParams vertParams{};
|
||||||
vertParams.has_normal = true;
|
vertParams.has_normal = true;
|
||||||
|
vertParams.has_tangent = true;
|
||||||
vertParams.has_uv0 = true;
|
vertParams.has_uv0 = true;
|
||||||
resources::Shader::ShaderSettings shaderSettings{};
|
Shader::ShaderSettings shaderSettings{};
|
||||||
shaderSettings.vertexParams = vertParams;
|
shaderSettings.vertexParams = vertParams;
|
||||||
shaderSettings.alpha_blending = false;
|
shaderSettings.alpha_blending = false;
|
||||||
shaderSettings.cull_backface = true;
|
shaderSettings.cull_backface = true;
|
||||||
shaderSettings.write_z = true;
|
shaderSettings.write_z = true;
|
||||||
shaderSettings.render_order = 0;
|
shaderSettings.render_order = 0;
|
||||||
auto skyboxShader = std::make_unique<resources::Shader>(renderer(), GetResourcePath("engine/shaders/skybox.vert").c_str(),
|
auto fancyShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/fancy.vert").c_str(),
|
||||||
GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings);
|
GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings);
|
||||||
GetResourceManager<resources::Shader>()->AddPersistent("builtin.skybox", std::move(skyboxShader));
|
GetResourceManager<Shader>()->AddPersistent("builtin.fancy", std::move(fancyShader));
|
||||||
}
|
}
|
||||||
if (0) {
|
{
|
||||||
resources::Shader::VertexParams vertParams{};
|
Shader::VertexParams vertParams{};
|
||||||
vertParams.has_normal = true;
|
vertParams.has_normal = true;
|
||||||
|
vertParams.has_tangent = true;
|
||||||
vertParams.has_uv0 = true;
|
vertParams.has_uv0 = true;
|
||||||
resources::Shader::ShaderSettings shaderSettings{};
|
Shader::ShaderSettings shaderSettings{};
|
||||||
|
shaderSettings.vertexParams = vertParams;
|
||||||
|
shaderSettings.alpha_blending = false;
|
||||||
|
shaderSettings.cull_backface = true;
|
||||||
|
shaderSettings.write_z = true;
|
||||||
|
shaderSettings.render_order = 0;
|
||||||
|
auto skyboxShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/skybox.vert").c_str(),
|
||||||
|
GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings);
|
||||||
|
GetResourceManager<Shader>()->AddPersistent("builtin.skybox", std::move(skyboxShader));
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
Shader::VertexParams vertParams{};
|
||||||
|
vertParams.has_normal = true;
|
||||||
|
vertParams.has_tangent = true;
|
||||||
|
vertParams.has_uv0 = true;
|
||||||
|
Shader::ShaderSettings shaderSettings{};
|
||||||
shaderSettings.vertexParams = vertParams;
|
shaderSettings.vertexParams = vertParams;
|
||||||
shaderSettings.alpha_blending = true;
|
shaderSettings.alpha_blending = true;
|
||||||
shaderSettings.cull_backface = true;
|
shaderSettings.cull_backface = true;
|
||||||
shaderSettings.write_z = false;
|
shaderSettings.write_z = false;
|
||||||
shaderSettings.render_order = 1;
|
shaderSettings.render_order = 1;
|
||||||
auto quadShader = std::make_unique<resources::Shader>(renderer(), GetResourcePath("engine/shaders/quad.vert").c_str(),
|
auto quadShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/quad.vert").c_str(),
|
||||||
GetResourcePath("engine/shaders/quad.frag").c_str(), shaderSettings);
|
GetResourcePath("engine/shaders/quad.frag").c_str(), shaderSettings);
|
||||||
GetResourceManager<resources::Shader>()->AddPersistent("builtin.quad", std::move(quadShader));
|
GetResourceManager<Shader>()->AddPersistent("builtin.quad", std::move(quadShader));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* default textures */
|
/* default textures */
|
||||||
{
|
{
|
||||||
auto whiteTexture = std::make_unique<resources::Texture>(renderer(), GetResourcePath("engine/textures/white.png"), resources::Texture::Filtering::kOff);
|
auto whiteTexture = LoadTextureFromFile(GetResourcePath("engine/textures/white.png"), Texture::Filtering::kOff, renderer());
|
||||||
GetResourceManager<resources::Texture>()->AddPersistent("builtin.white", std::move(whiteTexture));
|
GetResourceManager<Texture>()->AddPersistent("builtin.white", std::move(whiteTexture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,6 +248,7 @@ void Application::GameLoop()
|
|||||||
return find_depth(parent, current_depth + 1);
|
return find_depth(parent, current_depth + 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (scene)
|
||||||
{
|
{
|
||||||
for (Entity i = 1; i < scene->next_entity_id_; ++i) {
|
for (Entity i = 1; i < scene->next_entity_id_; ++i) {
|
||||||
auto t = scene->GetComponent<TransformComponent>(i);
|
auto t = scene->GetComponent<TransformComponent>(i);
|
||||||
@ -235,8 +256,12 @@ void Application::GameLoop()
|
|||||||
int depth = find_depth(i, 0);
|
int depth = find_depth(i, 0);
|
||||||
for (int j = 0; j < depth; ++j) tabs += std::string{" "};
|
for (int j = 0; j < depth; ++j) tabs += std::string{" "};
|
||||||
ImGui::Text("%s%s", tabs.c_str(), t->tag.c_str());
|
ImGui::Text("%s%s", tabs.c_str(), t->tag.c_str());
|
||||||
|
ImGui::Text("%.1f %.1f %.1f", t->position.x, t->position.y, t->position.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ImGui::Text("No scene active!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
@ -253,7 +278,7 @@ void Application::GameLoop()
|
|||||||
dynamic_list = mesh_render_system->GetDynamicRenderList();
|
dynamic_list = mesh_render_system->GetDynamicRenderList();
|
||||||
}
|
}
|
||||||
renderer_->PreRender(window()->GetWindowResized(), camera_transform);
|
renderer_->PreRender(window()->GetWindowResized(), camera_transform);
|
||||||
renderer_->Render(*static_list, *dynamic_list);
|
renderer_->Render(static_list, dynamic_list);
|
||||||
|
|
||||||
/* poll events */
|
/* poll events */
|
||||||
window_->GetInputAndEvents();
|
window_->GetInputAndEvents();
|
||||||
|
267
src/renderer.cpp
267
src/renderer.cpp
@ -6,157 +6,146 @@
|
|||||||
|
|
||||||
#include "imgui/imgui.h"
|
#include "imgui/imgui.h"
|
||||||
|
|
||||||
[[maybe_unused]] static glm::mat4 GenPerspectiveMatrix(float vertical_fov_radians,
|
[[maybe_unused]] static glm::mat4 GenPerspectiveMatrix(float vertical_fov_radians, float aspect_ratio, float znear, float zfar)
|
||||||
float aspect_ratio, float znear,
|
{
|
||||||
float zfar) {
|
float g = 1.0f / tanf(vertical_fov_radians * 0.5f);
|
||||||
float g = 1.0f / tanf(vertical_fov_radians * 0.5f);
|
float k1 = zfar / (zfar - znear);
|
||||||
float k1 = zfar / (zfar - znear);
|
float k2 = -(zfar * znear) / (znear - zfar);
|
||||||
float k2 = -(zfar * znear) / (znear - zfar);
|
glm::mat4 m{1.0f};
|
||||||
glm::mat4 m{1.0f};
|
|
||||||
|
|
||||||
m[0][0] = g / aspect_ratio;
|
m[0][0] = g / aspect_ratio;
|
||||||
m[1][1] = g;
|
m[1][1] = g;
|
||||||
m[2][2] = k1;
|
m[2][2] = k1;
|
||||||
m[2][3] = -1.0f;
|
m[2][3] = -1.0f;
|
||||||
m[3][2] = k2;
|
m[3][2] = k2;
|
||||||
m[3][3] = 0.0f;
|
m[3][3] = 0.0f;
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
Renderer::Renderer(const char* app_name, const char* app_version,
|
Renderer::Renderer(const char* app_name, const char* app_version, SDL_Window* window, gfx::GraphicsSettings settings)
|
||||||
SDL_Window* window, gfx::GraphicsSettings settings) {
|
{
|
||||||
device_ =
|
device_ = std::make_unique<GFXDevice>(app_name, app_version, window, settings);
|
||||||
std::make_unique<GFXDevice>(app_name, app_version, window, settings);
|
|
||||||
|
|
||||||
// sort out descriptor set layouts:
|
// sort out descriptor set layouts:
|
||||||
std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
|
std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
|
||||||
{
|
{
|
||||||
auto& binding0 = globalSetBindings.emplace_back();
|
auto& binding0 = globalSetBindings.emplace_back();
|
||||||
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
||||||
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
||||||
}
|
}
|
||||||
global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings);
|
global_uniform.layout = device_->CreateDescriptorSetLayout(globalSetBindings);
|
||||||
global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout);
|
global_uniform.set = device_->AllocateDescriptorSet(global_uniform.layout);
|
||||||
global_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
global_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
||||||
global_uniform.uniform_buffer =
|
global_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
|
||||||
device_->CreateUniformBuffer(sizeof(global_uniform.uniform_buffer_data),
|
device_->UpdateDescriptorUniformBuffer(global_uniform.set, 0, global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data));
|
||||||
&global_uniform.uniform_buffer_data);
|
|
||||||
device_->UpdateDescriptorUniformBuffer(
|
|
||||||
global_uniform.set, 0, global_uniform.uniform_buffer, 0,
|
|
||||||
sizeof(global_uniform.uniform_buffer_data));
|
|
||||||
|
|
||||||
std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
|
std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
|
||||||
{
|
{
|
||||||
auto& binding0 = frameSetBindings.emplace_back();
|
auto& binding0 = frameSetBindings.emplace_back();
|
||||||
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
|
||||||
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
|
||||||
}
|
}
|
||||||
frame_uniform.layout = device_->CreateDescriptorSetLayout(frameSetBindings);
|
frame_uniform.layout = device_->CreateDescriptorSetLayout(frameSetBindings);
|
||||||
frame_uniform.set = device_->AllocateDescriptorSet(frame_uniform.layout);
|
frame_uniform.set = device_->AllocateDescriptorSet(frame_uniform.layout);
|
||||||
frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
frame_uniform.uniform_buffer_data.data = glm::mat4{1.0f};
|
||||||
frame_uniform.uniform_buffer =
|
frame_uniform.uniform_buffer = device_->CreateUniformBuffer(sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
|
||||||
device_->CreateUniformBuffer(sizeof(frame_uniform.uniform_buffer_data),
|
device_->UpdateDescriptorUniformBuffer(frame_uniform.set, 0, frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data));
|
||||||
&frame_uniform.uniform_buffer_data);
|
|
||||||
device_->UpdateDescriptorUniformBuffer(
|
|
||||||
frame_uniform.set, 0, frame_uniform.uniform_buffer, 0,
|
|
||||||
sizeof(frame_uniform.uniform_buffer_data));
|
|
||||||
|
|
||||||
std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings;
|
std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings;
|
||||||
{
|
gfx::DescriptorSetLayoutBinding materialSetBinding{};
|
||||||
auto& binding0 = materialSetBindings.emplace_back();
|
materialSetBinding.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
|
||||||
binding0.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
|
materialSetBinding.stage_flags = gfx::ShaderStageFlags::kFragment;
|
||||||
binding0.stage_flags = gfx::ShaderStageFlags::kFragment;
|
materialSetBindings.push_back(materialSetBinding); // albedo
|
||||||
}
|
materialSetBindings.push_back(materialSetBinding); // normal
|
||||||
material_set_layout = device_->CreateDescriptorSetLayout(materialSetBindings);
|
materialSetBindings.push_back(materialSetBinding); // occlusion
|
||||||
|
materialSetBindings.push_back(materialSetBinding); // metallic-roughness
|
||||||
|
material_set_layout = device_->CreateDescriptorSetLayout(materialSetBindings);
|
||||||
|
|
||||||
device_->SetupImguiBackend();
|
device_->SetupImguiBackend();
|
||||||
};
|
};
|
||||||
|
|
||||||
Renderer::~Renderer() {
|
Renderer::~Renderer()
|
||||||
for (const auto& [info, sampler] : samplers) {
|
{
|
||||||
device_->DestroySampler(sampler);
|
for (const auto& [info, sampler] : samplers) {
|
||||||
}
|
device_->DestroySampler(sampler);
|
||||||
device_->DestroyDescriptorSetLayout(material_set_layout);
|
|
||||||
|
|
||||||
device_->DestroyUniformBuffer(frame_uniform.uniform_buffer);
|
|
||||||
device_->DestroyDescriptorSetLayout(frame_uniform.layout);
|
|
||||||
|
|
||||||
device_->DestroyUniformBuffer(global_uniform.uniform_buffer);
|
|
||||||
device_->DestroyDescriptorSetLayout(global_uniform.layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform) {
|
|
||||||
if (window_is_resized) {
|
|
||||||
uint32_t w, h;
|
|
||||||
device_->GetViewportSize(&w, &h);
|
|
||||||
viewport_aspect_ratio_ = (float)w / (float)h;
|
|
||||||
const glm::mat4 proj_matrix = glm::perspectiveRH_ZO(
|
|
||||||
camera_settings_.vertical_fov_radians, viewport_aspect_ratio_,
|
|
||||||
camera_settings_.clip_near, camera_settings_.clip_far);
|
|
||||||
/* update SET 0 (rarely changing uniforms)*/
|
|
||||||
global_uniform.uniform_buffer_data.data = proj_matrix;
|
|
||||||
device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0,
|
|
||||||
sizeof(global_uniform.uniform_buffer_data),
|
|
||||||
&global_uniform.uniform_buffer_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set camera view matrix uniform
|
|
||||||
/* update SET 1 (per frame uniforms) */
|
|
||||||
const glm::mat4 view_matrix = glm::inverse(camera_transform);
|
|
||||||
frame_uniform.uniform_buffer_data.data = view_matrix;
|
|
||||||
device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0,
|
|
||||||
sizeof(frame_uniform.uniform_buffer_data),
|
|
||||||
&frame_uniform.uniform_buffer_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::Render(const RenderList& static_list,
|
|
||||||
const RenderList& dynamic_list) {
|
|
||||||
last_bound_pipeline_ = nullptr;
|
|
||||||
|
|
||||||
gfx::DrawBuffer* draw_buffer = device_->BeginRender();
|
|
||||||
|
|
||||||
if (!static_list.empty()) {
|
|
||||||
DrawRenderList(draw_buffer, static_list);
|
|
||||||
}
|
|
||||||
if (!dynamic_list.empty()) {
|
|
||||||
DrawRenderList(draw_buffer, dynamic_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
device_->CmdRenderImguiDrawData(draw_buffer, ImGui::GetDrawData());
|
|
||||||
|
|
||||||
device_->FinishRender(draw_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::DrawRenderList(gfx::DrawBuffer* draw_buffer,
|
|
||||||
const RenderList& render_list) {
|
|
||||||
// if a pipeline hasn't been bound yet at all
|
|
||||||
if (last_bound_pipeline_ == nullptr) {
|
|
||||||
const gfx::Pipeline* first_pipeline = render_list.begin()->pipeline;
|
|
||||||
// these bindings persist between all pipelines
|
|
||||||
device_->CmdBindDescriptorSet(draw_buffer, first_pipeline,
|
|
||||||
global_uniform.set, 0);
|
|
||||||
device_->CmdBindDescriptorSet(draw_buffer, first_pipeline,
|
|
||||||
frame_uniform.set, 1);
|
|
||||||
device_->CmdBindPipeline(draw_buffer, first_pipeline);
|
|
||||||
last_bound_pipeline_ = first_pipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& entry : render_list) {
|
|
||||||
if (entry.pipeline != last_bound_pipeline_) {
|
|
||||||
device_->CmdBindPipeline(draw_buffer, entry.pipeline);
|
|
||||||
last_bound_pipeline_ = entry.pipeline;
|
|
||||||
}
|
}
|
||||||
device_->CmdBindDescriptorSet(draw_buffer, entry.pipeline,
|
device_->DestroyDescriptorSetLayout(material_set_layout);
|
||||||
entry.base_colour_texture, 2);
|
|
||||||
device_->CmdPushConstants(draw_buffer, entry.pipeline, 0,
|
device_->DestroyUniformBuffer(frame_uniform.uniform_buffer);
|
||||||
sizeof(entry.model_matrix), &entry.model_matrix);
|
device_->DestroyDescriptorSetLayout(frame_uniform.layout);
|
||||||
device_->CmdBindVertexBuffer(draw_buffer, 0, entry.vertex_buffer);
|
|
||||||
device_->CmdBindIndexBuffer(draw_buffer, entry.index_buffer);
|
device_->DestroyUniformBuffer(global_uniform.uniform_buffer);
|
||||||
device_->CmdDrawIndexed(draw_buffer, entry.index_count, 1, 0, 0, 0);
|
device_->DestroyDescriptorSetLayout(global_uniform.layout);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace engine
|
void Renderer::PreRender(bool window_is_resized, glm::mat4 camera_transform)
|
||||||
|
{
|
||||||
|
if (window_is_resized) {
|
||||||
|
uint32_t w, h;
|
||||||
|
device_->GetViewportSize(&w, &h);
|
||||||
|
viewport_aspect_ratio_ = (float)w / (float)h;
|
||||||
|
const glm::mat4 proj_matrix =
|
||||||
|
glm::perspectiveRH_ZO(camera_settings_.vertical_fov_radians, viewport_aspect_ratio_, camera_settings_.clip_near, camera_settings_.clip_far);
|
||||||
|
/* update SET 0 (rarely changing uniforms)*/
|
||||||
|
global_uniform.uniform_buffer_data.data = proj_matrix;
|
||||||
|
device_->WriteUniformBuffer(global_uniform.uniform_buffer, 0, sizeof(global_uniform.uniform_buffer_data), &global_uniform.uniform_buffer_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set camera view matrix uniform
|
||||||
|
/* update SET 1 (per frame uniforms) */
|
||||||
|
const glm::mat4 view_matrix = glm::inverse(camera_transform);
|
||||||
|
frame_uniform.uniform_buffer_data.data = view_matrix;
|
||||||
|
device_->WriteUniformBuffer(frame_uniform.uniform_buffer, 0, sizeof(frame_uniform.uniform_buffer_data), &frame_uniform.uniform_buffer_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::Render(const RenderList* static_list, const RenderList* dynamic_list)
|
||||||
|
{
|
||||||
|
last_bound_pipeline_ = nullptr;
|
||||||
|
|
||||||
|
gfx::DrawBuffer* draw_buffer = device_->BeginRender();
|
||||||
|
|
||||||
|
if (static_list) {
|
||||||
|
if (!static_list->empty()) {
|
||||||
|
DrawRenderList(draw_buffer, *static_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dynamic_list) {
|
||||||
|
if (!dynamic_list->empty()) {
|
||||||
|
DrawRenderList(draw_buffer, *dynamic_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_->CmdRenderImguiDrawData(draw_buffer, ImGui::GetDrawData());
|
||||||
|
|
||||||
|
device_->FinishRender(draw_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::DrawRenderList(gfx::DrawBuffer* draw_buffer, const RenderList& render_list)
|
||||||
|
{
|
||||||
|
// if a pipeline hasn't been bound yet at all
|
||||||
|
if (last_bound_pipeline_ == nullptr) {
|
||||||
|
const gfx::Pipeline* first_pipeline = render_list.begin()->pipeline;
|
||||||
|
// these bindings persist between all pipelines
|
||||||
|
device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, global_uniform.set, 0);
|
||||||
|
device_->CmdBindDescriptorSet(draw_buffer, first_pipeline, frame_uniform.set, 1);
|
||||||
|
device_->CmdBindPipeline(draw_buffer, first_pipeline);
|
||||||
|
last_bound_pipeline_ = first_pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : render_list) {
|
||||||
|
if (entry.pipeline != last_bound_pipeline_) {
|
||||||
|
device_->CmdBindPipeline(draw_buffer, entry.pipeline);
|
||||||
|
last_bound_pipeline_ = entry.pipeline;
|
||||||
|
}
|
||||||
|
device_->CmdBindDescriptorSet(draw_buffer, entry.pipeline, entry.material_set, 2);
|
||||||
|
device_->CmdPushConstants(draw_buffer, entry.pipeline, 0, sizeof(entry.model_matrix), &entry.model_matrix);
|
||||||
|
device_->CmdBindVertexBuffer(draw_buffer, 0, entry.vertex_buffer);
|
||||||
|
device_->CmdBindIndexBuffer(draw_buffer, entry.index_buffer);
|
||||||
|
device_->CmdDrawIndexed(draw_buffer, entry.index_count, 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace engine
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util/files.h"
|
#include "util/files.h"
|
||||||
|
|
||||||
namespace engine::resources {
|
namespace engine {
|
||||||
|
|
||||||
Font::Font(const std::string& path) {
|
Font::Font(const std::string& path) {
|
||||||
font_buffer_ = util::ReadBinaryFile(path);
|
font_buffer_ = util::ReadBinaryFile(path);
|
||||||
@ -131,4 +131,4 @@ int Font::GetGlyphIndex(int unicode_codepoint) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace engine::resources
|
} // namespace engine
|
||||||
|
@ -2,18 +2,37 @@
|
|||||||
|
|
||||||
#include "resources/shader.h"
|
#include "resources/shader.h"
|
||||||
|
|
||||||
namespace engine::resources {
|
namespace engine {
|
||||||
|
|
||||||
Material::Material(std::shared_ptr<Shader> shader)
|
|
||||||
: shader_(shader)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Material::Material(const Material& original)
|
|
||||||
: texture_(original.texture_), shader_(original.shader_)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Material::Material(Renderer* renderer, std::shared_ptr<Shader> shader) : shader_(shader), renderer_(renderer)
|
||||||
|
{
|
||||||
|
material_set_ = renderer->GetDevice()->AllocateDescriptorSet(renderer->GetMaterialSetLayout());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material::~Material() { renderer_->GetDevice()->FreeDescriptorSet(material_set_); }
|
||||||
|
|
||||||
|
void Material::SetAlbedoTexture(std::shared_ptr<Texture> texture)
|
||||||
|
{
|
||||||
|
renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 0, texture->GetImage(), texture->GetSampler());
|
||||||
|
texture_albedo_ = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::SetNormalTexture(std::shared_ptr<Texture> texture)
|
||||||
|
{
|
||||||
|
renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 1, texture->GetImage(), texture->GetSampler());
|
||||||
|
texture_normal_ = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::SetOcclusionTexture(std::shared_ptr<Texture> texture)
|
||||||
|
{
|
||||||
|
renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 2, texture->GetImage(), texture->GetSampler());
|
||||||
|
texture_occlusion_ = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::SetMetallicRoughnessTexture(std::shared_ptr<Texture> texture)
|
||||||
|
{
|
||||||
|
renderer_->GetDevice()->UpdateDescriptorCombinedImageSampler(material_set_, 3, texture->GetImage(), texture->GetSampler());
|
||||||
|
texture_metallic_roughness_ = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace engine
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "gfx_device.h"
|
#include "gfx_device.h"
|
||||||
|
|
||||||
namespace engine::resources {
|
namespace engine {
|
||||||
|
|
||||||
Mesh::Mesh(GFXDevice* gfx, const std::vector<Vertex>& vertices) : gfx_(gfx) {
|
Mesh::Mesh(GFXDevice* gfx, const std::vector<Vertex>& vertices) : gfx_(gfx) {
|
||||||
std::vector<uint32_t> indices(vertices.size());
|
std::vector<uint32_t> indices(vertices.size());
|
||||||
@ -36,4 +36,4 @@ void Mesh::InitMesh(const std::vector<Vertex>& vertices,
|
|||||||
indices.size());
|
indices.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace engine::resources
|
} // namespace engine
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
|
||||||
namespace engine::resources {
|
namespace engine {
|
||||||
|
|
||||||
Shader::Shader(Renderer* renderer, const char* vertPath, const char* fragPath,
|
Shader::Shader(Renderer* renderer, const char* vertPath, const char* fragPath,
|
||||||
const ShaderSettings& settings)
|
const ShaderSettings& settings)
|
||||||
@ -67,4 +67,4 @@ Shader::~Shader() {
|
|||||||
|
|
||||||
const gfx::Pipeline* Shader::GetPipeline() { return pipeline_; }
|
const gfx::Pipeline* Shader::GetPipeline() { return pipeline_; }
|
||||||
|
|
||||||
} // namespace engine::resources
|
} // namespace engine
|
||||||
|
@ -6,102 +6,57 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace engine::resources {
|
namespace engine {
|
||||||
|
|
||||||
Texture::Texture(Renderer* renderer, const std::string& path,
|
Texture::Texture(Renderer* renderer, const uint8_t* bitmap, int width, int height, Filtering filtering) : gfx_(renderer->GetDevice())
|
||||||
Filtering filtering)
|
{
|
||||||
: gfx_(renderer->GetDevice()) {
|
gfx::SamplerInfo samplerInfo{};
|
||||||
int width, height;
|
|
||||||
std::unique_ptr<std::vector<uint8_t>> texbuf =
|
|
||||||
util::ReadImageFile(path, &width, &height);
|
|
||||||
|
|
||||||
gfx::SamplerInfo samplerInfo{};
|
samplerInfo.magnify = gfx::Filter::kLinear;
|
||||||
|
|
||||||
samplerInfo.magnify = gfx::Filter::kLinear;
|
switch (filtering) {
|
||||||
|
case Filtering::kOff:
|
||||||
|
samplerInfo.minify = gfx::Filter::kNearest;
|
||||||
|
samplerInfo.mipmap = gfx::Filter::kNearest;
|
||||||
|
samplerInfo.anisotropic_filtering = false;
|
||||||
|
break;
|
||||||
|
case Filtering::kBilinear:
|
||||||
|
samplerInfo.minify = gfx::Filter::kLinear;
|
||||||
|
samplerInfo.mipmap = gfx::Filter::kNearest;
|
||||||
|
samplerInfo.anisotropic_filtering = false;
|
||||||
|
break;
|
||||||
|
case Filtering::kTrilinear:
|
||||||
|
samplerInfo.minify = gfx::Filter::kLinear;
|
||||||
|
samplerInfo.mipmap = gfx::Filter::kLinear;
|
||||||
|
samplerInfo.anisotropic_filtering = false;
|
||||||
|
break;
|
||||||
|
case Filtering::kAnisotropic:
|
||||||
|
samplerInfo.minify = gfx::Filter::kLinear;
|
||||||
|
samplerInfo.mipmap = gfx::Filter::kLinear;
|
||||||
|
samplerInfo.anisotropic_filtering = true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (filtering) {
|
if (renderer->samplers.contains(samplerInfo) == false) {
|
||||||
case Filtering::kOff:
|
renderer->samplers.insert(std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo)));
|
||||||
samplerInfo.minify = gfx::Filter::kNearest;
|
}
|
||||||
samplerInfo.mipmap = gfx::Filter::kNearest;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kBilinear:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kNearest;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kTrilinear:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kAnisotropic:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.anisotropic_filtering = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderer->samplers.contains(samplerInfo) == false) {
|
image_ = gfx_->CreateImage(width, height, bitmap);
|
||||||
renderer->samplers.insert(
|
sampler_ = renderer->samplers.at(samplerInfo);
|
||||||
std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo)));
|
|
||||||
}
|
|
||||||
|
|
||||||
image_ = gfx_->CreateImage(width, height, texbuf->data());
|
LOG_DEBUG("Created texture: width: {}, height: {}", width, height);
|
||||||
descriptor_set_ =
|
|
||||||
gfx_->AllocateDescriptorSet(renderer->GetMaterialSetLayout());
|
|
||||||
gfx_->UpdateDescriptorCombinedImageSampler(
|
|
||||||
descriptor_set_, 0, image_, renderer->samplers.at(samplerInfo));
|
|
||||||
|
|
||||||
LOG_DEBUG("Created texture: {}, width: {} height: {}", path, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::Texture(Renderer* renderer, const uint8_t* bitmap, int width,
|
Texture::~Texture()
|
||||||
int height, Filtering filtering)
|
{
|
||||||
: gfx_(renderer->GetDevice()) {
|
LOG_DEBUG("Destroying texture...");
|
||||||
gfx::SamplerInfo samplerInfo{};
|
gfx_->DestroyImage(image_);
|
||||||
|
|
||||||
samplerInfo.magnify = gfx::Filter::kLinear;
|
|
||||||
|
|
||||||
switch (filtering) {
|
|
||||||
case Filtering::kOff:
|
|
||||||
samplerInfo.minify = gfx::Filter::kNearest;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kNearest;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kBilinear:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kNearest;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kTrilinear:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.anisotropic_filtering = false;
|
|
||||||
break;
|
|
||||||
case Filtering::kAnisotropic:
|
|
||||||
samplerInfo.minify = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.mipmap = gfx::Filter::kLinear;
|
|
||||||
samplerInfo.anisotropic_filtering = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderer->samplers.contains(samplerInfo) == false) {
|
|
||||||
renderer->samplers.insert(
|
|
||||||
std::make_pair(samplerInfo, gfx_->CreateSampler(samplerInfo)));
|
|
||||||
}
|
|
||||||
|
|
||||||
image_ = gfx_->CreateImage(width, height, bitmap);
|
|
||||||
descriptor_set_ =
|
|
||||||
gfx_->AllocateDescriptorSet(renderer->GetMaterialSetLayout());
|
|
||||||
gfx_->UpdateDescriptorCombinedImageSampler(
|
|
||||||
descriptor_set_, 0, image_, renderer->samplers.at(samplerInfo));
|
|
||||||
|
|
||||||
LOG_DEBUG("Created texture: BITMAP, width: {} height: {}", width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture::~Texture() {
|
std::unique_ptr<Texture> LoadTextureFromFile(const std::string& path, Texture::Filtering filtering, Renderer* renderer)
|
||||||
LOG_DEBUG("Destroying texture...");
|
{
|
||||||
gfx_->FreeDescriptorSet(descriptor_set_);
|
int width, height;
|
||||||
gfx_->DestroyImage(image_);
|
auto bitmap = util::ReadImageFile(path, width, height);
|
||||||
|
return std::make_unique<Texture>(renderer, bitmap->data(), width, height, filtering);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace engine::resources
|
} // namespace engine
|
@ -7,31 +7,28 @@
|
|||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
SceneManager::SceneManager(Application* app)
|
SceneManager::SceneManager(Application* app) : app_(app) {}
|
||||||
: app_(app)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneManager::~SceneManager() {}
|
SceneManager::~SceneManager() {}
|
||||||
|
|
||||||
Scene* SceneManager::CreateEmptyScene()
|
|
||||||
{
|
|
||||||
auto scene = std::make_unique<Scene>(app_);
|
|
||||||
scenes_.emplace_back(std::move(scene));
|
|
||||||
active_scene_index_ = (int)scenes_.size() - 1;
|
|
||||||
return scenes_.back().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
Scene* SceneManager::UpdateActiveScene(float ts)
|
|
||||||
{
|
|
||||||
if (active_scene_index_ >= 0) [[likely]] {
|
|
||||||
assert((size_t)active_scene_index_ < scenes_.size());
|
|
||||||
Scene* activeScene = scenes_[active_scene_index_].get();
|
|
||||||
activeScene->Update(ts);
|
|
||||||
return activeScene;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Scene* SceneManager::CreateEmptyScene()
|
||||||
|
{
|
||||||
|
auto scene = std::make_unique<Scene>(app_);
|
||||||
|
scenes_.emplace_back(std::move(scene));
|
||||||
|
return scenes_.back().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scene* SceneManager::UpdateActiveScene(float ts)
|
||||||
|
{
|
||||||
|
if (active_scene_index_ >= 0) [[likely]] {
|
||||||
|
assert((size_t)active_scene_index_ < scenes_.size());
|
||||||
|
Scene* activeScene = scenes_[active_scene_index_].get();
|
||||||
|
activeScene->Update(ts);
|
||||||
|
return activeScene;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace engine
|
||||||
|
@ -8,72 +8,68 @@
|
|||||||
|
|
||||||
namespace engine {
|
namespace engine {
|
||||||
|
|
||||||
MeshRenderSystem::MeshRenderSystem(Scene* scene)
|
MeshRenderSystem::MeshRenderSystem(Scene* scene) : System(scene, {typeid(TransformComponent).hash_code(), typeid(MeshRenderableComponent).hash_code()}) {}
|
||||||
: System(scene, {typeid(TransformComponent).hash_code(),
|
|
||||||
typeid(MeshRenderableComponent).hash_code()}) {}
|
|
||||||
|
|
||||||
MeshRenderSystem::~MeshRenderSystem() {}
|
MeshRenderSystem::~MeshRenderSystem() {}
|
||||||
|
|
||||||
void MeshRenderSystem::RebuildStaticRenderList() {
|
void MeshRenderSystem::RebuildStaticRenderList()
|
||||||
BuildRenderList(static_render_list_, true);
|
{
|
||||||
list_needs_rebuild_ = false;
|
BuildRenderList(static_render_list_, true);
|
||||||
|
list_needs_rebuild_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderSystem::OnComponentInsert(Entity entity) {
|
void MeshRenderSystem::OnComponentInsert(Entity entity)
|
||||||
(void)entity;
|
{
|
||||||
list_needs_rebuild_ = true;
|
(void)entity;
|
||||||
|
list_needs_rebuild_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshRenderSystem::OnUpdate(float ts) {
|
void MeshRenderSystem::OnUpdate(float ts)
|
||||||
// do stuff
|
{
|
||||||
(void)ts;
|
// do stuff
|
||||||
// update the static render list only if it needs updating
|
(void)ts;
|
||||||
if (list_needs_rebuild_) {
|
// update the static render list only if it needs updating
|
||||||
RebuildStaticRenderList();
|
if (list_needs_rebuild_) {
|
||||||
}
|
RebuildStaticRenderList();
|
||||||
// update the dynamic render list always
|
|
||||||
BuildRenderList(dynamic_render_list_, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshRenderSystem::BuildRenderList(RenderList& render_list,
|
|
||||||
bool with_static_entities) {
|
|
||||||
render_list.clear();
|
|
||||||
render_list.reserve(entities_.size());
|
|
||||||
|
|
||||||
std::unordered_map<const gfx::Pipeline*, int> render_orders;
|
|
||||||
|
|
||||||
for (Entity entity : entities_) {
|
|
||||||
auto transform = scene_->GetComponent<engine::TransformComponent>(entity);
|
|
||||||
|
|
||||||
if (transform->is_static != with_static_entities) continue;
|
|
||||||
|
|
||||||
auto renderable = scene_->GetComponent<engine::MeshRenderableComponent>(entity);
|
|
||||||
|
|
||||||
const gfx::Pipeline* pipeline =
|
|
||||||
renderable->material->GetShader()->GetPipeline();
|
|
||||||
|
|
||||||
render_list.emplace_back(
|
|
||||||
RenderListEntry{.pipeline = pipeline,
|
|
||||||
.vertex_buffer = renderable->mesh->GetVB(),
|
|
||||||
.index_buffer = renderable->mesh->GetIB(),
|
|
||||||
.base_colour_texture =
|
|
||||||
renderable->material->texture_->GetDescriptorSet(),
|
|
||||||
.model_matrix = transform->world_matrix,
|
|
||||||
.index_count = renderable->mesh->GetCount()});
|
|
||||||
|
|
||||||
if (render_orders.contains(pipeline) == false) {
|
|
||||||
render_orders.emplace(
|
|
||||||
pipeline, renderable->material->GetShader()->GetRenderOrder());
|
|
||||||
}
|
}
|
||||||
}
|
// update the dynamic render list always
|
||||||
|
BuildRenderList(dynamic_render_list_, false);
|
||||||
|
}
|
||||||
|
|
||||||
// sort the meshes by pipeline
|
void MeshRenderSystem::BuildRenderList(RenderList& render_list, bool with_static_entities)
|
||||||
auto sort_by_pipeline = [&render_orders](const RenderListEntry& e1,
|
{
|
||||||
const RenderListEntry& e2) -> bool {
|
render_list.clear();
|
||||||
return (render_orders.at(e1.pipeline) < render_orders.at(e2.pipeline));
|
render_list.reserve(entities_.size());
|
||||||
};
|
|
||||||
|
|
||||||
std::sort(render_list.begin(), render_list.end(), sort_by_pipeline);
|
std::unordered_map<const gfx::Pipeline*, int> render_orders;
|
||||||
|
|
||||||
|
for (Entity entity : entities_) {
|
||||||
|
auto transform = scene_->GetComponent<engine::TransformComponent>(entity);
|
||||||
|
|
||||||
|
if (transform->is_static != with_static_entities) continue;
|
||||||
|
|
||||||
|
auto renderable = scene_->GetComponent<engine::MeshRenderableComponent>(entity);
|
||||||
|
|
||||||
|
const gfx::Pipeline* pipeline = renderable->material->GetShader()->GetPipeline();
|
||||||
|
|
||||||
|
render_list.emplace_back(RenderListEntry{.pipeline = pipeline,
|
||||||
|
.vertex_buffer = renderable->mesh->GetVB(),
|
||||||
|
.index_buffer = renderable->mesh->GetIB(),
|
||||||
|
.material_set = renderable->material->GetDescriptorSet(),
|
||||||
|
.model_matrix = transform->world_matrix,
|
||||||
|
.index_count = renderable->mesh->GetCount()});
|
||||||
|
|
||||||
|
if (render_orders.contains(pipeline) == false) {
|
||||||
|
render_orders.emplace(pipeline, renderable->material->GetShader()->GetRenderOrder());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort the meshes by pipeline
|
||||||
|
auto sort_by_pipeline = [&render_orders](const RenderListEntry& e1, const RenderListEntry& e2) -> bool {
|
||||||
|
return (render_orders.at(e1.pipeline) < render_orders.at(e2.pipeline));
|
||||||
|
};
|
||||||
|
|
||||||
|
std::sort(render_list.begin(), render_list.end(), sort_by_pipeline);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
LOG_TRACE("\nPRINTING RENDER LIST ({})\n", with_static_entities ? "STATIC" : "DYNAMIC");
|
LOG_TRACE("\nPRINTING RENDER LIST ({})\n", with_static_entities ? "STATIC" : "DYNAMIC");
|
||||||
@ -91,4 +87,4 @@ void MeshRenderSystem::BuildRenderList(RenderList& render_list,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
|
@ -54,7 +54,7 @@ std::unique_ptr<std::vector<uint8_t>> ReadBinaryFile(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
|
std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
|
||||||
int* width, int* height) {
|
int& width, int& height) {
|
||||||
int x, y, n;
|
int x, y, n;
|
||||||
unsigned char* data =
|
unsigned char* data =
|
||||||
stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha); // Image is 4 bpp
|
stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha); // Image is 4 bpp
|
||||||
@ -68,8 +68,8 @@ std::unique_ptr<std::vector<uint8_t>> ReadImageFile(const std::string& path,
|
|||||||
auto buffer = std::make_unique<std::vector<uint8_t>>(size);
|
auto buffer = std::make_unique<std::vector<uint8_t>>(size);
|
||||||
memcpy(buffer->data(), data, buffer->size());
|
memcpy(buffer->data(), data, buffer->size());
|
||||||
|
|
||||||
*width = x;
|
width = x;
|
||||||
*height = y;
|
height = y;
|
||||||
|
|
||||||
stbi_image_free(data);
|
stbi_image_free(data);
|
||||||
|
|
||||||
|
@ -27,226 +27,198 @@
|
|||||||
|
|
||||||
namespace engine::util {
|
namespace engine::util {
|
||||||
|
|
||||||
static void buildGraph(
|
static void buildGraph(const std::map<int, std::shared_ptr<Texture>>& textures, const std::vector<std::shared_ptr<Mesh>>& meshes,
|
||||||
const std::map<int, std::shared_ptr<resources::Texture>>& textures,
|
const std::vector<unsigned int>& meshTextureIndices, aiNode* parentNode, Scene* scene, Entity parentObj, bool is_static)
|
||||||
const std::vector<std::shared_ptr<resources::Mesh>>& meshes,
|
{
|
||||||
const std::vector<unsigned int>& meshTextureIndices,
|
|
||||||
aiNode* parentNode, Scene* scene, Entity parentObj, bool is_static)
|
|
||||||
{
|
|
||||||
|
|
||||||
// convert to glm column major
|
// convert to glm column major
|
||||||
glm::mat4 transform{};
|
glm::mat4 transform{};
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
transform[i][j] = parentNode->mTransformation[j][i];
|
transform[i][j] = parentNode->mTransformation[j][i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get position
|
// get position
|
||||||
glm::vec3 position{ transform[3][0], transform[3][1], transform[3][2] };
|
glm::vec3 position{transform[3][0], transform[3][1], transform[3][2]};
|
||||||
|
|
||||||
// remove position from matrix
|
// remove position from matrix
|
||||||
transform[3][0] = 0.0f;
|
transform[3][0] = 0.0f;
|
||||||
transform[3][1] = 0.0f;
|
transform[3][1] = 0.0f;
|
||||||
transform[3][2] = 0.0f;
|
transform[3][2] = 0.0f;
|
||||||
|
|
||||||
// get scale
|
// get scale
|
||||||
glm::vec3 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.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.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]);
|
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
|
// remove scaling from matrix
|
||||||
for (int row = 0; row < 3; row++) {
|
for (int row = 0; row < 3; row++) {
|
||||||
transform[0][row] /= scale.x;
|
transform[0][row] /= scale.x;
|
||||||
transform[1][row] /= scale.y;
|
transform[1][row] /= scale.y;
|
||||||
transform[2][row] /= scale.z;
|
transform[2][row] /= scale.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get rotation
|
// get rotation
|
||||||
glm::quat rotation = glm::quat_cast(transform);
|
glm::quat rotation = glm::quat_cast(transform);
|
||||||
|
|
||||||
// ASSIMP always makes the root node Y-up
|
// ASSIMP always makes the root node Y-up
|
||||||
// We want Z-up
|
// We want Z-up
|
||||||
if (parentNode->mParent == nullptr) {
|
if (parentNode->mParent == nullptr) {
|
||||||
// if this is the root node
|
// if this is the root node
|
||||||
rotation *= glm::angleAxis(glm::half_pi<float>(), glm::vec3{1.0f, 0.0f, 0.0f});
|
rotation *= glm::angleAxis(glm::half_pi<float>(), glm::vec3{1.0f, 0.0f, 0.0f});
|
||||||
}
|
}
|
||||||
|
|
||||||
// update position, scale, rotation
|
// update position, scale, rotation
|
||||||
auto parentTransform = scene->GetComponent<TransformComponent>(parentObj);
|
auto parentTransform = scene->GetComponent<TransformComponent>(parentObj);
|
||||||
parentTransform->position = position;
|
parentTransform->position = position;
|
||||||
parentTransform->scale = scale;
|
parentTransform->scale = scale;
|
||||||
parentTransform->rotation = rotation;
|
parentTransform->rotation = rotation;
|
||||||
parentTransform->is_static = is_static;
|
parentTransform->is_static = is_static;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) {
|
for (uint32_t i = 0; i < parentNode->mNumMeshes; i++) {
|
||||||
// create child node for each mesh
|
// create child node for each mesh
|
||||||
auto child = scene->CreateEntity("_mesh" + std::to_string(i), parentObj);
|
auto child = scene->CreateEntity("_mesh" + std::to_string(i), parentObj);
|
||||||
scene->GetComponent<TransformComponent>(child)->is_static = is_static;
|
scene->GetComponent<TransformComponent>(child)->is_static = is_static;
|
||||||
auto childRenderer = scene->AddComponent<MeshRenderableComponent>(child);
|
auto childRenderer = scene->AddComponent<MeshRenderableComponent>(child);
|
||||||
childRenderer->mesh = meshes[parentNode->mMeshes[i]];
|
childRenderer->mesh = meshes[parentNode->mMeshes[i]];
|
||||||
childRenderer->material = std::make_shared<resources::Material>(scene->app()->GetResource<resources::Shader>("builtin.standard"));
|
childRenderer->material = std::make_shared<Material>(scene->app()->renderer(), scene->app()->GetResource<Shader>("builtin.standard"));
|
||||||
if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) {
|
if (textures.contains(meshTextureIndices[parentNode->mMeshes[i]])) {
|
||||||
childRenderer->material->texture_ = textures.at(meshTextureIndices[parentNode->mMeshes[i]]);
|
childRenderer->material->SetAlbedoTexture(textures.at(meshTextureIndices[parentNode->mMeshes[i]]));
|
||||||
} else {
|
}
|
||||||
childRenderer->material->texture_ = scene->app()->GetResource<resources::Texture>("builtin.white");
|
else {
|
||||||
}
|
childRenderer->material->SetAlbedoTexture(scene->app()->GetResource<Texture>("builtin.white"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (uint32_t i = 0; i < parentNode->mNumChildren; i++) {
|
|
||||||
buildGraph(
|
|
||||||
textures,
|
|
||||||
meshes,
|
|
||||||
meshTextureIndices,
|
|
||||||
parentNode->mChildren[i],
|
|
||||||
scene,
|
|
||||||
scene->CreateEntity("child" + std::to_string(i), parentObj), is_static
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity LoadMeshFromFile(Scene* parent, const std::string& path, bool is_static)
|
|
||||||
{
|
|
||||||
|
|
||||||
Assimp::Importer importer;
|
|
||||||
|
|
||||||
class myStream : public Assimp::LogStream {
|
|
||||||
public:
|
|
||||||
void write(const char* message) override {
|
|
||||||
(void)message;
|
|
||||||
LOG_TRACE("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 | // Collada uses bottom-left origin
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
const char* errString = importer.GetErrorString();
|
|
||||||
if (errString[0] != '\0' || scene == nullptr) {
|
|
||||||
throw std::runtime_error("assimp error: " + std::string(errString));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
|
|
||||||
throw std::runtime_error("assimp error (incomplete): " + std::string(errString));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(scene->HasAnimations() == false);
|
|
||||||
assert(scene->HasCameras() == false);
|
|
||||||
assert(scene->HasLights() == false);
|
|
||||||
assert(scene->hasSkeletons() == false);
|
|
||||||
|
|
||||||
LOG_TRACE("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes);
|
|
||||||
|
|
||||||
std::map<int, std::shared_ptr<resources::Texture>> textures{};
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < scene->mNumMaterials; i++) {
|
|
||||||
const aiMaterial* m = scene->mMaterials[i];
|
|
||||||
LOG_TRACE("Material {}:", i);
|
|
||||||
LOG_TRACE(" Name: {}", m->GetName().C_Str());
|
|
||||||
for (uint32_t j = 0; j < m->mNumProperties; j++) {
|
|
||||||
[[maybe_unused]] const aiMaterialProperty* p = m->mProperties[j];
|
|
||||||
LOG_TRACE(" prop {}, key: {}", j, p->mKey.C_Str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) {
|
|
||||||
aiString texPath{};
|
|
||||||
aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath);
|
|
||||||
LOG_TRACE(" Diffuse tex: {}", texPath.C_Str());
|
|
||||||
std::filesystem::path absPath = path;
|
|
||||||
absPath = absPath.parent_path();
|
|
||||||
absPath /= texPath.C_Str();
|
|
||||||
try {
|
|
||||||
textures[i] = std::make_shared<resources::Texture>(
|
|
||||||
parent->app()->renderer(),
|
|
||||||
absPath.string(),
|
|
||||||
resources::Texture::Filtering::kTrilinear);
|
|
||||||
} catch (const std::runtime_error&) {
|
|
||||||
textures[i] = parent->app()->GetResource<resources::Texture>("builtin.white");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<resources::Mesh>> meshes{};
|
|
||||||
std::vector<unsigned int> meshMaterialIndices{};
|
|
||||||
for (uint32_t 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((size_t)m->mNumFaces * 3);
|
|
||||||
LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size());
|
|
||||||
LOG_TRACE("Mesh {}: index count {}", i, indices.size());
|
|
||||||
|
|
||||||
for (uint32_t 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 (uint32_t 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 (uint32_t j = 0; j < indices.size() / 3; j++) {
|
|
||||||
indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0];
|
|
||||||
indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1];
|
|
||||||
indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2];
|
|
||||||
}
|
|
||||||
meshes.push_back(std::make_shared<resources::Mesh>(
|
|
||||||
parent->app()->renderer()->GetDevice(), vertices,
|
|
||||||
indices));
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity obj = parent->CreateEntity(scene->GetShortFilename(path.c_str()));
|
|
||||||
|
|
||||||
buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj, is_static);
|
|
||||||
|
|
||||||
LOG_INFO("Loaded model: {}, meshes: {}, textures: {}", scene->GetShortFilename(path.c_str()), meshes.size(), textures.size());
|
|
||||||
|
|
||||||
Assimp::DefaultLogger::kill();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < parentNode->mNumChildren; i++) {
|
||||||
|
buildGraph(textures, meshes, meshTextureIndices, parentNode->mChildren[i], scene, scene->CreateEntity("child" + std::to_string(i), parentObj),
|
||||||
|
is_static);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity LoadMeshFromFile(Scene* parent, const std::string& path, bool is_static)
|
||||||
|
{
|
||||||
|
|
||||||
|
Assimp::Importer importer;
|
||||||
|
|
||||||
|
class myStream : public Assimp::LogStream {
|
||||||
|
public:
|
||||||
|
void write(const char* message) override
|
||||||
|
{
|
||||||
|
(void)message;
|
||||||
|
LOG_TRACE("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 | // Collada uses bottom-left origin
|
||||||
|
aiProcess_CalcTangentSpace | 0);
|
||||||
|
|
||||||
|
const char* errString = importer.GetErrorString();
|
||||||
|
if (errString[0] != '\0' || scene == nullptr) {
|
||||||
|
throw std::runtime_error("assimp error: " + std::string(errString));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) {
|
||||||
|
throw std::runtime_error("assimp error (incomplete): " + std::string(errString));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(scene->HasAnimations() == false);
|
||||||
|
assert(scene->HasCameras() == false);
|
||||||
|
assert(scene->HasLights() == false);
|
||||||
|
assert(scene->hasSkeletons() == false);
|
||||||
|
|
||||||
|
LOG_TRACE("material count: {}, mesh count: {}", scene->mNumMaterials, scene->mNumMeshes);
|
||||||
|
|
||||||
|
std::map<int, std::shared_ptr<Texture>> textures{};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < scene->mNumMaterials; i++) {
|
||||||
|
const aiMaterial* m = scene->mMaterials[i];
|
||||||
|
LOG_TRACE("Material {}:", i);
|
||||||
|
LOG_TRACE(" Name: {}", m->GetName().C_Str());
|
||||||
|
for (uint32_t j = 0; j < m->mNumProperties; j++) {
|
||||||
|
[[maybe_unused]] const aiMaterialProperty* p = m->mProperties[j];
|
||||||
|
LOG_TRACE(" prop {}, key: {}", j, p->mKey.C_Str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aiGetMaterialTextureCount(m, aiTextureType_DIFFUSE) >= 1) {
|
||||||
|
aiString texPath{};
|
||||||
|
aiGetMaterialTexture(m, aiTextureType_DIFFUSE, 0, &texPath);
|
||||||
|
LOG_TRACE(" Diffuse tex: {}", texPath.C_Str());
|
||||||
|
std::filesystem::path absPath = path;
|
||||||
|
absPath = absPath.parent_path();
|
||||||
|
absPath /= texPath.C_Str();
|
||||||
|
try {
|
||||||
|
textures[i] = LoadTextureFromFile(absPath.string(), Texture::Filtering::kTrilinear, parent->app()->renderer());
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error&) {
|
||||||
|
textures[i] = parent->app()->GetResource<Texture>("builtin.white");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Mesh>> meshes{};
|
||||||
|
std::vector<unsigned int> meshMaterialIndices{};
|
||||||
|
for (uint32_t 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((size_t)m->mNumFaces * 3);
|
||||||
|
LOG_TRACE("Mesh {}: vertex count {}", i, vertices.size());
|
||||||
|
LOG_TRACE("Mesh {}: index count {}", i, indices.size());
|
||||||
|
|
||||||
|
if (m->mTangents == nullptr) {
|
||||||
|
throw std::runtime_error("No tangents array found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t 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;
|
||||||
|
v.tangent.x = m->mTangents[j].x;
|
||||||
|
v.tangent.y = m->mTangents[j].y;
|
||||||
|
v.tangent.z = m->mTangents[j].z;
|
||||||
|
v.tangent.w = 1.0f;
|
||||||
|
v.uv.x = m->mTextureCoords[0][j].x;
|
||||||
|
v.uv.y = m->mTextureCoords[0][j].y;
|
||||||
|
vertices[j] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < indices.size() / 3; j++) {
|
||||||
|
indices[(size_t)j * 3 + 0] = m->mFaces[j].mIndices[0];
|
||||||
|
indices[(size_t)j * 3 + 1] = m->mFaces[j].mIndices[1];
|
||||||
|
indices[(size_t)j * 3 + 2] = m->mFaces[j].mIndices[2];
|
||||||
|
}
|
||||||
|
meshes.push_back(std::make_shared<Mesh>(parent->app()->renderer()->GetDevice(), vertices, indices));
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity obj = parent->CreateEntity(scene->GetShortFilename(path.c_str()));
|
||||||
|
|
||||||
|
buildGraph(textures, meshes, meshMaterialIndices, scene->mRootNode, parent, obj, is_static);
|
||||||
|
|
||||||
|
LOG_INFO("Loaded model: {}, meshes: {}, textures: {}", scene->GetShortFilename(path.c_str()), meshes.size(), textures.size());
|
||||||
|
|
||||||
|
Assimp::DefaultLogger::kill();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace engine::util
|
||||||
|
@ -167,8 +167,8 @@ namespace engine {
|
|||||||
{
|
{
|
||||||
const ImGuiIO& io = ImGui::GetIO();
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
if (io.WantCaptureMouse) {
|
if (io.WantCaptureMouse) {
|
||||||
mouse_.dx = 0.0f;
|
mouse_.dx = 0;
|
||||||
mouse_.dy = 0.0f;
|
mouse_.dy = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mouse_.x = e.x;
|
mouse_.x = e.x;
|
||||||
|
BIN
test/res/textures/bricks_normal.png
Normal file
BIN
test/res/textures/bricks_normal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 MiB |
BIN
test/res/textures/brickwall_albedo.jpg
Normal file
BIN
test/res/textures/brickwall_albedo.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
BIN
test/res/textures/brickwall_normal.jpg
Normal file
BIN
test/res/textures/brickwall_normal.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 559 KiB |
BIN
test/res/textures/testnormal.png
Normal file
BIN
test/res/textures/testnormal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 KiB |
@ -105,6 +105,7 @@ void CameraControllerSystem::OnUpdate(float ts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scene_->app()->input_manager()->GetButtonPress("exit")) {
|
if (scene_->app()->input_manager()->GetButtonPress("exit")) {
|
||||||
scene_->app()->window()->SetCloseFlag();
|
//scene_->app()->window()->SetCloseFlag();
|
||||||
|
scene_->app()->scene_manager()->SetActiveScene(next_scene_);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,6 +23,8 @@ class CameraControllerSystem
|
|||||||
|
|
||||||
engine::TransformComponent* t = nullptr;
|
engine::TransformComponent* t = nullptr;
|
||||||
CameraControllerComponent* c = nullptr;
|
CameraControllerComponent* c = nullptr;
|
||||||
|
|
||||||
|
engine::Scene* next_scene_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -56,12 +56,11 @@ void PlayGame(GameSettings settings)
|
|||||||
app.window()->SetRelativeMouseMode(true);
|
app.window()->SetRelativeMouseMode(true);
|
||||||
ConfigureInputs(app.input_manager());
|
ConfigureInputs(app.input_manager());
|
||||||
|
|
||||||
|
engine::Scene* my_scene = app.scene_manager()->CreateEmptyScene();
|
||||||
{
|
{
|
||||||
static auto my_scene = app.scene_manager()->CreateEmptyScene();
|
|
||||||
|
|
||||||
/* create camera */
|
{ /* create camera */
|
||||||
{
|
engine::Entity camera = my_scene->CreateEntity("camera");
|
||||||
auto camera = my_scene->CreateEntity("camera");
|
|
||||||
|
|
||||||
/* as of right now, the entity with tag 'camera' is used to build the view
|
/* as of right now, the entity with tag 'camera' is used to build the view
|
||||||
* matrix */
|
* matrix */
|
||||||
@ -74,19 +73,23 @@ void PlayGame(GameSettings settings)
|
|||||||
my_scene->AddComponent<CameraControllerComponent>(camera);
|
my_scene->AddComponent<CameraControllerComponent>(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shared resources */
|
{ /* floor */
|
||||||
auto grass_texture = std::make_shared<engine::resources::Texture>(app.renderer(), app.GetResourcePath("textures/grass.png"),
|
engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true);
|
||||||
engine::resources::Texture::Filtering::kAnisotropic);
|
}
|
||||||
|
|
||||||
auto sky_texture = std::make_shared<engine::resources::Texture>(app.renderer(), app.GetResourcePath("textures/sky.jpg"),
|
#if 0
|
||||||
engine::resources::Texture::Filtering::kAnisotropic);
|
|
||||||
|
/* shared resources */
|
||||||
|
auto grass_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/grass.png"), engine::Texture::Filtering::kAnisotropic, app.renderer());
|
||||||
|
|
||||||
|
std::shared_ptr<engine::Texture> sky_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/sky.jpg"), engine::Texture::Filtering::kAnisotropic, app.renderer());
|
||||||
|
|
||||||
/* skybox */
|
/* skybox */
|
||||||
{
|
{
|
||||||
engine::Entity skybox = my_scene->CreateEntity("skybox");
|
engine::Entity skybox = my_scene->CreateEntity("skybox");
|
||||||
|
|
||||||
auto skybox_renderable = my_scene->AddComponent<engine::MeshRenderableComponent>(skybox);
|
auto skybox_renderable = my_scene->AddComponent<engine::MeshRenderableComponent>(skybox);
|
||||||
skybox_renderable->material = std::make_unique<engine::resources::Material>(app.GetResource<engine::resources::Shader>("builtin.skybox"));
|
skybox_renderable->material = std::make_unique<engine::Material>(app.GetResource<engine::Shader>("builtin.skybox"));
|
||||||
skybox_renderable->material->texture_ = sky_texture;
|
skybox_renderable->material->texture_ = sky_texture;
|
||||||
skybox_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 10.0f, 10.0f, 10.0f, 1.0f, true);
|
skybox_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 10.0f, 10.0f, 10.0f, 1.0f, true);
|
||||||
|
|
||||||
@ -95,14 +98,6 @@ void PlayGame(GameSettings settings)
|
|||||||
skybox_transform->position = {-5.0f, -5.0f, -5.0f};
|
skybox_transform->position = {-5.0f, -5.0f, -5.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floor */
|
|
||||||
{
|
|
||||||
engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true);
|
|
||||||
|
|
||||||
auto floor_transform = my_scene->GetComponent<engine::TransformComponent>(floor);
|
|
||||||
floor_transform->is_static = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* building */
|
/* building */
|
||||||
{
|
{
|
||||||
auto cobbleHouse = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/cobble_house/cobble_house.dae"), false);
|
auto cobbleHouse = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/cobble_house/cobble_house.dae"), false);
|
||||||
@ -119,9 +114,9 @@ void PlayGame(GameSettings settings)
|
|||||||
engine::Entity cube = my_scene->CreateEntity("cube", 0, glm::vec3{40.0f, 10.0f, 5.0f});
|
engine::Entity cube = my_scene->CreateEntity("cube", 0, glm::vec3{40.0f, 10.0f, 5.0f});
|
||||||
auto cubeRenderable = my_scene->AddComponent<engine::MeshRenderableComponent>(cube);
|
auto cubeRenderable = my_scene->AddComponent<engine::MeshRenderableComponent>(cube);
|
||||||
cubeRenderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 1.0f, 1.0f, 1.0f);
|
cubeRenderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 1.0f, 1.0f, 1.0f);
|
||||||
cubeRenderable->material = std::make_unique<engine::resources::Material>(app.GetResource<engine::resources::Shader>("builtin.standard"));
|
cubeRenderable->material = std::make_unique<engine::Material>(app.GetResource<engine::Shader>("builtin.standard"));
|
||||||
cubeRenderable->material->texture_ = std::make_unique<engine::resources::Texture>(app.renderer(), app.GetResourcePath("textures/uvcheck.png"),
|
cubeRenderable->material->texture_ =
|
||||||
engine::resources::Texture::Filtering::kAnisotropic);
|
engine::LoadTextureFromFile(app.GetResourcePath("textures/uvcheck.png"), engine::Texture::Filtering::kAnisotropic, app.renderer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some text */
|
/* some text */
|
||||||
@ -147,8 +142,61 @@ void PlayGame(GameSettings settings)
|
|||||||
my_scene->GetComponent<engine::TransformComponent>(engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/teapot.dae"), true))
|
my_scene->GetComponent<engine::TransformComponent>(engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/teapot.dae"), true))
|
||||||
->position += glm::vec3{10.0f, 10.0f, 10.0f};
|
->position += glm::vec3{10.0f, 10.0f, 10.0f};
|
||||||
|
|
||||||
//engine::util::LoadGLTF(*my_scene, app.GetResourcePath("engine/models/test/test.gltf"));
|
// engine::util::LoadGLTF(*my_scene, app.GetResourcePath("engine/models/test/test.gltf"));
|
||||||
|
|
||||||
app.GameLoop();
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine::Scene* scene2 = app.scene_manager()->CreateEmptyScene();
|
||||||
|
{
|
||||||
|
|
||||||
|
{ /* create camera */
|
||||||
|
engine::Entity camera = scene2->CreateEntity("camera");
|
||||||
|
|
||||||
|
/* as of right now, the entity with tag 'camera' is used to build the view
|
||||||
|
* matrix */
|
||||||
|
|
||||||
|
auto camera_transform = scene2->GetComponent<engine::TransformComponent>(camera);
|
||||||
|
camera_transform->position = {0.0f, 0.0f, 10.0f};
|
||||||
|
|
||||||
|
scene2->RegisterComponent<CameraControllerComponent>();
|
||||||
|
scene2->RegisterSystem<CameraControllerSystem>();
|
||||||
|
scene2->AddComponent<CameraControllerComponent>(camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* house */
|
||||||
|
engine::Entity floor = engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/cobble_house/cobble_house.dae"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* axes */
|
||||||
|
engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* a wall */
|
||||||
|
engine::Entity wall = scene2->CreateEntity("wall", 0, glm::vec3{50.0f, 0.0f, 0.0f});
|
||||||
|
auto wall_renderable = scene2->AddComponent<engine::MeshRenderableComponent>(wall);
|
||||||
|
wall_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 8.0f, 8.0f, 8.0f);
|
||||||
|
wall_renderable->material = std::make_unique<engine::Material>(app.renderer(), app.GetResource<engine::Shader>("builtin.fancy"));
|
||||||
|
|
||||||
|
std::shared_ptr<engine::Texture> albedo_texture =
|
||||||
|
engine::LoadTextureFromFile(app.GetResourcePath("textures/brickwall_albedo.jpg"), engine::Texture::Filtering::kTrilinear, app.renderer());
|
||||||
|
std::shared_ptr<engine::Texture> normal_texture =
|
||||||
|
engine::LoadTextureFromFile(app.GetResourcePath("textures/testnormal.png"), engine::Texture::Filtering::kTrilinear, app.renderer());
|
||||||
|
|
||||||
|
wall_renderable->material->SetAlbedoTexture(app.GetResource<engine::Texture>("builtin.white"));
|
||||||
|
wall_renderable->material->SetNormalTexture(normal_texture);
|
||||||
|
|
||||||
|
auto custom = scene2->AddComponent<engine::CustomComponent>(wall);
|
||||||
|
custom->onInit = []() {};
|
||||||
|
custom->onUpdate = [&](float dt) {
|
||||||
|
//scene2->GetComponent<engine::TransformComponent>(wall)->rotation *= glm::angleAxis(dt, glm::normalize(glm::vec3{2.0f, 1.0f, 1.0f}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my_scene->GetSystem<CameraControllerSystem>()->next_scene_ = scene2;
|
||||||
|
scene2->GetSystem<CameraControllerSystem>()->next_scene_ = my_scene;
|
||||||
|
|
||||||
|
app.scene_manager()->SetActiveScene(my_scene);
|
||||||
|
app.GameLoop();
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "resources/mesh.h"
|
#include "resources/mesh.h"
|
||||||
|
|
||||||
std::unique_ptr<engine::resources::Mesh> GenSphereMesh(engine::GFXDevice* gfx, float r, int detail, bool wind_inside, bool flip_normals)
|
std::unique_ptr<engine::Mesh> GenSphereMesh(engine::GFXDevice* gfx, float r, int detail, bool wind_inside, bool flip_normals)
|
||||||
{
|
{
|
||||||
using namespace glm;
|
using namespace glm;
|
||||||
|
|
||||||
@ -34,26 +34,26 @@ std::unique_ptr<engine::resources::Mesh> GenSphereMesh(engine::GFXDevice* gfx, f
|
|||||||
// tris are visible from outside the sphere
|
// tris are visible from outside the sphere
|
||||||
|
|
||||||
// triangle 1
|
// triangle 1
|
||||||
vertices.push_back({top_left, {}, {0.0f, 0.0f}});
|
vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}});
|
||||||
vertices.push_back({bottom_left, {}, {0.0f, 1.0f}});
|
vertices.push_back({bottom_left, {}, {}, {0.0f, 1.0f}});
|
||||||
vertices.push_back({bottom_right, {}, {1.0f, 1.0f}});
|
vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}});
|
||||||
// triangle 2
|
// triangle 2
|
||||||
vertices.push_back({top_right, {}, {1.0f, 0.0f}});
|
vertices.push_back({top_right, {}, {}, {1.0f, 0.0f}});
|
||||||
vertices.push_back({top_left, {}, {0.0f, 0.0f}});
|
vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}});
|
||||||
vertices.push_back({bottom_right, {}, {1.0f, 1.0f}});
|
vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// tris are visible from inside the sphere
|
// tris are visible from inside the sphere
|
||||||
|
|
||||||
// triangle 1
|
// triangle 1
|
||||||
vertices.push_back({bottom_right, {}, {1.0f, 1.0f}});
|
vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}});
|
||||||
vertices.push_back({bottom_left, {}, {0.0f, 1.0f}});
|
vertices.push_back({bottom_left, {}, {}, {0.0f, 1.0f}});
|
||||||
vertices.push_back({top_left, {}, {0.0f, 0.0f}});
|
vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}});
|
||||||
|
|
||||||
// triangle 2
|
// triangle 2
|
||||||
vertices.push_back({bottom_right, {}, {1.0f, 1.0f}});
|
vertices.push_back({bottom_right, {}, {}, {1.0f, 1.0f}});
|
||||||
vertices.push_back({top_left, {}, {0.0f, 0.0f}});
|
vertices.push_back({top_left, {}, {}, {0.0f, 0.0f}});
|
||||||
vertices.push_back({top_right, {}, {1.0f, 0.0f}});
|
vertices.push_back({top_right, {}, {}, {1.0f, 0.0f}});
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 vector1 = (vertices.end() - 1)->pos - (vertices.end() - 2)->pos;
|
vec3 vector1 = (vertices.end() - 1)->pos - (vertices.end() - 2)->pos;
|
||||||
@ -72,10 +72,10 @@ std::unique_ptr<engine::resources::Mesh> GenSphereMesh(engine::GFXDevice* gfx, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<engine::resources::Mesh>(gfx, vertices);
|
return std::make_unique<engine::Mesh>(gfx, vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<engine::resources::Mesh> GenCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling, bool wind_inside)
|
std::unique_ptr<engine::Mesh> GenCuboidMesh(engine::GFXDevice* gfx, float x, float y, float z, float tiling, bool wind_inside)
|
||||||
{
|
{
|
||||||
// x goes ->
|
// x goes ->
|
||||||
// y goes ^
|
// y goes ^
|
||||||
@ -86,47 +86,47 @@ std::unique_ptr<engine::resources::Mesh> GenCuboidMesh(engine::GFXDevice* gfx, f
|
|||||||
std::vector<engine::Vertex> v{};
|
std::vector<engine::Vertex> v{};
|
||||||
|
|
||||||
// front
|
// front
|
||||||
v.push_back({ {0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {0.0f, tiling} });
|
v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, tiling}});
|
||||||
v.push_back({ {x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}});
|
||||||
v.push_back({ {x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{x, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}});
|
||||||
v.push_back({ {x, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {tiling, 0.0f} });
|
v.push_back({{x, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, 0.0f}});
|
||||||
v.push_back({ {0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, 0.0f, z}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}});
|
||||||
// back
|
// back
|
||||||
v.push_back({ {x, y, z}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, y, z}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {x, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, tiling} });
|
v.push_back({{x, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, tiling}});
|
||||||
v.push_back({ {0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, y, 0.0f}, {0.0f, 1.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, y, z}, {0.0f, 1.0f, 0.0f}, {tiling, 0.0f} });
|
v.push_back({{0.0f, y, z}, {0.0f, 1.0f, 0.0f}, {}, {tiling, 0.0f}});
|
||||||
v.push_back({ {x, y, z}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, y, z}, {0.0f, 1.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
// left
|
// left
|
||||||
v.push_back({ {0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {0.0f, y, 0.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, tiling} });
|
v.push_back({{0.0f, y, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, tiling}});
|
||||||
v.push_back({ {0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, 0.0f, z}, {-1.0f, 0.0f, 0.0f}, {tiling, 0.0f} });
|
v.push_back({{0.0f, 0.0f, z}, {-1.0f, 0.0f, 0.0f}, {}, {tiling, 0.0f}});
|
||||||
v.push_back({ {0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, y, z}, {-1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
// right
|
// right
|
||||||
v.push_back({ {x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {x, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {0.0f, tiling} });
|
v.push_back({{x, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, tiling}});
|
||||||
v.push_back({ {x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {tiling, tiling} });
|
v.push_back({{x, y, 0.0f}, {1.0f, 0.0f, 0.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {x, y, z}, {1.0f, 0.0f, 0.0f}, {tiling, 0.0f} });
|
v.push_back({{x, y, z}, {1.0f, 0.0f, 0.0f}, {}, {tiling, 0.0f}});
|
||||||
v.push_back({ {x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, 0.0f, z}, {1.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}});
|
||||||
// top
|
// top
|
||||||
v.push_back({ {0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {0.0f, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {0.0f, tiling} });
|
v.push_back({{0.0f, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, tiling}});
|
||||||
v.push_back({ {x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {tiling, tiling} });
|
v.push_back({{x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}});
|
||||||
v.push_back({ {x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {tiling, tiling} });
|
v.push_back({{x, 0.0f, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, tiling}});
|
||||||
v.push_back({ {x, y, z}, {0.0f, 0.0f, 1.0f}, {tiling, 0.0f} });
|
v.push_back({{x, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {tiling, 0.0f}});
|
||||||
v.push_back({ {0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f} });
|
v.push_back({{0.0f, y, z}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f}});
|
||||||
// bottom
|
// bottom
|
||||||
v.push_back({ {x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, 0.0f}});
|
||||||
v.push_back({ {x, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, tiling} });
|
v.push_back({{x, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, tiling}});
|
||||||
v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, tiling} });
|
v.push_back({{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, tiling}});
|
||||||
v.push_back({ {0.0f, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {tiling, 0.0f} });
|
v.push_back({{0.0f, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {tiling, 0.0f}});
|
||||||
v.push_back({ {x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f} });
|
v.push_back({{x, y, 0.0f}, {0.0f, 0.0f, -1.0f}, {}, {0.0f, 0.0f}});
|
||||||
|
|
||||||
if (wind_inside) {
|
if (wind_inside) {
|
||||||
for (size_t i = 0; i < v.size(); i += 3) {
|
for (size_t i = 0; i < v.size(); i += 3) {
|
||||||
@ -134,5 +134,5 @@ std::unique_ptr<engine::resources::Mesh> GenCuboidMesh(engine::GFXDevice* gfx, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<engine::resources::Mesh>(gfx, v);
|
return std::make_unique<engine::Mesh>(gfx, v);
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
#include "resources/mesh.h"
|
#include "resources/mesh.h"
|
||||||
|
|
||||||
std::unique_ptr<engine::resources::Mesh> GenSphereMesh(
|
std::unique_ptr<engine::Mesh> GenSphereMesh(
|
||||||
engine::GFXDevice* gfx, float r, int detail, bool wind_inside = false,
|
engine::GFXDevice* gfx, float r, int detail, bool wind_inside = false,
|
||||||
bool flip_normals = false);
|
bool flip_normals = false);
|
||||||
|
|
||||||
std::unique_ptr<engine::resources::Mesh> GenCuboidMesh(
|
std::unique_ptr<engine::Mesh> GenCuboidMesh(
|
||||||
engine::GFXDevice* gfx, float x, float y, float z, float tiling = 1.0f,
|
engine::GFXDevice* gfx, float x, float y, float z, float tiling = 1.0f,
|
||||||
bool wind_inside = false);
|
bool wind_inside = false);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user