Reworked SHMaterialSpec and SHMaterial loading system

This commit is contained in:
Kah Wei 2022-11-02 16:56:38 +08:00
parent 129f92e4b6
commit d207042fec
5 changed files with 238 additions and 160 deletions

View File

@ -0,0 +1,74 @@
/************************************************************************************//*!
\file SHMaterialSpec.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 2, 2022
\brief Contains the function definitions of SHMaterialSpec.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#include "SHpch.h"
#include "SHMaterialSpec.h"
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "Resource/SHResourceManager.h"
#include "Graphics/MiddleEnd/Interface/SHMaterial.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHMaterialSpec::SHMaterialSpec(const SHMaterial& material)
{
// Get Shader Handles
const auto& SHADERS = material.GetPipeline()->GetPipelineLayout()->GetShaderModules();
Handle<SHVkShaderModule> vShaderMod, fShaderMod;
for (const auto& shader : SHADERS)
{
const auto FLAG_BITS = shader->GetShaderStageFlagBits();
if (FLAG_BITS & vk::ShaderStageFlagBits::eVertex)
vShaderMod = shader;
else if (FLAG_BITS & vk::ShaderStageFlagBits::eFragment)
fShaderMod = shader;
}
vertexShader = SHResourceManager::GetAssetID<SHVkShaderModule>(vShaderMod).value_or(0);
fragShader = SHResourceManager::GetAssetID<SHVkShaderModule>(vShaderMod).value_or(0);
subpassName = material.GetPipeline()->GetPipelineState().GetSubpass()->GetName();
// Write Properties
Handle<SHShaderBlockInterface> pipelineProperties = material.GetShaderBlockInterface();
for (int i = 0; i < static_cast<int>(pipelineProperties->GetVariableCount()); ++i)
{
const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i);
if (!VARIABLE)
break;
const std::string& VAR_NAME = pipelineProperties->GetVariableName(i);
YAML::Node propNode;
switch (VARIABLE->type)
{
case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT:
propNode = material.GetProperty<float>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::INT:
propNode = material.GetProperty<int>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2:
propNode = material.GetProperty<SHVec2>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3:
propNode = material.GetProperty<SHVec3>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4:
propNode = material.GetProperty<SHVec4>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::OTHER:
default:
continue;
break;
}
properties[VAR_NAME.data()] = propNode;
}
}
}

View File

@ -20,6 +20,14 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declaration */
/*-----------------------------------------------------------------------------------*/
class SHMaterial;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/*************************************************************************************/
/*!
\brief
@ -33,5 +41,11 @@ namespace SHADE
AssetID fragShader;
std::string subpassName;
YAML::Node properties;
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
SHMaterialSpec() = default;
SHMaterialSpec(const SHMaterial& material);
};
}

View File

@ -13,6 +13,8 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes
#include <unordered_map>
namespace SHADE { class SHMaterial; }
// Project Includes
#include "SH_API.h"
#include "SHResourceLibrary.h"
@ -24,6 +26,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h"
#include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Assets/Asset Types/SHMaterialAsset.h"
namespace SHADE
@ -50,9 +53,11 @@ namespace SHADE
using AssetType = SHShaderAsset;
};
template<>
struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; };
template<>
struct SHResourceLoader<SHMaterial>
{
using AssetType = SHMaterialAsset;
using AssetType = SHMaterialSpec;
};
@ -79,6 +84,8 @@ namespace SHADE
/// <returns>Handle to a loaded runtime asset.</returns>
template<typename ResourceType>
static Handle<ResourceType> LoadOrGet(AssetID assetId);
template<>
static inline Handle<SHMaterial> LoadOrGet<SHMaterial>(AssetID assetId);
/// <summary>
/// Unloads an existing loaded asset. Attempting to unload an invalid Handle will
/// simply do nothing except emit a warning.

View File

@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Serialization/SHSerializationHelper.hpp"
namespace SHADE
{
@ -34,7 +35,12 @@ namespace SHADE
Handle<ResourceType> SHResourceManager::LoadOrGet(AssetID assetId)
{
// Check if it is an unsupported type
if (!std::is_same_v<ResourceType, SHMesh> && !std::is_same_v<ResourceType, SHTexture>)
if (!std::is_same_v<ResourceType, SHMesh> &&
!std::is_same_v<ResourceType, SHTexture> &&
!std::is_same_v<ResourceType, SHVkShaderModule> &&
!std::is_same_v<ResourceType, SHMaterialSpec> &&
!std::is_same_v<ResourceType, SHMaterial>
)
{
static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
}
@ -54,14 +60,41 @@ namespace SHADE
}
auto handle = load<ResourceType>(assetId, *assetData);
Handle genericHandle = Handle();
Handle genericHandle = Handle(handle);
typedHandleMap.get().emplace(assetId, genericHandle);
typedAssetIdMap.get().emplace(genericHandle, assetId);
return handle;
}
template<>
Handle<SHMaterial> SHResourceManager::LoadOrGet<SHMaterial>(AssetID assetId)
{
/* Attempt to get existing loaded asset */
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<SHMaterial>();
if (typedHandleMap.get().contains(assetId))
return Handle<SHMaterial>(typedHandleMap.get()[assetId]);
/* Otherwise, we need to load it! */
// Get system
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem == nullptr)
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
// Get SHMaterialSpec
Handle<SHMaterialSpec> matSpec = LoadOrGet<SHMaterialSpec>(assetId);
if (!matSpec)
return {};
// Create the material
auto handle = load<SHMaterial>(assetId, *matSpec);
Handle genericHandle = Handle(handle);
typedHandleMap.get().emplace(assetId, genericHandle);
typedAssetIdMap.get().emplace(genericHandle, assetId);
return handle;
}
template<typename ResourceType>
void SHResourceManager::Unload(Handle<ResourceType> assetId)
void SHResourceManager::Unload(Handle<ResourceType> asset)
{
// Check if it is an unsupported type
if (!std::is_same_v<ResourceType, SHMesh> && !std::is_same_v<ResourceType, SHTexture>)
@ -71,14 +104,18 @@ namespace SHADE
/* Attempt to get existing loaded asset */
auto [typedHandleMap, typedAssetIdMap] = getAssetHandleMap<ResourceType>();
if (typedHandleMap.get().contains(assetId))
if (typedHandleMap.get().contains(asset))
{
// Remove from ResourceHub if SHMaterialSpec
if (std::is_same_v<ResourceType, SHMaterialSpec>)
resourceHub.Free(asset);
// Dispose
Handle handle = typedHandleMap.get()[assetId];
Handle<ResourceType> typedHandle = static_cast<Handle<ResourceType>>(handle);
Handle handle = typedHandleMap.get()[asset];
auto typedHandle = static_cast<Handle<ResourceType>>(handle);
typedHandle.Free();
typedAssetIdMap.get().erase(handle);
typedHandleMap.get().erase(assetId);
typedHandleMap.get().erase(asset);
}
else
{
@ -179,15 +216,20 @@ namespace SHADE
shader->Reflect();
return shader;
}
// Material Spec
else if constexpr (std::is_same_v<ResourceType, SHMaterialSpec>)
{
// Get the data we need to construct
auto matSpec = resourceHub.Create<SHMaterialSpec>();
*matSpec = YAML::Node(assetData.data).as<SHMaterialSpec>();
return matSpec;
}
// Materials
else if constexpr (std::is_same_v<ResourceType, SHMaterial>)
{
// Get the data we need to construct
SHMaterialSpec matSpec = YAML::Node(assetData.data).as<SHMaterialSpec>();
// Load shaders
auto vertexShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(matSpec.vertexShader);
auto fragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(matSpec.fragShader);
auto vertexShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(assetData.vertexShader);
auto fragShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(assetData.fragShader);
// Ensure that both shaders are present
if (!(vertexShader && fragShader))
@ -203,7 +245,7 @@ namespace SHADE
SHLOG_ERROR("[SHResourceManager] Failed to load material as RenderPass could not be found.");
return {};
}
auto subPass = renderPass->GetSubpass(matSpec.subpassName);
auto subPass = renderPass->GetSubpass(assetData.subpassName);
if (!subPass)
{
SHLOG_ERROR("[SHResourceManager] Failed to load material as SubPass could not be found.");
@ -218,7 +260,7 @@ namespace SHADE
for (int i = 0; i < static_cast<int>(pipelineProperties->GetVariableCount()); ++i)
{
const std::string& PROP_NAME = pipelineProperties->GetVariableName(i);
const auto& PROP_NODE = matSpec.properties;
const auto& PROP_NODE = assetData.properties;
if (PROP_NODE)
{
const std::string& VAR_NAME = pipelineProperties->GetVariableName(i);

View File

@ -20,9 +20,9 @@
namespace YAML
{
using namespace SHADE;
using namespace SHADE;
template<>
template<>
struct convert<SHVec4>
{
static constexpr const char* x = "x";
@ -172,17 +172,17 @@ namespace YAML
switch (colliderType)
{
case SHCollider::Type::BOX:
{
if(node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>());
}
break;
{
if (node[HalfExtents].IsDefined())
rhs.SetBoundingBox(node[HalfExtents].as<SHVec3>());
}
break;
case SHCollider::Type::SPHERE:
{
if(node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>());
}
break;
{
if (node[Radius].IsDefined())
rhs.SetBoundingSphere(node[Radius].as<float>());
}
break;
case SHCollider::Type::CAPSULE: break;
default:;
}
@ -194,7 +194,7 @@ namespace YAML
rhs.SetDensity(node[Density].as<float>());
if (node[PositionOffset].IsDefined())
rhs.SetPositionOffset(node[PositionOffset].as<SHVec3>());
return true;
}
};
@ -231,7 +231,7 @@ namespace YAML
const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert<SHCollider>::Type].as<std::string>()).convert<SHCollider::Type>(&ok);
if (!ok)
return false;
switch (colliderType)
{
case SHCollider::Type::BOX: rhs.AddBoundingBox(); break;
@ -246,143 +246,84 @@ namespace YAML
}
};
template<>
struct convert<SHMaterial>
template<>
struct convert<SHMaterialSpec>
{
static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader";
static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader";
static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass";
static constexpr std::string_view PROPS_YAML_TAG = "Properties";
static YAML::Node encode(SHMaterialSpec const& rhs)
{
static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader";
static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader";
static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass";
static constexpr std::string_view PROPS_YAML_TAG = "Properties";
YAML::Node node;
node[VERT_SHADER_YAML_TAG.data()] = rhs.vertexShader;
node[FRAG_SHADER_YAML_TAG.data()] = rhs.fragShader;
node[SUBPASS_YAML_TAG.data()] = rhs.subpassName;
node[PROPS_YAML_TAG.data()] = rhs.properties;
return node;
}
static YAML::Node encode(SHMaterial const& rhs)
{
// Write Properties
YAML::Node propertiesNode;
Handle<SHShaderBlockInterface> pipelineProperties = rhs.GetShaderBlockInterface();
for (int i = 0; i < static_cast<int>(pipelineProperties->GetVariableCount()); ++i)
{
const SHShaderBlockInterface::Variable* VARIABLE = pipelineProperties->GetVariable(i);
if (!VARIABLE)
break;
const std::string& VAR_NAME = pipelineProperties->GetVariableName(i);
YAML::Node propNode;
switch (VARIABLE->type)
{
case SHADE::SHShaderBlockInterface::Variable::Type::FLOAT:
propNode = rhs.GetProperty<float>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::INT:
propNode = rhs.GetProperty<int>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR2:
propNode = rhs.GetProperty<SHVec2>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR3:
propNode = rhs.GetProperty<SHVec3>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::VECTOR4:
propNode = rhs.GetProperty<SHVec4>(VARIABLE->offset);
break;
case SHADE::SHShaderBlockInterface::Variable::Type::OTHER:
default:
continue;
break;
}
propertiesNode[VAR_NAME.data()] = propNode;
}
// Get Shader Handles
const auto& SHADERS = rhs.GetPipeline()->GetPipelineLayout()->GetShaderModules();
Handle<SHVkShaderModule> vertexShader, fragShader;
for (const auto& shader : SHADERS)
{
const auto FLAG_BITS = shader->GetShaderStageFlagBits();
if (FLAG_BITS & vk::ShaderStageFlagBits::eVertex)
vertexShader = shader;
else if (FLAG_BITS & vk::ShaderStageFlagBits::eFragment)
fragShader = shader;
}
// Write Material
YAML::Node node;
node[VERT_SHADER_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHVkShaderModule>(vertexShader).value_or(0);
node[FRAG_SHADER_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHVkShaderModule>(fragShader).value_or(0);
node[SUBPASS_YAML_TAG.data()] = rhs.GetPipeline()->GetPipelineState().GetSubpass()->GetName();
node[PROPS_YAML_TAG.data()] = propertiesNode;
return node;
}
};
template<>
struct convert<SHMaterialSpec>
static bool decode(YAML::Node const& node, SHMaterialSpec& rhs)
{
static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader";
static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader";
static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass";
static constexpr std::string_view PROPS_YAML_TAG = "Properties";
// Retrieve Shader Asset IDs
if (!node[VERT_SHADER_YAML_TAG.data()])
return false;
rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as<AssetID>();
if (!node[FRAG_SHADER_YAML_TAG.data()])
return false;
rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as<AssetID>();
static bool decode(YAML::Node const& node, SHMaterialSpec& rhs)
// Retrieve Subpass
if (!node[SUBPASS_YAML_TAG.data()])
return false;
rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as<std::string>();
// Retrieve
if (!node[PROPS_YAML_TAG.data()])
return false;
rhs.properties = node[PROPS_YAML_TAG.data()];
return true;
}
};
template<>
struct convert<SHRenderable>
{
static constexpr std::string_view MESH_YAML_TAG = "Mesh";
static constexpr std::string_view MAT_YAML_TAG = "Material";
static YAML::Node encode(SHRenderable const& rhs)
{
YAML::Node node;
node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMesh>(rhs.GetMesh()).value_or(0);
node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMaterial>(rhs.GetMaterial()->GetBaseMaterial()).value_or(0);
return node;
}
static bool decode(YAML::Node const& node, SHRenderable& rhs)
{
if (node[MESH_YAML_TAG.data()].IsDefined())
{
// Retrieve Shader Asset IDs
if (!node[VERT_SHADER_YAML_TAG.data()])
return false;
rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as<AssetID>();
if (!node[FRAG_SHADER_YAML_TAG.data()])
return false;
rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as<AssetID>();
// Retrieve Subpass
if (!node[SUBPASS_YAML_TAG.data()])
return false;
rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as<std::string>();
// Retrieve
if (!node[PROPS_YAML_TAG.data()])
return false;
rhs.properties = node[PROPS_YAML_TAG.data()];
return true;
rhs.SetMesh(SHResourceManager::LoadOrGet<SHMesh>(node[MESH_YAML_TAG.data()].as<AssetID>()));
}
};
template<>
struct convert<SHRenderable>
{
static constexpr std::string_view MESH_YAML_TAG = "Mesh";
static constexpr std::string_view MAT_YAML_TAG = "Material";
static YAML::Node encode(SHRenderable const& rhs)
if (node[MAT_YAML_TAG.data()].IsDefined())
{
// Temporarily, use default material
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (!gfxSystem)
return false;
Handle<SHMaterial> baseMat = SHResourceManager::LoadOrGet<SHMaterial>(node[MAT_YAML_TAG.data()].as<AssetID>());
if (!baseMat)
{
YAML::Node node;
node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMesh>(rhs.GetMesh()).value_or(0);
node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHMaterial>(rhs.GetMaterial()->GetBaseMaterial()).value_or(0);
return node;
baseMat = gfxSystem->GetDefaultMaterial();
SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material.");
}
static bool decode(YAML::Node const& node, SHRenderable& rhs)
{
if (node[MESH_YAML_TAG.data()].IsDefined())
{
rhs.SetMesh(SHResourceManager::LoadOrGet<SHMesh>(node[MESH_YAML_TAG.data()].as<AssetID>()));
}
if (node[MAT_YAML_TAG.data()].IsDefined())
{
// Temporarily, use default material
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (!gfxSystem)
return false;
Handle<SHMaterial> baseMat = SHResourceManager::LoadOrGet<SHMaterial>(node[MAT_YAML_TAG.data()].as<AssetID>());
if (!baseMat)
{
baseMat = gfxSystem->GetDefaultMaterial();
SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material.");
}
rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat));
}
return true;
}
};
rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat));
}
return true;
}
};
}
namespace SHADE
@ -550,7 +491,7 @@ namespace SHADE
auto properties = propType.get_properties();
for (auto const& property : properties)
{
if(propertyNode[property.get_name().data()].IsDefined())
if (propertyNode[property.get_name().data()].IsDefined())
InitializeProperty(component, property, propertyNode[property.get_name().data()]);
}
}
@ -564,7 +505,7 @@ namespace SHADE
return;
auto rttrType = rttr::type::get<ComponentType>();
auto componentNode = componentsNode[rttrType.get_name().data()];
if(!componentNode.IsDefined())
if (!componentNode.IsDefined())
return;
auto properties = rttrType.get_properties();
for (auto const& prop : properties)