Refactor material system (#382)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
340
src/Nazara/Graphics/MaterialInstance.cpp
Normal file
340
src/Nazara/Graphics/MaterialInstance.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
22
src/Nazara/Graphics/MaterialSettings.cpp
Normal file
22
src/Nazara/Graphics/MaterialSettings.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
61
src/Nazara/Graphics/PredefinedMaterials.cpp
Normal file
61
src/Nazara/Graphics/PredefinedMaterials.cpp
Normal 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"));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
21
src/Nazara/Graphics/PropertyHandler/PropertyHandler.cpp
Normal file
21
src/Nazara/Graphics/PropertyHandler/PropertyHandler.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
68
src/Nazara/Graphics/RenderBufferPool.cpp
Normal file
68
src/Nazara/Graphics/RenderBufferPool.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
178
src/Nazara/Graphics/ShaderReflection.cpp
Normal file
178
src/Nazara/Graphics/ShaderReflection.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
11
src/Nazara/Graphics/TransferInterface.cpp
Normal file
11
src/Nazara/Graphics/TransferInterface.cpp
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,4 +22,9 @@ namespace Nz
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const Vector2ui& OpenGLWindowFramebuffer::GetSize() const
|
||||
{
|
||||
return m_renderWindow.GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user