Refactor material system (#382)
This commit is contained in:
@@ -3,7 +3,11 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/MaterialInstance.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <NZSL/Ast/SanitizeVisitor.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
@@ -13,22 +17,172 @@ namespace Nz
|
||||
return true;
|
||||
}
|
||||
|
||||
void Material::AddPass(std::string passName, std::shared_ptr<MaterialPass> pass)
|
||||
|
||||
Material::Material(MaterialSettings settings, const std::string& referenceModuleName) :
|
||||
Material(std::move(settings), Graphics::Instance()->GetShaderModuleResolver()->Resolve(referenceModuleName))
|
||||
{
|
||||
auto& registry = Graphics::Instance()->GetMaterialPassRegistry();
|
||||
return AddPass(registry.GetPassIndex(passName), std::move(pass));
|
||||
}
|
||||
|
||||
const std::shared_ptr<MaterialPass>& Material::FindPass(const std::string& passName) const
|
||||
Material::Material(MaterialSettings settings, const nzsl::Ast::ModulePtr& referenceModule) :
|
||||
m_settings(std::move(settings))
|
||||
{
|
||||
auto& registry = Graphics::Instance()->GetMaterialPassRegistry();
|
||||
return GetPass(registry.GetPassIndex(passName));
|
||||
NazaraAssert(referenceModule, "invalid module");
|
||||
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
|
||||
const std::shared_ptr<RenderDevice>& renderDevice = graphics->GetRenderDevice();
|
||||
|
||||
nzsl::Ast::SanitizeVisitor::Options options;
|
||||
options.allowPartialSanitization = true;
|
||||
options.moduleResolver = graphics->GetShaderModuleResolver();
|
||||
options.optionValues[CRC32("MaxLightCount")] = SafeCast<UInt32>(PredefinedLightData::MaxLightCount);
|
||||
options.optionValues[CRC32("MaxJointCount")] = SafeCast<UInt32>(PredefinedSkeletalData::MaxMatricesCount);
|
||||
|
||||
nzsl::Ast::ModulePtr sanitizedModule = nzsl::Ast::Sanitize(*referenceModule, options);
|
||||
|
||||
m_reflection.Reflect(*sanitizedModule);
|
||||
|
||||
m_renderPipelineLayout = renderDevice->InstantiateRenderPipelineLayout(m_reflection.GetPipelineLayoutInfo());
|
||||
|
||||
if (const ShaderReflection::ExternalBlockData* block = m_reflection.GetExternalBlockByTag("Material"))
|
||||
{
|
||||
for (const auto& [tag, shaderSampler] : block->samplers)
|
||||
{
|
||||
std::size_t textureIndex = m_textures.size();
|
||||
|
||||
auto& texture = m_textures.emplace_back();
|
||||
texture.bindingIndex = shaderSampler.bindingIndex;
|
||||
texture.bindingSet = shaderSampler.bindingSet;
|
||||
texture.imageType = ToImageType(shaderSampler.imageType);
|
||||
|
||||
m_textureByTag.emplace(tag, textureIndex);
|
||||
}
|
||||
|
||||
assert(block->storageBlocks.empty()); //< TODO
|
||||
|
||||
for (const auto& [tag, shaderBlock] : block->uniformBlocks)
|
||||
{
|
||||
std::size_t blockIndex = m_uniformBlocks.size();
|
||||
|
||||
const ShaderReflection::StructData* structData = m_reflection.GetStructByIndex(shaderBlock.structIndex);
|
||||
assert(structData);
|
||||
|
||||
std::size_t size = structData->fieldOffsets.GetSize();
|
||||
|
||||
auto& uniformBlock = m_uniformBlocks.emplace_back();
|
||||
uniformBlock.bindingIndex = shaderBlock.bindingIndex;
|
||||
uniformBlock.bindingSet = shaderBlock.bindingSet;
|
||||
uniformBlock.bufferPool = std::make_unique<RenderBufferPool>(renderDevice, BufferType::Uniform, size);
|
||||
uniformBlock.structIndex = shaderBlock.structIndex;
|
||||
|
||||
m_uniformBlockByTag.emplace(tag, blockIndex);
|
||||
}
|
||||
}
|
||||
|
||||
m_engineShaderBindings.fill(InvalidBindingIndex);
|
||||
if (const ShaderReflection::ExternalBlockData* block = m_reflection.GetExternalBlockByTag("Engine"))
|
||||
{
|
||||
// TODO: Ensure structs layout is what's expected
|
||||
|
||||
if (auto it = block->uniformBlocks.find("InstanceData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::InstanceDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->uniformBlocks.find("LightData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::LightDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->uniformBlocks.find("ViewerData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::ViewerDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->uniformBlocks.find("SkeletalData"); it != block->uniformBlocks.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::SkeletalDataUbo)] = it->second.bindingIndex;
|
||||
|
||||
if (auto it = block->samplers.find("TextureOverlay"); it != block->samplers.end())
|
||||
m_engineShaderBindings[UnderlyingCast(EngineShaderBinding::OverlayTexture)] = it->second.bindingIndex;
|
||||
}
|
||||
|
||||
for (const auto& handlerPtr : m_settings.GetPropertyHandlers())
|
||||
handlerPtr->Setup(*this, m_reflection);
|
||||
|
||||
for (const auto& passOpt : m_settings.GetPasses())
|
||||
{
|
||||
if (!passOpt)
|
||||
continue;
|
||||
|
||||
for (const auto& uberShader : passOpt->shaders)
|
||||
{
|
||||
uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
|
||||
{
|
||||
if (vertexBuffers.empty())
|
||||
return;
|
||||
|
||||
const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration;
|
||||
const auto& components = vertexDeclaration.GetComponents();
|
||||
|
||||
Int32 locationIndex = 0;
|
||||
for (const auto& component : components)
|
||||
{
|
||||
switch (component.component)
|
||||
{
|
||||
case VertexComponent::Color:
|
||||
config.optionValues[CRC32("VertexColorLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Normal:
|
||||
config.optionValues[CRC32("VertexNormalLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Position:
|
||||
config.optionValues[CRC32("VertexPositionLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Tangent:
|
||||
config.optionValues[CRC32("VertexTangentLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::TexCoord:
|
||||
config.optionValues[CRC32("VertexUvLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::JointIndices:
|
||||
config.optionValues[CRC32("VertexJointIndicesLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::JointWeights:
|
||||
config.optionValues[CRC32("VertexJointWeightsLoc")] = locationIndex;
|
||||
break;
|
||||
|
||||
case VertexComponent::Unused:
|
||||
case VertexComponent::Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
++locationIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Material::RemovePass(const std::string& passName)
|
||||
std::shared_ptr<MaterialInstance> Material::CreateInstance() const
|
||||
{
|
||||
auto& registry = Graphics::Instance()->GetMaterialPassRegistry();
|
||||
return RemovePass(registry.GetPassIndex(passName));
|
||||
return std::make_shared<MaterialInstance>(shared_from_this());
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialInstance> Material::GetDefaultInstance() const
|
||||
{
|
||||
std::shared_ptr<MaterialInstance> instance = m_defaultInstance.lock();
|
||||
if (!instance)
|
||||
{
|
||||
instance = CreateInstance();
|
||||
m_defaultInstance = std::weak_ptr<MaterialInstance>(instance);
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::shared_ptr<Material> Material::Build(const ParameterList& materialData)
|
||||
{
|
||||
return std::shared_ptr<Material>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Material> Material::LoadFromFile(const std::filesystem::path& filePath, const MaterialParams& params)
|
||||
|
||||
Reference in New Issue
Block a user