diff --git a/examples/GraphicsTest/main.cpp b/examples/GraphicsTest/main.cpp index 6575a1724..503d18936 100644 --- a/examples/GraphicsTest/main.cpp +++ b/examples/GraphicsTest/main.cpp @@ -115,13 +115,11 @@ int main() Nz::PredefinedViewerData viewerUboOffsets = Nz::PredefinedViewerData::GetOffsets(); const Nz::BasicMaterial::UniformOffsets& materialSettingOffsets = Nz::BasicMaterial::GetOffsets(); - std::vector instanceDataBuffer(instanceUboOffsets.totalSize); std::vector viewerDataBuffer(viewerUboOffsets.totalSize); std::vector materialSettings(materialSettingOffsets.totalSize); Nz::Vector2ui windowSize = window.GetSize(); - Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.viewMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Backward() * 1); Nz::AccessByOffset(viewerDataBuffer.data(), viewerUboOffsets.projMatrixOffset) = Nz::Matrix4f::Perspective(70.f, float(windowSize.x) / windowSize.y, 0.1f, 1000.f); @@ -130,22 +128,6 @@ int main() std::shared_ptr renderPipelineLayout = material.GetSettings()->GetRenderPipelineLayout(); - std::shared_ptr instanceDataUbo = device->InstantiateBuffer(Nz::BufferType_Uniform); - if (!instanceDataUbo->Initialize(instanceDataBuffer.size(), Nz::BufferUsage_DeviceLocal | Nz::BufferUsage_Dynamic)) - { - NazaraError("Failed to create instance UBO"); - return __LINE__; - } - - instanceDataUbo->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); - - std::shared_ptr viewerDataUbo = device->InstantiateBuffer(Nz::BufferType_Uniform); - if (!viewerDataUbo->Initialize(viewerDataBuffer.size(), Nz::BufferUsage_DeviceLocal | Nz::BufferUsage_Dynamic)) - { - NazaraError("Failed to create viewer UBO"); - return __LINE__; - } - std::shared_ptr matSettingUBO = device->InstantiateBuffer(Nz::BufferType_Uniform); if (!matSettingUBO->Initialize(materialSettings.size(), Nz::BufferUsage_DeviceLocal | Nz::BufferUsage_Dynamic)) { @@ -155,40 +137,6 @@ int main() matSettingUBO->Fill(materialSettings.data(), 0, materialSettings.size()); - Nz::ShaderBindingPtr shaderBinding = renderPipelineLayout->AllocateShaderBinding(); - shaderBinding->Update({ - { - material.GetSettings()->GetPredefinedBindingIndex(Nz::PredefinedShaderBinding::UboViewerData), - Nz::ShaderBinding::UniformBufferBinding { - viewerDataUbo.get(), 0, viewerDataBuffer.size() - } - }, - { - material.GetSettings()->GetPredefinedBindingIndex(Nz::PredefinedShaderBinding::UboInstanceData), - Nz::ShaderBinding::UniformBufferBinding { - instanceDataUbo.get(), 0, instanceDataBuffer.size() - } - }, - { - 3, - Nz::ShaderBinding::UniformBufferBinding { - matSettingUBO.get(), 0, materialSettings.size() - } - }, - { - 0, - Nz::ShaderBinding::TextureBinding { - alphaTexture.get(), textureSampler.get() - } - }, - { - 1, - Nz::ShaderBinding::TextureBinding { - texture.get(), textureSampler.get() - } - } - }); - std::vector vertexBuffers = { { 0, @@ -196,6 +144,30 @@ int main() } }; + std::vector instanceDataBuffer(instanceUboOffsets.totalSize); + + Nz::ModelInstance modelInstance(material.GetSettings()); + { + material.UpdateShaderBinding(modelInstance.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()); + + std::shared_ptr& instanceDataUBO = modelInstance.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + Nz::ModelInstance modelInstance2(material.GetSettings()); + { + material.UpdateShaderBinding(modelInstance2.GetShaderBinding()); + + Nz::AccessByOffset(instanceDataBuffer.data(), instanceUboOffsets.worldMatrixOffset) = Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right() * 3.f); + + std::shared_ptr& instanceDataUBO = modelInstance2.GetInstanceBuffer(); + instanceDataUBO->Fill(instanceDataBuffer.data(), 0, instanceDataBuffer.size()); + } + + std::shared_ptr viewerDataUBO = Nz::Graphics::Instance()->GetViewerDataUBO(); + std::shared_ptr pipeline = material.GetPipeline()->GetRenderPipeline(vertexBuffers); Nz::RenderDevice* renderDevice = window.GetRenderDevice().get(); @@ -239,13 +211,18 @@ int main() { builder.BeginRenderPass(windowImpl->GetFramebuffer(), windowImpl->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] }); { + builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.BindIndexBuffer(indexBufferImpl); builder.BindPipeline(*pipeline); builder.BindVertexBuffer(0, vertexBufferImpl); - builder.BindShaderBinding(*shaderBinding); - builder.SetScissor(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); - builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); + builder.BindShaderBinding(modelInstance.GetShaderBinding()); + + builder.DrawIndexed(drfreakIB->GetIndexCount()); + + builder.BindShaderBinding(modelInstance2.GetShaderBinding()); builder.DrawIndexed(drfreakIB->GetIndexCount()); } @@ -363,7 +340,7 @@ int main() builder.BeginDebugRegion("UBO Update", Nz::Color::Yellow); { builder.PreTransferBarrier(); - builder.CopyBuffer(allocation, viewerDataUbo.get()); + builder.CopyBuffer(allocation, viewerDataUBO.get()); builder.PostTransferBarrier(); } builder.EndDebugRegion(); diff --git a/include/Nazara/Graphics/ModelInstance.hpp b/include/Nazara/Graphics/ModelInstance.hpp new file mode 100644 index 000000000..4067249e4 --- /dev/null +++ b/include/Nazara/Graphics/ModelInstance.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_MODELINSTANCE_HPP +#define NAZARA_MODELINSTANCE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class AbstractBuffer; + class MaterialSettings; + + class NAZARA_GRAPHICS_API ModelInstance + { + public: + ModelInstance(const std::shared_ptr& settings); + ModelInstance(const ModelInstance&) = delete; + ModelInstance(ModelInstance&&) noexcept = default; + ~ModelInstance() = default; + + inline std::shared_ptr& GetInstanceBuffer(); + inline const std::shared_ptr& GetInstanceBuffer() const; + inline ShaderBinding& GetShaderBinding(); + + ModelInstance& operator=(const ModelInstance&) = delete; + ModelInstance& operator=(ModelInstance&&) noexcept = default; + + private: + std::shared_ptr m_instanceDataBuffer; + ShaderBindingPtr m_shaderBinding; + }; +} + +#include + +#endif // NAZARA_MODELINSTANCE_HPP diff --git a/include/Nazara/Graphics/ModelInstance.inl b/include/Nazara/Graphics/ModelInstance.inl new file mode 100644 index 000000000..2c87c6ecf --- /dev/null +++ b/include/Nazara/Graphics/ModelInstance.inl @@ -0,0 +1,26 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline std::shared_ptr& ModelInstance::GetInstanceBuffer() + { + return m_instanceDataBuffer; + } + + inline const std::shared_ptr& ModelInstance::GetInstanceBuffer() const + { + return m_instanceDataBuffer; + } + + inline ShaderBinding& ModelInstance::GetShaderBinding() + { + return *m_shaderBinding; + } +} + +#include diff --git a/src/Nazara/Graphics/ModelInstance.cpp b/src/Nazara/Graphics/ModelInstance.cpp new file mode 100644 index 000000000..96479ea0b --- /dev/null +++ b/src/Nazara/Graphics/ModelInstance.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + ModelInstance::ModelInstance(const std::shared_ptr& settings) + { + Nz::PredefinedInstanceData instanceUboOffsets = Nz::PredefinedInstanceData::GetOffsets(); + + m_instanceDataBuffer = Graphics::Instance()->GetRenderDevice().InstantiateBuffer(BufferType_Uniform); + if (!m_instanceDataBuffer->Initialize(instanceUboOffsets.totalSize, Nz::BufferUsage_DeviceLocal | Nz::BufferUsage_Dynamic)) + throw std::runtime_error("failed to initialize viewer data UBO"); + + m_shaderBinding = settings->GetRenderPipelineLayout()->AllocateShaderBinding(); + + // TODO: Use StackVector + StackVector bindings = NazaraStackVector(ShaderBinding::Binding, 2); + + if (std::size_t bindingIndex = settings->GetPredefinedBindingIndex(PredefinedShaderBinding::UboInstanceData); bindingIndex != MaterialSettings::InvalidIndex) + { + bindings.push_back({ + bindingIndex, + ShaderBinding::UniformBufferBinding { + m_instanceDataBuffer.get(), 0, m_instanceDataBuffer->GetSize() + } + }); + } + + if (std::size_t bindingIndex = settings->GetPredefinedBindingIndex(PredefinedShaderBinding::UboViewerData); bindingIndex != MaterialSettings::InvalidIndex) + { + const std::shared_ptr& instanceDataUBO = Graphics::Instance()->GetViewerDataUBO(); + + bindings.push_back({ + bindingIndex, + ShaderBinding::UniformBufferBinding { + instanceDataUBO.get(), 0, instanceDataUBO->GetSize() + } + }); + } + + if (!bindings.empty()) + m_shaderBinding->Update(bindings.data(), bindings.size()); + } +}