Refactor material system (#382)

This commit is contained in:
Jérôme Leclercq
2022-10-31 19:53:41 +01:00
committed by GitHub
parent 0a8048809c
commit dc6ce8427c
156 changed files with 3633 additions and 4569 deletions

View File

@@ -1,289 +0,0 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/UberShader.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <NZSL/Parser.hpp>
#include <NZSL/Math/FieldOffsets.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
BasicMaterial::BasicMaterial(MaterialPass& material) :
BasicMaterial(material, NoInit{})
{
// Most common case: don't fetch texture indexes as a little optimization
const std::shared_ptr<const MaterialSettings>& materialSettings = material.GetSettings();
if (materialSettings == s_basicMaterialSettings)
{
m_basicOptionIndexes = s_basicOptionIndexes;
m_basicTextureIndexes = s_basicTextureIndexes;
m_uniformBlockIndex = s_uniformBlockIndex;
m_basicUniformOffsets = s_basicUniformOffsets;
}
else
{
m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_basicOptionIndexes.hasBaseColorMap = materialSettings->GetOptionIndex("HasBaseColorMap");
m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_basicTextureIndexes.baseColor = materialSettings->GetTextureIndex("BaseColor");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings");
if (m_uniformBlockIndex != MaterialSettings::InvalidIndex)
{
m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_basicUniformOffsets.baseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "BaseColor");
}
else
{
m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex;
m_basicUniformOffsets.baseColor = MaterialSettings::InvalidIndex;
}
}
}
float BasicMaterial::GetAlphaTestThreshold() const
{
NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex);
return AccessByOffset<const float&>(bufferData.data(), m_basicUniformOffsets.alphaThreshold);
}
Color BasicMaterial::GetBaseColor() const
{
NazaraAssert(HasBaseColor(), "Material has no base color uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_basicUniformOffsets.baseColor);
return Color(colorPtr[0], colorPtr[1], colorPtr[2], colorPtr[3]);
}
void BasicMaterial::SetAlphaTestThreshold(float alphaThreshold)
{
NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex);
AccessByOffset<float&>(bufferData.data(), m_basicUniformOffsets.alphaThreshold) = alphaThreshold;
}
void BasicMaterial::SetBaseColor(const Color& baseColor)
{
NazaraAssert(HasBaseColor(), "Material has no base color uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_basicUniformOffsets.baseColor);
colorPtr[0] = baseColor.r;
colorPtr[1] = baseColor.g;
colorPtr[2] = baseColor.b;
colorPtr[3] = baseColor.a;
}
MaterialSettings::Builder BasicMaterial::Build(BasicBuildOptions& options)
{
MaterialSettings::Builder settings;
std::vector<MaterialSettings::UniformVariable> variables;
if (options.basicOffsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"AlphaThreshold",
options.basicOffsets.alphaThreshold
});
}
if (options.basicOffsets.baseColor != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"BaseColor",
options.basicOffsets.baseColor
});
}
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
if (options.basicOffsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(options.defaultValues.data(), options.basicOffsets.alphaThreshold) = 0.2f;
if (options.basicOffsets.baseColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.basicOffsets.baseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
// Textures
if (options.basicTextureIndexes)
options.basicTextureIndexes->alpha = settings.textures.size();
settings.textures.push_back({
2,
"Alpha",
ImageType::E2D
});
if (options.basicTextureIndexes)
options.basicTextureIndexes->baseColor = settings.textures.size();
settings.textures.push_back({
1,
"BaseColor",
ImageType::E2D
});
if (options.uniformBlockIndex)
*options.uniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"MaterialSettings",
options.basicOffsets.totalSize,
std::move(variables),
options.defaultValues
});
// Common data
settings.textures.push_back({
3,
"TextureOverlay",
ImageType::E2D
});
settings.sharedUniformBlocks.push_back(PredefinedInstanceData::GetUniformBlock(4, nzsl::ShaderStageType::Vertex));
settings.sharedUniformBlocks.push_back(PredefinedSkeletalData::GetUniformBlock(6, nzsl::ShaderStageType::Vertex));
settings.sharedUniformBlocks.push_back(PredefinedViewerData::GetUniformBlock(5, nzsl::ShaderStageType_All));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::InstanceDataUbo)] = 4;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::OverlayTexture)] = 3;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::SkeletalDataUbo)] = 6;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::ViewerDataUbo)] = 5;
settings.shaders = options.shaders;
for (const std::shared_ptr<UberShader>& uberShader : settings.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::Position:
config.optionValues[CRC32("PosLocation")] = locationIndex;
break;
case VertexComponent::Color:
config.optionValues[CRC32("ColorLocation")] = locationIndex;
break;
case VertexComponent::TexCoord:
config.optionValues[CRC32("UvLocation")] = locationIndex;
break;
case VertexComponent::JointIndices:
config.optionValues[CRC32("JointIndicesLocation")] = locationIndex;
break;
case VertexComponent::JointWeights:
config.optionValues[CRC32("JointWeightsLocation")] = locationIndex;
break;
case VertexComponent::Unused:
default:
break;
}
++locationIndex;
}
});
}
// Options
// HasBaseColorMap
if (options.basicOptionIndexes)
options.basicOptionIndexes->hasBaseColorMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasBaseColorMap", "HasBaseColorTexture");
// HasAlphaMap
if (options.basicOptionIndexes)
options.basicOptionIndexes->hasAlphaMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasAlphaMap", "HasAlphaTexture");
// AlphaTest
if (options.basicOptionIndexes)
options.basicOptionIndexes->alphaTest = settings.options.size();
MaterialSettings::BuildOption(settings.options, "AlphaTest", "AlphaTest");
return settings;
}
std::vector<std::shared_ptr<UberShader>> BasicMaterial::BuildShaders()
{
auto shader = std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "BasicMaterial");
return { std::move(shader) };
}
auto BasicMaterial::BuildUniformOffsets() -> std::pair<BasicUniformOffsets, nzsl::FieldOffsets>
{
nzsl::FieldOffsets fieldOffsets(nzsl::StructLayout::Std140);
BasicUniformOffsets uniformOffsets;
uniformOffsets.alphaThreshold = fieldOffsets.AddField(nzsl::StructFieldType::Float1);
uniformOffsets.baseColor = fieldOffsets.AddField(nzsl::StructFieldType::Float4);
uniformOffsets.totalSize = fieldOffsets.GetAlignedSize();
return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets));
}
bool BasicMaterial::Initialize()
{
std::tie(s_basicUniformOffsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(s_basicUniformOffsets.totalSize);
BasicBuildOptions options;
options.defaultValues.resize(s_basicUniformOffsets.totalSize);
options.shaders = BuildShaders();
options.basicOffsets = s_basicUniformOffsets;
options.basicOptionIndexes = &s_basicOptionIndexes;
options.basicTextureIndexes = &s_basicTextureIndexes;
options.uniformBlockIndex = &s_uniformBlockIndex;
s_basicMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void BasicMaterial::Uninitialize()
{
s_basicMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> BasicMaterial::s_basicMaterialSettings;
std::size_t BasicMaterial::s_uniformBlockIndex;
BasicMaterial::BasicOptionIndexes BasicMaterial::s_basicOptionIndexes;
BasicMaterial::BasicTextureIndexes BasicMaterial::s_basicTextureIndexes;
BasicMaterial::BasicUniformOffsets BasicMaterial::s_basicUniformOffsets;
}

View File

@@ -1,43 +0,0 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/DepthMaterial.hpp>
#include <NZSL/Parser.hpp>
#include <NZSL/Math/FieldOffsets.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
std::vector<std::shared_ptr<UberShader>> DepthMaterial::BuildShaders()
{
auto shader = std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "DepthMaterial");
return { std::move(shader) };
}
bool DepthMaterial::Initialize()
{
BasicUniformOffsets offsets;
std::tie(offsets, std::ignore) = BuildUniformOffsets();
BasicBuildOptions options;
options.defaultValues.resize(offsets.totalSize);
options.shaders = BuildShaders();
options.basicOffsets = s_basicUniformOffsets;
options.basicOptionIndexes = &s_basicOptionIndexes;
options.basicTextureIndexes = &s_basicTextureIndexes;
s_depthMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void DepthMaterial::Uninitialize()
{
s_depthMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> DepthMaterial::s_depthMaterialSettings;
}

View File

@@ -27,15 +27,9 @@ namespace Nz
m_depthPassIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex("DepthPass");
}
DepthPipelinePass::~DepthPipelinePass()
{
for (auto&& [materialPass, entry] : m_materialPasses)
m_pipeline.UnregisterMaterialPass(materialPass);
}
void DepthPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, std::size_t visibilityHash)
{
if (m_lastVisibilityHash != visibilityHash)
if (m_lastVisibilityHash != visibilityHash || m_rebuildElements) //< FIXME
{
renderFrame.PushForRelease(std::move(m_renderElements));
m_renderElements.clear();
@@ -109,25 +103,24 @@ namespace Nz
}
}
void DepthPipelinePass::RegisterMaterial(const Material& material)
void DepthPipelinePass::RegisterMaterialInstance(const MaterialInstance& materialInstance)
{
if (!material.HasPass(m_depthPassIndex))
if (!materialInstance.HasPass(m_depthPassIndex))
return;
MaterialPass* materialPass = material.GetPass(m_depthPassIndex).get();
auto it = m_materialPasses.find(materialPass);
if (it == m_materialPasses.end())
auto it = m_materialInstances.find(&materialInstance);
if (it == m_materialInstances.end())
{
m_pipeline.RegisterMaterialPass(materialPass);
auto& matPassEntry = m_materialPasses[materialPass];
matPassEntry.onMaterialPipelineInvalidated.Connect(materialPass->OnMaterialPassPipelineInvalidated, [=](const MaterialPass*)
auto& matPassEntry = m_materialInstances[&materialInstance];
matPassEntry.onMaterialInstancePipelineInvalidated.Connect(materialInstance.OnMaterialInstancePipelineInvalidated, [=](const MaterialInstance*, std::size_t passIndex)
{
if (passIndex != m_depthPassIndex)
return;
m_rebuildElements = true;
});
matPassEntry.onMaterialShaderBindingInvalidated.Connect(materialPass->OnMaterialPassShaderBindingInvalidated, [=](const MaterialPass*)
matPassEntry.onMaterialInstanceShaderBindingInvalidated.Connect(materialInstance.OnMaterialInstanceShaderBindingInvalidated, [=](const MaterialInstance*)
{
m_rebuildCommandBuffer = true;
});
@@ -166,21 +159,13 @@ namespace Nz
});
}
void DepthPipelinePass::UnregisterMaterial(const Material& material)
void DepthPipelinePass::UnregisterMaterialInstance(const MaterialInstance& materialInstance)
{
if (!material.HasPass(m_depthPassIndex))
return;
MaterialPass* materialPass = material.GetPass(m_depthPassIndex).get();
auto it = m_materialPasses.find(materialPass);
if (it != m_materialPasses.end())
auto it = m_materialInstances.find(&materialInstance);
if (it != m_materialInstances.end())
{
if (--it->second.usedCount == 0)
{
m_pipeline.UnregisterMaterialPass(materialPass);
m_materialPasses.erase(it);
}
m_materialInstances.erase(it);
}
}
}

View File

@@ -3,11 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Formats/TextureLoader.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/DepthMaterial.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/PhongLightingMaterial.hpp>
#include <Nazara/Graphics/PhysicallyBasedMaterial.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Utility/Utility.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -16,15 +12,15 @@ namespace Nz
{
namespace Loaders
{
MaterialLoader::Entry GetMaterialLoader_Texture()
MaterialInstanceLoader::Entry GetMaterialInstanceLoader_Texture()
{
MaterialLoader::Entry loaderEntry;
MaterialInstanceLoader::Entry loaderEntry;
loaderEntry.extensionSupport = [](std::string_view extension)
{
return Utility::Instance()->GetImageLoader().IsExtensionSupported(extension);
};
loaderEntry.streamLoader = [](Stream& stream, const MaterialParams& parameters) -> Result<std::shared_ptr<Material>, ResourceLoadingError>
loaderEntry.streamLoader = [](Stream& stream, const MaterialInstanceParams& parameters) -> Result<std::shared_ptr<MaterialInstance>, ResourceLoadingError>
{
TextureParams texParams;
texParams.renderDevice = Graphics::Instance()->GetRenderDevice();
@@ -33,50 +29,35 @@ namespace Nz
if (!texture)
return Err(ResourceLoadingError::Unrecognized);
std::shared_ptr<Material> material = std::make_shared<Material>();
bool hasAlphaTest = parameters.custom.GetBooleanParameter("EnableAlphaTest").GetValueOr(false);
// ForwardPass
std::shared_ptr<MaterialInstance> materialInstance;
switch (parameters.lightingType)
{
std::shared_ptr<MaterialPass> matPass;
if (parameters.lightingType == MaterialLightingType::Phong)
matPass = std::make_shared<MaterialPass>(PhongLightingMaterial::GetSettings());
else if (parameters.lightingType == MaterialLightingType::PhysicallyBased)
matPass = std::make_shared<MaterialPass>(PhysicallyBasedMaterial::GetSettings());
else
matPass = std::make_shared<MaterialPass>(BasicMaterial::GetSettings());
case MaterialLightingType::Phong:
materialInstance = Graphics::Instance()->GetDefaultMaterials().phongMaterial->CreateInstance();
break;
matPass->EnableDepthBuffer(true);
case MaterialLightingType::PhysicallyBased:
materialInstance = Graphics::Instance()->GetDefaultMaterials().pbrMaterial->CreateInstance();
break;
BasicMaterial forwardPass(*matPass);
forwardPass.SetBaseColorMap(texture);
if (hasAlphaTest && PixelFormatInfo::HasAlpha(texture->GetFormat()))
forwardPass.EnableAlphaTest(true);
material->AddPass("ForwardPass", std::move(matPass));
case MaterialLightingType::None:
break;
}
// DepthPass
{
std::shared_ptr<MaterialPass> matPass = std::make_shared<MaterialPass>(DepthMaterial::GetSettings());
matPass->EnableDepthBuffer(true);
if (!materialInstance)
materialInstance = Graphics::Instance()->GetDefaultMaterials().basicMaterial->CreateInstance();
if (hasAlphaTest && PixelFormatInfo::HasAlpha(texture->GetFormat()))
{
BasicMaterial depthPass(*matPass);
depthPass.SetBaseColorMap(texture);
depthPass.EnableAlphaTest(true);
}
if (hasAlphaTest && PixelFormatInfo::HasAlpha(texture->GetFormat()))
materialInstance->SetValueProperty("AlphaTest", true);
material->AddPass("DepthPass", std::move(matPass));
}
materialInstance->SetTextureProperty("BaseColorMap", std::move(texture));
return material;
return materialInstance;
};
loaderEntry.parameterFilter = [](const MaterialParams& parameters)
loaderEntry.parameterFilter = [](const MaterialInstanceParams& parameters)
{
if (auto result = parameters.custom.GetBooleanParameter("SkipNativeTextureLoader"); result.GetValueOr(false))
return false;

View File

@@ -8,11 +8,11 @@
#define NAZARA_GRAPHICS_FORMATS_TEXTURELOADER_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
namespace Nz::Loaders
{
MaterialLoader::Entry GetMaterialLoader_Texture();
MaterialInstanceLoader::Entry GetMaterialInstanceLoader_Texture();
}
#endif // NAZARA_GRAPHICS_FORMATS_TEXTURELOADER_HPP

View File

@@ -43,21 +43,6 @@ namespace Nz
m_viewerPool.Clear();
}
void ForwardFramePipeline::InvalidateSkeletalInstance(std::size_t skeletalInstanceIndex)
{
m_invalidatedSkeletonInstances.Set(skeletalInstanceIndex);
}
void ForwardFramePipeline::InvalidateViewer(std::size_t viewerIndex)
{
m_invalidatedViewerInstances.Set(viewerIndex);
}
void ForwardFramePipeline::InvalidateWorldInstance(std::size_t worldInstanceIndex)
{
m_invalidatedWorldInstances.Set(worldInstanceIndex);
}
std::size_t ForwardFramePipeline::RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask)
{
std::size_t lightIndex;
@@ -78,23 +63,6 @@ namespace Nz
return lightIndex;
}
void ForwardFramePipeline::RegisterMaterialPass(MaterialPass* materialPass)
{
auto it = m_activeMaterialPasses.find(materialPass);
if (it == m_activeMaterialPasses.end())
{
it = m_activeMaterialPasses.emplace(materialPass, MaterialPassData{}).first;
it->second.onMaterialPassInvalided.Connect(materialPass->OnMaterialPassInvalidated, [=](const MaterialPass* /*material*/)
{
m_invalidatedMaterialPasses.insert(materialPass);
});
m_invalidatedMaterialPasses.insert(materialPass);
}
it->second.usedCount++;
}
std::size_t ForwardFramePipeline::RegisterRenderable(std::size_t worldInstanceIndex, std::size_t skeletonInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox)
{
@@ -123,28 +91,32 @@ namespace Nz
}
});
renderableData->onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr<Material>& newMaterial)
renderableData->onMaterialInvalidated.Connect(instancedRenderable->OnMaterialInvalidated, [this](InstancedRenderable* instancedRenderable, std::size_t materialIndex, const std::shared_ptr<MaterialInstance>& newMaterial)
{
if (newMaterial)
{
RegisterMaterialInstance(newMaterial.get());
for (auto& viewerData : m_viewerPool)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->RegisterMaterial(*newMaterial);
viewerData.depthPrepass->RegisterMaterialInstance(*newMaterial);
viewerData.forwardPass->RegisterMaterial(*newMaterial);
viewerData.forwardPass->RegisterMaterialInstance(*newMaterial);
}
}
const auto& prevMaterial = instancedRenderable->GetMaterial(materialIndex);
if (prevMaterial)
{
UnregisterMaterialInstance(prevMaterial.get());
for (auto& viewerData : m_viewerPool)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->UnregisterMaterial(*prevMaterial);
viewerData.depthPrepass->UnregisterMaterialInstance(*prevMaterial);
viewerData.forwardPass->UnregisterMaterial(*prevMaterial);
viewerData.forwardPass->UnregisterMaterialInstance(*prevMaterial);
}
}
});
@@ -152,14 +124,16 @@ namespace Nz
std::size_t matCount = instancedRenderable->GetMaterialCount();
for (std::size_t i = 0; i < matCount; ++i)
{
if (Material* mat = instancedRenderable->GetMaterial(i).get())
if (MaterialInstance* mat = instancedRenderable->GetMaterial(i).get())
{
RegisterMaterialInstance(mat);
for (auto& viewerData : m_viewerPool)
{
if (viewerData.depthPrepass)
viewerData.depthPrepass->RegisterMaterial(*mat);
viewerData.depthPrepass->RegisterMaterialInstance(*mat);
viewerData.forwardPass->RegisterMaterial(*mat);
viewerData.forwardPass->RegisterMaterialInstance(*mat);
}
}
}
@@ -170,9 +144,13 @@ namespace Nz
std::size_t ForwardFramePipeline::RegisterSkeleton(SkeletonInstancePtr skeletonInstance)
{
std::size_t skeletonInstanceIndex;
m_skeletonInstances.Allocate(skeletonInstanceIndex, std::move(skeletonInstance));
m_invalidatedSkeletonInstances.UnboundedSet(skeletonInstanceIndex);
SkeletonInstanceData& skeletonInstanceData = *m_skeletonInstances.Allocate(skeletonInstanceIndex);
skeletonInstanceData.skeleton = std::move(skeletonInstance);
skeletonInstanceData.onTransferRequired.Connect(skeletonInstanceData.skeleton->OnTransferRequired, [this](TransferInterface* transferInterface)
{
m_transferSet.insert(transferInterface);
});
m_transferSet.insert(skeletonInstanceData.skeleton.get());
return skeletonInstanceIndex;
}
@@ -186,8 +164,13 @@ namespace Nz
viewerData.depthPrepass = std::make_unique<DepthPipelinePass>(*this, m_elementRegistry, viewerInstance);
viewerData.forwardPass = std::make_unique<ForwardPipelinePass>(*this, m_elementRegistry, viewerInstance);
viewerData.viewer = viewerInstance;
viewerData.onTransferRequired.Connect(viewerInstance->GetViewerInstance().OnTransferRequired, [this](TransferInterface* transferInterface)
{
m_transferSet.insert(transferInterface);
});
m_transferSet.insert(&viewerInstance->GetViewerInstance());
m_invalidatedViewerInstances.UnboundedSet(viewerIndex);
m_rebuildFrameGraph = true;
return viewerIndex;
@@ -196,9 +179,14 @@ namespace Nz
std::size_t ForwardFramePipeline::RegisterWorldInstance(WorldInstancePtr worldInstance)
{
std::size_t worldInstanceIndex;
m_worldInstances.Allocate(worldInstanceIndex, std::move(worldInstance));
WorldInstanceData& worldInstanceData = *m_worldInstances.Allocate(worldInstanceIndex);
worldInstanceData.worldInstance = std::move(worldInstance);
worldInstanceData.onTransferRequired.Connect(worldInstanceData.worldInstance->OnTransferRequired, [this](TransferInterface* transferInterface)
{
m_transferSet.insert(transferInterface);
});
m_invalidatedWorldInstances.UnboundedSet(worldInstanceIndex);
m_transferSet.insert(worldInstanceData.worldInstance.get());
return worldInstanceIndex;
}
@@ -238,42 +226,18 @@ namespace Nz
}
// Update UBOs and materials
UploadPool& uploadPool = renderFrame.GetUploadPool();
renderFrame.Execute([&](CommandBufferBuilder& builder)
{
builder.BeginDebugRegion("CPU to GPU transfers", Color::Yellow);
{
builder.PreTransferBarrier();
for (TransferInterface* transferInterface : m_transferSet)
transferInterface->OnTransfer(renderFrame, builder);
m_transferSet.clear();
OnTransfer(this, renderFrame, builder);
for (std::size_t skeletonIndex = m_invalidatedSkeletonInstances.FindFirst(); skeletonIndex != m_invalidatedSkeletonInstances.npos; skeletonIndex = m_invalidatedSkeletonInstances.FindNext(skeletonIndex))
{
SkeletonInstancePtr& skeletonInstance = *m_skeletonInstances.RetrieveFromIndex(skeletonIndex);
skeletonInstance->UpdateBuffers(uploadPool, builder);
}
m_invalidatedSkeletonInstances.Reset();
for (std::size_t viewerIndex = m_invalidatedViewerInstances.FindFirst(); viewerIndex != m_invalidatedViewerInstances.npos; viewerIndex = m_invalidatedViewerInstances.FindNext(viewerIndex))
{
ViewerData* viewerData = m_viewerPool.RetrieveFromIndex(viewerIndex);
viewerData->viewer->GetViewerInstance().UpdateBuffers(uploadPool, builder);
}
m_invalidatedViewerInstances.Reset();
for (std::size_t worldInstanceIndex = m_invalidatedWorldInstances.FindFirst(); worldInstanceIndex != m_invalidatedWorldInstances.npos; worldInstanceIndex = m_invalidatedWorldInstances.FindNext(worldInstanceIndex))
{
WorldInstancePtr& worldInstance = *m_worldInstances.RetrieveFromIndex(worldInstanceIndex);
worldInstance->UpdateBuffers(uploadPool, builder);
}
m_invalidatedWorldInstances.Reset();
for (MaterialPass* materialPass : m_invalidatedMaterialPasses)
materialPass->Update(renderFrame, builder);
m_invalidatedMaterialPasses.clear();
builder.PostTransferBarrier();
}
builder.EndDebugRegion();
@@ -302,7 +266,7 @@ namespace Nz
if ((renderMask & renderableData.renderMask) == 0)
continue;
WorldInstancePtr& worldInstance = *m_worldInstances.RetrieveFromIndex(renderableData.worldInstanceIndex);
WorldInstancePtr& worldInstance = m_worldInstances.RetrieveFromIndex(renderableData.worldInstanceIndex)->worldInstance;
// Get global AABB
BoundingVolumef boundingVolume(renderableData.renderable->GetAABB());
@@ -317,7 +281,7 @@ namespace Nz
visibleRenderable.worldInstance = worldInstance.get();
if (renderableData.skeletonInstanceIndex != NoSkeletonInstance)
visibleRenderable.skeletonInstance = m_skeletonInstances.RetrieveFromIndex(renderableData.skeletonInstanceIndex)->get();
visibleRenderable.skeletonInstance = m_skeletonInstances.RetrieveFromIndex(renderableData.skeletonInstanceIndex)->skeleton.get();
else
visibleRenderable.skeletonInstance = nullptr;
@@ -436,17 +400,6 @@ namespace Nz
m_lightPool.Free(lightIndex);
}
void ForwardFramePipeline::UnregisterMaterialPass(MaterialPass* materialPass)
{
auto it = m_activeMaterialPasses.find(materialPass);
assert(it != m_activeMaterialPasses.end());
MaterialPassData& materialData = it->second;
assert(materialData.usedCount > 0);
if (--materialData.usedCount == 0)
m_activeMaterialPasses.erase(materialPass);
}
void ForwardFramePipeline::UnregisterRenderable(std::size_t renderableIndex)
{
RenderableData& renderable = *m_renderablePool.RetrieveFromIndex(renderableIndex);
@@ -457,10 +410,12 @@ namespace Nz
for (auto& viewerData : m_viewerPool)
{
const auto& material = renderable.renderable->GetMaterial(i);
if (viewerData.depthPrepass)
viewerData.depthPrepass->UnregisterMaterial(*material);
UnregisterMaterialInstance(material.get());
viewerData.forwardPass->UnregisterMaterial(*material);
if (viewerData.depthPrepass)
viewerData.depthPrepass->UnregisterMaterialInstance(*material);
viewerData.forwardPass->UnregisterMaterialInstance(*material);
}
}
@@ -623,4 +578,31 @@ namespace Nz
return frameGraph.Bake();
}
void ForwardFramePipeline::RegisterMaterialInstance(MaterialInstance* materialInstance)
{
auto it = m_materialInstances.find(materialInstance);
if (it == m_materialInstances.end())
{
it = m_materialInstances.emplace(materialInstance, MaterialInstanceData{}).first;
it->second.onTransferRequired.Connect(materialInstance->OnTransferRequired, [this](TransferInterface* transferInterface)
{
m_transferSet.insert(transferInterface);
});
m_transferSet.insert(materialInstance);
}
it->second.usedCount++;
}
void ForwardFramePipeline::UnregisterMaterialInstance(MaterialInstance* materialInstance)
{
auto it = m_materialInstances.find(materialInstance);
assert(it != m_materialInstances.end());
MaterialInstanceData& materialInstanceData = it->second;
assert(materialInstanceData.usedCount > 0);
if (--materialInstanceData.usedCount == 0)
m_materialInstances.erase(it);
}
}

View File

@@ -7,6 +7,7 @@
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/FrameGraph.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
@@ -30,12 +31,6 @@ namespace Nz
m_lightUboPool = std::make_shared<LightUboPool>();
}
ForwardPipelinePass::~ForwardPipelinePass()
{
for (auto&& [materialPass, entry] : m_materialPasses)
m_pipeline.UnregisterMaterialPass(materialPass);
}
void ForwardPipelinePass::Prepare(RenderFrame& renderFrame, const Frustumf& frustum, const std::vector<FramePipelinePass::VisibleRenderable>& visibleRenderables, const std::vector<const Light*>& visibleLights, std::size_t visibilityHash)
{
if (m_lastVisibilityHash != visibilityHash || m_rebuildElements) //< FIXME
@@ -244,25 +239,24 @@ namespace Nz
}
}
void ForwardPipelinePass::RegisterMaterial(const Material& material)
void ForwardPipelinePass::RegisterMaterialInstance(const MaterialInstance& materialInstance)
{
if (!material.HasPass(m_forwardPassIndex))
if (!materialInstance.HasPass(m_forwardPassIndex))
return;
MaterialPass* materialPass = material.GetPass(m_forwardPassIndex).get();
auto it = m_materialPasses.find(materialPass);
if (it == m_materialPasses.end())
auto it = m_materialInstances.find(&materialInstance);
if (it == m_materialInstances.end())
{
m_pipeline.RegisterMaterialPass(materialPass);
auto& matPassEntry = m_materialPasses[materialPass];
matPassEntry.onMaterialPipelineInvalidated.Connect(materialPass->OnMaterialPassPipelineInvalidated, [=](const MaterialPass*)
auto& matPassEntry = m_materialInstances[&materialInstance];
matPassEntry.onMaterialInstancePipelineInvalidated.Connect(materialInstance.OnMaterialInstancePipelineInvalidated, [=](const MaterialInstance*, std::size_t passIndex)
{
if (passIndex != m_forwardPassIndex)
return;
m_rebuildElements = true;
});
matPassEntry.onMaterialShaderBindingInvalidated.Connect(materialPass->OnMaterialPassShaderBindingInvalidated, [=](const MaterialPass*)
matPassEntry.onMaterialInstanceShaderBindingInvalidated.Connect(materialInstance.OnMaterialInstanceShaderBindingInvalidated, [=](const MaterialInstance*)
{
m_rebuildCommandBuffer = true;
});
@@ -307,21 +301,13 @@ namespace Nz
});
}
void ForwardPipelinePass::UnregisterMaterial(const Material& material)
void ForwardPipelinePass::UnregisterMaterialInstance(const MaterialInstance& materialInstance)
{
if (!material.HasPass(m_forwardPassIndex))
return;
MaterialPass* materialPass = material.GetPass(m_forwardPassIndex).get();
auto it = m_materialPasses.find(materialPass);
if (it != m_materialPasses.end())
auto it = m_materialInstances.find(&materialInstance);
if (it != m_materialInstances.end())
{
if (--it->second.usedCount == 0)
{
m_materialPasses.erase(it);
m_pipeline.UnregisterMaterialPass(materialPass);
}
m_materialInstances.erase(it);
}
}
}

View File

@@ -3,10 +3,10 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/DepthMaterial.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Graphics/PredefinedMaterials.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/Formats/TextureLoader.hpp>
#include <Nazara/Utility/Font.hpp>
@@ -28,10 +28,6 @@ namespace Nz
#include <Nazara/Graphics/Resources/Shaders/BasicMaterial.nzslb.h>
};
const UInt8 r_depthMaterialShader[] = {
#include <Nazara/Graphics/Resources/Shaders/DepthMaterial.nzslb.h>
};
const UInt8 r_fullscreenVertexShader[] = {
#include <Nazara/Graphics/Resources/Shaders/FullscreenVertex.nzslb.h>
};
@@ -72,7 +68,7 @@ namespace Nz
/*!
* \ingroup graphics
* \class Nz::Graphics
* \class Graphics
* \brief Graphics class that represents the module initializer of Graphics
*/
Graphics::Graphics(Config config) :
@@ -124,7 +120,7 @@ namespace Nz
Font::SetDefaultAtlas(std::make_shared<GuillotineTextureAtlas>(*m_renderDevice));
m_materialLoader.RegisterLoader(Loaders::GetMaterialLoader_Texture()); // texture to material loader
m_materialInstanceLoader.RegisterLoader(Loaders::GetMaterialInstanceLoader_Texture()); // texture to material loader
}
Graphics::~Graphics()
@@ -208,30 +204,91 @@ namespace Nz
void Graphics::BuildDefaultMaterials()
{
m_defaultMaterials.depthMaterial = std::make_shared<Material>();
std::size_t depthPassIndex = m_materialPassRegistry.GetPassIndex("DepthPass");
std::size_t forwardPassIndex = m_materialPassRegistry.GetPassIndex("ForwardPass");
// BasicMaterial
{
std::shared_ptr<Nz::MaterialPass> depthPass = std::make_shared<Nz::MaterialPass>(Nz::DepthMaterial::GetSettings());
depthPass->EnableDepthBuffer(true);
MaterialSettings settings;
PredefinedMaterials::AddBasicSettings(settings);
m_defaultMaterials.depthMaterial->AddPass("DepthPass", depthPass);
MaterialPass forwardPass;
forwardPass.states.depthBuffer = true;
forwardPass.shaders.push_back(std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "BasicMaterial"));
settings.AddPass(forwardPassIndex, forwardPass);
std::shared_ptr<Nz::MaterialPass> forwardPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
forwardPass->EnableDepthBuffer(true);
MaterialPass depthPass = forwardPass;
depthPass.options[CRC32("DepthPass")] = true;
settings.AddPass(depthPassIndex, depthPass);
m_defaultMaterials.depthMaterial->AddPass("ForwardPass", forwardPass);
m_defaultMaterials.basicMaterial = std::make_shared<Material>(std::move(settings), "BasicMaterial");
}
m_defaultMaterials.noDepthMaterial = std::make_shared<Material>();
// PbrMaterial
{
m_defaultMaterials.noDepthMaterial->AddPass("ForwardPass", std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings()));
MaterialSettings settings;
PredefinedMaterials::AddBasicSettings(settings);
PredefinedMaterials::AddPbrSettings(settings);
MaterialPass forwardPass;
forwardPass.states.depthBuffer = true;
forwardPass.shaders.push_back(std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "PhysicallyBasedMaterial"));
settings.AddPass(forwardPassIndex, forwardPass);
MaterialPass depthPass = forwardPass;
depthPass.options[CRC32("DepthPass")] = true;
settings.AddPass(depthPassIndex, depthPass);
m_defaultMaterials.pbrMaterial = std::make_shared<Material>(std::move(settings), "PhysicallyBasedMaterial");
}
// PhongMaterial
{
MaterialSettings settings;
PredefinedMaterials::AddBasicSettings(settings);
PredefinedMaterials::AddPhongSettings(settings);
MaterialPass forwardPass;
forwardPass.states.depthBuffer = true;
forwardPass.shaders.push_back(std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "PhongMaterial"));
settings.AddPass(forwardPassIndex, forwardPass);
MaterialPass depthPass = forwardPass;
depthPass.options[CRC32("DepthPass")] = true;
settings.AddPass(depthPassIndex, depthPass);
m_defaultMaterials.phongMaterial = std::make_shared<Material>(std::move(settings), "PhongMaterial");
}
m_defaultMaterials.basicDefault = m_defaultMaterials.basicMaterial->GetDefaultInstance();
m_defaultMaterials.basicNoDepth = m_defaultMaterials.basicMaterial->CreateInstance();
m_defaultMaterials.basicNoDepth->DisablePass(depthPassIndex);
m_defaultMaterials.basicNoDepth->UpdatePassStates(forwardPassIndex, [](RenderStates& states)
{
states.depthBuffer = false;
});
m_defaultMaterials.basicTransparent = m_defaultMaterials.basicMaterial->CreateInstance();
m_defaultMaterials.basicTransparent->DisablePass(depthPassIndex);
m_defaultMaterials.basicTransparent->UpdatePassStates(forwardPassIndex, [](RenderStates& renderStates)
{
renderStates.depthWrite = false;
renderStates.blending = true;
renderStates.blend.modeColor = BlendEquation::Add;
renderStates.blend.modeAlpha = BlendEquation::Add;
renderStates.blend.srcColor = BlendFunc::SrcAlpha;
renderStates.blend.dstColor = BlendFunc::InvSrcAlpha;
renderStates.blend.srcAlpha = BlendFunc::One;
renderStates.blend.dstAlpha = BlendFunc::One;
});
}
void Graphics::BuildDefaultTextures()
{
// White texture 2D
{
Nz::TextureInfo texInfo;
TextureInfo texInfo;
texInfo.width = texInfo.height = texInfo.depth = texInfo.mipmapLevel = 1;
texInfo.pixelFormat = PixelFormat::L8;
@@ -257,7 +314,6 @@ namespace Nz
{
m_shaderModuleResolver = std::make_shared<nzsl::FilesystemModuleResolver>();
RegisterEmbedShaderModule(r_basicMaterialShader);
RegisterEmbedShaderModule(r_depthMaterialShader);
RegisterEmbedShaderModule(r_fullscreenVertexShader);
RegisterEmbedShaderModule(r_instanceDataModule);
RegisterEmbedShaderModule(r_lightDataModule);

View File

@@ -3,15 +3,15 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/LinearSlicedSprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
LinearSlicedSprite::LinearSlicedSprite(std::shared_ptr<Material> material, Orientation orientation) :
LinearSlicedSprite::LinearSlicedSprite(std::shared_ptr<MaterialInstance> material, Orientation orientation) :
m_material(std::move(material)),
m_sectionCount(0),
m_spriteCount(0),
@@ -25,24 +25,26 @@ namespace Nz
void LinearSlicedSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
const auto& materialPipeline = m_material->GetPipeline(passIndex);
if (!materialPipeline)
return;
MaterialPassFlags passFlags = m_material->GetPassFlags(passIndex);
const std::shared_ptr<VertexDeclaration>& vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Color_UV);
RenderPipelineInfo::VertexBufferData vertexBufferData = {
0,
vertexDeclaration
};
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(&vertexBufferData, 1);
const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1);
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), m_material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& LinearSlicedSprite::GetMaterial(std::size_t i) const
const std::shared_ptr<MaterialInstance>& LinearSlicedSprite::GetMaterial(std::size_t i) const
{
assert(i == 0);
NazaraUnused(i);
@@ -59,19 +61,14 @@ namespace Nz
{
assert(m_material);
//TODO: Cache index in registry?
if (const auto& material = m_material->FindPass("ForwardPass"))
// TODO: Move this in a separate function
if (const std::shared_ptr<Texture>* textureOpt = m_material->GetTextureProperty("BaseColorMap"))
{
BasicMaterial mat(*material);
if (mat.HasBaseColorMap())
{
// Material should always have textures but we're better safe than sorry
if (const auto& texture = mat.GetBaseColorMap())
return texture->GetSize();
}
// Material should always have textures but we're better safe than sorry
if (const std::shared_ptr<Texture>& texture = *textureOpt)
return texture->GetSize();
}
// Couldn't get material pass or texture
return Vector3ui::Unit(); //< prevents division by zero
}

View File

@@ -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)

View File

@@ -0,0 +1,340 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
bool MaterialInstanceParams::IsValid() const
{
return true;
}
MaterialInstance::MaterialInstance(std::shared_ptr<const Material> parent) :
m_parent(std::move(parent)),
m_materialSettings(m_parent->GetSettings())
{
const auto& settings = m_parent->GetSettings();
m_textureOverride.resize(settings.GetTexturePropertyCount());
for (std::size_t i = 0; i < m_textureOverride.size(); ++i)
m_textureOverride[i].samplerInfo = settings.GetTextureProperty(i).defaultSamplerInfo;
m_valueOverride.resize(settings.GetValuePropertyCount());
const auto& passSettings = settings.GetPasses();
m_passes.resize(passSettings.size());
for (std::size_t i = 0; i < m_passes.size(); ++i)
{
const auto& passSettingOpt = passSettings[i];
if (!passSettingOpt.has_value())
continue;
const auto& passSetting = *passSettingOpt;
auto& pass = m_passes[i];
pass.enabled = true;
pass.flags = passSetting.flags;
static_cast<RenderStates&>(pass.pipelineInfo) = passSetting.states;
pass.shaders.reserve(passSetting.shaders.size());
for (const std::shared_ptr<UberShader>& uberShader : passSetting.shaders)
{
auto& shaderEntry = pass.shaders.emplace_back();
shaderEntry.shader = uberShader;
shaderEntry.onShaderUpdated.Connect(shaderEntry.shader->OnShaderUpdated, [this, passIndex = i](UberShader*)
{
InvalidatePassPipeline(passIndex);
});
auto& pipelineShaderEntry = pass.pipelineInfo.shaders.emplace_back();
pipelineShaderEntry.uberShader = uberShader;
}
}
m_textureBinding.resize(m_parent->GetTextureCount());
m_uniformBuffers.resize(m_parent->GetUniformBlockCount());
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)
{
const auto& uniformBlockData = m_parent->GetUniformBlockData(i);
auto& uniformBuffer = m_uniformBuffers[i];
uniformBuffer.bufferView = uniformBlockData.bufferPool->Allocate(uniformBuffer.bufferIndex);
uniformBuffer.values.resize(uniformBlockData.bufferPool->GetBufferSize());
}
for (const auto& handler : m_materialSettings.GetPropertyHandlers())
handler->Update(*this);
}
MaterialInstance::MaterialInstance(const MaterialInstance& material, CopyToken) :
m_parent(material.m_parent),
m_optionValuesOverride(material.m_optionValuesOverride),
m_valueOverride(material.m_valueOverride),
m_textureBinding(material.m_textureBinding),
m_textureOverride(material.m_textureOverride),
m_materialSettings(material.m_materialSettings)
{
m_passes.resize(material.m_passes.size());
for (std::size_t i = 0; i < m_passes.size(); ++i)
{
m_passes[i].enabled = material.m_passes[i].enabled;
m_passes[i].flags = material.m_passes[i].flags;
m_passes[i].pipeline = material.m_passes[i].pipeline;
m_passes[i].pipelineInfo = material.m_passes[i].pipelineInfo;
m_passes[i].shaders.resize(material.m_passes[i].shaders.size());
for (std::size_t j = 0; j < m_passes[i].shaders.size(); ++j)
{
m_passes[i].shaders[j].shader = material.m_passes[i].shaders[j].shader;
m_passes[i].shaders[j].onShaderUpdated.Connect(m_passes[i].shaders[j].shader->OnShaderUpdated, [this, passIndex = i](UberShader*)
{
InvalidatePassPipeline(passIndex);
});
}
}
m_uniformBuffers.resize(m_parent->GetUniformBlockCount());
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)
{
const auto& uniformBlockData = m_parent->GetUniformBlockData(i);
auto& uniformBuffer = m_uniformBuffers[i];
uniformBuffer.bufferView = uniformBlockData.bufferPool->Allocate(uniformBuffer.bufferIndex);
assert(material.m_uniformBuffers[i].values.size() == uniformBlockData.bufferPool->GetBufferSize());
uniformBuffer.values = material.m_uniformBuffers[i].values;
}
}
MaterialInstance::~MaterialInstance()
{
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)
{
auto& uniformBuffer = m_uniformBuffers[i];
m_parent->GetUniformBlockData(i).bufferPool->Free(uniformBuffer.bufferIndex);
}
}
void MaterialInstance::DisablePass(std::string_view passName)
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return DisablePass(passIndex);
}
void MaterialInstance::EnablePass(std::string_view passName, bool enable)
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return EnablePass(passIndex, enable);
}
void MaterialInstance::FillShaderBinding(std::vector<ShaderBinding::Binding>& bindings) const
{
// Textures
const auto& defaultTextures = Graphics::Instance()->GetDefaultTextures();
for (std::size_t i = 0; i < m_textureBinding.size(); ++i)
{
const auto& textureSlot = m_parent->GetTextureData(i);
const auto& textureBinding = m_textureBinding[i];
const std::shared_ptr<Texture>& texture = (textureBinding.texture) ? textureBinding.texture : defaultTextures.whiteTextures[UnderlyingCast(textureSlot.imageType)];
const std::shared_ptr<TextureSampler>& sampler = (textureBinding.sampler) ? textureBinding.sampler : Graphics::Instance()->GetSamplerCache().Get({});
bindings.push_back({
textureSlot.bindingIndex,
ShaderBinding::TextureBinding {
texture.get(), sampler.get()
}
});
}
// UBO
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)
{
const auto& uboSlot = m_parent->GetUniformBlockData(i);
const auto& uboInfo = m_uniformBuffers[i];
bindings.push_back({
uboSlot.bindingIndex,
ShaderBinding::UniformBufferBinding {
uboInfo.bufferView.GetBuffer(), uboInfo.bufferView.GetOffset(), uboInfo.bufferView.GetSize()
}
});
}
}
const std::shared_ptr<MaterialPipeline>& MaterialInstance::GetPipeline(std::size_t passIndex) const
{
if (passIndex >= m_passes.size() || !m_passes[passIndex].enabled)
{
static std::shared_ptr<MaterialPipeline> s_invalidPipeline;
return s_invalidPipeline;
}
auto& pass = m_passes[passIndex];
if (!pass.pipeline)
{
pass.pipelineInfo.pipelineLayout = m_parent->GetRenderPipelineLayout();
// Options
pass.pipelineInfo.optionValues.clear();
const MaterialPass* passSetting = m_materialSettings.GetPass(passIndex);
assert(passSetting);
// Pass options
for (const auto& [hash, value] : passSetting->options)
{
if (m_optionValuesOverride.find(hash) != m_optionValuesOverride.end())
continue;
auto& optionValue = pass.pipelineInfo.optionValues.emplace_back();
optionValue.hash = hash;
optionValue.value = value;
}
// Custom options
for (const auto& [hash, value] : m_optionValuesOverride)
{
auto& optionValue = pass.pipelineInfo.optionValues.emplace_back();
optionValue.hash = hash;
optionValue.value = value;
}
// make option values consistent (required for hash/equality)
std::sort(pass.pipelineInfo.optionValues.begin(), pass.pipelineInfo.optionValues.end(), [](const auto& lhs, const auto& rhs) { return lhs.hash < rhs.hash; });
m_passes[passIndex].pipeline = MaterialPipeline::Get(pass.pipelineInfo);
}
return m_passes[passIndex].pipeline;
}
bool MaterialInstance::HasPass(std::string_view passName) const
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return HasPass(passIndex);
}
void MaterialInstance::OnTransfer(RenderFrame& renderFrame, CommandBufferBuilder& builder)
{
UploadPool& uploadPool = renderFrame.GetUploadPool();
for (UniformBuffer& uniformBuffer : m_uniformBuffers)
{
if (!uniformBuffer.dataInvalidated)
continue;
auto& allocation = uploadPool.Allocate(uniformBuffer.values.size());
std::memcpy(allocation.mappedPtr, uniformBuffer.values.data(), uniformBuffer.values.size());
builder.CopyBuffer(allocation, uniformBuffer.bufferView);
uniformBuffer.dataInvalidated = false;
}
}
void MaterialInstance::UpdatePassFlags(std::string_view passName, MaterialPassFlags materialFlags)
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return UpdatePassFlags(passIndex, materialFlags);
}
void MaterialInstance::UpdatePassStates(std::string_view passName, FunctionRef<bool(RenderStates&)> stateUpdater)
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return UpdatePassStates(passIndex, stateUpdater);
}
void MaterialInstance::SetTextureProperty(std::size_t textureIndex, std::shared_ptr<Texture> texture)
{
assert(textureIndex < m_textureOverride.size());
m_textureOverride[textureIndex].texture = std::move(texture);
for (const auto& handler : m_materialSettings.GetPropertyHandlers())
{
if (handler->NeedsUpdateOnTextureUpdate(textureIndex))
handler->Update(*this);
}
}
void MaterialInstance::SetTextureProperty(std::size_t textureIndex, std::shared_ptr<Texture> texture, const TextureSamplerInfo& samplerInfo)
{
assert(textureIndex < m_textureOverride.size());
m_textureOverride[textureIndex].samplerInfo = samplerInfo;
m_textureOverride[textureIndex].texture = std::move(texture);
for (const auto& handler : m_materialSettings.GetPropertyHandlers())
{
if (handler->NeedsUpdateOnTextureUpdate(textureIndex))
handler->Update(*this);
}
}
void MaterialInstance::SetTextureSamplerProperty(std::size_t textureIndex, const TextureSamplerInfo& samplerInfo)
{
assert(textureIndex < m_textureOverride.size());
m_textureOverride[textureIndex].samplerInfo = samplerInfo;
for (const auto& handler : m_materialSettings.GetPropertyHandlers())
{
if (handler->NeedsUpdateOnTextureUpdate(textureIndex))
handler->Update(*this);
}
}
void MaterialInstance::SetValueProperty(std::size_t valueIndex, const MaterialSettings::Value& value)
{
assert(valueIndex < m_valueOverride.size());
m_valueOverride[valueIndex] = value;
for (const auto& handler : m_materialSettings.GetPropertyHandlers())
{
if (handler->NeedsUpdateOnValueUpdate(valueIndex))
handler->Update(*this);
}
}
void MaterialInstance::UpdateOptionValue(UInt32 optionHash, const nzsl::Ast::ConstantSingleValue& value)
{
auto it = m_optionValuesOverride.find(optionHash);
if (it == m_optionValuesOverride.end())
m_optionValuesOverride.emplace(optionHash, value);
else if (it->second != value)
it->second = value;
else
return;
for (std::size_t i = 0; i < m_passes.size(); ++i)
InvalidatePassPipeline(i);
}
void MaterialInstance::UpdateTextureBinding(std::size_t textureBinding, std::shared_ptr<Texture> texture, std::shared_ptr<TextureSampler> textureSampler)
{
assert(textureBinding < m_textureBinding.size());
auto& binding = m_textureBinding[textureBinding];
binding.texture = std::move(texture);
binding.sampler = std::move(textureSampler);
InvalidateShaderBinding();
}
void MaterialInstance::UpdateUniformBufferData(std::size_t uniformBufferIndex, std::size_t offset, std::size_t size, const void* data)
{
assert(uniformBufferIndex < m_uniformBuffers.size());
auto& uniformBlock = m_uniformBuffers[uniformBufferIndex];
uniformBlock.dataInvalidated = true;
assert(offset + size <= uniformBlock.values.size());
std::memcpy(&uniformBlock.values[offset], data, size);
OnTransferRequired(this);
}
}

View File

@@ -1,177 +0,0 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/UberShader.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
/*!
* \ingroup graphics
* \class Nz::Material
* \brief Graphics class that represents a material
*/
/*!
* \brief Constructs a Material object with default states
*
* \see Reset
*/
MaterialPass::MaterialPass(std::shared_ptr<const MaterialSettings> settings) :
m_settings(std::move(settings)),
m_pipelineUpdated(false)
{
m_pipelineInfo.settings = m_settings;
const auto& shaders = m_settings->GetShaders();
m_shaders.resize(shaders.size());
for (std::size_t i = 0; i < m_shaders.size(); ++i)
{
auto& shaderData = m_pipelineInfo.shaders.emplace_back();
shaderData.uberShader = shaders[i];
m_shaders[i].onShaderUpdated.Connect(shaders[i]->OnShaderUpdated, [this](UberShader*)
{
InvalidatePipeline();
});
}
const auto& textureSettings = m_settings->GetTextures();
const auto& sharedUboSettings = m_settings->GetSharedUniformBlocks();
const auto& uboSettings = m_settings->GetUniformBlocks();
m_textures.resize(textureSettings.size());
m_sharedUniformBuffers.resize(sharedUboSettings.size());
m_uniformBuffers.reserve(uboSettings.size());
for (const auto& uniformBufferInfo : uboSettings)
{
auto& uniformBuffer = m_uniformBuffers.emplace_back();
uniformBuffer.buffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, uniformBufferInfo.blockSize, BufferUsage::Dynamic | BufferUsage::Write);
assert(uniformBufferInfo.defaultValues.size() <= uniformBufferInfo.blockSize);
uniformBuffer.data.resize(uniformBufferInfo.blockSize);
std::memcpy(uniformBuffer.data.data(), uniformBufferInfo.defaultValues.data(), uniformBufferInfo.defaultValues.size());
}
}
void MaterialPass::FillShaderBinding(std::vector<ShaderBinding::Binding>& bindings) const
{
const auto& textureSettings = m_settings->GetTextures();
const auto& sharedUboSettings = m_settings->GetSharedUniformBlocks();
const auto& uboSettings = m_settings->GetUniformBlocks();
// Textures
for (std::size_t i = 0; i < m_textures.size(); ++i)
{
const auto& textureSetting = textureSettings[i];
const auto& textureSlot = m_textures[i];
if (!textureSlot.sampler)
{
TextureSamplerCache& samplerCache = Graphics::Instance()->GetSamplerCache();
textureSlot.sampler = samplerCache.Get(textureSlot.samplerInfo);
}
//TODO: Use "missing" texture
Texture* texture = textureSlot.texture.get();
if (!texture)
{
const auto& defaultTextures = Graphics::Instance()->GetDefaultTextures();
texture = defaultTextures.whiteTextures[UnderlyingCast(textureSetting.type)].get();
}
bindings.push_back({
textureSetting.bindingIndex,
ShaderBinding::TextureBinding {
texture, textureSlot.sampler.get()
}
});
}
// Shared UBO
for (std::size_t i = 0; i < m_sharedUniformBuffers.size(); ++i)
{
const auto& sharedUboSlot = m_sharedUniformBuffers[i];
if (!sharedUboSlot.bufferView)
continue;
const auto& sharedUboSetting = sharedUboSettings[i];
bindings.push_back({
sharedUboSetting.bindingIndex,
ShaderBinding::UniformBufferBinding {
sharedUboSlot.bufferView.GetBuffer(), sharedUboSlot.bufferView.GetOffset(), sharedUboSlot.bufferView.GetSize()
}
});
}
// Owned UBO
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)
{
const auto& uboSetting = uboSettings[i];
const auto& uboSlot = m_uniformBuffers[i];
bindings.push_back({
uboSetting.bindingIndex,
ShaderBinding::UniformBufferBinding {
uboSlot.buffer.get(), 0, uboSlot.buffer->GetSize()
}
});
}
}
void MaterialPass::Update(RenderFrame& renderFrame, CommandBufferBuilder& builder)
{
UploadPool& uploadPool = renderFrame.GetUploadPool();
for (auto& ubo : m_uniformBuffers)
{
if (ubo.dataInvalidated)
{
auto& allocation = uploadPool.Allocate(ubo.data.size());
std::memcpy(allocation.mappedPtr, ubo.data.data(), ubo.data.size());
builder.CopyBuffer(allocation, ubo.buffer.get());
ubo.dataInvalidated = false;
}
}
}
void MaterialPass::UpdatePipeline() const
{
m_pipelineInfo.optionCount = 0;
const auto& options = m_settings->GetOptions();
for (std::size_t optionIndex = 0; optionIndex < options.size(); ++optionIndex)
{
if (!std::holds_alternative<nzsl::Ast::NoValue>(m_optionValues[optionIndex]))
{
auto& optionValue = m_pipelineInfo.optionValues[m_pipelineInfo.optionCount];
optionValue.hash = options[optionIndex].hash;
optionValue.value = m_optionValues[optionIndex];
m_pipelineInfo.optionCount++;
}
}
// make option values consistent (required for hash/equality)
std::sort(m_pipelineInfo.optionValues.begin(), m_pipelineInfo.optionValues.begin() + m_pipelineInfo.optionCount, [](const auto& lhs, const auto& rhs) { return lhs.hash < rhs.hash; });
m_pipeline = MaterialPipeline::Get(m_pipelineInfo);
m_pipelineUpdated = true;
}
}

View File

@@ -5,12 +5,8 @@
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/DepthMaterial.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/PhongLightingMaterial.hpp>
#include <Nazara/Graphics/PhysicallyBasedMaterial.hpp>
#include <Nazara/Graphics/UberShader.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -50,10 +46,10 @@ namespace Nz
RenderPipelineInfo renderPipelineInfo;
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not the line I'm the most proud of
renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
renderPipelineInfo.pipelineLayout = m_pipelineInfo.pipelineLayout;
std::unordered_map<UInt32, nzsl::Ast::ConstantSingleValue> optionValues;
for (std::size_t i = 0; i < m_pipelineInfo.optionCount; ++i)
for (std::size_t i = 0; i < m_pipelineInfo.optionValues.size(); ++i)
{
const auto& option = m_pipelineInfo.optionValues[i];
@@ -94,10 +90,10 @@ namespace Nz
bool MaterialPipeline::Initialize()
{
BasicMaterial::Initialize();
DepthMaterial::Initialize();
PhongLightingMaterial::Initialize();
PhysicallyBasedMaterial::Initialize();
/*BasicMaterialPass::Initialize();
DepthMaterialPass::Initialize();
PhongLightingMaterialPass::Initialize();
PhysicallyBasedMaterialPass::Initialize();*/
return true;
}
@@ -105,10 +101,10 @@ namespace Nz
void MaterialPipeline::Uninitialize()
{
s_pipelineCache.clear();
PhysicallyBasedMaterial::Uninitialize();
PhongLightingMaterial::Uninitialize();
DepthMaterial::Uninitialize();
BasicMaterial::Uninitialize();
/*PhysicallyBasedMaterialPass::Uninitialize();
PhongLightingMaterialPass::Uninitialize();
DepthMaterialPass::Uninitialize();
BasicMaterialPass::Uninitialize();*/
}
MaterialPipeline::PipelineCache MaterialPipeline::s_pipelineCache;

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
void MaterialSettings::AddPass(std::string_view passName, MaterialPass materialPass)
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return AddPass(passIndex, std::move(materialPass));
}
const MaterialPass* MaterialSettings::GetPass(std::string_view passName) const
{
std::size_t passIndex = Graphics::Instance()->GetMaterialPassRegistry().GetPassIndex(passName);
return GetPass(passIndex);
}
}

View File

@@ -6,7 +6,7 @@
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/GraphicalMesh.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSubmesh.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
@@ -23,7 +23,7 @@ namespace Nz
for (std::size_t i = 0; i < m_graphicalMesh->GetSubMeshCount(); ++i)
{
auto& subMeshData = m_submeshes.emplace_back();
subMeshData.material = graphics->GetDefaultMaterials().depthMaterial;
subMeshData.material = graphics->GetDefaultMaterials().basicDefault;
subMeshData.vertexBufferData = {
{
0,
@@ -46,18 +46,20 @@ namespace Nz
{
const auto& submeshData = m_submeshes[i];
const auto& materialPass = submeshData.material->GetPass(passIndex);
if (!materialPass)
const auto& materialPipeline = submeshData.material->GetPipeline(passIndex);
if (!materialPipeline)
continue;
MaterialPassFlags passFlags = submeshData.material->GetPassFlags(passIndex);
const auto& indexBuffer = m_graphicalMesh->GetIndexBuffer(i);
const auto& vertexBuffer = m_graphicalMesh->GetVertexBuffer(i);
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(submeshData.vertexBufferData.data(), submeshData.vertexBufferData.size());
const auto& renderPipeline = materialPipeline->GetRenderPipeline(submeshData.vertexBufferData.data(), submeshData.vertexBufferData.size());
std::size_t indexCount = m_graphicalMesh->GetIndexCount(i);
IndexType indexType = m_graphicalMesh->GetIndexType(i);
elements.emplace_back(registry.AllocateElement<RenderSubmesh>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, elementData.skeletonInstance, indexCount, indexType, indexBuffer, vertexBuffer, *elementData.scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSubmesh>(GetRenderLayer(), submeshData.material, passFlags, renderPipeline, *elementData.worldInstance, elementData.skeletonInstance, indexCount, indexType, indexBuffer, vertexBuffer, *elementData.scissorBox));
}
}
@@ -71,7 +73,7 @@ namespace Nz
return m_graphicalMesh->GetIndexCount(subMeshIndex);
}
const std::shared_ptr<Material>& Model::GetMaterial(std::size_t subMeshIndex) const
const std::shared_ptr<MaterialInstance>& Model::GetMaterial(std::size_t subMeshIndex) const
{
assert(subMeshIndex < m_submeshes.size());
const auto& subMeshData = m_submeshes[subMeshIndex];

View File

@@ -1,366 +0,0 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PhongLightingMaterial.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <NZSL/Parser.hpp>
#include <NZSL/Math/FieldOffsets.hpp>
#include <cassert>
#include <filesystem>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
PhongLightingMaterial::PhongLightingMaterial(MaterialPass& material) :
BasicMaterial(material, NoInit{})
{
// Most common case: don't fetch texture indexes as a little optimization
const std::shared_ptr<const MaterialSettings>& materialSettings = GetMaterial().GetSettings();
if (materialSettings == s_phongMaterialSettings)
{
m_basicUniformOffsets = s_basicUniformOffsets;
m_basicOptionIndexes = s_basicOptionIndexes;
m_basicTextureIndexes = s_basicTextureIndexes;
m_phongOptionIndexes = s_phongOptionIndexes;
m_phongTextureIndexes = s_phongTextureIndexes;
m_phongUniformOffsets = s_phongUniformOffsets;
}
else
{
m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_basicOptionIndexes.hasBaseColorMap = materialSettings->GetOptionIndex("HasBaseColorMap");
m_phongOptionIndexes.hasEmissiveMap = materialSettings->GetOptionIndex("HasEmissiveMap");
m_phongOptionIndexes.hasHeightMap = materialSettings->GetOptionIndex("HasHeightMap");
m_phongOptionIndexes.hasNormalMap = materialSettings->GetOptionIndex("HasNormalMap");
m_phongOptionIndexes.hasSpecularMap = materialSettings->GetOptionIndex("HasSpecularMap");
m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_basicTextureIndexes.baseColor = materialSettings->GetTextureIndex("BaseColor");
m_phongTextureIndexes.emissive = materialSettings->GetTextureIndex("Emissive");
m_phongTextureIndexes.height = materialSettings->GetTextureIndex("Height");
m_phongTextureIndexes.normal = materialSettings->GetTextureIndex("Normal");
m_phongTextureIndexes.specular = materialSettings->GetTextureIndex("Specular");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings");
if (m_uniformBlockIndex != MaterialSettings::InvalidIndex)
{
m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_basicUniformOffsets.baseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "BaseColor");
m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AmbientColor");
m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "Shininess");
m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "SpecularColor");
}
else
{
m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex;
m_basicUniformOffsets.baseColor = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.ambientColor = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.shininess = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.specularColor = MaterialSettings::InvalidIndex;
}
}
}
Color PhongLightingMaterial::GetAmbientColor() const
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_phongUniformOffsets.ambientColor);
return Color(colorPtr[0], colorPtr[1], colorPtr[2], colorPtr[3]);
}
float Nz::PhongLightingMaterial::GetShininess() const
{
NazaraAssert(HasShininess(), "Material has no shininess uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
return AccessByOffset<const float&>(bufferData.data(), m_phongUniformOffsets.shininess);
}
Color PhongLightingMaterial::GetSpecularColor() const
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_phongUniformOffsets.specularColor);
return Color(colorPtr[0], colorPtr[1], colorPtr[2], colorPtr[3]);
}
void PhongLightingMaterial::SetAmbientColor(const Color& ambient)
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_phongUniformOffsets.ambientColor);
colorPtr[0] = ambient.r;
colorPtr[1] = ambient.g;
colorPtr[2] = ambient.b;
colorPtr[3] = ambient.a;
}
void PhongLightingMaterial::SetShininess(float shininess)
{
NazaraAssert(HasShininess(), "Material has no shininess uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
AccessByOffset<float&>(bufferData.data(), m_phongUniformOffsets.shininess) = shininess;
}
void PhongLightingMaterial::SetSpecularColor(const Color& specular)
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_phongUniformOffsets.specularColor);
colorPtr[0] = specular.r;
colorPtr[1] = specular.g;
colorPtr[2] = specular.b;
colorPtr[3] = specular.a;
}
const std::shared_ptr<MaterialSettings>& PhongLightingMaterial::GetSettings()
{
return s_phongMaterialSettings;
}
MaterialSettings::Builder PhongLightingMaterial::Build(PhongBuildOptions& options)
{
MaterialSettings::Builder settings = BasicMaterial::Build(options);
assert(settings.uniformBlocks.size() == 1);
std::vector<MaterialSettings::UniformVariable> variables = std::move(settings.uniformBlocks.front().uniforms);
settings.uniformBlocks.clear();
if (options.phongOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"AmbientColor",
options.phongOffsets.ambientColor
});
}
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"Shininess",
options.phongOffsets.shininess
});
}
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"SpecularColor",
options.phongOffsets.specularColor
});
}
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
if (options.phongOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.phongOffsets.ambientColor) = Vector4f(0.f, 0.f, 0.f, 1.f);
if (options.phongOffsets.specularColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.phongOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(options.defaultValues.data(), options.phongOffsets.shininess) = 2.f;
// Textures
if (options.phongTextureIndexes)
options.phongTextureIndexes->emissive = settings.textures.size();
settings.textures.push_back({
8,
"Emissive",
ImageType::E2D
});
if (options.phongTextureIndexes)
options.phongTextureIndexes->height = settings.textures.size();
settings.textures.push_back({
9,
"Height",
ImageType::E2D
});
if (options.phongTextureIndexes)
options.phongTextureIndexes->normal = settings.textures.size();
settings.textures.push_back({
10,
"Normal",
ImageType::E2D
});
if (options.phongTextureIndexes)
options.phongTextureIndexes->specular = settings.textures.size();
settings.textures.push_back({
11,
"Specular",
ImageType::E2D
});
if (options.uniformBlockIndex)
*options.uniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"MaterialSettings",
options.phongOffsets.totalSize,
std::move(variables),
options.defaultValues
});
settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(7, nzsl::ShaderStageType::Fragment));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 7;
settings.shaders = options.shaders;
for (const std::shared_ptr<UberShader>& uberShader : settings.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::Position:
config.optionValues[CRC32("PosLocation")] = locationIndex;
break;
case VertexComponent::Color:
config.optionValues[CRC32("ColorLocation")] = locationIndex;
break;
case VertexComponent::Normal:
config.optionValues[CRC32("NormalLocation")] = locationIndex;
break;
case VertexComponent::Tangent:
config.optionValues[CRC32("TangentLocation")] = locationIndex;
break;
case VertexComponent::TexCoord:
config.optionValues[CRC32("UvLocation")] = locationIndex;
break;
case VertexComponent::Unused:
default:
break;
}
++locationIndex;
}
});
}
// Options
// HasEmissiveMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasEmissiveMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasEmissiveMap", "HasEmissiveTexture");
// HasHeightMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasHeightMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasHeightMap", "HasHeightTexture");
// HasNormalMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasNormalMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasNormalMap", "HasNormalTexture");
// HasSpecularMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasSpecularMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasSpecularMap", "HasSpecularTexture");
return settings;
}
std::vector<std::shared_ptr<UberShader>> PhongLightingMaterial::BuildShaders()
{
auto shader = std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "PhongMaterial");
return { std::move(shader) };
}
auto PhongLightingMaterial::BuildUniformOffsets() -> std::pair<PhongUniformOffsets, nzsl::FieldOffsets>
{
auto basicOffsets = BasicMaterial::BuildUniformOffsets();
nzsl::FieldOffsets fieldOffsets = basicOffsets.second;
PhongUniformOffsets uniformOffsets;
uniformOffsets.ambientColor = fieldOffsets.AddField(nzsl::StructFieldType::Float3);
uniformOffsets.specularColor = fieldOffsets.AddField(nzsl::StructFieldType::Float3);
uniformOffsets.shininess = fieldOffsets.AddField(nzsl::StructFieldType::Float1);
uniformOffsets.totalSize = fieldOffsets.GetAlignedSize();
return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets));
}
bool PhongLightingMaterial::Initialize()
{
std::tie(s_phongUniformOffsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(s_phongUniformOffsets.totalSize);
PhongBuildOptions options;
options.defaultValues = std::move(defaultValues);
options.shaders = BuildShaders();
// Basic material
options.basicOffsets = s_basicUniformOffsets;
// Phong Material
options.phongOffsets = s_phongUniformOffsets;
options.phongOptionIndexes = &s_phongOptionIndexes;
options.phongTextureIndexes = &s_phongTextureIndexes;
s_phongMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void PhongLightingMaterial::Uninitialize()
{
s_phongMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> PhongLightingMaterial::s_phongMaterialSettings;
std::size_t PhongLightingMaterial::s_phongUniformBlockIndex;
PhongLightingMaterial::PhongOptionIndexes PhongLightingMaterial::s_phongOptionIndexes;
PhongLightingMaterial::PhongTextureIndexes PhongLightingMaterial::s_phongTextureIndexes;
PhongLightingMaterial::PhongUniformOffsets PhongLightingMaterial::s_phongUniformOffsets;
}

View File

@@ -1,398 +0,0 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PhysicallyBasedMaterial.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <NZSL/Parser.hpp>
#include <NZSL/Math/FieldOffsets.hpp>
#include <cassert>
#include <filesystem>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
PhysicallyBasedMaterial::PhysicallyBasedMaterial(MaterialPass& material) :
BasicMaterial(material, NoInit{})
{
// Most common case: don't fetch texture indexes as a little optimization
const std::shared_ptr<const MaterialSettings>& materialSettings = GetMaterial().GetSettings();
if (materialSettings == s_pbrMaterialSettings)
{
m_basicUniformOffsets = s_basicUniformOffsets;
m_basicOptionIndexes = s_basicOptionIndexes;
m_basicTextureIndexes = s_basicTextureIndexes;
m_pbrOptionIndexes = s_pbrOptionIndexes;
m_pbrTextureIndexes = s_pbrTextureIndexes;
m_pbrUniformOffsets = s_pbrUniformOffsets;
}
else
{
m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_basicOptionIndexes.hasBaseColorMap = materialSettings->GetOptionIndex("HasBaseColorMap");
m_pbrOptionIndexes.hasEmissiveMap = materialSettings->GetOptionIndex("HasEmissiveMap");
m_pbrOptionIndexes.hasHeightMap = materialSettings->GetOptionIndex("HasHeightMap");
m_pbrOptionIndexes.hasMetallicMap = materialSettings->GetOptionIndex("HasMetallicMap");
m_pbrOptionIndexes.hasNormalMap = materialSettings->GetOptionIndex("HasNormalMap");
m_pbrOptionIndexes.hasRoughnessMap = materialSettings->GetOptionIndex("HasRoughnessMap");
m_pbrOptionIndexes.hasSpecularMap = materialSettings->GetOptionIndex("HasSpecularMap");
m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_basicTextureIndexes.baseColor = materialSettings->GetTextureIndex("BaseColor");
m_pbrTextureIndexes.emissive = materialSettings->GetTextureIndex("Emissive");
m_pbrTextureIndexes.height = materialSettings->GetTextureIndex("Height");
m_pbrTextureIndexes.normal = materialSettings->GetTextureIndex("Normal");
m_pbrTextureIndexes.specular = materialSettings->GetTextureIndex("Specular");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings");
if (m_uniformBlockIndex != MaterialSettings::InvalidIndex)
{
m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_basicUniformOffsets.baseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "BaseColor");
m_pbrUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AmbientColor");
m_pbrUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "Shininess");
m_pbrUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "SpecularColor");
}
else
{
m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex;
m_basicUniformOffsets.baseColor = MaterialSettings::InvalidIndex;
m_pbrUniformOffsets.ambientColor = MaterialSettings::InvalidIndex;
m_pbrUniformOffsets.shininess = MaterialSettings::InvalidIndex;
m_pbrUniformOffsets.specularColor = MaterialSettings::InvalidIndex;
}
}
}
Color PhysicallyBasedMaterial::GetAmbientColor() const
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_pbrUniformOffsets.ambientColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
float Nz::PhysicallyBasedMaterial::GetShininess() const
{
NazaraAssert(HasShininess(), "Material has no shininess uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
return AccessByOffset<const float&>(bufferData.data(), m_pbrUniformOffsets.shininess);
}
Color PhysicallyBasedMaterial::GetSpecularColor() const
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_pbrUniformOffsets.specularColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
void PhysicallyBasedMaterial::SetAmbientColor(const Color& ambient)
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_pbrUniformOffsets.ambientColor);
colorPtr[0] = ambient.r;
colorPtr[1] = ambient.g;
colorPtr[2] = ambient.b;
colorPtr[3] = ambient.a;
}
void PhysicallyBasedMaterial::SetShininess(float shininess)
{
NazaraAssert(HasShininess(), "Material has no shininess uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
AccessByOffset<float&>(bufferData.data(), m_pbrUniformOffsets.shininess) = shininess;
}
void PhysicallyBasedMaterial::SetSpecularColor(const Color& specular)
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_pbrUniformOffsets.specularColor);
colorPtr[0] = specular.r;
colorPtr[1] = specular.g;
colorPtr[2] = specular.b;
colorPtr[3] = specular.a;
}
const std::shared_ptr<MaterialSettings>& PhysicallyBasedMaterial::GetSettings()
{
return s_pbrMaterialSettings;
}
MaterialSettings::Builder PhysicallyBasedMaterial::Build(PbrBuildOptions& options)
{
MaterialSettings::Builder settings = BasicMaterial::Build(options);
assert(settings.uniformBlocks.size() == 1);
std::vector<MaterialSettings::UniformVariable> variables = std::move(settings.uniformBlocks.front().uniforms);
settings.uniformBlocks.clear();
if (options.pbrOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"AmbientColor",
options.pbrOffsets.ambientColor
});
}
if (options.pbrOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"Shininess",
options.pbrOffsets.shininess
});
}
if (options.pbrOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"SpecularColor",
options.pbrOffsets.specularColor
});
}
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
if (options.pbrOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.pbrOffsets.ambientColor) = Vector4f(0.f, 0.f, 0.f, 1.f);
if (options.pbrOffsets.specularColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.pbrOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
if (options.pbrOffsets.shininess != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(options.defaultValues.data(), options.pbrOffsets.shininess) = 2.f;
// Textures
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->emissive = settings.textures.size();
settings.textures.push_back({
8,
"Emissive",
ImageType::E2D
});
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->height = settings.textures.size();
settings.textures.push_back({
9,
"Height",
ImageType::E2D
});
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->metallic = settings.textures.size();
settings.textures.push_back({
10,
"Metallic",
ImageType::E2D
});
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->normal = settings.textures.size();
settings.textures.push_back({
11,
"Normal",
ImageType::E2D
});
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->roughness = settings.textures.size();
settings.textures.push_back({
12,
"Roughness",
ImageType::E2D
});
if (options.pbrTextureIndexes)
options.pbrTextureIndexes->specular = settings.textures.size();
settings.textures.push_back({
13,
"Specular",
ImageType::E2D
});
if (options.uniformBlockIndex)
*options.uniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"MaterialSettings",
options.pbrOffsets.totalSize,
std::move(variables),
options.defaultValues
});
settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(7, nzsl::ShaderStageType::Fragment));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 7;
settings.shaders = options.shaders;
for (const std::shared_ptr<UberShader>& uberShader : settings.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::Position:
config.optionValues[CRC32("PosLocation")] = locationIndex;
break;
case VertexComponent::Color:
config.optionValues[CRC32("ColorLocation")] = locationIndex;
break;
case VertexComponent::Normal:
config.optionValues[CRC32("NormalLocation")] = locationIndex;
break;
case VertexComponent::Tangent:
config.optionValues[CRC32("TangentLocation")] = locationIndex;
break;
case VertexComponent::TexCoord:
config.optionValues[CRC32("UvLocation")] = locationIndex;
break;
case VertexComponent::Unused:
default:
break;
}
++locationIndex;
}
});
}
// Options
// HasEmissiveMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasEmissiveMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasEmissiveMap", "HasEmissiveTexture");
// HasHeightMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasHeightMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasHeightMap", "HasHeightTexture");
// HasNormalMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasMetallicMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasMetallicMap", "HasMetallicTexture");
// HasNormalMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasNormalMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasNormalMap", "HasNormalTexture");
// HasRoughnessMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasRoughnessMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasRoughnessMap", "HasRoughnessTexture");
// HasSpecularMap
if (options.pbrOptionIndexes)
options.pbrOptionIndexes->hasSpecularMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, "HasSpecularMap", "HasSpecularTexture");
return settings;
}
std::vector<std::shared_ptr<UberShader>> PhysicallyBasedMaterial::BuildShaders()
{
auto shader = std::make_shared<UberShader>(nzsl::ShaderStageType::Fragment | nzsl::ShaderStageType::Vertex, "PhysicallyBasedMaterial");
return { std::move(shader) };
}
auto PhysicallyBasedMaterial::BuildUniformOffsets() -> std::pair<PbrUniformOffsets, nzsl::FieldOffsets>
{
auto basicOffsets = BasicMaterial::BuildUniformOffsets();
nzsl::FieldOffsets fieldOffsets = basicOffsets.second;
PbrUniformOffsets uniformOffsets;
uniformOffsets.ambientColor = fieldOffsets.AddField(nzsl::StructFieldType::Float3);
uniformOffsets.specularColor = fieldOffsets.AddField(nzsl::StructFieldType::Float3);
uniformOffsets.shininess = fieldOffsets.AddField(nzsl::StructFieldType::Float1);
uniformOffsets.totalSize = fieldOffsets.GetAlignedSize();
return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets));
}
bool PhysicallyBasedMaterial::Initialize()
{
std::tie(s_pbrUniformOffsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(s_pbrUniformOffsets.totalSize);
PbrBuildOptions options;
options.defaultValues = std::move(defaultValues);
options.shaders = BuildShaders();
// Basic material
options.basicOffsets = s_basicUniformOffsets;
// Phong Material
options.pbrOffsets = s_pbrUniformOffsets;
options.pbrOptionIndexes = &s_pbrOptionIndexes;
options.pbrTextureIndexes = &s_pbrTextureIndexes;
s_pbrMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void PhysicallyBasedMaterial::Uninitialize()
{
s_pbrMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> PhysicallyBasedMaterial::s_pbrMaterialSettings;
std::size_t PhysicallyBasedMaterial::s_pbrUniformBlockIndex;
PhysicallyBasedMaterial::PbrOptionIndexes PhysicallyBasedMaterial::s_pbrOptionIndexes;
PhysicallyBasedMaterial::PbrTextureIndexes PhysicallyBasedMaterial::s_pbrTextureIndexes;
PhysicallyBasedMaterial::PbrUniformOffsets PhysicallyBasedMaterial::s_pbrUniformOffsets;
}

View File

@@ -0,0 +1,61 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PredefinedMaterials.hpp>
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/PropertyHandler/OptionValuePropertyHandler.hpp>
#include <Nazara/Graphics/PropertyHandler/TexturePropertyHandler.hpp>
#include <Nazara/Graphics/PropertyHandler/UniformValuePropertyHandler.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
void PredefinedMaterials::AddBasicSettings(MaterialSettings& settings)
{
settings.AddValueProperty<Color>("BaseColor", Color::White);
settings.AddValueProperty<bool>("AlphaTest", false);
settings.AddValueProperty<float>("AlphaTestThreshold", 0.2f);
settings.AddTextureProperty("BaseColorMap", ImageType::E2D);
settings.AddTextureProperty("AlphaMap", ImageType::E2D);
settings.AddPropertyHandler(std::make_unique<OptionValuePropertyHandler>("AlphaTest", "AlphaTest"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("BaseColorMap", "HasBaseColorTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("AlphaMap", "HasAlphaTexture"));
settings.AddPropertyHandler(std::make_unique<UniformValuePropertyHandler>("BaseColor"));
settings.AddPropertyHandler(std::make_unique<UniformValuePropertyHandler>("AlphaTestThreshold"));
}
void PredefinedMaterials::AddPbrSettings(MaterialSettings& settings)
{
settings.AddTextureProperty("EmissiveMap", ImageType::E2D);
settings.AddTextureProperty("HeightMap", ImageType::E2D);
settings.AddTextureProperty("MetallicMap", ImageType::E2D);
settings.AddTextureProperty("NormalMap", ImageType::E2D);
settings.AddTextureProperty("RoughnessMap", ImageType::E2D);
settings.AddTextureProperty("SpecularMap", ImageType::E2D);
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("EmissiveMap", "HasEmissiveTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("HeightMap", "HasHeightTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("MetallicMap", "HasMetallicTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("NormalMap", "HasNormalTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("RoughnessMap", "HasRoughnessTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("SpecularMap", "HasSpecularTexture"));
}
void PredefinedMaterials::AddPhongSettings(MaterialSettings& settings)
{
settings.AddValueProperty<Color>("AmbientColor", Color::Black);
settings.AddValueProperty<Color>("SpecularColor", Color::White);
settings.AddValueProperty<float>("Shininess", 2.f);
settings.AddTextureProperty("EmissiveMap", ImageType::E2D);
settings.AddTextureProperty("HeightMap", ImageType::E2D);
settings.AddTextureProperty("NormalMap", ImageType::E2D);
settings.AddTextureProperty("SpecularMap", ImageType::E2D);
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("EmissiveMap", "HasEmissiveTexture"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("HeightMap", "HasHeightMap"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("NormalMap", "HasNormalMap"));
settings.AddPropertyHandler(std::make_unique<TexturePropertyHandler>("SpecularMap", "HasSpecularMap"));
settings.AddPropertyHandler(std::make_unique<UniformValuePropertyHandler>("AmbientColor"));
settings.AddPropertyHandler(std::make_unique<UniformValuePropertyHandler>("SpecularColor"));
settings.AddPropertyHandler(std::make_unique<UniformValuePropertyHandler>("Shininess"));
}
}

View File

@@ -33,25 +33,6 @@ namespace Nz
return lightData;
}
MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock(UInt32 bindingIndex, nzsl::ShaderStageTypeFlags shaderStages)
{
PredefinedLightData lightData = GetOffsets();
std::vector<MaterialSettings::UniformVariable> variables;
auto& var = variables.emplace_back();
var.name = "Lights";
var.offset = lightData.lightsOffset;
MaterialSettings::SharedUniformBlock uniformBlock = {
bindingIndex,
"LightData",
std::move(variables),
shaderStages
};
return uniformBlock;
}
// PredefinedInstanceData
PredefinedInstanceData PredefinedInstanceData::GetOffsets()
{
@@ -66,27 +47,6 @@ namespace Nz
return instanceData;
}
MaterialSettings::SharedUniformBlock PredefinedInstanceData::GetUniformBlock(UInt32 bindingIndex, nzsl::ShaderStageTypeFlags shaderStages)
{
PredefinedInstanceData instanceData = GetOffsets();
std::vector<MaterialSettings::UniformVariable> variables = {
{
{ "WorldMatrix", instanceData.worldMatrixOffset },
{ "InvWorldMatrix", instanceData.invWorldMatrixOffset }
}
};
MaterialSettings::SharedUniformBlock uniformBlock = {
bindingIndex,
"InstanceData",
std::move(variables),
shaderStages
};
return uniformBlock;
}
// PredefinedSkeletalData
PredefinedSkeletalData PredefinedSkeletalData::GetOffsets()
{
@@ -100,26 +60,6 @@ namespace Nz
return skeletalData;
}
MaterialSettings::SharedUniformBlock PredefinedSkeletalData::GetUniformBlock(UInt32 bindingIndex, nzsl::ShaderStageTypeFlags shaderStages)
{
PredefinedSkeletalData skeletalData = GetOffsets();
std::vector<MaterialSettings::UniformVariable> variables = {
{
{ "JointMatrices", skeletalData.jointMatricesOffset }
}
};
MaterialSettings::SharedUniformBlock uniformBlock = {
bindingIndex,
"SkeletalData",
std::move(variables),
shaderStages
};
return uniformBlock;
}
// PredefinedViewerData
PredefinedViewerData PredefinedViewerData::GetOffsets()
{
@@ -140,32 +80,4 @@ namespace Nz
return viewerData;
}
MaterialSettings::SharedUniformBlock PredefinedViewerData::GetUniformBlock(UInt32 bindingIndex, nzsl::ShaderStageTypeFlags shaderStages)
{
PredefinedViewerData viewerData = GetOffsets();
std::vector<MaterialSettings::UniformVariable> variables = {
{
{ "EyePosition", viewerData.eyePositionOffset },
{ "InvProjMatrix", viewerData.invProjMatrixOffset },
{ "InvTargetSize", viewerData.invTargetSizeOffset },
{ "InvViewMatrix", viewerData.invViewMatrixOffset },
{ "InvViewProjMatrix", viewerData.invViewProjMatrixOffset },
{ "ProjMatrix", viewerData.projMatrixOffset },
{ "TargetSize", viewerData.targetSizeOffset },
{ "ViewMatrix", viewerData.viewMatrixOffset },
{ "ViewProjMatrix", viewerData.viewProjMatrixOffset }
}
};
MaterialSettings::SharedUniformBlock uniformBlock = {
bindingIndex,
"ViewerData",
std::move(variables),
shaderStages
};
return uniformBlock;
}
}

View File

@@ -0,0 +1,61 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PropertyHandler/OptionValuePropertyHandler.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <type_traits>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
bool OptionValuePropertyHandler::NeedsUpdateOnValueUpdate(std::size_t updatedPropertyIndex) const
{
return m_propertyIndex == updatedPropertyIndex;
}
void OptionValuePropertyHandler::Setup(const Material& material, const ShaderReflection& reflection)
{
m_propertyIndex = MaterialSettings::InvalidPropertyIndex;
const MaterialSettings& settings = material.GetSettings();
std::size_t propertyIndex = settings.FindValueProperty(m_propertyName);
if (propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const auto& valueProperty = settings.GetValueProperty(propertyIndex);
if (const ShaderReflection::OptionData* optionData = reflection.GetOptionByName(m_optionName))
{
// TODO: Check if option type matches property type
NazaraAssert(optionData->hash != 0, "unexpected option hash");
m_optionHash = optionData->hash;
m_propertyIndex = propertyIndex;
}
}
void OptionValuePropertyHandler::Update(MaterialInstance& materialInstance) const
{
if (m_propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const MaterialSettings::Value& value = materialInstance.GetValueProperty(m_propertyIndex);
std::visit([&](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<T, MaterialPropertyNoValue>)
{
constexpr MaterialPropertyType PropertyType = TypeToMaterialPropertyType_v<T>;
using BufferType = typename MaterialPropertyTypeInfo<PropertyType>::BufferType;
materialInstance.UpdateOptionValue(m_optionHash, MaterialPropertyTypeInfo<PropertyType>::EncodeToOption(arg));
}
else
throw std::runtime_error("value properties must have a default value");
}, value);
}
}

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PropertyHandler/PropertyHandler.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
PropertyHandler::~PropertyHandler() = default;
bool PropertyHandler::NeedsUpdateOnTextureUpdate(std::size_t /*updatedTexturePropertyIndex*/) const
{
return false;
}
bool PropertyHandler::NeedsUpdateOnValueUpdate(std::size_t /*updatedValuePropertyIndex*/) const
{
return false;
}
}

View File

@@ -0,0 +1,73 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PropertyHandler/TexturePropertyHandler.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
bool TexturePropertyHandler::NeedsUpdateOnTextureUpdate(std::size_t updatedPropertyIndex) const
{
return m_propertyIndex == updatedPropertyIndex;
}
void TexturePropertyHandler::Setup(const Material& material, const ShaderReflection& reflection)
{
m_propertyIndex = MaterialSettings::InvalidPropertyIndex;
const MaterialSettings& settings = material.GetSettings();
std::size_t propertyIndex = settings.FindTextureProperty(m_propertyName);
if (propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const auto& textureProperty = settings.GetTextureProperty(propertyIndex);
m_textureIndex = material.FindTextureByTag(m_samplerTag);
if (m_textureIndex == Material::InvalidIndex)
return;
const auto& textureData = material.GetTextureData(m_textureIndex);
if (textureProperty.type != textureData.imageType)
{
// TODO: Use EnumToString to show image type as string
NazaraError("unmatching texture type: material property is of type " +
std::to_string(UnderlyingCast(textureProperty.type)) +
" but shader sampler is of type " +
std::to_string(UnderlyingCast(textureData.imageType)));
return;
}
m_propertyIndex = propertyIndex;
m_optionHash = 0;
if (const ShaderReflection::OptionData* optionData = reflection.GetOptionByName(m_optionName))
{
if (IsPrimitiveType(optionData->type) && std::get<nzsl::Ast::PrimitiveType>(optionData->type) == nzsl::Ast::PrimitiveType::Boolean)
{
NazaraAssert(optionData->hash != 0, "unexpected option hash");
m_optionHash = optionData->hash;
}
else
NazaraError("option " + m_optionName + " is not a boolean option (got " + ToString(optionData->type) + ")");
}
}
void TexturePropertyHandler::Update(MaterialInstance& materialInstance) const
{
if (m_propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const std::shared_ptr<Texture>& texture = materialInstance.GetTextureProperty(m_propertyIndex);
const std::shared_ptr<TextureSampler>& sampler = Graphics::Instance()->GetSamplerCache().Get(materialInstance.GetTextureSamplerProperty(m_propertyIndex));
materialInstance.UpdateTextureBinding(m_textureIndex, texture, sampler);
if (m_optionHash != 0)
materialInstance.UpdateOptionValue(m_optionHash, texture != nullptr);
}
}

View File

@@ -0,0 +1,74 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PropertyHandler/UniformValuePropertyHandler.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <type_traits>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
bool UniformValuePropertyHandler::NeedsUpdateOnValueUpdate(std::size_t updatedPropertyIndex) const
{
return m_propertyIndex == updatedPropertyIndex;
}
void UniformValuePropertyHandler::Setup(const Material& material, const ShaderReflection& reflection)
{
m_propertyIndex = MaterialSettings::InvalidPropertyIndex;
const MaterialSettings& settings = material.GetSettings();
std::size_t propertyIndex = settings.FindValueProperty(m_propertyName);
if (propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const auto& valueProperty = settings.GetValueProperty(propertyIndex);
m_uniformBlockIndex = material.FindUniformBlockByTag(m_blockTag);
if (m_uniformBlockIndex == Material::InvalidIndex)
return;
const auto& uniformBlockData = material.GetUniformBlockData(m_uniformBlockIndex);
const ShaderReflection::StructData* structData = reflection.GetStructByIndex(uniformBlockData.structIndex);
NazaraAssert(structData, "invalid struct index " + std::to_string(uniformBlockData.structIndex));
auto it = structData->members.find(m_memberTag);
if (it == structData->members.end())
return;
m_offset = it->second.offset;
m_size = it->second.size;
m_propertyIndex = propertyIndex;
// TODO: Check if member type matches property type
}
void UniformValuePropertyHandler::Update(MaterialInstance& materialInstance) const
{
if (m_propertyIndex == MaterialSettings::InvalidPropertyIndex)
return;
const MaterialSettings::Value& value = materialInstance.GetValueProperty(m_propertyIndex);
std::visit([&](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<T, MaterialPropertyNoValue>)
{
constexpr MaterialPropertyType PropertyType = TypeToMaterialPropertyType_v<T>;
using BufferType = typename MaterialPropertyTypeInfo<PropertyType>::BufferType;
BufferType value = MaterialPropertyTypeInfo<PropertyType>::EncodeToBuffer(arg);
assert(sizeof(value) == m_size);
materialInstance.UpdateUniformBufferData(m_uniformBlockIndex, m_offset, m_size, &value);
}
else
throw std::runtime_error("value properties must have a default value");
}, value);
}
}

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/RenderBufferPool.hpp>
#include <Nazara/Renderer/RenderDevice.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
RenderBufferPool::RenderBufferPool(std::shared_ptr<RenderDevice> renderDevice, BufferType bufferType, std::size_t bufferSize, std::size_t bufferPerBlock) :
m_bufferPerBlock(bufferPerBlock),
m_bufferSize(bufferSize),
m_renderDevice(std::move(renderDevice)),
m_bufferType(bufferType)
{
m_bufferAlignedSize = m_bufferSize;
switch (bufferType)
{
case BufferType::Index:
case BufferType::Vertex:
break; // TODO
case BufferType::Storage:
m_bufferAlignedSize = Align(m_bufferAlignedSize, m_renderDevice->GetDeviceInfo().limits.minStorageBufferOffsetAlignment);
break;
case BufferType::Uniform:
m_bufferAlignedSize = Align(m_bufferAlignedSize, m_renderDevice->GetDeviceInfo().limits.minUniformBufferOffsetAlignment);
break;
}
}
RenderBufferView RenderBufferPool::Allocate(std::size_t& index)
{
// First try to fetch from an already allocated block
index = m_availableEntries.FindFirst();
if (index != m_availableEntries.npos)
{
std::size_t blockIndex = index / m_bufferPerBlock;
m_availableEntries.Set(index, false);
std::size_t localIndex = index - (blockIndex * m_bufferPerBlock); //< faster than index % m_bufferPerBlock
return RenderBufferView(m_bufferBlocks[blockIndex].get(), localIndex * m_bufferAlignedSize, m_bufferSize);
}
// Allocate a new block
std::size_t blockIndex = m_bufferBlocks.size();
m_bufferBlocks.emplace_back(m_renderDevice->InstantiateBuffer(m_bufferType, m_bufferAlignedSize * m_bufferPerBlock, BufferUsage::DeviceLocal));
m_availableEntries.Resize(m_availableEntries.GetSize() + m_bufferPerBlock, true);
index = blockIndex * m_bufferPerBlock;
m_availableEntries.Set(index, false);
std::size_t localIndex = index - (blockIndex * m_bufferPerBlock); //< faster than index % m_bufferPerBlock
return RenderBufferView(m_bufferBlocks[blockIndex].get(), localIndex * m_bufferAlignedSize, m_bufferSize);
}
void RenderBufferPool::Free(std::size_t index)
{
NazaraAssert(!m_availableEntries.Test(index), "index is not a currently active buffer");
m_availableEntries.Set(index, true);
}
}

View File

@@ -5,6 +5,10 @@ import InstanceData from Engine.InstanceData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
// Pass-specific options
option DepthPass: bool = false;
// Material options
option HasBaseColorTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
@@ -16,34 +20,43 @@ option BillboardColorLocation: i32 = -1;
option BillboardSizeRotLocation: i32 = -1;
// Vertex declaration related options
option ColorLocation: i32 = -1;
option PosLocation: i32;
option UvLocation: i32 = -1;
option VertexColorLoc: i32 = -1;
option VertexPositionLoc: i32;
option VertexUvLoc: i32 = -1;
option JointIndicesLocation: i32 = -1;
option JointWeightsLocation: i32 = -1;
option VertexJointIndicesLoc: i32 = -1;
option VertexJointWeightsLoc: i32 = -1;
const HasVertexColor = (ColorLocation >= 0);
const HasVertexColor = (VertexColorLoc >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasUV = (UvLocation >= 0);
const HasSkinning = (JointIndicesLocation >= 0 && JointWeightsLocation >= 0);
const HasUV = (VertexUvLoc >= 0);
const HasSkinning = (VertexJointIndicesLoc >= 0 && VertexJointWeightsLoc >= 0);
[layout(std140)]
struct MaterialSettings
{
[tag("AlphaTestThreshold")]
AlphaThreshold: f32,
[tag("BaseColor")]
BaseColor: vec4[f32]
}
[tag("Material")]
external
{
[binding(0)] settings: uniform[MaterialSettings],
[binding(1)] MaterialBaseColorMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] skeletalData: uniform[SkeletalData]
[tag("Settings"), binding(0)] settings: uniform[MaterialSettings],
[tag("BaseColorMap"), binding(1)] MaterialBaseColorMap: sampler2D[f32],
[tag("AlphaMap"), binding(2)] MaterialAlphaMap: sampler2D[f32],
}
[tag("Engine")]
external
{
[tag("TextureOverlay"), binding(3)] TextureOverlay: sampler2D[f32],
[tag("InstanceData"), binding(4)] instanceData: uniform[InstanceData],
[tag("ViewerData"), binding(5)] viewerData: uniform[ViewerData],
[tag("SkeletalData"), binding(6)] skeletalData: uniform[SkeletalData]
}
// Fragment stage
@@ -58,7 +71,7 @@ struct FragOut
[location(0)] RenderTarget0: vec4[f32]
}
[entry(frag)]
[entry(frag), cond(!DepthPass || AlphaTest)]
fn main(input: FragIn) -> FragOut
{
let color = settings.BaseColor;
@@ -86,22 +99,26 @@ fn main(input: FragIn) -> FragOut
return output;
}
// Dummy fragment shader (TODO: Add a way to delete stage?)
[entry(frag), cond(DepthPass && !AlphaTest)]
fn main() {}
// Vertex stage
struct VertIn
{
[location(PosLocation)]
[location(VertexPositionLoc)]
pos: vec3[f32],
[cond(HasVertexColor), location(ColorLocation)]
[cond(HasVertexColor), location(VertexColorLoc)]
color: vec4[f32],
[cond(HasUV), location(UvLocation)]
[cond(HasUV), location(VertexUvLoc)]
uv: vec2[f32],
[cond(HasSkinning), location(JointIndicesLocation)]
[cond(HasSkinning), location(VertexJointIndicesLoc)]
jointIndices: vec4[i32],
[cond(HasSkinning), location(JointWeightsLocation)]
[cond(HasSkinning), location(VertexJointWeightsLoc)]
jointWeights: vec4[f32],
[cond(Billboard), location(BillboardCenterLocation)]

View File

@@ -1,117 +0,0 @@
[nzsl_version("1.0")]
module DepthMaterial;
import InstanceData from Engine.InstanceData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
option HasBaseColorTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
option PosLocation: i32;
option UvLocation: i32 = -1;
option JointIndicesLocation: i32 = -1;
option JointWeightsLocation: i32 = -1;
const HasUV = AlphaTest && (HasBaseColorTexture || HasAlphaTexture);
const HasSkinning = (JointIndicesLocation >= 0 && JointWeightsLocation >= 0);
[layout(std140)]
struct BasicSettings
{
AlphaThreshold: f32,
BaseColor: vec4[f32]
}
external
{
[binding(0)] settings: uniform[BasicSettings],
[binding(1)] MaterialBaseColorMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] skeletalData: uniform[SkeletalData]
}
// Fragment stage
struct FragIn
{
[location(0), cond(HasUV)] uv: vec2[f32]
}
[entry(frag), cond(AlphaTest)]
fn main(input: FragIn)
{
let alpha = settings.BaseColor.a;
const if (HasUV)
alpha *= TextureOverlay.Sample(input.uv).a;
const if (HasBaseColorTexture)
alpha *= MaterialBaseColorMap.Sample(input.uv).a;
const if (HasAlphaTexture)
alpha *= MaterialAlphaMap.Sample(input.uv).x;
if (alpha < settings.AlphaThreshold)
discard;
}
// Dummy fragment shader (TODO: Add a way to delete stage?)
[entry(frag), cond(!AlphaTest)]
fn main() {}
// Vertex stage
struct VertIn
{
[location(PosLocation)] pos: vec3[f32],
[cond(HasUV), location(UvLocation)]
uv: vec2[f32],
[cond(HasSkinning), location(JointIndicesLocation)]
jointIndices: vec4[i32],
[cond(HasSkinning), location(JointWeightsLocation)]
jointWeights: vec4[f32],
}
struct VertOut
{
[location(0), cond(HasUV)] uv: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(vert)]
fn main(input: VertIn) -> VertOut
{
let pos: vec3[f32];
const if (HasSkinning)
{
pos = vec3[f32](0.0, 0.0, 0.0);
[unroll]
for i in 0 -> 4
{
let jointIndex = input.jointIndices[i];
let jointWeight = input.jointWeights[i];
let jointMatrix = skeletalData.JointMatrices[jointIndex];
pos += (jointMatrix * vec4[f32](input.pos, 1.0)).xyz * jointWeight;
}
}
else
pos = input.pos;
let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0);
let output: VertOut;
output.position = viewerData.viewProjMatrix * worldPosition;
const if (HasUV)
output.uv = input.uv;
return output;
}

View File

@@ -6,6 +6,9 @@ import LightData from Engine.LightData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
// Pass-specific options
option DepthPass: bool = false;
// Basic material options
option HasBaseColorTexture: bool = false;
option HasAlphaTexture: bool = false;
@@ -24,30 +27,39 @@ option BillboardColorLocation: i32 = -1;
option BillboardSizeRotLocation: i32 = -1;
// Vertex declaration related options
option ColorLocation: i32 = -1;
option NormalLocation: i32 = -1;
option PosLocation: i32;
option TangentLocation: i32 = -1;
option UvLocation: i32 = -1;
option VertexColorLoc: i32 = -1;
option VertexNormalLoc: i32 = -1;
option VertexPositionLoc: i32;
option VertexTangentLoc: i32 = -1;
option VertexUvLoc: i32 = -1;
const HasNormal = (NormalLocation >= 0);
const HasVertexColor = (ColorLocation >= 0);
const HasNormal = (VertexNormalLoc >= 0);
const HasVertexColor = (VertexColorLoc >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasTangent = (TangentLocation >= 0);
const HasUV = (UvLocation >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent;
const HasTangent = (VertexTangentLoc >= 0);
const HasUV = (VertexUvLoc >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent && !DepthPass;
[layout(std140)]
struct MaterialSettings
{
// BasicSettings
// Basic settings
[tag("AlphaTestThreshold")]
AlphaThreshold: f32,
[tag("BaseColor")]
BaseColor: vec4[f32],
// PhongSettings
AmbientColor: vec3[f32],
SpecularColor: vec3[f32],
Shininess: f32,
// Phong settings
[tag("AmbientColor")]
AmbientColor: vec4[f32], //< TODO: Switch to vec3[f32]
[tag("SpecularColor")]
SpecularColor: vec4[f32], //< TODO: Switch to vec3[f32
[tag("Shininess")]
Shininess: f32
}
// TODO: Add enums
@@ -55,20 +67,26 @@ const DirectionalLight = 0;
const PointLight = 1;
const SpotLight = 2;
[tag("Material")]
external
{
[binding(0)] settings: uniform[MaterialSettings],
[binding(1)] MaterialBaseColorMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] skeletalData: uniform[SkeletalData],
[binding(7)] lightData: uniform[LightData],
[binding(8)] MaterialEmissiveMap: sampler2D[f32],
[binding(9)] MaterialHeightMap: sampler2D[f32],
[binding(10)] MaterialNormalMap: sampler2D[f32],
[binding(11)] MaterialSpecularMap: sampler2D[f32],
[tag("Settings"), binding(0)] settings: uniform[MaterialSettings],
[tag("BaseColorMap"), binding(1)] MaterialBaseColorMap: sampler2D[f32],
[tag("AlphaMap"), binding(2)] MaterialAlphaMap: sampler2D[f32],
[tag("EmissiveMap"), binding(3)] MaterialEmissiveMap: sampler2D[f32],
[tag("HeightMap"), binding(4)] MaterialHeightMap: sampler2D[f32],
[tag("NormalMap"), binding(5)] MaterialNormalMap: sampler2D[f32],
[tag("SpecularMap"), binding(6)] MaterialSpecularMap: sampler2D[f32],
}
[tag("Engine")]
external
{
[tag("TextureOverlay"), binding(7)] TextureOverlay: sampler2D[f32],
[tag("InstanceData"), binding(8)] instanceData: uniform[InstanceData],
[tag("ViewerData"), binding(9)] viewerData: uniform[ViewerData],
[tag("SkeletalData"), binding(10)] skeletalData: uniform[SkeletalData],
[tag("LightData"), binding(11)] lightData: uniform[LightData]
}
struct VertToFrag
@@ -87,7 +105,7 @@ struct FragOut
[location(0)] RenderTarget0: vec4[f32]
}
[entry(frag)]
[entry(frag), cond(!DepthPass || AlphaTest)]
fn main(input: VertToFrag) -> FragOut
{
let color = settings.BaseColor;
@@ -110,7 +128,7 @@ fn main(input: VertToFrag) -> FragOut
discard;
}
const if (HasNormal)
const if (HasNormal && !DepthPass)
{
let lightAmbient = vec3[f32](0.0, 0.0, 0.0);
let lightDiffuse = vec3[f32](0.0, 0.0, 0.0);
@@ -143,7 +161,7 @@ fn main(input: VertToFrag) -> FragOut
{
let lightDir = light.parameter1.xyz;
lightAmbient += light.color.rgb * lightAmbientFactor * settings.AmbientColor;
lightAmbient += light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
let lambert = max(dot(normal, -lightDir), 0.0);
@@ -166,7 +184,7 @@ fn main(input: VertToFrag) -> FragOut
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor;
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
@@ -196,7 +214,7 @@ fn main(input: VertToFrag) -> FragOut
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
attenuationFactor *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0);
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor;
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor.rgb;
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
@@ -210,7 +228,7 @@ fn main(input: VertToFrag) -> FragOut
}
}
lightSpecular *= settings.SpecularColor;
lightSpecular *= settings.SpecularColor.rgb;
const if (HasSpecularTexture)
lightSpecular *= MaterialSpecularMap.Sample(input.uv).rgb;
@@ -229,22 +247,27 @@ fn main(input: VertToFrag) -> FragOut
}
}
// Dummy fragment shader (TODO: Add a way to delete stage?)
[entry(frag), cond(DepthPass && !AlphaTest)]
fn main() {}
// Vertex stage
struct VertIn
{
[location(PosLocation)]
[location(VertexPositionLoc)]
pos: vec3[f32],
[cond(HasVertexColor), location(ColorLocation)]
[cond(HasVertexColor), location(VertexColorLoc)]
color: vec4[f32],
[cond(HasUV), location(UvLocation)]
[cond(HasUV), location(VertexUvLoc)]
uv: vec2[f32],
[cond(HasNormal), location(NormalLocation)]
[cond(HasNormal), location(VertexNormalLoc)]
normal: vec3[f32],
[cond(HasTangent), location(TangentLocation)]
[cond(HasTangent), location(VertexTangentLoc)]
tangent: vec3[f32],
[cond(Billboard), location(BillboardCenterLocation)]

View File

@@ -6,6 +6,9 @@ import LightData from Engine.LightData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
// Pass-specific options
option DepthPass: bool = false;
// Basic material options
option HasBaseColorTexture: bool = false;
option HasAlphaTexture: bool = false;
@@ -26,30 +29,28 @@ option BillboardColorLocation: i32 = -1;
option BillboardSizeRotLocation: i32 = -1;
// Vertex declaration related options
option ColorLocation: i32 = -1;
option NormalLocation: i32 = -1;
option PosLocation: i32;
option TangentLocation: i32 = -1;
option UvLocation: i32 = -1;
option VertexColorLoc: i32 = -1;
option VertexNormalLoc: i32 = -1;
option VertexPositionLoc: i32;
option VertexTangentLoc: i32 = -1;
option VertexUvLoc: i32 = -1;
const HasNormal = (NormalLocation >= 0);
const HasVertexColor = (ColorLocation >= 0);
const HasNormal = (VertexNormalLoc >= 0);
const HasVertexColor = (VertexColorLoc >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasTangent = (TangentLocation >= 0);
const HasUV = (UvLocation >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent;
const HasTangent = (VertexTangentLoc >= 0);
const HasUV = (VertexUvLoc >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent && !DepthPass;
[layout(std140)]
struct MaterialSettings
{
// BasicSettings
// Basic settings
[tag("AlphaTestThreshold")]
AlphaThreshold: f32,
BaseColor: vec4[f32],
// PhongSettings
AmbientColor: vec3[f32],
SpecularColor: vec3[f32],
Shininess: f32,
[tag("BaseColor")]
BaseColor: vec4[f32],
}
// TODO: Add enums
@@ -57,22 +58,28 @@ const DirectionalLight = 0;
const PointLight = 1;
const SpotLight = 2;
[tag("Material")]
external
{
[binding(0)] settings: uniform[MaterialSettings],
[binding(1)] MaterialBaseColorMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] skeletalData: uniform[SkeletalData],
[binding(7)] lightData: uniform[LightData],
[binding(8)] MaterialEmissiveMap: sampler2D[f32],
[binding(9)] MaterialHeightMap: sampler2D[f32],
[binding(10)] MaterialMetallicMap: sampler2D[f32],
[binding(11)] MaterialNormalMap: sampler2D[f32],
[binding(12)] MaterialRoughnessMap: sampler2D[f32],
[binding(13)] MaterialSpecularMap: sampler2D[f32],
[tag("Settings"), binding(0)] settings: uniform[MaterialSettings],
[tag("BaseColorMap"), binding(1)] MaterialBaseColorMap: sampler2D[f32],
[tag("AlphaMap"), binding(2)] MaterialAlphaMap: sampler2D[f32],
[tag("EmissiveMap"), binding(3)] MaterialEmissiveMap: sampler2D[f32],
[tag("HeightMap"), binding(4)] MaterialHeightMap: sampler2D[f32],
[tag("MetallicMap"), binding(5)] MaterialMetallicMap: sampler2D[f32],
[tag("NormalMap"), binding(6)] MaterialNormalMap: sampler2D[f32],
[tag("RoughnessMap"), binding(7)] MaterialRoughnessMap: sampler2D[f32],
[tag("SpecularMap"), binding(8)] MaterialSpecularMap: sampler2D[f32],
}
[tag("Engine")]
external
{
[tag("TextureOverlay"), binding(9)] TextureOverlay: sampler2D[f32],
[tag("InstanceData"), binding(10)] instanceData: uniform[InstanceData],
[tag("ViewerData"), binding(11)] viewerData: uniform[ViewerData],
[tag("SkeletalData"), binding(12)] skeletalData: uniform[SkeletalData],
[tag("LightData"), binding(13)] lightData: uniform[LightData]
}
struct VertToFrag
@@ -94,7 +101,7 @@ struct FragOut
[location(0)] RenderTarget0: vec4[f32]
}
[entry(frag)]
[entry(frag), cond(!DepthPass || AlphaTest)]
fn main(input: VertToFrag) -> FragOut
{
let color = settings.BaseColor;
@@ -117,7 +124,7 @@ fn main(input: VertToFrag) -> FragOut
discard;
}
const if (HasNormal)
const if (HasNormal && !DepthPass)
{
let lightRadiance = vec3[f32](0.0, 0.0, 0.0);
@@ -229,22 +236,26 @@ fn main(input: VertToFrag) -> FragOut
}
}
// Dummy fragment shader (TODO: Add a way to delete stage?)
[entry(frag), cond(DepthPass && !AlphaTest)]
fn main() {}
// Vertex stage
struct VertIn
{
[location(PosLocation)]
[location(VertexPositionLoc)]
pos: vec3[f32],
[cond(HasVertexColor), location(ColorLocation)]
[cond(HasVertexColor), location(VertexColorLoc)]
color: vec4[f32],
[cond(HasUV), location(UvLocation)]
[cond(HasUV), location(VertexUvLoc)]
uv: vec2[f32],
[cond(HasNormal), location(NormalLocation)]
[cond(HasNormal), location(VertexNormalLoc)]
normal: vec3[f32],
[cond(HasTangent), location(TangentLocation)]
[cond(HasTangent), location(VertexTangentLoc)]
tangent: vec3[f32],
[cond(Billboard), location(BillboardCenterLocation)]

View File

@@ -0,0 +1,178 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ShaderReflection.hpp>
#include <NZSL/Ast/ExpressionType.hpp>
#include <optional>
#include <stdexcept>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
void ShaderReflection::Reflect(nzsl::Ast::Module& module)
{
m_isConditional = false;
for (auto& importedModule : module.importedModules)
importedModule.module->rootNode->Visit(*this);
module.rootNode->Visit(*this);
}
void ShaderReflection::Visit(nzsl::Ast::ConditionalStatement& node)
{
bool previousConditional = m_isConditional;
m_isConditional = true;
RecursiveVisitor::Visit(node);
m_isConditional = previousConditional;
}
void ShaderReflection::Visit(nzsl::Ast::DeclareExternalStatement& node)
{
ExternalBlockData* externalBlock = nullptr;
if (!node.tag.empty())
{
if (m_externalBlocks.find(node.tag) != m_externalBlocks.end())
throw std::runtime_error("duplicate tag " + node.tag);
externalBlock = &m_externalBlocks[node.tag];
}
if (m_isConditional)
throw std::runtime_error("external block " + node.tag + " condition must be resolved");
for (auto& externalVar : node.externalVars)
{
UInt32 bindingIndex = externalVar.bindingIndex.GetResultingValue();
UInt32 bindingSet = externalVar.bindingSet.GetResultingValue();
ShaderBindingType bindingType;
const auto& varType = externalVar.type.GetResultingValue();
if (IsStorageType(varType))
bindingType = ShaderBindingType::StorageBuffer;
else if (IsSamplerType(varType))
bindingType = ShaderBindingType::Texture;
else if (IsUniformType(varType))
bindingType = ShaderBindingType::UniformBuffer;
else
throw std::runtime_error("unexpected type " + ToString(varType));
// TODO: Get correct shader stage type
m_pipelineLayoutInfo.bindings.push_back({
bindingSet, // setIndex
bindingIndex, // bindingIndex
bindingType, // type
nzsl::ShaderStageType_All // shaderStageFlags
});
if (!externalVar.tag.empty() && externalBlock)
{
switch (bindingType)
{
case ShaderBindingType::StorageBuffer:
{
if (externalBlock->storageBlocks.find(externalVar.tag) != externalBlock->storageBlocks.end())
throw std::runtime_error("duplicate storage buffer tag " + externalVar.tag + " in external block " + node.tag);
ExternalStorageBlock& storageBuffer = externalBlock->storageBlocks[externalVar.tag];
storageBuffer.bindingIndex = bindingIndex;
storageBuffer.bindingSet = bindingSet;
storageBuffer.structIndex = std::get<nzsl::Ast::StorageType>(varType).containedType.structIndex;
break;
}
case ShaderBindingType::Texture:
{
if (externalBlock->samplers.find(externalVar.tag) != externalBlock->samplers.end())
throw std::runtime_error("duplicate textures tag " + externalVar.tag + " in external block " + node.tag);
const auto& samplerType = std::get<nzsl::Ast::SamplerType>(varType);
ExternalTexture& texture = externalBlock->samplers[externalVar.tag];
texture.bindingIndex = bindingIndex;
texture.bindingSet = bindingSet;
texture.imageType = samplerType.dim;
texture.sampledType = samplerType.sampledType;
break;
}
case ShaderBindingType::UniformBuffer:
{
if (externalBlock->uniformBlocks.find(externalVar.tag) != externalBlock->uniformBlocks.end())
throw std::runtime_error("duplicate storage buffer tag " + externalVar.tag + " in external block " + node.tag);
ExternalUniformBlock& uniformBuffer = externalBlock->uniformBlocks[externalVar.tag];
uniformBuffer.bindingIndex = bindingIndex;
uniformBuffer.bindingSet = bindingSet;
uniformBuffer.structIndex = std::get<nzsl::Ast::UniformType>(varType).containedType.structIndex;
break;
}
}
}
}
}
void ShaderReflection::Visit(nzsl::Ast::DeclareOptionStatement& node)
{
if (!node.optType.IsResultingValue())
throw std::runtime_error("option " + node.optName + " has unresolved type " + node.optName);
if (m_isConditional)
throw std::runtime_error("option " + node.optName + " condition must be resolved");
OptionData& optionData = m_options[node.optName];
optionData.hash = CRC32(node.optName);
optionData.type = node.optType.GetResultingValue();
}
void ShaderReflection::Visit(nzsl::Ast::DeclareStructStatement& node)
{
if (!node.description.layout.HasValue())
return;
if (node.description.layout.GetResultingValue() != nzsl::Ast::MemoryLayout::Std140)
throw std::runtime_error("unexpected layout for struct " + node.description.name);
if (node.description.isConditional || m_isConditional)
throw std::runtime_error("struct " + node.description.name + " condition must be resolved");
StructData structData(nzsl::StructLayout::Std140);
for (auto& member : node.description.members)
{
if (member.cond.HasValue() && !member.cond.IsResultingValue())
throw std::runtime_error("unresolved member " + member.name + " condition in struct " + node.description.name);
if (!member.type.IsResultingValue())
throw std::runtime_error("unresolved member " + member.name + " type in struct " + node.description.name);
std::size_t offset = nzsl::Ast::RegisterStructField(structData.fieldOffsets, member.type.GetResultingValue(), [&](std::size_t structIndex) -> const nzsl::FieldOffsets&
{
auto it = m_structs.find(structIndex);
if (it == m_structs.end())
throw std::runtime_error("struct #" + std::to_string(structIndex) + " not found");
return it->second.fieldOffsets;
});
std::size_t size = structData.fieldOffsets.GetSize() - offset;
if (member.tag.empty())
continue;
if (structData.members.find(member.tag) != structData.members.end())
throw std::runtime_error("duplicate struct member tag " + member.tag + " in struct " + node.description.name);
auto& structMember = structData.members[member.tag];
structMember.offset = offset;
structMember.size = size;
structMember.type = member.type.GetResultingValue();
}
m_structs.emplace(node.structIndex.value(), std::move(structData));
}
}

View File

@@ -4,8 +4,10 @@
#include <Nazara/Graphics/SkeletonInstance.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Utility/Joint.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -24,6 +26,7 @@ namespace Nz
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
{
m_dataInvalided = true;
OnTransferRequired(this);
});
}
@@ -35,25 +38,26 @@ namespace Nz
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
{
m_dataInvalided = true;
OnTransferRequired(this);
});
}
void SkeletonInstance::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder)
void SkeletonInstance::OnTransfer(RenderFrame& renderFrame, CommandBufferBuilder& builder)
{
if (m_dataInvalided)
{
PredefinedSkeletalData skeletalUboOffsets = PredefinedSkeletalData::GetOffsets();
if (!m_dataInvalided)
return;
auto& allocation = uploadPool.Allocate(m_skeletalDataBuffer->GetSize());
Matrix4f* matrices = AccessByOffset<Matrix4f*>(allocation.mappedPtr, skeletalUboOffsets.jointMatricesOffset);
PredefinedSkeletalData skeletalUboOffsets = PredefinedSkeletalData::GetOffsets();
for (std::size_t i = 0; i < m_skeleton->GetJointCount(); ++i)
matrices[i] = m_skeleton->GetJoint(i)->GetSkinningMatrix();
auto& allocation = renderFrame.GetUploadPool().Allocate(m_skeletalDataBuffer->GetSize());
Matrix4f* matrices = AccessByOffset<Matrix4f*>(allocation.mappedPtr, skeletalUboOffsets.jointMatricesOffset);
builder.CopyBuffer(allocation, m_skeletalDataBuffer.get());
for (std::size_t i = 0; i < m_skeleton->GetJointCount(); ++i)
matrices[i] = m_skeleton->GetJoint(i)->GetSkinningMatrix();
m_dataInvalided = false;
}
builder.CopyBuffer(allocation, m_skeletalDataBuffer.get());
m_dataInvalided = false;
}
SkeletonInstance& SkeletonInstance::operator=(SkeletonInstance&& skeletonInstance) noexcept
@@ -65,6 +69,7 @@ namespace Nz
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
{
m_dataInvalided = true;
OnTransferRequired(this);
});
return *this;

View File

@@ -3,15 +3,15 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/SlicedSprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
SlicedSprite::SlicedSprite(std::shared_ptr<Material> material) :
SlicedSprite::SlicedSprite(std::shared_ptr<MaterialInstance> material) :
m_material(std::move(material)),
m_color(Color::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f),
@@ -22,24 +22,26 @@ namespace Nz
void SlicedSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
const auto& materialPipeline = m_material->GetPipeline(passIndex);
if (!materialPipeline)
return;
MaterialPassFlags passFlags = m_material->GetPassFlags(passIndex);
const std::shared_ptr<VertexDeclaration>& vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Color_UV);
RenderPipelineInfo::VertexBufferData vertexBufferData = {
0,
vertexDeclaration
};
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(&vertexBufferData, 1);
const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1);
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), m_material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, m_spriteCount, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& SlicedSprite::GetMaterial(std::size_t i) const
const std::shared_ptr<MaterialInstance>& SlicedSprite::GetMaterial(std::size_t i) const
{
assert(i == 0);
NazaraUnused(i);
@@ -57,15 +59,11 @@ namespace Nz
assert(m_material);
//TODO: Cache index in registry?
if (const auto& material = m_material->FindPass("ForwardPass"))
if (const std::shared_ptr<Texture>* textureOpt = m_material->GetTextureProperty("BaseColorMap"))
{
BasicMaterial mat(*material);
if (mat.HasBaseColorMap())
{
// Material should always have textures but we're better safe than sorry
if (const auto& texture = mat.GetBaseColorMap())
return texture->GetSize();
}
// Material should always have textures but we're better safe than sorry
if (const std::shared_ptr<Texture>& texture = *textureOpt)
return texture->GetSize();
}
// Couldn't get material pass or texture

View File

@@ -3,16 +3,16 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
Sprite::Sprite(std::shared_ptr<Material> material) :
Sprite::Sprite(std::shared_ptr<MaterialInstance> material) :
m_material(std::move(material)),
m_color(Color::White),
m_textureCoords(0.f, 0.f, 1.f, 1.f),
@@ -26,24 +26,26 @@ namespace Nz
void Sprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
const auto& materialPipeline = m_material->GetPipeline(passIndex);
if (!materialPipeline)
return;
MaterialPassFlags passFlags = m_material->GetPassFlags(passIndex);
const std::shared_ptr<VertexDeclaration>& vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Color_UV);
RenderPipelineInfo::VertexBufferData vertexBufferData = {
0,
vertexDeclaration
};
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(&vertexBufferData, 1);
const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1);
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, 1, m_vertices.data(), *elementData.scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), m_material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, whiteTexture, 1, m_vertices.data(), *elementData.scissorBox));
}
const std::shared_ptr<Material>& Sprite::GetMaterial(std::size_t i) const
const std::shared_ptr<MaterialInstance>& Sprite::GetMaterial(std::size_t i) const
{
assert(i == 0);
NazaraUnused(i);
@@ -61,15 +63,11 @@ namespace Nz
assert(m_material);
//TODO: Cache index in registry?
if (const auto& material = m_material->FindPass("ForwardPass"))
if (const std::shared_ptr<Texture>* textureOpt = m_material->GetTextureProperty("BaseColorMap"))
{
BasicMaterial mat(*material);
if (mat.HasBaseColorMap())
{
// Material should always have textures but we're better safe than sorry
if (const auto& texture = mat.GetBaseColorMap())
return texture->GetSize();
}
// Material should always have textures but we're better safe than sorry
if (const std::shared_ptr<Texture>& texture = *textureOpt)
return texture->GetSize();
}
// Couldn't get material pass or texture

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
@@ -59,12 +60,12 @@ namespace Nz
{
Graphics* graphics = Graphics::Instance();
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
Recti invalidScissorBox(-1, -1, -1, -1);
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
std::size_t oldDrawCallCount = data.drawCalls.size();
for (std::size_t i = 0; i < elementCount; ++i)
@@ -90,10 +91,10 @@ namespace Nz
m_pendingData.currentPipeline = pipeline;
}
if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); m_pendingData.currentMaterialPass != materialPass)
if (const MaterialInstance* materialInstance = &spriteChain.GetMaterialInstance(); m_pendingData.currentMaterialInstance != materialInstance)
{
FlushDrawData();
m_pendingData.currentMaterialPass = materialPass;
m_pendingData.currentMaterialInstance = materialInstance;
}
if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); m_pendingData.currentWorldInstance != worldInstance)
@@ -154,12 +155,13 @@ namespace Nz
{
m_bindingCache.clear();
const MaterialPass& materialPass = spriteChain.GetMaterialPass();
materialPass.FillShaderBinding(m_bindingCache);
const MaterialInstance& materialInstance = spriteChain.GetMaterialInstance();
materialInstance.FillShaderBinding(m_bindingCache);
// Predefined shader bindings
const auto& matSettings = materialPass.GetSettings();
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
// Engine shader bindings
const Material& material = *materialInstance.GetParentMaterial();
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::InstanceDataUbo); bindingIndex != Material::InvalidBindingIndex)
{
const auto& instanceBuffer = m_pendingData.currentWorldInstance->GetInstanceBuffer();
@@ -171,7 +173,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && m_pendingData.currentLightData)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::LightDataUbo); bindingIndex != Material::InvalidBindingIndex && m_pendingData.currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
@@ -181,7 +183,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::ViewerDataUbo); bindingIndex != Material::InvalidBindingIndex)
{
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();
@@ -193,7 +195,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::OverlayTexture); bindingIndex != MaterialSettings::InvalidIndex)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::OverlayTexture); bindingIndex != Material::InvalidBindingIndex)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;

View File

@@ -4,6 +4,7 @@
#include <Nazara/Graphics/SubmeshRenderer.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSubmesh.hpp>
#include <Nazara/Graphics/SkeletonInstance.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
@@ -33,7 +34,7 @@ namespace Nz
const RenderBuffer* currentIndexBuffer = nullptr;
const RenderBuffer* currentVertexBuffer = nullptr;
const MaterialPass* currentMaterialPass = nullptr;
const MaterialInstance* currentMaterialInstance = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentShaderBinding = nullptr;
const SkeletonInstance* currentSkeletonInstance = nullptr;
@@ -70,10 +71,10 @@ namespace Nz
currentPipeline = pipeline;
}
if (const MaterialPass* materialPass = &submesh.GetMaterialPass(); currentMaterialPass != materialPass)
if (const MaterialInstance* materialInstance = &submesh.GetMaterialInstance(); currentMaterialInstance != materialInstance)
{
FlushDrawData();
currentMaterialPass = materialPass;
currentMaterialInstance = materialInstance;
}
if (const RenderBuffer* indexBuffer = submesh.GetIndexBuffer(); currentIndexBuffer != indexBuffer)
@@ -118,14 +119,15 @@ namespace Nz
if (!currentShaderBinding)
{
assert(currentMaterialPass);
assert(currentMaterialInstance);
m_bindingCache.clear();
currentMaterialPass->FillShaderBinding(m_bindingCache);
currentMaterialInstance->FillShaderBinding(m_bindingCache);
const Material& material = *currentMaterialInstance->GetParentMaterial();
// Predefined shader bindings
const auto& matSettings = currentMaterialPass->GetSettings();
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::InstanceDataUbo); bindingIndex != Material::InvalidBindingIndex)
{
assert(currentWorldInstance);
const auto& instanceBuffer = currentWorldInstance->GetInstanceBuffer();
@@ -138,7 +140,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentLightData)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::LightDataUbo); bindingIndex != Material::InvalidBindingIndex && currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
@@ -148,7 +150,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::SkeletalDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentSkeletonInstance)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::SkeletalDataUbo); bindingIndex != Material::InvalidBindingIndex && currentSkeletonInstance)
{
const auto& skeletalBuffer = currentSkeletonInstance->GetSkeletalBuffer();
@@ -160,7 +162,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::ViewerDataUbo); bindingIndex != Material::InvalidBindingIndex)
{
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();
@@ -172,7 +174,7 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::OverlayTexture); bindingIndex != MaterialSettings::InvalidIndex)
if (UInt32 bindingIndex = material.GetEngineBindingIndex(EngineShaderBinding::OverlayTexture); bindingIndex != Material::InvalidBindingIndex)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;

View File

@@ -222,8 +222,6 @@ namespace Nz
ViewerInstance& viewerInstance = entityCamera.GetViewerInstance();
viewerInstance.UpdateEyePosition(cameraPosition);
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::TransformInverse(cameraPosition, entityNode.GetRotation(CoordSys::Global)));
m_pipeline->InvalidateViewer(cameraEntity->viewerIndex);
}
m_invalidatedCameraNode.clear();
@@ -236,8 +234,6 @@ namespace Nz
const WorldInstancePtr& worldInstance = entityGraphics.GetWorldInstance();
worldInstance->UpdateWorldMatrix(entityNode.GetTransformMatrix());
m_pipeline->InvalidateWorldInstance(graphicsEntity->worldInstanceIndex);
}
m_invalidatedGfxWorldNode.clear();
@@ -437,10 +433,6 @@ namespace Nz
SharedSkeleton& sharedSkeleton = m_sharedSkeletonInstances[skeleton.get()];
sharedSkeleton.skeletonInstanceIndex = m_pipeline->RegisterSkeleton(std::make_shared<SkeletonInstance>(skeleton));
sharedSkeleton.useCount = 1;
sharedSkeleton.onJointsInvalidated.Connect(skeleton->OnSkeletonJointsInvalidated, [this, instanceIndex = sharedSkeleton.skeletonInstanceIndex](const Skeleton* /*skeleton*/)
{
m_pipeline->InvalidateSkeletalInstance(instanceIndex);
});
graphicsEntity->skeletonInstanceIndex = sharedSkeleton.skeletonInstanceIndex;
}
@@ -459,10 +451,6 @@ namespace Nz
const std::shared_ptr<Skeleton>& skeleton = skeletonComponent.GetSkeleton();
graphicsEntity->skeletonInstanceIndex = m_pipeline->RegisterSkeleton(std::make_shared<SkeletonInstance>(skeleton));
graphicsEntity->onSkeletonJointsInvalidated.Connect(skeleton->OnSkeletonJointsInvalidated, [this, instanceIndex = graphicsEntity->skeletonInstanceIndex](const Skeleton* /*skeleton*/)
{
m_pipeline->InvalidateSkeletalInstance(instanceIndex);
});
});
}

View File

@@ -4,7 +4,8 @@
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
#include <Nazara/Utility/AbstractTextDrawer.hpp>
@@ -13,25 +14,29 @@
namespace Nz
{
TextSprite::TextSprite(std::shared_ptr<Material> material) :
TextSprite::TextSprite(std::shared_ptr<MaterialInstance> material) :
InstancedRenderable(),
m_material(std::move(material))
{
if (!m_material)
m_material = Graphics::Instance()->GetDefaultMaterials().basicTransparent->Clone();
}
void TextSprite::BuildElement(ElementRendererRegistry& registry, const ElementData& elementData, std::size_t passIndex, std::vector<RenderElementOwner>& elements) const
{
const auto& materialPass = m_material->GetPass(passIndex);
if (!materialPass)
const auto& materialPipeline = m_material->GetPipeline(passIndex);
if (!materialPipeline)
return;
MaterialPassFlags passFlags = m_material->GetPassFlags(passIndex);
const std::shared_ptr<VertexDeclaration>& vertexDeclaration = VertexDeclaration::Get(VertexLayout::XYZ_Color_UV);
RenderPipelineInfo::VertexBufferData vertexBufferData = {
0,
vertexDeclaration
};
const auto& renderPipeline = materialPass->GetPipeline()->GetRenderPipeline(&vertexBufferData, 1);
const auto& renderPipeline = materialPipeline->GetRenderPipeline(&vertexBufferData, 1);
for (auto& pair : m_renderInfos)
{
@@ -39,11 +44,11 @@ namespace Nz
RenderIndices& indices = pair.second;
if (indices.count > 0)
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), materialPass, renderPipeline, *elementData.worldInstance, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], *elementData.scissorBox));
elements.emplace_back(registry.AllocateElement<RenderSpriteChain>(GetRenderLayer(), m_material, passFlags, renderPipeline, *elementData.worldInstance, vertexDeclaration, key.texture->shared_from_this(), indices.count, &m_vertices[indices.first * 4], *elementData.scissorBox));
}
}
const std::shared_ptr<Material>& TextSprite::GetMaterial(std::size_t i) const
const std::shared_ptr<MaterialInstance>& TextSprite::GetMaterial(std::size_t i) const
{
assert(i == 0);
NazaraUnused(i);

View File

@@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/TransferInterface.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
TransferInterface::~TransferInterface() = default;
}

View File

@@ -7,6 +7,7 @@
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Utils/StackVector.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -29,27 +30,27 @@ namespace Nz
m_viewerDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, viewerUboOffsets.totalSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
}
void ViewerInstance::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder)
void ViewerInstance::OnTransfer(RenderFrame& renderFrame, CommandBufferBuilder& builder)
{
if (m_dataInvalidated)
{
PredefinedViewerData viewerDataOffsets = PredefinedViewerData::GetOffsets();
if (!m_dataInvalidated)
return;
auto& allocation = uploadPool.Allocate(viewerDataOffsets.totalSize);
AccessByOffset<Vector3f&>(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_eyePosition;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.invTargetSizeOffset) = 1.f / m_targetSize;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.targetSizeOffset) = m_targetSize;
PredefinedViewerData viewerDataOffsets = PredefinedViewerData::GetOffsets();
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invProjMatrixOffset) = m_invProjectionMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invViewMatrixOffset) = m_invViewMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invViewProjMatrixOffset) = m_invViewProjMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.projMatrixOffset) = m_projectionMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.viewProjMatrixOffset) = m_viewProjMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.viewMatrixOffset) = m_viewMatrix;
auto& allocation = renderFrame.GetUploadPool().Allocate(viewerDataOffsets.totalSize);
AccessByOffset<Vector3f&>(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_eyePosition;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.invTargetSizeOffset) = 1.f / m_targetSize;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.targetSizeOffset) = m_targetSize;
builder.CopyBuffer(allocation, m_viewerDataBuffer.get());
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invProjMatrixOffset) = m_invProjectionMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invViewMatrixOffset) = m_invViewMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.invViewProjMatrixOffset) = m_invViewProjMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.projMatrixOffset) = m_projectionMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.viewProjMatrixOffset) = m_viewProjMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, viewerDataOffsets.viewMatrixOffset) = m_viewMatrix;
m_dataInvalidated = false;
}
builder.CopyBuffer(allocation, m_viewerDataBuffer.get());
m_dataInvalidated = false;
}
}

View File

@@ -7,6 +7,7 @@
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <Nazara/Utils/StackVector.hpp>
#include <Nazara/Graphics/Debug.hpp>
@@ -23,19 +24,19 @@ namespace Nz
m_instanceDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, instanceUboOffsets.totalSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
}
void WorldInstance::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder)
void WorldInstance::OnTransfer(RenderFrame& renderFrame, CommandBufferBuilder& builder)
{
if (m_dataInvalided)
{
PredefinedInstanceData instanceUboOffsets = PredefinedInstanceData::GetOffsets();
if (!m_dataInvalided)
return;
auto& allocation = uploadPool.Allocate(m_instanceDataBuffer->GetSize());
AccessByOffset<Matrix4f&>(allocation.mappedPtr, instanceUboOffsets.worldMatrixOffset) = m_worldMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, instanceUboOffsets.invWorldMatrixOffset) = m_invWorldMatrix;
PredefinedInstanceData instanceUboOffsets = PredefinedInstanceData::GetOffsets();
builder.CopyBuffer(allocation, m_instanceDataBuffer.get());
auto& allocation = renderFrame.GetUploadPool().Allocate(m_instanceDataBuffer->GetSize());
AccessByOffset<Matrix4f&>(allocation.mappedPtr, instanceUboOffsets.worldMatrixOffset) = m_worldMatrix;
AccessByOffset<Matrix4f&>(allocation.mappedPtr, instanceUboOffsets.invWorldMatrixOffset) = m_invWorldMatrix;
m_dataInvalided = false;
}
builder.CopyBuffer(allocation, m_instanceDataBuffer.get());
m_dataInvalided = false;
}
}

View File

@@ -251,7 +251,7 @@ namespace Nz
{
context->ResetColorWriteMasks();
Color color = command.clearValues[colorAttachmentIndex].color;
const Color& color = command.clearValues[colorAttachmentIndex].color;
context->glClearColor(color.r, color.g, color.b, color.a);
clearFields |= GL_COLOR_BUFFER_BIT;
@@ -286,7 +286,12 @@ namespace Nz
}
if (clearFields)
{
const Vector2ui& size = command.framebuffer->GetSize();
context->SetScissorBox(0, 0, size.x, size.y);
context->SetViewport(0, 0, size.x, size.y);
context->glClear(clearFields);
}
}
if (!invalidateAttachments.empty())

View File

@@ -86,6 +86,12 @@ namespace Nz
if (m_deviceInfo.features.storageBuffers)
{
GLint minStorageOffsetAlignment;
m_referenceContext->glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &minStorageOffsetAlignment);
assert(minStorageOffsetAlignment >= 1);
m_deviceInfo.limits.minStorageBufferOffsetAlignment = static_cast<UInt64>(minStorageOffsetAlignment);
GLint maxStorageBlockSize;
m_referenceContext->glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxStorageBlockSize);

View File

@@ -17,7 +17,7 @@ namespace Nz
throw std::runtime_error("failed to create framebuffer object");
std::size_t colorAttachmentCount = 0;
bool hasDepth = false;
bool hasDepth = false;
bool hasStencil = false;
for (std::size_t i = 0; i < attachments.size(); ++i)
@@ -25,6 +25,13 @@ namespace Nz
assert(attachments[i]);
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(*attachments[i]);
Vector2ui textureSize = Vector2ui(glTexture.GetSize());
if (i == 0)
m_size = textureSize;
else
m_size.Minimize(textureSize);
PixelFormat textureFormat = glTexture.GetFormat();
GLenum attachment;
@@ -89,4 +96,9 @@ namespace Nz
{
return m_colorAttachmentCount;
}
const Vector2ui& OpenGLFboFramebuffer::GetSize() const
{
return m_size;
}
}

View File

@@ -22,4 +22,9 @@ namespace Nz
{
return 1;
}
const Vector2ui& OpenGLWindowFramebuffer::GetSize() const
{
return m_renderWindow.GetSize();
}
}

View File

@@ -394,9 +394,9 @@ namespace Nz::GL
if ((m_params.type == ContextType::OpenGL && glVersion >= 430) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 320))
m_extensionStatus[UnderlyingCast(Extension::DebugOutput)] = ExtensionStatus::Core;
else if (m_supportedExtensions.count("GL_KHR_debug"))
m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::KHR;
m_extensionStatus[UnderlyingCast(Extension::DebugOutput)] = ExtensionStatus::KHR;
else if (m_supportedExtensions.count("GL_ARB_debug_output"))
m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::ARB;
m_extensionStatus[UnderlyingCast(Extension::DebugOutput)] = ExtensionStatus::ARB;
// Depth clamp
if (m_params.type == ContextType::OpenGL && glVersion >= 320)
@@ -558,7 +558,7 @@ namespace Nz::GL
m_state.viewport = { res[0], res[1], res[2], res[3] };
m_state.renderStates.depthCompare = RendererComparison::Less; //< OpenGL default depth mode is GL_LESS
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is counter-clockwise
m_state.renderStates.frontFace = FrontFace::CounterClockwise; //< OpenGL default front face is GL_CCW
EnableVerticalSync(false);
@@ -774,12 +774,10 @@ namespace Nz::GL
}
// Color write
if (m_state.renderStates.colorWrite != renderStates.colorWrite)
if (m_state.renderStates.colorWriteMask != renderStates.colorWriteMask)
{
GLboolean param = (renderStates.colorWrite) ? GL_TRUE : GL_FALSE;
glColorMask(param, param, param, param);
m_state.renderStates.colorWrite = renderStates.colorWrite;
glColorMask(renderStates.colorWriteMask.Test(ColorComponent::Red), renderStates.colorWriteMask.Test(ColorComponent::Green), renderStates.colorWriteMask.Test(ColorComponent::Blue), renderStates.colorWriteMask.Test(ColorComponent::Alpha));
m_state.renderStates.colorWriteMask = renderStates.colorWriteMask;
}
// Depth buffer
@@ -799,9 +797,9 @@ namespace Nz::GL
assert(IsExtensionSupported(Extension::DepthClamp));
if (renderStates.depthClamp)
glEnable(GL_DEPTH_CLAMP_EXT);
glEnable(GL_DEPTH_CLAMP);
else
glDisable(GL_DEPTH_CLAMP_EXT);
glDisable(GL_DEPTH_CLAMP);
m_state.renderStates.depthClamp = renderStates.depthClamp;
}

View File

@@ -60,6 +60,7 @@ namespace Nz
deviceInfo.limits.maxStorageBufferSize = physDevice.properties.limits.maxStorageBufferRange;
deviceInfo.limits.maxUniformBufferSize = physDevice.properties.limits.maxUniformBufferRange;
deviceInfo.limits.minStorageBufferOffsetAlignment = physDevice.properties.limits.minStorageBufferOffsetAlignment;
deviceInfo.limits.minUniformBufferOffsetAlignment = physDevice.properties.limits.minUniformBufferOffsetAlignment;
switch (physDevice.properties.deviceType)

View File

@@ -61,10 +61,7 @@ namespace Nz
VkPipelineColorBlendAttachmentState& colorBlendState = colorBlendStates.emplace_back();
colorBlendState.blendEnable = pipelineInfo.blending;
if (pipelineInfo.colorWrite)
colorBlendState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; //< TODO
else
colorBlendState.colorWriteMask = 0;
colorBlendState.colorWriteMask = static_cast<VkColorComponentFlags>(pipelineInfo.colorWriteMask);
if (pipelineInfo.blending)
{

View File

@@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/BaseWidget.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>

View File

@@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/CheckboxWidget.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Graphics/SlicedSprite.hpp>

View File

@@ -3,8 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/DefaultWidgetTheme.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Widgets/SimpleWidgetStyles.hpp>
#include <Nazara/Widgets/Widgets.hpp>
@@ -125,20 +124,30 @@ namespace Nz
texParams.renderDevice = Graphics::Instance()->GetRenderDevice();
texParams.loadFormat = PixelFormat::RGBA8; //< TODO: Re-enable gamma correction
auto CreateMaterialFromTexture = [](std::shared_ptr<Texture> texture)
const auto& defaultBasicMaterial = Graphics::Instance()->GetDefaultMaterials();
const MaterialPassRegistry& materialPassRegistry = Graphics::Instance()->GetMaterialPassRegistry();
std::size_t depthPassIndex = materialPassRegistry.GetPassIndex("DepthPass");
std::size_t forwardPassIndex = materialPassRegistry.GetPassIndex("ForwardPass");
auto CreateMaterialFromTexture = [&](std::shared_ptr<Texture> texture)
{
std::shared_ptr<MaterialPass> buttonMaterialPass = std::make_shared<MaterialPass>(BasicMaterial::GetSettings());
buttonMaterialPass->EnableDepthBuffer(true);
buttonMaterialPass->EnableDepthWrite(false);
buttonMaterialPass->EnableBlending(true);
buttonMaterialPass->SetBlendEquation(BlendEquation::Add, BlendEquation::Add);
buttonMaterialPass->SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::InvSrcAlpha, BlendFunc::One, BlendFunc::One);
std::shared_ptr<MaterialInstance> material = defaultBasicMaterial.basicMaterial->CreateInstance();
material->DisablePass(depthPassIndex);
material->UpdatePassStates(forwardPassIndex, [](RenderStates& renderStates)
{
renderStates.depthWrite = false;
renderStates.scissorTest = true;
renderStates.blending = true;
renderStates.blend.modeColor = BlendEquation::Add;
renderStates.blend.modeAlpha = BlendEquation::Add;
renderStates.blend.srcColor = BlendFunc::SrcAlpha;
renderStates.blend.dstColor = BlendFunc::InvSrcAlpha;
renderStates.blend.srcAlpha = BlendFunc::One;
renderStates.blend.dstAlpha = BlendFunc::One;
});
std::shared_ptr<Material> material = std::make_shared<Material>();
material->AddPass("ForwardPass", buttonMaterialPass);
BasicMaterial buttonBasicMat(*buttonMaterialPass);
buttonBasicMat.SetBaseColorMap(texture);
material->SetTextureProperty("BaseColorMap", std::move(texture));
return material;
};

View File

@@ -3,13 +3,12 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/ImageButtonWidget.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Widgets/Debug.hpp>
namespace Nz
{
ImageButtonWidget::ImageButtonWidget(BaseWidget* parent, std::shared_ptr<Material> material, std::shared_ptr<Material> hoveredMaterial, std::shared_ptr<Material> pressedMaterial, float cornerSize, float cornerTexCoords) :
ImageButtonWidget::ImageButtonWidget(BaseWidget* parent, std::shared_ptr<MaterialInstance> material, std::shared_ptr<MaterialInstance> hoveredMaterial, std::shared_ptr<MaterialInstance> pressedMaterial, float cornerSize, float cornerTexCoords) :
BaseWidget(parent),
m_hoveredMaterial(std::move(hoveredMaterial)),
m_material(std::move(material)),
@@ -80,20 +79,16 @@ namespace Nz
const Rectf& textureCoords = GetTextureCoords();
// TODO: Move this in a separate function
if (const auto& material = m_material->FindPass("ForwardPass"))
if (const std::shared_ptr<Texture>* textureOpt = m_material->GetTextureProperty("BaseColorMap"))
{
BasicMaterial mat(*material);
if (mat.HasBaseColorMap())
// Material should always have textures but we're better safe than sorry
if (const std::shared_ptr<Texture>& texture = *textureOpt)
{
// Material should always have textures but we're better safe than sorry
if (const auto& texture = mat.GetBaseColorMap())
{
Vector2f textureSize = Vector2f(Vector2ui(texture->GetSize()));
textureSize.x *= textureCoords.width;
textureSize.y *= textureCoords.height;
Vector2f textureSize = Vector2f(Vector2ui(texture->GetSize()));
textureSize.x *= textureCoords.width;
textureSize.y *= textureCoords.height;
SetPreferredSize(textureSize);
}
SetPreferredSize(textureSize);
}
}
}

View File

@@ -11,10 +11,10 @@
namespace Nz
{
ImageWidget::ImageWidget(BaseWidget* parent, std::shared_ptr<Material> material) :
ImageWidget::ImageWidget(BaseWidget* parent, std::shared_ptr<MaterialInstance> material) :
BaseWidget(parent)
{
m_sprite = std::make_shared<Sprite>(Widgets::Instance()->GetTransparentMaterial());
m_sprite = std::make_shared<Sprite>(std::move(material));
auto& registry = GetRegistry();
@@ -25,8 +25,6 @@ namespace Nz
auto& nodeComponent = registry.emplace<NodeComponent>(m_entity);
nodeComponent.SetParent(this);
SetMaterial(std::move(material));
}
void ImageWidget::Layout()

View File

@@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/LabelWidget.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
#include <Nazara/Utility/AbstractTextDrawer.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>

View File

@@ -331,7 +331,7 @@ namespace Nz
}
SimpleLabelWidgetStyle::SimpleLabelWidgetStyle(LabelWidget* labelWidget, std::shared_ptr<Material> material, std::shared_ptr<Material> hoveredMaterial) :
SimpleLabelWidgetStyle::SimpleLabelWidgetStyle(LabelWidget* labelWidget, std::shared_ptr<MaterialInstance> material, std::shared_ptr<MaterialInstance> hoveredMaterial) :
LabelWidgetStyle(labelWidget, 1),
m_hoveredMaterial(std::move(hoveredMaterial)),
m_material(std::move(material))

View File

@@ -3,8 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Widgets/Widgets.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialInstance.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Widgets/Debug.hpp>
@@ -23,24 +22,36 @@ namespace Nz
void Widgets::CreateDefaultMaterials()
{
m_opaqueMaterialPass = std::make_shared<MaterialPass>(BasicMaterial::GetSettings());
m_opaqueMaterialPass->EnableDepthBuffer(true);
m_opaqueMaterialPass->EnableDepthWrite(false);
m_opaqueMaterialPass->EnableScissorTest(true);
const auto& defaultMaterials = Graphics::Instance()->GetDefaultMaterials();
m_opaqueMaterial = std::make_shared<Material>();
m_opaqueMaterial->AddPass("ForwardPass", m_opaqueMaterialPass);
const MaterialPassRegistry& materialPassRegistry = Graphics::Instance()->GetMaterialPassRegistry();
std::size_t depthPassIndex = materialPassRegistry.GetPassIndex("DepthPass");
std::size_t forwardPassIndex = materialPassRegistry.GetPassIndex("ForwardPass");
m_transparentMaterialPass = std::make_shared<MaterialPass>(BasicMaterial::GetSettings());
m_transparentMaterialPass->EnableDepthBuffer(true);
m_transparentMaterialPass->EnableDepthWrite(false);
m_transparentMaterialPass->EnableScissorTest(true);
m_transparentMaterialPass->EnableBlending(true);
m_transparentMaterialPass->SetBlendEquation(BlendEquation::Add, BlendEquation::Add);
m_transparentMaterialPass->SetBlendFunc(BlendFunc::SrcAlpha, BlendFunc::InvSrcAlpha, BlendFunc::One, BlendFunc::One);
m_opaqueMaterial = defaultMaterials.basicMaterial->CreateInstance();
for (std::size_t passIndex : { depthPassIndex, forwardPassIndex })
{
m_opaqueMaterial->UpdatePassStates(passIndex, [](RenderStates& renderStates)
{
renderStates.scissorTest = true;
});
}
m_transparentMaterial = std::make_shared<Material>();
m_transparentMaterial->AddPass("ForwardPass", m_transparentMaterialPass);
m_transparentMaterial = defaultMaterials.basicMaterial->CreateInstance();
m_transparentMaterial->DisablePass(depthPassIndex);
m_transparentMaterial->UpdatePassStates(forwardPassIndex, [](RenderStates& renderStates)
{
renderStates.blending = true;
renderStates.blend.modeColor = BlendEquation::Add;
renderStates.blend.modeAlpha = BlendEquation::Add;
renderStates.blend.srcColor = BlendFunc::SrcAlpha;
renderStates.blend.dstColor = BlendFunc::InvSrcAlpha;
renderStates.blend.srcAlpha = BlendFunc::One;
renderStates.blend.dstAlpha = BlendFunc::One;
renderStates.depthWrite = false;
renderStates.scissorTest = true;
});
}
Widgets* Widgets::s_instance = nullptr;