Get PBR rendering working

This commit is contained in:
bailehuni 2024-02-28 22:18:19 +00:00
parent 59eb1842e4
commit 984941d546
14 changed files with 247 additions and 211 deletions

BIN
doc/template.blend (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -11,6 +11,7 @@ namespace engine {
struct MeshRenderableComponent { struct MeshRenderableComponent {
std::shared_ptr<Mesh> mesh; std::shared_ptr<Mesh> mesh;
std::shared_ptr<Material> material; std::shared_ptr<Material> material;
bool visible = true; // for static meshes, changes to this may require the static render list to be rebuilt
}; };
} // namespace engine } // namespace engine

View File

@ -1,5 +1,8 @@
#version 450 #version 450
#define PI 3.1415926535897932384626433832795
#define PI_INV 0.31830988618379067153776752674503
layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler; layout(set = 2, binding = 0) uniform sampler2D materialSetAlbedoSampler;
layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler; layout(set = 2, binding = 1) uniform sampler2D materialSetNormalSampler;
layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler; layout(set = 2, binding = 2) uniform sampler2D materialSetOcclusionSampler;
@ -12,30 +15,61 @@ layout(location = 3) in vec3 fragLightPosTangentSpace;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
void main() { vec3 GetNormal() {
const vec3 norm_colour = vec3(texture(materialSetNormalSampler, fragUV));
// constants return normalize(norm_colour * 2.0 - 1.0);
vec3 lightColor = vec3(1.0, 0.9, 0.9);
vec3 ambientColor = vec3(1.0, 0.0, 0.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.y = 1.0 - norm.y;
norm = normalize(norm * 2.0 - 1.0);
vec3 lightDir = normalize(fragLightPosTangentSpace - fragPosTangentSpace);
vec3 viewDir = normalize(fragViewPosTangentSpace - fragPosTangentSpace);
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 = diffuse + ambient + specular;
outColor = vec4(min(baseColor * (lighting + emission), 1.0), 1.0);
} }
float GGXDist(float alpha_2, float N_dot_H) {
const float num = alpha_2 * max(N_dot_H, 0.0);
const float den = PI * pow(N_dot_H * N_dot_H * (alpha_2 - 1) + 1, 2.0);
return num / den;
}
void main() {
const vec3 metallic_roughness = vec3(texture(materialSetMetallicRoughnessSampler, fragUV));
const float metallic = metallic_roughness.g;
const float roughness = metallic_roughness.b;
const float roughness_2 = roughness * roughness;
const vec3 light_colour = vec3(1.0, 1.0, 1.0) * 2.4;
const vec3 emission = vec3(0.0, 0.0, 0.0);
const float ao = texture(materialSetOcclusionSampler, fragUV).r;
const vec3 albedo = vec3(texture(materialSetAlbedoSampler, fragUV));
const vec3 N = GetNormal();
const vec3 V = normalize(fragViewPosTangentSpace - fragPosTangentSpace);
//const vec3 L = normalize(fragLightPosTangentSpace - fragPosTangentSpace);
const vec3 L = normalize(vec3(5.0, 0.0, 3.0));
const vec3 H = normalize(V + L);
//const vec3 dielectric_brdf = FresnelMix();
//const vec3 brdf = mix(dielectric_brdf, metal_brdf, metallic);
const float L_dot_N = max(dot(L, N), 0.000001);
const float L_dot_H = max(dot(L, H), 0.000001);
const float V_dot_H = max(dot(V, H), 0.000001);
const float V_dot_N = max(dot(V, N), 0.000001);
const float N_dot_H = max(dot(N, H), 0.000001);
const float vis = ( max(L_dot_H, 0.0) / ( L_dot_N + sqrt(roughness_2 + (1 - roughness_2) * L_dot_N * L_dot_N) ) ) *
( max(V_dot_H, 0.0) / ( V_dot_N + sqrt(roughness_2 + (1 - roughness_2) * V_dot_N * V_dot_N) ) );
const vec3 diffuse_brdf = albedo * PI_INV;
const vec3 specular_brdf = vec3(vis * GGXDist(roughness_2, N_dot_H));
const vec3 dielectric_brdf = mix(diffuse_brdf, specular_brdf, 0.04 + (1 - 0.04) * pow(1 - abs(V_dot_H), 5));
const vec3 metal_brdf = specular_brdf * (albedo + (1 - albedo) * pow(1 - V_dot_H, 5.0) );
const vec3 brdf = mix(dielectric_brdf, metal_brdf, metallic);
const vec3 lighting = brdf * light_colour * L_dot_N;
outColor = vec4(min(emission + lighting, 1.0), 1.0);
}

View File

@ -118,16 +118,63 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings); GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings);
GetResourceManager<Shader>()->AddPersistent("builtin.fancy", std::move(fancyShader)); GetResourceManager<Shader>()->AddPersistent("builtin.fancy", std::move(fancyShader));
} }
{
Shader::VertexParams vertParams{};
vertParams.has_normal = true;
vertParams.has_tangent = true;
vertParams.has_uv0 = true;
Shader::ShaderSettings shaderSettings{};
shaderSettings.vertexParams = vertParams;
shaderSettings.alpha_blending = false;
shaderSettings.cull_backface = true;
shaderSettings.write_z = false;
shaderSettings.render_order = 1;
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));
}
/* default textures */ /* default textures */
{ {
auto whiteTexture = LoadTextureFromFile(GetResourcePath("engine/textures/white.png"), gfx::SamplerInfo{}, renderer(), true); const uint8_t pixel[4] = { 255, 255, 255, 255 };
gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest;
samplerInfo.mipmap = gfx::Filter::kNearest;
samplerInfo.anisotropic_filtering = false;
auto whiteTexture = std::make_unique<Texture>(renderer(), pixel, 1, 1, samplerInfo, true);
GetResourceManager<Texture>()->AddPersistent("builtin.white", std::move(whiteTexture)); GetResourceManager<Texture>()->AddPersistent("builtin.white", std::move(whiteTexture));
} }
{ {
auto normalTexture = LoadTextureFromFile(GetResourcePath("engine/textures/normal.png"), gfx::SamplerInfo{}, renderer(), false); const uint8_t pixel[4] = { 0, 0, 0, 255 };
gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest;
samplerInfo.mipmap = gfx::Filter::kNearest;
samplerInfo.anisotropic_filtering = false;
auto blackTexture = std::make_unique<Texture>(renderer(), pixel, 1, 1, samplerInfo, true);
GetResourceManager<Texture>()->AddPersistent("builtin.black", std::move(blackTexture));
}
{
const uint8_t pixel[4] = { 127, 127, 255, 255 };
gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest;
samplerInfo.mipmap = gfx::Filter::kNearest;
samplerInfo.anisotropic_filtering = false;
auto normalTexture = std::make_unique<Texture>(renderer(), pixel, 1, 1, samplerInfo, false);
GetResourceManager<Texture>()->AddPersistent("builtin.normal", std::move(normalTexture)); GetResourceManager<Texture>()->AddPersistent("builtin.normal", std::move(normalTexture));
} }
{
const uint8_t pixel[4] = { 255, 0, 127, 255 };
gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest;
samplerInfo.mipmap = gfx::Filter::kNearest;
samplerInfo.anisotropic_filtering = false;
auto mrTexture = std::make_unique<Texture>(renderer(), pixel, 1, 1, samplerInfo, false);
GetResourceManager<Texture>()->AddPersistent("builtin.mr", std::move(mrTexture));
}
/* default materials */ /* default materials */
{ {

View File

@ -731,9 +731,9 @@ gfx::DrawBuffer* GFXDevice::BeginRender()
std::array<VkClearValue, 2> clearValues{}; // Using same value for all components enables std::array<VkClearValue, 2> clearValues{}; // Using same value for all components enables
// compression according to NVIDIA Best Practices // compression according to NVIDIA Best Practices
clearValues[0].color.float32[0] = 0.02f; clearValues[0].color.float32[0] = 1.0f;
clearValues[0].color.float32[1] = 0.0f; clearValues[0].color.float32[1] = 1.0f;
clearValues[0].color.float32[2] = 0.0f; clearValues[0].color.float32[2] = 1.0f;
clearValues[0].color.float32[3] = 1.0f; clearValues[0].color.float32[3] = 1.0f;
clearValues[1].depthStencil.depth = 1.0f; clearValues[1].depthStencil.depth = 1.0f;

View File

@ -50,6 +50,8 @@ void MeshRenderSystem::BuildRenderList(RenderList& render_list, bool with_static
auto renderable = scene_->GetComponent<engine::MeshRenderableComponent>(entity); auto renderable = scene_->GetComponent<engine::MeshRenderableComponent>(entity);
if (renderable->visible == false) continue;
const gfx::Pipeline* pipeline = renderable->material->GetShader()->GetPipeline(); const gfx::Pipeline* pipeline = renderable->material->GetShader()->GetPipeline();
render_list.emplace_back(RenderListEntry{.pipeline = pipeline, render_list.emplace_back(RenderListEntry{.pipeline = pipeline,

View File

@ -26,7 +26,10 @@ struct Color {
namespace std { namespace std {
template <> template <>
struct std::hash<Color> { struct std::hash<Color> {
std::size_t operator()(const Color& k) const { return k.r << 24 | k.g << 16 | k.b << 8 | k.a; } std::size_t operator()(const Color& k) const
{
return static_cast<size_t>(k.r) << 24 | static_cast<size_t>(k.g) << 16 | static_cast<size_t>(k.b) << 8 | static_cast<size_t>(k.a);
}
}; };
} // namespace std } // namespace std
@ -116,14 +119,14 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
const tg::Scene& s = model.scenes.at(scene_index); const tg::Scene& s = model.scenes.at(scene_index);
/* Find which texture indices point to normal maps. */ /* Find which texture indices point to base color maps. */
/* This must be done for the Texture constructor to know to use srgb or not. */ /* This must be done for the Texture constructor to know to use srgb or not. */
std::vector<bool> tex_index_is_normal_map(model.textures.size(), false); std::vector<bool> tex_index_is_base_color(model.textures.size(), false);
for (const tg::Material& mat : model.materials) { for (const tg::Material& mat : model.materials) {
int texture_index = mat.normalTexture.index; int texture_index = mat.pbrMetallicRoughness.baseColorTexture.index;
if (texture_index != -1) { if (texture_index != -1) {
assert(texture_index < tex_index_is_normal_map.size()); assert(texture_index < tex_index_is_base_color.size());
tex_index_is_normal_map[texture_index] = true; tex_index_is_base_color[texture_index] = true;
} }
} }
@ -186,7 +189,8 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
const tg::Image& image = model.images.at(texture.source); const tg::Image& image = model.images.at(texture.source);
if (image.as_is == false && image.bits == 8 && image.component == 4 && image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { if (image.as_is == false && image.bits == 8 && image.component == 4 && image.pixel_type == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
// create texture on GPU // create texture on GPU
textures.back() = std::make_shared<Texture>(scene.app()->renderer(), image.image.data(), image.width, image.height, samplerInfo, !tex_index_is_normal_map[texture_idx]); textures.back() = std::make_shared<Texture>(scene.app()->renderer(), image.image.data(), image.width, image.height, samplerInfo,
tex_index_is_base_color[texture_idx]);
} }
++texture_idx; ++texture_idx;
@ -196,6 +200,8 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
// store some 1x1 colour textures as a hack to render solid colours // store some 1x1 colour textures as a hack to render solid colours
std::unordered_map<Color, std::shared_ptr<Texture>> colour_textures; std::unordered_map<Color, std::shared_ptr<Texture>> colour_textures;
// same for metallic roughness:
std::unordered_map<Color, std::shared_ptr<Texture>> metal_rough_textures;
std::vector<std::shared_ptr<Material>> materials{}; std::vector<std::shared_ptr<Material>> materials{};
materials.reserve(model.materials.size()); materials.reserve(model.materials.size());
@ -213,10 +219,6 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
LOG_WARN("Material {} contains an emissive texture or non-zero emissive factor. Emission is currently unsupported.", material.name); LOG_WARN("Material {} contains an emissive texture or non-zero emissive factor. Emission is currently unsupported.", material.name);
LOG_WARN("Material will be created without emission."); LOG_WARN("Material will be created without emission.");
} }
if (material.occlusionTexture.index != -1) {
LOG_WARN("Material {} contains an ambient occlusion texture which isn't supported yet.", material.name);
LOG_WARN("Material will be created without an occlusion map.");
}
const auto& baseColorFactor4 = material.pbrMetallicRoughness.baseColorFactor; const auto& baseColorFactor4 = material.pbrMetallicRoughness.baseColorFactor;
if (baseColorFactor4[0] != 1.0 || baseColorFactor4[1] != 1.0 || baseColorFactor4[2] != 1.0 || baseColorFactor4[3] != 1.0) { if (baseColorFactor4[0] != 1.0 || baseColorFactor4[1] != 1.0 || baseColorFactor4[2] != 1.0 || baseColorFactor4[3] != 1.0) {
if (material.pbrMetallicRoughness.baseColorTexture.index != -1) { if (material.pbrMetallicRoughness.baseColorTexture.index != -1) {
@ -224,20 +226,16 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
LOG_WARN("The material's base color texture will be used as-is."); LOG_WARN("The material's base color texture will be used as-is.");
} }
} }
if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) { if (material.pbrMetallicRoughness.metallicFactor != 1.0 || material.pbrMetallicRoughness.roughnessFactor != 1.0) {
LOG_WARN("Material {} contains a metallic-roughness texture which isn't supported yet.", material.name); if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) {
LOG_WARN("This texture will be ignored."); LOG_WARN("Material {} contains a metallic and/or roughness multiplier which isn't supported yet.", material.name);
} LOG_WARN("The material's metallic-roughness texture will be used as-is.");
if (material.pbrMetallicRoughness.metallicFactor != 1.0) { }
LOG_WARN("Material {} contains a metallic factor != 1.0 which isn't supported yet.", material.name);
LOG_WARN("Material will be created as fully metallic");
}
if (material.pbrMetallicRoughness.roughnessFactor != 1.0) {
LOG_WARN("Material {} contains a roughness factor != 1.0 which isn't supported yet.", material.name);
LOG_WARN("Material will be created as fully rough");
} }
materials.emplace_back(std::make_shared<Material>(scene.app()->renderer(), scene.app()->GetResource<Shader>("builtin.fancy"))); materials.emplace_back(std::make_shared<Material>(scene.app()->renderer(), scene.app()->GetResource<Shader>("builtin.fancy")));
// base color
materials.back()->SetAlbedoTexture(scene.app()->GetResource<Texture>("builtin.white")); materials.back()->SetAlbedoTexture(scene.app()->GetResource<Texture>("builtin.white"));
if (material.pbrMetallicRoughness.baseColorTexture.index != -1) { if (material.pbrMetallicRoughness.baseColorTexture.index != -1) {
if (material.pbrMetallicRoughness.baseColorTexture.texCoord == 0) { if (material.pbrMetallicRoughness.baseColorTexture.texCoord == 0) {
@ -252,11 +250,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
LOG_INFO("Creating a base-color texture..."); LOG_INFO("Creating a base-color texture...");
Color c(baseColorFactor4); Color c(baseColorFactor4);
if (colour_textures.contains(c) == false) { if (colour_textures.contains(c) == false) {
uint8_t pixel[4]; const uint8_t pixel[4] = {c.r, c.g, c.b, c.a};
pixel[0] = c.r;
pixel[1] = c.g;
pixel[2] = c.b;
pixel[3] = c.a;
gfx::SamplerInfo samplerInfo{}; gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest; samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest; samplerInfo.magnify = gfx::Filter::kNearest;
@ -267,6 +261,48 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
materials.back()->SetAlbedoTexture(colour_textures.at(c)); materials.back()->SetAlbedoTexture(colour_textures.at(c));
} }
// metallic roughness
materials.back()->SetMetallicRoughnessTexture(scene.app()->GetResource<Texture>("builtin.white")); // default metal = 1.0, rough = 1.0
if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) {
if (material.pbrMetallicRoughness.metallicRoughnessTexture.texCoord == 0) {
LOG_INFO("Setting metallic roughness texture!");
materials.back()->SetMetallicRoughnessTexture(textures.at(material.pbrMetallicRoughness.metallicRoughnessTexture.index));
}
else {
LOG_WARN("Material {} metallic roughness texture specifies a UV channel other than zero which is unsupported.", material.name);
LOG_WARN("Material will be created with a default metallic roughness");
}
}
else {
LOG_INFO("Creating a metallic-roughness texture...");
const std::vector<double> mr_values{1.0f, material.pbrMetallicRoughness.metallicFactor, material.pbrMetallicRoughness.roughnessFactor, 1.0f};
Color mr(mr_values);
if (metal_rough_textures.contains(mr) == false) {
const uint8_t pixel[4] = {mr.r, mr.g, mr.b, mr.a};
gfx::SamplerInfo samplerInfo{};
samplerInfo.minify = gfx::Filter::kNearest;
samplerInfo.magnify = gfx::Filter::kNearest;
samplerInfo.mipmap = gfx::Filter::kNearest;
samplerInfo.anisotropic_filtering = false;
metal_rough_textures.emplace(std::make_pair(mr, std::make_shared<Texture>(scene.app()->renderer(), pixel, 1, 1, samplerInfo, false)));
}
materials.back()->SetMetallicRoughnessTexture(metal_rough_textures.at(mr));
}
// occlusion texture
materials.back()->SetOcclusionTexture(scene.app()->GetResource<Texture>("builtin.white")); // R=255 means no AO so white will work
if (material.occlusionTexture.index != -1) {
if (material.occlusionTexture.texCoord == 0) {
LOG_INFO("Setting occlusion texture!");
materials.back()->SetOcclusionTexture(textures.at(material.occlusionTexture.index));
}
else {
LOG_WARN("Material {} occlusion texture specifies a UV channel other than zero which is unsupported.", material.name);
LOG_WARN("Material will be created with no ambient occlusion");
}
}
// normal map
materials.back()->SetNormalTexture(scene.app()->GetResource<Texture>("builtin.normal")); materials.back()->SetNormalTexture(scene.app()->GetResource<Texture>("builtin.normal"));
if (material.normalTexture.index != -1) { if (material.normalTexture.index != -1) {
if (material.normalTexture.texCoord == 0) { if (material.normalTexture.texCoord == 0) {
@ -412,7 +448,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
mts_interface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext*, const int) -> int { return 3; }; mts_interface.m_getNumVerticesOfFace = [](const SMikkTSpaceContext*, const int) -> int { return 3; };
mts_interface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) -> void { mts_interface.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) -> void {
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData); const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
const size_t i = iFace * 3 + iVert; const size_t i = static_cast<size_t>(iFace) * 3 + static_cast<size_t>(iVert);
assert(i < meshData->num_indices); assert(i < meshData->num_indices);
const size_t vertex_index = meshData->indices[i]; const size_t vertex_index = meshData->indices[i];
const glm::vec3 pos = meshData->positions->operator[](vertex_index); const glm::vec3 pos = meshData->positions->operator[](vertex_index);
@ -422,7 +458,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
}; };
mts_interface.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) -> void { mts_interface.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) -> void {
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData); const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
const size_t i = iFace * 3 + iVert; const size_t i = static_cast<size_t>(iFace) * 3 + static_cast<size_t>(iVert);
assert(i < meshData->num_indices); assert(i < meshData->num_indices);
const size_t vertex_index = meshData->indices[i]; const size_t vertex_index = meshData->indices[i];
const glm::vec3 norm = meshData->normals->operator[](vertex_index); const glm::vec3 norm = meshData->normals->operator[](vertex_index);
@ -432,7 +468,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
}; };
mts_interface.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) -> void { mts_interface.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) -> void {
const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData); const MeshData* const meshData = static_cast<const MeshData*>(pContext->m_pUserData);
const size_t i = iFace * 3 + iVert; const size_t i = static_cast<size_t>(iFace) * 3 + static_cast<size_t>(iVert);
assert(i < meshData->num_indices); assert(i < meshData->num_indices);
const size_t vertex_index = meshData->indices[i]; const size_t vertex_index = meshData->indices[i];
const glm::vec2 uv = meshData->uvs->operator[](vertex_index); const glm::vec2 uv = meshData->uvs->operator[](vertex_index);
@ -442,7 +478,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
mts_interface.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, mts_interface.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace,
const int iVert) -> void { const int iVert) -> void {
MeshData* const meshData = static_cast<MeshData*>(pContext->m_pUserData); MeshData* const meshData = static_cast<MeshData*>(pContext->m_pUserData);
const size_t i = iFace * 3 + iVert; const size_t i = static_cast<size_t>(iFace) * 3 + static_cast<size_t>(iVert);
assert(i < meshData->num_indices); assert(i < meshData->num_indices);
const size_t vertex_index = meshData->indices[i]; const size_t vertex_index = meshData->indices[i];
@ -470,7 +506,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
std::vector<Vertex> vertex_data_out(num_indices); // initialised to zeros std::vector<Vertex> vertex_data_out(num_indices); // initialised to zeros
const int num_unq_vertices = WeldMesh(remap_table.data(), reinterpret_cast<float*>(vertex_data_out.data()), const int num_unq_vertices = WeldMesh(remap_table.data(), reinterpret_cast<float*>(vertex_data_out.data()),
reinterpret_cast<float*>(vertices.data()), static_cast<int>(num_indices), Vertex::FloatsPerVertex()); reinterpret_cast<float*>(vertices.data()), static_cast<int>(num_indices), Vertex::FloatsPerVertex());
assert(num_unq_vertices >= 0); assert(num_unq_vertices >= 0);
// get new vertices into the vector // get new vertices into the vector

View File

@ -42,6 +42,9 @@ namespace engine {
sc->surfaceFormat = format; // prefer using srgb non linear colors sc->surfaceFormat = format; // prefer using srgb non linear colors
} }
} }
if (sc->surfaceFormat.colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
LOG_ERROR("Swapchain not using an SRGB surface!!!");
}
// check there is at least one supported present mode // check there is at least one supported present mode
uint32_t surfacePresentModeCount = 0; uint32_t surfacePresentModeCount = 0;

BIN
test/res/models/bottle.glb Normal file

Binary file not shown.

BIN
test/res/models/monke.glb Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -59,168 +59,78 @@ 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(); engine::Scene* start_scene = app.scene_manager()->CreateEmptyScene();
{ {
/* create camera */
engine::Entity camera = start_scene->CreateEntity("camera");
{ /* create camera */ /* as of right now, the entity with tag 'camera' is used to build the view
engine::Entity camera = my_scene->CreateEntity("camera"); * matrix */
/* as of right now, the entity with tag 'camera' is used to build the view auto camera_transform = start_scene->GetComponent<engine::TransformComponent>(camera);
* matrix */ camera_transform->position = {0.0f, 0.0f, 10.0f};
auto camera_transform = my_scene->GetComponent<engine::TransformComponent>(camera); start_scene->RegisterComponent<CameraControllerComponent>();
camera_transform->position = {0.0f, 0.0f, 10.0f}; start_scene->RegisterSystem<CameraControllerSystem>();
start_scene->AddComponent<CameraControllerComponent>(camera);
}
my_scene->RegisterComponent<CameraControllerComponent>(); engine::Scene* main_scene = app.scene_manager()->CreateEmptyScene();
my_scene->RegisterSystem<CameraControllerSystem>(); {
my_scene->AddComponent<CameraControllerComponent>(camera); /* create camera */
} engine::Entity camera = main_scene->CreateEntity("camera");
{ /* floor */ /* as of right now, the entity with tag 'camera' is used to build the view
[[maybe_unused]] engine::Entity floor = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/terrain.dae"), true); * matrix */
}
#if 0 auto camera_transform = main_scene->GetComponent<engine::TransformComponent>(camera);
camera_transform->position = {-5.0f, -10.0f, 4.0f};
/* shared resources */ main_scene->RegisterComponent<CameraControllerComponent>();
auto grass_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/grass.png"), engine::Texture::Filtering::kAnisotropic, app.renderer()); main_scene->RegisterSystem<CameraControllerSystem>();
main_scene->AddComponent<CameraControllerComponent>(camera);
std::shared_ptr<engine::Texture> sky_texture = engine::LoadTextureFromFile(app.GetResourcePath("textures/sky.jpg"), engine::Texture::Filtering::kAnisotropic, app.renderer()); /* floor */
engine::Entity floor = main_scene->CreateEntity("floor", 0, glm::vec3{-50.0f, -50.0f, 0.0f});
auto floor_renderable = main_scene->AddComponent<engine::MeshRenderableComponent>(floor);
floor_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 50.0f);
floor_renderable->material = std::make_unique<engine::Material>(app.renderer(), app.GetResource<engine::Shader>("builtin.fancy"));
std::shared_ptr<engine::Texture> floor_albedo =
engine::LoadTextureFromFile(app.GetResourcePath("textures/bricks-mortar-albedo.png"), engine::gfx::SamplerInfo{}, app.renderer());
std::shared_ptr<engine::Texture> floor_normal =
engine::LoadTextureFromFile(app.GetResourcePath("textures/bricks-mortar-normal.png"), engine::gfx::SamplerInfo{}, app.renderer(), false);
std::shared_ptr<engine::Texture> floor_mr =
engine::LoadTextureFromFile(app.GetResourcePath("textures/bricks-mortar-roughness.png"), engine::gfx::SamplerInfo{}, app.renderer(), false);
floor_renderable->material->SetAlbedoTexture(floor_albedo);
floor_renderable->material->SetNormalTexture(floor_normal);
floor_renderable->material->SetMetallicRoughnessTexture(floor_mr);
floor_renderable->material->SetOcclusionTexture(app.GetResource<engine::Texture>("builtin.white"));
floor_renderable->visible = false;
engine::Entity normal_map_test = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/normalmaptest.glb"));
main_scene->GetComponent<engine::TransformComponent>(normal_map_test)->position += glm::vec3{-10.0f, 0.0f, 1.0f};
engine::Entity monke = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/monke.glb"));
engine::Entity bottle = engine::util::LoadGLTF(*main_scene, app.GetResourcePath("models/bottle.glb"));
main_scene->GetComponent<engine::TransformComponent>(bottle)->scale *= 50.0f;
main_scene->GetComponent<engine::TransformComponent>(bottle)->position.z += 50.0f;;
/* skybox */ /* skybox */
{ engine::Entity skybox = main_scene->CreateEntity("skybox");
engine::Entity skybox = my_scene->CreateEntity("skybox"); auto skybox_transform = main_scene->GetComponent<engine::TransformComponent>(skybox);
skybox_transform->is_static = true;
auto skybox_renderable = my_scene->AddComponent<engine::MeshRenderableComponent>(skybox); skybox_transform->position = { -5.0f, -5.0f, -5.0f };
skybox_renderable->material = std::make_unique<engine::Material>(app.GetResource<engine::Shader>("builtin.skybox")); auto skybox_renderable = main_scene->AddComponent<engine::MeshRenderableComponent>(skybox);
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); skybox_renderable->material = std::make_unique<engine::Material>(app.renderer(), app.GetResource<engine::Shader>("builtin.skybox"));
skybox_renderable->material->SetAlbedoTexture(app.GetResource<engine::Texture>("builtin.black"));
auto skybox_transform = my_scene->GetComponent<engine::TransformComponent>(skybox);
skybox_transform->is_static = true;
skybox_transform->position = {-5.0f, -5.0f, -5.0f};
}
/* building */
{
auto cobbleHouse = engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/cobble_house/cobble_house.dae"), false);
my_scene->GetComponent<engine::TransformComponent>(cobbleHouse)->position += glm::vec3{33.0f, 35.0f, 0.1f};
auto cobbleCustom = my_scene->AddComponent<engine::CustomComponent>(cobbleHouse);
cobbleCustom->onInit = [](void) { LOG_INFO("Cobble house spin component initialised!"); };
cobbleCustom->onUpdate = [&](float ts) {
static auto t = my_scene->GetComponent<engine::TransformComponent>(cobbleHouse);
t->rotation *= glm::angleAxis(ts, glm::vec3{0.0f, 0.0f, 1.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);
cubeRenderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 1.0f, 1.0f, 1.0f);
cubeRenderable->material = std::make_unique<engine::Material>(app.GetResource<engine::Shader>("builtin.standard"));
cubeRenderable->material->texture_ =
engine::LoadTextureFromFile(app.GetResourcePath("textures/uvcheck.png"), engine::Texture::Filtering::kAnisotropic, app.renderer());
}
/* some text */
{
engine::Entity textbox = my_scene->CreateEntity("textbox", 0, glm::vec3{0.0f, 0.8f, 0.0f});
auto textboxComponent = my_scene->AddComponent<engine::CustomComponent>(textbox);
textboxComponent->onInit = [](void) { LOG_DEBUG("Textbox custom component initialised!"); };
textboxComponent->onUpdate = [&](float ts) {
static float time_elapsed;
time_elapsed += ts;
if (time_elapsed >= 1.0f) {
time_elapsed = 0.0f;
}
};
}
engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/MY_AXES.dae"), true);
my_scene->GetComponent<engine::TransformComponent>(engine::util::LoadMeshFromFile(my_scene, app.GetResourcePath("models/uvcheck.dae"), true))
->position += glm::vec3{20.0f, 20.0f, 20.0f};
/* teapot */
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};
// engine::util::LoadGLTF(*my_scene, app.GetResourcePath("engine/models/test/test.gltf"));
#endif
} }
engine::Scene* scene2 = app.scene_manager()->CreateEmptyScene(); start_scene->GetSystem<CameraControllerSystem>()->next_scene_ = main_scene;
{ main_scene->GetSystem<CameraControllerSystem>()->next_scene_ = start_scene;
{ /* create camera */ app.scene_manager()->SetActiveScene(start_scene);
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);
}
{
/* axes */
auto axes = engine::util::LoadMeshFromFile(scene2, app.GetResourcePath("models/MY_AXES.dae"), true);
scene2->GetComponent<engine::TransformComponent>(axes)->position += glm::vec3{20.0f, 20.0f, 0.0f};
}
{ /* floor */
engine::Entity floor = scene2->CreateEntity("floor", 0, glm::vec3{-50.0f, -50.0f, 0.0f});
auto floor_renderable = scene2->AddComponent<engine::MeshRenderableComponent>(floor);
floor_renderable->mesh = GenCuboidMesh(app.renderer()->GetDevice(), 100.0f, 100.0f, 0.1f, 100.0f);
floor_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::gfx::SamplerInfo{}, app.renderer());
std::shared_ptr<engine::Texture> normal_texture =
engine::LoadTextureFromFile(app.GetResourcePath("textures/brickwall_normal.jpg"), engine::gfx::SamplerInfo{}, app.renderer(), false);
floor_renderable->material->SetAlbedoTexture(albedo_texture);
floor_renderable->material->SetNormalTexture(normal_texture);
}
{ /* teapots */
auto teapot = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot_with_tangents.glb"));
scene2->GetComponent<engine::TransformComponent>(teapot)->scale *= 10.0f;
auto teapot2 = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/teapot.glb"));
scene2->GetComponent<engine::TransformComponent>(teapot2)->scale *= 10.0f;
scene2->GetComponent<engine::TransformComponent>(teapot2)->position.z += 10.0f;
auto custom = scene2->AddComponent<engine::CustomComponent>(teapot2);
custom->onInit = [](void) { return; };
custom->onUpdate = [&](float dt) {
dt *= 0.1f;
scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation *= glm::angleAxis(dt, glm::vec3{0.0f, 1.0f, 0.0f});
//scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
scene2->GetComponent<engine::TransformComponent>(teapot)->rotation *= glm::angleAxis(dt, glm::vec3{0.0f, 1.0f, 0.0f});
};
}
{
auto redcube = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/redcube.glb"));
}
auto normalmaptest = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/normalmaptest.glb"));
scene2->GetComponent<engine::TransformComponent>(normalmaptest)->position += glm::vec3{-10.0f, 0.0f, 1.0f};
auto normalmaptest_notang = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/normalmaptest_notang.glb"));
scene2->GetComponent<engine::TransformComponent>(normalmaptest_notang)->position += glm::vec3{-10.0f, 10.0f, 1.0f};
auto custom = scene2->AddComponent<engine::CustomComponent>(normalmaptest);
custom->onInit = [](void) { return; };
custom->onUpdate = [&](float dt) {
scene2->GetComponent<engine::TransformComponent>(normalmaptest)->rotation *= glm::angleAxis(dt, glm::vec3{ 0.0f, 0.0f, 1.0f });
scene2->GetComponent<engine::TransformComponent>(normalmaptest_notang)->rotation *= glm::angleAxis(dt, glm::vec3{ 0.0f, 0.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(); app.GameLoop();
} }