Add initial support for skeletal entities / components
This commit is contained in:
parent
01f3f350fe
commit
50ed8b4028
|
|
@ -794,9 +794,9 @@ int main()
|
|||
builder.SetViewport(env.renderRect);
|
||||
|
||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, elements, env.renderRect);
|
||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, elements, env.renderRect);
|
||||
planeModel.BuildElement(forwardPassIndex, planeInstance, elements, env.renderRect);
|
||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance1, nullptr, elements, env.renderRect);
|
||||
spaceshipModel.BuildElement(forwardPassIndex, modelInstance2, nullptr, elements, env.renderRect);
|
||||
planeModel.BuildElement(forwardPassIndex, planeInstance, nullptr, elements, env.renderRect);
|
||||
|
||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||
|
|
@ -860,7 +860,7 @@ int main()
|
|||
builder.DrawIndexed(Nz::SafeCast<Nz::UInt32>(cubeMeshGfx->GetIndexCount(0)));
|
||||
|
||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements, env.renderRect);
|
||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, nullptr, elements, env.renderRect);
|
||||
|
||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||
|
|
@ -889,7 +889,7 @@ int main()
|
|||
builder.SetViewport(env.renderRect);
|
||||
|
||||
std::vector<std::unique_ptr<Nz::RenderElement>> elements;
|
||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements, env.renderRect);
|
||||
flareSprite.BuildElement(forwardPassIndex, flareInstance, nullptr, elements, env.renderRect);
|
||||
|
||||
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
|
||||
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@ int main()
|
|||
std::size_t cameraIndex = framePipeline.RegisterViewer(&camera, 0);
|
||||
std::size_t worldInstanceIndex1 = framePipeline.RegisterWorldInstance(modelInstance);
|
||||
std::size_t worldInstanceIndex2 = framePipeline.RegisterWorldInstance(modelInstance2);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex1, &model, 0xFFFFFFFF, scissorBox);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex2, &model, 0xFFFFFFFF, scissorBox);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex1, Nz::FramePipeline::NoSkeletonInstance, &model, 0xFFFFFFFF, scissorBox);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex2, Nz::FramePipeline::NoSkeletonInstance, &model, 0xFFFFFFFF, scissorBox);
|
||||
|
||||
std::shared_ptr<Nz::SpotLight> light = std::make_shared<Nz::SpotLight>();
|
||||
light->UpdateInnerAngle(Nz::DegreeAnglef(15.f));
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ int main()
|
|||
Nz::ForwardFramePipeline framePipeline;
|
||||
std::size_t cameraIndex = framePipeline.RegisterViewer(&camera, 0);
|
||||
std::size_t worldInstanceIndex1 = framePipeline.RegisterWorldInstance(modelInstance);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex1, &model, 0xFFFFFFFF, scissorBox);
|
||||
framePipeline.RegisterRenderable(worldInstanceIndex1, Nz::FramePipeline::NoSkeletonInstance, &model, 0xFFFFFFFF, scissorBox);
|
||||
|
||||
std::shared_ptr<Nz::DirectionalLight> light = std::make_shared<Nz::DirectionalLight>();
|
||||
light->UpdateRotation(Nz::EulerAnglesf(-45.f, 0.f, 0.f));
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <Nazara/Renderer.hpp>
|
||||
#include <Nazara/Utility.hpp>
|
||||
#include <Nazara/Utility/Components.hpp>
|
||||
#include <Nazara/Utility/Systems.hpp>
|
||||
#include <Nazara/Utility/Plugins/AssimpPlugin.hpp>
|
||||
#include <Nazara/Utils/CallOnExit.hpp>
|
||||
#include <NZSL/Math/FieldOffsets.hpp>
|
||||
|
|
@ -40,6 +41,7 @@ int main()
|
|||
|
||||
entt::registry registry;
|
||||
Nz::SystemGraph systemGraph(registry);
|
||||
systemGraph.AddSystem<Nz::SkeletonSystem>();
|
||||
|
||||
Nz::Physics3DSystem& physSytem = systemGraph.AddSystem<Nz::Physics3DSystem>();
|
||||
Nz::RenderSystem& renderSystem = systemGraph.AddSystem<Nz::RenderSystem>();
|
||||
|
|
@ -76,12 +78,6 @@ int main()
|
|||
cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
|
||||
nzsl::FieldOffsets skeletalOffsets(nzsl::StructLayout::Std140);
|
||||
std::size_t arrayOffset = skeletalOffsets.AddMatrixArray(nzsl::StructFieldType::Float1, 4, 4, true, 200);
|
||||
|
||||
std::vector<Nz::UInt8> skeletalBufferMem(skeletalOffsets.GetAlignedSize());
|
||||
Nz::Matrix4f* matrices = Nz::AccessByOffset<Nz::Matrix4f*>(skeletalBufferMem.data(), arrayOffset);
|
||||
|
||||
Nz::MeshParams meshParams;
|
||||
meshParams.animated = true;
|
||||
meshParams.center = true;
|
||||
|
|
@ -108,31 +104,9 @@ int main()
|
|||
return __LINE__;
|
||||
}
|
||||
|
||||
Nz::Skeleton skeleton = *bobMesh->GetSkeleton();
|
||||
std::shared_ptr<Nz::Skeleton> skeleton = std::make_shared<Nz::Skeleton>(*bobMesh->GetSkeleton());
|
||||
|
||||
std::cout << "joint count: " << skeleton.GetJointCount() << std::endl;
|
||||
//std::cout << "anim joint count: " << bobAnim->GetJointCount() << std::endl;
|
||||
|
||||
//bobAnim->AnimateSkeleton(&skeleton, 0, 1, 0.5f);
|
||||
|
||||
/*for (std::size_t i = 0; i < bobMesh->GetSubMeshCount(); ++i)
|
||||
{
|
||||
Nz::VertexMapper mapper(*bobMesh->GetSubMesh(i));
|
||||
|
||||
Nz::SkinningData skinningData;
|
||||
skinningData.joints = skeleton.GetJoints();
|
||||
skinningData.inputJointIndices = mapper.GetComponentPtr<Nz::Vector4i32>(Nz::VertexComponent::JointIndices);
|
||||
skinningData.inputJointWeights = mapper.GetComponentPtr<Nz::Vector4f>(Nz::VertexComponent::JointWeights);
|
||||
skinningData.outputPositions = mapper.GetComponentPtr<Nz::Vector3f>(Nz::VertexComponent::Position);
|
||||
skinningData.inputPositions = skinningData.outputPositions;
|
||||
|
||||
Nz::SkinLinearBlend(skinningData, 0, mapper.GetVertexCount());
|
||||
}*/
|
||||
|
||||
/*for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i)
|
||||
matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix();*/
|
||||
|
||||
std::shared_ptr<Nz::RenderBuffer> renderBuffer = device->InstantiateBuffer(Nz::BufferType::Uniform, skeletalBufferMem.size(), Nz::BufferUsage::Write, skeletalBufferMem.data());
|
||||
std::cout << "joint count: " << skeleton->GetJointCount() << std::endl;
|
||||
|
||||
const Nz::Boxf& bobAABB = bobMesh->GetAABB();
|
||||
std::shared_ptr<Nz::GraphicalMesh> bobGfxMesh = Nz::GraphicalMesh::BuildFromMesh(*bobMesh);
|
||||
|
|
@ -147,7 +121,6 @@ int main()
|
|||
std::shared_ptr<Nz::Material> bobMat = std::make_shared<Nz::Material>();
|
||||
|
||||
std::shared_ptr<Nz::MaterialPass> bobMatPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
|
||||
bobMatPass->SetSharedUniformBuffer(1, renderBuffer);
|
||||
|
||||
bobMatPass->EnableDepthBuffer(true);
|
||||
{
|
||||
|
|
@ -178,16 +151,16 @@ int main()
|
|||
for (std::size_t i = 0; i < bobMesh->GetSubMeshCount(); ++i)
|
||||
bobModel->SetMaterial(i, materials[bobMesh->GetSubMesh(i)->GetMaterialIndex()]);
|
||||
|
||||
/*for (std::size_t y = 0; y < 50; ++y)
|
||||
/*for (std::size_t y = 0; y < 10; ++y)
|
||||
{
|
||||
for (std::size_t x = 0; x < 50; ++x)
|
||||
for (std::size_t x = 0; x < 10; ++x)
|
||||
{
|
||||
entt::entity bobEntity = registry.create();
|
||||
|
||||
auto& bobNode = registry.emplace<Nz::NodeComponent>(bobEntity);
|
||||
bobNode.SetPosition(Nz::Vector3f(x - 25.f, bobAABB.height / 2.f, -float(y)));
|
||||
bobNode.SetRotation(Nz::EulerAnglesf(-90.f, -90.f, 0.f));
|
||||
bobNode.SetScale(1.f / 40.f * 0.5f);
|
||||
bobNode.SetPosition(Nz::Vector3f(x - 5.f, 0.f, -float(y)));
|
||||
//bobNode.SetRotation(Nz::EulerAnglesf(-90.f, -90.f, 0.f));
|
||||
//bobNode.SetScale(1.f / 40.f * 0.5f);
|
||||
|
||||
auto& bobGfx = registry.emplace<Nz::GraphicsComponent>(bobEntity);
|
||||
bobGfx.AttachRenderable(bobModel, 0xFFFFFFFF);
|
||||
|
|
@ -203,8 +176,69 @@ int main()
|
|||
|
||||
auto& bobGfx = registry.emplace<Nz::GraphicsComponent>(bobEntity);
|
||||
bobGfx.AttachRenderable(bobModel, 0xFFFFFFFF);
|
||||
|
||||
auto& sharedSkeleton = registry.emplace<Nz::SharedSkeletonComponent>(bobEntity, skeleton);
|
||||
|
||||
|
||||
entt::entity sphereEntity = registry.create();
|
||||
{
|
||||
std::shared_ptr<Nz::Mesh> sphereMesh = std::make_shared<Nz::Mesh>();
|
||||
sphereMesh->CreateStatic();
|
||||
sphereMesh->BuildSubMesh(Nz::Primitive::UVSphere(1.f, 50, 50));
|
||||
sphereMesh->SetMaterialCount(1);
|
||||
sphereMesh->GenerateNormalsAndTangents();
|
||||
|
||||
std::shared_ptr<Nz::GraphicalMesh> gfxMesh = Nz::GraphicalMesh::BuildFromMesh(*sphereMesh);
|
||||
|
||||
// Textures
|
||||
Nz::TextureParams texParams;
|
||||
texParams.renderDevice = device;
|
||||
|
||||
Nz::TextureParams srgbTexParams = texParams;
|
||||
srgbTexParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB;
|
||||
|
||||
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>();
|
||||
|
||||
std::shared_ptr<Nz::MaterialPass> forwardPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
|
||||
forwardPass->EnableDepthBuffer(true);
|
||||
forwardPass->EnableFaceCulling(true);
|
||||
|
||||
material->AddPass("ForwardPass", forwardPass);
|
||||
|
||||
std::shared_ptr<Nz::Texture> normalMap = Nz::Texture::LoadFromFile(resourceDir / "Rusty/rustediron2_normal.png", texParams);
|
||||
|
||||
Nz::BasicMaterial pbrMat(*forwardPass);
|
||||
pbrMat.EnableAlphaTest(false);
|
||||
pbrMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
|
||||
pbrMat.SetBaseColorMap(Nz::Texture::LoadFromFile(resourceDir / "Rusty/rustediron2_basecolor.png", srgbTexParams));
|
||||
|
||||
std::shared_ptr<Nz::Model> sphereModel = std::make_shared<Nz::Model>(std::move(gfxMesh), sphereMesh->GetAABB());
|
||||
for (std::size_t i = 0; i < sphereModel->GetSubMeshCount(); ++i)
|
||||
sphereModel->SetMaterial(i, material);
|
||||
|
||||
auto& sphereNode = registry.emplace<Nz::NodeComponent>(sphereEntity);
|
||||
sphereNode.SetScale(0.1f);
|
||||
sphereNode.SetInheritScale(false);
|
||||
sphereNode.SetParent(sharedSkeleton.GetAttachedJoint(83));
|
||||
|
||||
auto& sphereBody = registry.emplace<Nz::RigidBody3DComponent>(sphereEntity, &physSytem.GetPhysWorld());
|
||||
sphereBody.SetGeom(std::make_shared<Nz::SphereCollider3D>(0.1f));
|
||||
|
||||
auto& sphereGfx = registry.emplace<Nz::GraphicsComponent>(sphereEntity);
|
||||
sphereGfx.AttachRenderable(sphereModel, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
entt::entity smallBobEntity = registry.create();
|
||||
auto& smallBobNode = registry.emplace<Nz::NodeComponent>(smallBobEntity);
|
||||
smallBobNode.SetParent(sharedSkeleton.GetAttachedJoint(59));
|
||||
|
||||
auto& smallBobGfx = registry.emplace<Nz::GraphicsComponent>(smallBobEntity);
|
||||
smallBobGfx.AttachRenderable(bobModel, 0xFFFFFFFF);
|
||||
|
||||
registry.emplace<Nz::SharedSkeletonComponent>(smallBobEntity, skeleton);
|
||||
}
|
||||
|
||||
|
||||
entt::entity planeEntity = registry.create();
|
||||
{
|
||||
Nz::MeshParams meshPrimitiveParams;
|
||||
|
|
@ -249,14 +283,6 @@ int main()
|
|||
|
||||
window.EnableEventPolling(true);
|
||||
|
||||
renderSystem.GetFramePipeline().OnTransfer.Connect([&](Nz::FramePipeline* pipeline, Nz::RenderFrame& renderFrame, Nz::CommandBufferBuilder& builder)
|
||||
{
|
||||
auto& skeletalAllocation = renderFrame.GetUploadPool().Allocate(skeletalBufferMem.size());
|
||||
std::memcpy(skeletalAllocation.mappedPtr, skeletalBufferMem.data(), skeletalBufferMem.size());
|
||||
|
||||
builder.CopyBuffer(skeletalAllocation, Nz::RenderBufferView(renderBuffer.get()));
|
||||
});
|
||||
|
||||
Nz::Clock fpsClock, updateClock;
|
||||
float incr = 0.f;
|
||||
unsigned int currentFrame = 0;
|
||||
|
|
@ -327,8 +353,8 @@ int main()
|
|||
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D))
|
||||
playerBody.AddForce(Nz::Vector3f::Right() * 25.f * mass, Nz::CoordSys::Local);
|
||||
|
||||
incr += 1.f / 60.f * 30.f;
|
||||
if (incr >= 1.f)
|
||||
incr += updateTime * bobAnim->GetSequence(0)->frameRate * 1.5f;
|
||||
while (incr >= 1.f)
|
||||
{
|
||||
incr -= 1.f;
|
||||
|
||||
|
|
@ -340,9 +366,9 @@ int main()
|
|||
|
||||
std::cout << currentFrame << std::endl;
|
||||
|
||||
bobAnim->AnimateSkeleton(&skeleton, currentFrame, nextFrame, incr);
|
||||
for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i)
|
||||
matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix();
|
||||
bobAnim->AnimateSkeleton(skeleton.get(), currentFrame, nextFrame, incr);
|
||||
//for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i)
|
||||
// matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix();
|
||||
|
||||
//renderBuffer->Fill(skeletalBufferMem.data(), 0, skeletalBufferMem.size());
|
||||
|
||||
|
|
@ -393,7 +419,7 @@ int main()
|
|||
}
|
||||
|
||||
Nz::DebugDrawer& debugDrawer = renderSystem.GetFramePipeline().GetDebugDrawer();
|
||||
debugDrawer.DrawSkeleton(skeleton, Nz::Color::Red);
|
||||
//debugDrawer.DrawSkeleton(*skeleton, Nz::Color::Red);
|
||||
|
||||
systemGraph.Update();
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
#include <Nazara/Graphics/RenderQueueRegistry.hpp>
|
||||
#include <Nazara/Graphics/RenderSpriteChain.hpp>
|
||||
#include <Nazara/Graphics/RenderSubmesh.hpp>
|
||||
#include <Nazara/Graphics/SkeletonInstance.hpp>
|
||||
#include <Nazara/Graphics/SlicedSprite.hpp>
|
||||
#include <Nazara/Graphics/SpotLight.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Nz
|
|||
struct Renderable;
|
||||
static constexpr std::size_t MaxRenderableCount = 8;
|
||||
|
||||
inline GraphicsComponent(bool initialyVisible = true);
|
||||
inline GraphicsComponent(bool initiallyVisible = true);
|
||||
GraphicsComponent(const GraphicsComponent&) = default;
|
||||
GraphicsComponent(GraphicsComponent&&) = default;
|
||||
~GraphicsComponent() = default;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline GraphicsComponent::GraphicsComponent(bool initialyVisible) :
|
||||
inline GraphicsComponent::GraphicsComponent(bool initiallyVisible) :
|
||||
m_scissorBox(-1, -1, -1, -1),
|
||||
m_isVisible(initialyVisible)
|
||||
m_isVisible(initiallyVisible)
|
||||
{
|
||||
m_worldInstance = std::make_shared<WorldInstance>(); //< FIXME: Use pools
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,12 +42,14 @@ namespace Nz
|
|||
ForwardFramePipeline(ForwardFramePipeline&&) = delete;
|
||||
~ForwardFramePipeline();
|
||||
|
||||
void InvalidateSkeletalInstance(std::size_t skeletalInstanceIndex) override;
|
||||
void InvalidateViewer(std::size_t viewerIndex) override;
|
||||
void InvalidateWorldInstance(std::size_t renderableIndex) override;
|
||||
|
||||
std::size_t RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) override;
|
||||
void RegisterMaterialPass(MaterialPass* materialPass) override;
|
||||
std::size_t RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) override;
|
||||
std::size_t RegisterRenderable(std::size_t worldInstanceIndex, std::size_t skeletonInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) override;
|
||||
std::size_t RegisterSkeleton(SkeletonInstancePtr skeletonInstance) override;
|
||||
std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override;
|
||||
std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) override;
|
||||
|
||||
|
|
@ -56,6 +58,7 @@ namespace Nz
|
|||
void UnregisterLight(std::size_t lightIndex) override;
|
||||
void UnregisterMaterialPass(MaterialPass* material) override;
|
||||
void UnregisterRenderable(std::size_t renderableIndex) override;
|
||||
void UnregisterSkeleton(std::size_t skeletonIndex) override;
|
||||
void UnregisterViewer(std::size_t viewerIndex) override;
|
||||
void UnregisterWorldInstance(std::size_t worldInstance) override;
|
||||
|
||||
|
|
@ -89,6 +92,7 @@ namespace Nz
|
|||
|
||||
struct RenderableData
|
||||
{
|
||||
std::size_t skeletonInstanceIndex;
|
||||
std::size_t worldInstanceIndex;
|
||||
const InstancedRenderable* renderable;
|
||||
Recti scissorBox;
|
||||
|
|
@ -127,11 +131,15 @@ namespace Nz
|
|||
std::vector<FramePipelinePass::VisibleRenderable> m_visibleRenderables;
|
||||
std::vector<const Light*> m_visibleLights;
|
||||
BakedFrameGraph m_bakedFrameGraph;
|
||||
Bitset<UInt64> m_invalidatedSkeletonInstances;
|
||||
Bitset<UInt64> m_invalidatedViewerInstances;
|
||||
Bitset<UInt64> m_invalidatedWorldInstances;
|
||||
Bitset<UInt64> m_removedSkeletonInstances;
|
||||
Bitset<UInt64> m_removedViewerInstances;
|
||||
Bitset<UInt64> m_removedWorldInstances;
|
||||
MemoryPool<RenderableData> m_renderablePool;
|
||||
MemoryPool<LightData> m_lightPool;
|
||||
MemoryPool<SkeletonInstancePtr> m_skeletonInstances;
|
||||
MemoryPool<ViewerData> m_viewerPool;
|
||||
MemoryPool<WorldInstancePtr> m_worldInstances;
|
||||
RenderFrame* m_currentRenderFrame;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Graphics/RenderElement.hpp>
|
||||
#include <Nazara/Graphics/RenderQueue.hpp>
|
||||
#include <Nazara/Graphics/SkeletonInstance.hpp>
|
||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||
#include <Nazara/Renderer/DebugDrawer.hpp>
|
||||
#include <memory>
|
||||
|
|
@ -39,14 +40,16 @@ namespace Nz
|
|||
inline ElementRenderer& GetElementRenderer(std::size_t elementIndex);
|
||||
inline std::size_t GetElementRendererCount() const;
|
||||
|
||||
virtual void InvalidateSkeletalInstance(std::size_t skeletalInstanceIndex) = 0;
|
||||
virtual void InvalidateViewer(std::size_t viewerIndex) = 0;
|
||||
virtual void InvalidateWorldInstance(std::size_t) = 0;
|
||||
virtual void InvalidateWorldInstance(std::size_t worldInstance) = 0;
|
||||
|
||||
template<typename F> void ProcessRenderQueue(const RenderQueue<RenderElement*>& renderQueue, F&& callback);
|
||||
|
||||
virtual std::size_t RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) = 0;
|
||||
virtual void RegisterMaterialPass(MaterialPass* materialPass) = 0;
|
||||
virtual std::size_t RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) = 0;
|
||||
virtual std::size_t RegisterRenderable(std::size_t worldInstanceIndex, std::size_t skeletonInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox) = 0;
|
||||
virtual std::size_t RegisterSkeleton(SkeletonInstancePtr skeletonInstance) = 0;
|
||||
virtual std::size_t RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0;
|
||||
virtual std::size_t RegisterWorldInstance(WorldInstancePtr worldInstance) = 0;
|
||||
|
||||
|
|
@ -55,6 +58,7 @@ namespace Nz
|
|||
virtual void UnregisterLight(std::size_t lightIndex) = 0;
|
||||
virtual void UnregisterMaterialPass(MaterialPass* materialPass) = 0;
|
||||
virtual void UnregisterRenderable(std::size_t renderableIndex) = 0;
|
||||
virtual void UnregisterSkeleton(std::size_t skeletonIndex) = 0;
|
||||
virtual void UnregisterViewer(std::size_t viewerIndex) = 0;
|
||||
virtual void UnregisterWorldInstance(std::size_t worldInstance) = 0;
|
||||
|
||||
|
|
@ -68,6 +72,8 @@ namespace Nz
|
|||
|
||||
NazaraSignal(OnTransfer, FramePipeline* /*pipeline*/, RenderFrame& /*renderFrame*/, CommandBufferBuilder& /*builder*/);
|
||||
|
||||
static constexpr std::size_t NoSkeletonInstance = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
|
||||
DebugDrawer m_debugDrawer;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
namespace Nz
|
||||
{
|
||||
class InstancedRenderable;
|
||||
class SkeletonInstance;
|
||||
class WorldInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API FramePipelinePass
|
||||
|
|
@ -30,6 +31,7 @@ namespace Nz
|
|||
struct VisibleRenderable
|
||||
{
|
||||
const InstancedRenderable* instancedRenderable;
|
||||
const SkeletonInstance* skeletonInstance;
|
||||
const WorldInstance* worldInstance;
|
||||
Recti scissorBox;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ namespace Nz
|
|||
class CommandBufferBuilder;
|
||||
class Material;
|
||||
class RenderElement;
|
||||
class SkeletonInstance;
|
||||
class WorldInstance;
|
||||
|
||||
class NAZARA_GRAPHICS_API InstancedRenderable
|
||||
|
|
@ -28,7 +29,7 @@ namespace Nz
|
|||
InstancedRenderable(InstancedRenderable&&) noexcept = default;
|
||||
~InstancedRenderable();
|
||||
|
||||
virtual void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const = 0;
|
||||
virtual void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const = 0;
|
||||
|
||||
inline const Boxf& GetAABB() const;
|
||||
virtual const std::shared_ptr<Material>& GetMaterial(std::size_t i) const = 0;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Nz
|
|||
|
||||
inline void AddSection(float size, float textureCoord);
|
||||
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
|
||||
inline void Clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Nz
|
|||
Model(Model&&) noexcept = default;
|
||||
~Model() = default;
|
||||
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
|
||||
const std::shared_ptr<RenderBuffer>& GetIndexBuffer(std::size_t subMeshIndex) const;
|
||||
std::size_t GetIndexCount(std::size_t subMeshIndex) const;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Nz
|
|||
{
|
||||
class MaterialPass;
|
||||
class RenderPipeline;
|
||||
class Skeleton;
|
||||
class VertexDeclaration;
|
||||
|
||||
class RenderQueueRegistry
|
||||
|
|
@ -28,6 +29,7 @@ namespace Nz
|
|||
inline std::size_t FetchLayerIndex(int renderLayer) const;
|
||||
inline std::size_t FetchMaterialPassIndex(const MaterialPass* materialPass) const;
|
||||
inline std::size_t FetchPipelineIndex(const RenderPipeline* pipeline) const;
|
||||
inline std::size_t FetchSkeletonIndex(const Skeleton* skeleton) const;
|
||||
inline std::size_t FetchVertexBuffer(const RenderBuffer* vertexBuffer) const;
|
||||
inline std::size_t FetchVertexDeclaration(const VertexDeclaration* vertexDeclaration) const;
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ namespace Nz
|
|||
inline void RegisterLayer(int renderLayer);
|
||||
inline void RegisterMaterialPass(const MaterialPass* materialPass);
|
||||
inline void RegisterPipeline(const RenderPipeline* pipeline);
|
||||
inline void RegisterSkeleton(const Skeleton* skeleton);
|
||||
inline void RegisterVertexBuffer(const RenderBuffer* vertexBuffer);
|
||||
inline void RegisterVertexDeclaration(const VertexDeclaration* vertexDeclaration);
|
||||
|
||||
|
|
@ -45,6 +48,7 @@ namespace Nz
|
|||
robin_hood::unordered_map<const MaterialPass*, std::size_t> m_materialPassRegistry;
|
||||
robin_hood::unordered_map<const RenderPipeline*, std::size_t> m_pipelineRegistry;
|
||||
robin_hood::unordered_map<const RenderBuffer*, std::size_t> m_vertexBufferRegistry;
|
||||
robin_hood::unordered_map<const Skeleton*, std::size_t> m_skeletonRegistry;
|
||||
robin_hood::unordered_map<const VertexDeclaration*, std::size_t> m_vertexDeclarationRegistry;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ namespace Nz
|
|||
return it->second;
|
||||
}
|
||||
|
||||
inline std::size_t RenderQueueRegistry::FetchSkeletonIndex(const Skeleton* skeleton) const
|
||||
{
|
||||
auto it = m_skeletonRegistry.find(skeleton);
|
||||
assert(it != m_skeletonRegistry.end());
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
inline std::size_t RenderQueueRegistry::FetchVertexBuffer(const RenderBuffer* vertexBuffer) const
|
||||
{
|
||||
auto it = m_vertexBufferRegistry.find(vertexBuffer);
|
||||
|
|
@ -80,6 +88,11 @@ namespace Nz
|
|||
m_pipelineRegistry.try_emplace(pipeline, m_pipelineRegistry.size());
|
||||
}
|
||||
|
||||
inline void RenderQueueRegistry::RegisterSkeleton(const Skeleton* skeleton)
|
||||
{
|
||||
m_skeletonRegistry.try_emplace(skeleton, m_skeletonRegistry.size());
|
||||
}
|
||||
|
||||
inline void RenderQueueRegistry::RegisterVertexBuffer(const RenderBuffer* vertexBuffer)
|
||||
{
|
||||
m_vertexBufferRegistry.try_emplace(vertexBuffer, m_vertexBufferRegistry.size());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/RenderElement.hpp>
|
||||
#include <Nazara/Graphics/RenderQueueRegistry.hpp>
|
||||
#include <Nazara/Graphics/SkeletonInstance.hpp>
|
||||
#include <Nazara/Graphics/WorldInstance.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
|
@ -23,7 +24,7 @@ namespace Nz
|
|||
class RenderSubmesh : public RenderElement
|
||||
{
|
||||
public:
|
||||
inline RenderSubmesh(int renderLayer, std::shared_ptr<MaterialPass> materialPass, std::shared_ptr<RenderPipeline> renderPipeline, const WorldInstance& worldInstance, std::size_t indexCount, IndexType indexType, std::shared_ptr<RenderBuffer> indexBuffer, std::shared_ptr<RenderBuffer> vertexBuffer, const Recti& scissorBox);
|
||||
inline RenderSubmesh(int renderLayer, std::shared_ptr<MaterialPass> materialPass, std::shared_ptr<RenderPipeline> renderPipeline, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::size_t indexCount, IndexType indexType, std::shared_ptr<RenderBuffer> indexBuffer, std::shared_ptr<RenderBuffer> vertexBuffer, const Recti& scissorBox);
|
||||
~RenderSubmesh() = default;
|
||||
|
||||
inline UInt64 ComputeSortingScore(const Frustumf& frustum, const RenderQueueRegistry& registry) const override;
|
||||
|
|
@ -34,6 +35,7 @@ namespace Nz
|
|||
inline const MaterialPass& GetMaterialPass() const;
|
||||
inline const RenderPipeline* GetRenderPipeline() const;
|
||||
inline const Recti& GetScissorBox() const;
|
||||
inline const SkeletonInstance* GetSkeletonInstance() const;
|
||||
inline const RenderBuffer* GetVertexBuffer() const;
|
||||
inline const WorldInstance& GetWorldInstance() const;
|
||||
|
||||
|
|
@ -45,6 +47,7 @@ namespace Nz
|
|||
std::shared_ptr<MaterialPass> m_materialPass;
|
||||
std::shared_ptr<RenderPipeline> m_renderPipeline;
|
||||
std::size_t m_indexCount;
|
||||
const SkeletonInstance* m_skeletonInstance;
|
||||
const WorldInstance& m_worldInstance;
|
||||
IndexType m_indexType;
|
||||
Recti m_scissorBox;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
inline RenderSubmesh::RenderSubmesh(int renderLayer, std::shared_ptr<MaterialPass> materialPass, std::shared_ptr<RenderPipeline> renderPipeline, const WorldInstance& worldInstance, std::size_t indexCount, IndexType indexType, std::shared_ptr<RenderBuffer> indexBuffer, std::shared_ptr<RenderBuffer> vertexBuffer, const Recti& scissorBox) :
|
||||
inline RenderSubmesh::RenderSubmesh(int renderLayer, std::shared_ptr<MaterialPass> materialPass, std::shared_ptr<RenderPipeline> renderPipeline, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::size_t indexCount, IndexType indexType, std::shared_ptr<RenderBuffer> indexBuffer, std::shared_ptr<RenderBuffer> vertexBuffer, const Recti& scissorBox) :
|
||||
RenderElement(BasicRenderElement::Submesh),
|
||||
m_indexBuffer(std::move(indexBuffer)),
|
||||
m_vertexBuffer(std::move(vertexBuffer)),
|
||||
m_materialPass(std::move(materialPass)),
|
||||
m_renderPipeline(std::move(renderPipeline)),
|
||||
m_indexCount(indexCount),
|
||||
m_skeletonInstance(skeletonInstance),
|
||||
m_worldInstance(worldInstance),
|
||||
m_indexType(indexType),
|
||||
m_scissorBox(scissorBox),
|
||||
|
|
@ -51,6 +52,10 @@ namespace Nz
|
|||
UInt64 pipelineIndex = registry.FetchPipelineIndex(m_renderPipeline.get());
|
||||
UInt64 vertexBufferIndex = registry.FetchVertexBuffer(m_vertexBuffer.get());
|
||||
|
||||
UInt64 skeletonIndex = 0;
|
||||
if (m_skeletonInstance)
|
||||
skeletonIndex = registry.FetchSkeletonIndex(m_skeletonInstance->GetSkeleton().get());
|
||||
|
||||
UInt64 matFlags = 0;
|
||||
|
||||
// Opaque RQ index:
|
||||
|
|
@ -60,14 +65,15 @@ namespace Nz
|
|||
// - Pipeline (16bits)
|
||||
// - MaterialPass (16bits)
|
||||
// - VertexBuffer (8bits)
|
||||
// - ?? (8bits) - Depth?
|
||||
// - Skeleton (8bits)
|
||||
|
||||
return (layerIndex & 0xFF) << 60 |
|
||||
(matFlags) << 52 |
|
||||
(elementType & 0xF) << 51 |
|
||||
(pipelineIndex & 0xFFFF) << 35 |
|
||||
(materialPassIndex & 0xFFFF) << 23 |
|
||||
(vertexBufferIndex & 0xFF) << 7;
|
||||
(vertexBufferIndex & 0xFF) << 7 |
|
||||
(skeletonIndex & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +107,11 @@ namespace Nz
|
|||
return m_scissorBox;
|
||||
}
|
||||
|
||||
inline const SkeletonInstance* RenderSubmesh::GetSkeletonInstance() const
|
||||
{
|
||||
return m_skeletonInstance;
|
||||
}
|
||||
|
||||
inline const RenderBuffer* RenderSubmesh::GetVertexBuffer() const
|
||||
{
|
||||
return m_vertexBuffer.get();
|
||||
|
|
@ -117,6 +128,8 @@ namespace Nz
|
|||
registry.RegisterMaterialPass(m_materialPass.get());
|
||||
registry.RegisterPipeline(m_renderPipeline.get());
|
||||
registry.RegisterVertexBuffer(m_vertexBuffer.get());
|
||||
if (m_skeletonInstance)
|
||||
registry.RegisterSkeleton(m_skeletonInstance->GetSkeleton().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GRAPHICS_SKELETONINSTANCE_HPP
|
||||
#define NAZARA_GRAPHICS_SKELETONINSTANCE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Graphics/Config.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Renderer/ShaderBinding.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class CommandBufferBuilder;
|
||||
class RenderBuffer;
|
||||
class SkeletonInstance;
|
||||
class UploadPool;
|
||||
|
||||
using SkeletonInstancePtr = std::shared_ptr<SkeletonInstance>;
|
||||
|
||||
class NAZARA_GRAPHICS_API SkeletonInstance
|
||||
{
|
||||
public:
|
||||
SkeletonInstance(std::shared_ptr<const Skeleton> skeleton);
|
||||
SkeletonInstance(const SkeletonInstance&) = delete;
|
||||
SkeletonInstance(SkeletonInstance&& skeletonInstance) noexcept;
|
||||
~SkeletonInstance() = default;
|
||||
|
||||
inline std::shared_ptr<RenderBuffer>& GetSkeletalBuffer();
|
||||
inline const std::shared_ptr<RenderBuffer>& GetSkeletalBuffer() const;
|
||||
inline const std::shared_ptr<const Skeleton>& GetSkeleton() const;
|
||||
|
||||
void UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder);
|
||||
|
||||
SkeletonInstance& operator=(const SkeletonInstance&) = delete;
|
||||
SkeletonInstance& operator=(SkeletonInstance&& skeletonInstance) noexcept;
|
||||
|
||||
private:
|
||||
NazaraSlot(Skeleton, OnSkeletonJointsInvalidated, m_onSkeletonJointsInvalidated);
|
||||
|
||||
std::shared_ptr<RenderBuffer> m_skeletalDataBuffer;
|
||||
std::shared_ptr<const Skeleton> m_skeleton;
|
||||
bool m_dataInvalided;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/SkeletonInstance.inl>
|
||||
|
||||
#endif // NAZARA_GRAPHICS_SKELETONINSTANCE_HPP
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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/SkeletonInstance.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline std::shared_ptr<RenderBuffer>& SkeletonInstance::GetSkeletalBuffer()
|
||||
{
|
||||
return m_skeletalDataBuffer;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<RenderBuffer>& SkeletonInstance::GetSkeletalBuffer() const
|
||||
{
|
||||
return m_skeletalDataBuffer;
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<const Skeleton>& SkeletonInstance::GetSkeleton() const
|
||||
{
|
||||
return m_skeleton;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Graphics/DebugOff.hpp>
|
||||
|
|
@ -27,7 +27,7 @@ namespace Nz
|
|||
SlicedSprite(SlicedSprite&&) noexcept = default;
|
||||
~SlicedSprite() = default;
|
||||
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
|
||||
inline const Color& GetColor() const;
|
||||
inline const Corner& GetBottomRightCorner() const;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Nz
|
|||
Sprite(Sprite&&) noexcept = default;
|
||||
~Sprite() = default;
|
||||
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
|
||||
inline const Color& GetColor() const;
|
||||
inline const Color& GetCornerColor(RectCorner corner) const;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
|
||||
#include <Nazara/Graphics/Components/LightComponent.hpp>
|
||||
#include <Nazara/Utility/Node.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <Nazara/Utils/MemoryPool.hpp>
|
||||
#include <entt/entt.hpp>
|
||||
#include <array>
|
||||
|
|
@ -53,10 +54,14 @@ namespace Nz
|
|||
void OnGraphicsDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnLightDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnNodeDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnSharedSkeletonDestroy(entt::registry& registry, entt::entity entity);
|
||||
void OnSkeletonDestroy(entt::registry& registry, entt::entity entity);
|
||||
void UpdateInstances();
|
||||
void UpdateObservers();
|
||||
void UpdateVisibility();
|
||||
|
||||
static constexpr std::size_t NoInstance = std::numeric_limits<std::size_t>::max();
|
||||
|
||||
struct CameraEntity
|
||||
{
|
||||
entt::entity entity;
|
||||
|
|
@ -71,6 +76,7 @@ namespace Nz
|
|||
entt::entity entity;
|
||||
std::array<std::size_t, GraphicsComponent::MaxRenderableCount> renderableIndices;
|
||||
std::size_t poolIndex;
|
||||
std::size_t skeletonInstanceIndex;
|
||||
std::size_t worldInstanceIndex;
|
||||
|
||||
NazaraSlot(GraphicsComponent, OnRenderableAttached, onRenderableAttached);
|
||||
|
|
@ -78,6 +84,7 @@ namespace Nz
|
|||
NazaraSlot(GraphicsComponent, OnScissorBoxUpdate, onScissorBoxUpdate);
|
||||
NazaraSlot(GraphicsComponent, OnVisibilityUpdate, onVisibilityUpdate);
|
||||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||
NazaraSlot(Skeleton, OnSkeletonJointsInvalidated, onSkeletonJointsInvalidated); //< only connected for owned skeleton
|
||||
};
|
||||
|
||||
struct LightEntity
|
||||
|
|
@ -92,14 +99,26 @@ namespace Nz
|
|||
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
|
||||
};
|
||||
|
||||
entt::connection m_cameraDestroyConnection;
|
||||
entt::connection m_graphicsDestroyConnection;
|
||||
entt::connection m_lightDestroyConnection;
|
||||
entt::connection m_nodeDestroyConnection;
|
||||
struct SharedSkeleton
|
||||
{
|
||||
std::size_t skeletonInstanceIndex;
|
||||
std::size_t useCount;
|
||||
|
||||
NazaraSlot(Skeleton, OnSkeletonJointsInvalidated, onJointsInvalidated);
|
||||
};
|
||||
|
||||
entt::registry& m_registry;
|
||||
entt::observer m_cameraConstructObserver;
|
||||
entt::observer m_graphicsConstructObserver;
|
||||
entt::observer m_lightConstructObserver;
|
||||
entt::registry& m_registry;
|
||||
entt::observer m_sharedSkeletonConstructObserver;
|
||||
entt::observer m_skeletonConstructObserver;
|
||||
entt::scoped_connection m_cameraDestroyConnection;
|
||||
entt::scoped_connection m_graphicsDestroyConnection;
|
||||
entt::scoped_connection m_lightDestroyConnection;
|
||||
entt::scoped_connection m_nodeDestroyConnection;
|
||||
entt::scoped_connection m_sharedSkeletonDestroyConnection;
|
||||
entt::scoped_connection m_skeletonDestroyConnection;
|
||||
std::set<CameraEntity*> m_invalidatedCameraNode;
|
||||
std::set<GraphicsEntity*> m_invalidatedGfxWorldNode;
|
||||
std::set<LightEntity*> m_invalidatedLightWorldNode;
|
||||
|
|
@ -107,6 +126,7 @@ namespace Nz
|
|||
std::unordered_map<entt::entity, CameraEntity*> m_cameraEntities;
|
||||
std::unordered_map<entt::entity, GraphicsEntity*> m_graphicsEntities;
|
||||
std::unordered_map<entt::entity, LightEntity*> m_lightEntities;
|
||||
std::unordered_map<Skeleton*, SharedSkeleton> m_sharedSkeletonInstances;
|
||||
std::unordered_set<GraphicsEntity*> m_newlyHiddenGfxEntities;
|
||||
std::unordered_set<GraphicsEntity*> m_newlyVisibleGfxEntities;
|
||||
std::unordered_set<LightEntity*> m_newlyHiddenLightEntities;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace Nz
|
|||
TextSprite(TextSprite&&) noexcept = default;
|
||||
~TextSprite() = default;
|
||||
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
void BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const override;
|
||||
|
||||
inline void Clear();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
namespace Nz
|
||||
{
|
||||
class CommandBufferBuilder;
|
||||
class MaterialSettings;
|
||||
class RenderBuffer;
|
||||
class UploadPool;
|
||||
class WorldInstance;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Nz
|
|||
static void OnConstruct(entt::registry& registry, entt::entity entity);
|
||||
|
||||
entt::registry& m_registry;
|
||||
entt::connection m_constructConnection;
|
||||
entt::scoped_connection m_constructConnection;
|
||||
PhysWorld2D m_physWorld;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Nz
|
|||
static void OnConstruct(entt::registry& registry, entt::entity entity);
|
||||
|
||||
entt::registry& m_registry;
|
||||
entt::connection m_constructConnection;
|
||||
entt::scoped_connection m_constructConnection;
|
||||
PhysWorld3D m_physWorld;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#define NAZARA_UTILITY_COMPONENTS_HPP
|
||||
|
||||
#include <Nazara/Utility/Components/NodeComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.hpp>
|
||||
#include <Nazara/Utility/Components/VelocityComponent.hpp>
|
||||
|
||||
#endif // NAZARA_UTILITY_COMPONENTS_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_UTILITY_COMPONENTS_SHAREDSKELETONCOMPONENT_HPP
|
||||
#define NAZARA_UTILITY_COMPONENTS_SHAREDSKELETONCOMPONENT_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_UTILITY_API SharedSkeletonComponent final : public SkeletonComponentBase
|
||||
{
|
||||
friend class SkeletonSystem;
|
||||
|
||||
public:
|
||||
SharedSkeletonComponent(std::shared_ptr<Skeleton> skeleton);
|
||||
SharedSkeletonComponent(const SharedSkeletonComponent& sharedSkeletalComponent);
|
||||
SharedSkeletonComponent(SharedSkeletonComponent&& sharedSkeletalComponent) noexcept;
|
||||
~SharedSkeletonComponent() = default;
|
||||
|
||||
const Joint& GetAttachedJoint(std::size_t jointIndex) const override;
|
||||
|
||||
SharedSkeletonComponent& operator=(const SharedSkeletonComponent& sharedSkeletalComponent);
|
||||
SharedSkeletonComponent& operator=(SharedSkeletonComponent&& sharedSkeletalComponent) noexcept;
|
||||
|
||||
private:
|
||||
inline bool IsAttachedSkeletonOutdated() const;
|
||||
void OnReferenceJointsInvalidated(const Skeleton* skeleton);
|
||||
void SetSkeletonParent(Node* parent);
|
||||
void SetupSkeleton();
|
||||
void UpdateAttachedSkeletonJoints();
|
||||
|
||||
NazaraSlot(Skeleton, OnSkeletonJointsInvalidated, m_onSkeletonJointsInvalidated);
|
||||
|
||||
Skeleton m_attachedSkeleton;
|
||||
bool m_skeletonJointInvalidated;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.inl>
|
||||
|
||||
#endif // NAZARA_UTILITY_COMPONENTS_SHAREDSKELETONCOMPONENT_HPP
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline bool SharedSkeletonComponent::IsAttachedSkeletonOutdated() const
|
||||
{
|
||||
return m_skeletonJointInvalidated;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENT_HPP
|
||||
#define NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENT_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class Node;
|
||||
|
||||
class NAZARA_UTILITY_API SkeletonComponent final : public SkeletonComponentBase
|
||||
{
|
||||
public:
|
||||
SkeletonComponent(std::shared_ptr<Skeleton> skeleton);
|
||||
SkeletonComponent(const SkeletonComponent&) = delete;
|
||||
SkeletonComponent(SkeletonComponent&& skeletalComponent) noexcept = default;
|
||||
~SkeletonComponent() = default;
|
||||
|
||||
const Joint& GetAttachedJoint(std::size_t jointIndex) const override;
|
||||
Node* GetRootNode();
|
||||
|
||||
SkeletonComponent& operator=(const SkeletonComponent&) = delete;
|
||||
SkeletonComponent& operator=(SkeletonComponent&& skeletalComponent) noexcept = default;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.inl>
|
||||
|
||||
#endif // NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENT_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/DebugOff.hpp>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENTBASE_HPP
|
||||
#define NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENTBASE_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Utility/Joint.hpp>
|
||||
#include <Nazara/Utility/Skeleton.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_UTILITY_API SkeletonComponentBase
|
||||
{
|
||||
public:
|
||||
SkeletonComponentBase(const SkeletonComponentBase&) = default;
|
||||
SkeletonComponentBase(SkeletonComponentBase&&) noexcept = default;
|
||||
~SkeletonComponentBase() = default;
|
||||
|
||||
virtual const Joint& GetAttachedJoint(std::size_t jointIndex) const = 0;
|
||||
inline const std::shared_ptr<Skeleton>& GetSkeleton() const;
|
||||
|
||||
SkeletonComponentBase& operator=(const SkeletonComponentBase&) = default;
|
||||
SkeletonComponentBase& operator=(SkeletonComponentBase&&) noexcept = default;
|
||||
|
||||
protected:
|
||||
SkeletonComponentBase(std::shared_ptr<Skeleton> skeleton);
|
||||
|
||||
std::shared_ptr<Skeleton> m_referenceSkeleton;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.inl>
|
||||
|
||||
#endif // NAZARA_UTILITY_COMPONENTS_SKELETONCOMPONENTBASE_HPP
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline SkeletonComponentBase::SkeletonComponentBase(std::shared_ptr<Skeleton> skeleton) :
|
||||
m_referenceSkeleton(std::move(skeleton))
|
||||
{
|
||||
}
|
||||
|
||||
inline const std::shared_ptr<Skeleton>& SkeletonComponentBase::GetSkeleton() const
|
||||
{
|
||||
return m_referenceSkeleton;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/DebugOff.hpp>
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef NAZARA_UTILITY_SYSTEMS_HPP
|
||||
#define NAZARA_UTILITY_SYSTEMS_HPP
|
||||
|
||||
#include <Nazara/Utility/Systems/SkeletonSystem.hpp>
|
||||
#include <Nazara/Utility/Systems/VelocitySystem.hpp>
|
||||
|
||||
#endif // NAZARA_UTILITY_SYSTEMS_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_UTILITY_SYSTEMS_SKELETONSYSTEM_HPP
|
||||
#define NAZARA_UTILITY_SYSTEMS_SKELETONSYSTEM_HPP
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
class NAZARA_UTILITY_API SkeletonSystem
|
||||
{
|
||||
public:
|
||||
static constexpr bool AllowConcurrent = false;
|
||||
static constexpr Int64 ExecutionOrder = -1'000;
|
||||
|
||||
SkeletonSystem(entt::registry& registry);
|
||||
SkeletonSystem(const SkeletonSystem&) = delete;
|
||||
SkeletonSystem(SkeletonSystem&&) = delete;
|
||||
~SkeletonSystem();
|
||||
|
||||
void Update(float elapsedTime);
|
||||
|
||||
SkeletonSystem& operator=(const SkeletonSystem&) = delete;
|
||||
SkeletonSystem& operator=(SkeletonSystem&&) = delete;
|
||||
|
||||
private:
|
||||
entt::registry& m_registry;
|
||||
entt::observer m_sharedSkeletonConstructObserver;
|
||||
entt::observer m_skeletonConstructObserver;
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/Systems/SkeletonSystem.inl>
|
||||
|
||||
#endif // NAZARA_UTILITY_SYSTEMS_SKELETONSYSTEM_HPP
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Systems/SkeletonSystem.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
#include <Nazara/Utility/DebugOff.hpp>
|
||||
|
|
@ -39,7 +39,7 @@ namespace Nz
|
|||
m_renderElements.clear();
|
||||
|
||||
for (const auto& renderableData : visibleRenderables)
|
||||
renderableData.instancedRenderable->BuildElement(m_depthPassIndex, *renderableData.worldInstance, m_renderElements, renderableData.scissorBox);
|
||||
renderableData.instancedRenderable->BuildElement(m_depthPassIndex, *renderableData.worldInstance, renderableData.skeletonInstance, m_renderElements, renderableData.scissorBox);
|
||||
|
||||
m_renderQueueRegistry.Clear();
|
||||
m_renderQueue.Clear();
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ namespace Nz
|
|||
ForwardFramePipeline::ForwardFramePipeline() :
|
||||
m_renderablePool(4096),
|
||||
m_lightPool(64),
|
||||
m_skeletonInstances(1024),
|
||||
m_viewerPool(8),
|
||||
m_worldInstances(2048),
|
||||
m_rebuildFrameGraph(true)
|
||||
|
|
@ -41,6 +42,11 @@ 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);
|
||||
|
|
@ -89,13 +95,14 @@ namespace Nz
|
|||
it->second.usedCount++;
|
||||
}
|
||||
|
||||
std::size_t ForwardFramePipeline::RegisterRenderable(std::size_t worldInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox)
|
||||
std::size_t ForwardFramePipeline::RegisterRenderable(std::size_t worldInstanceIndex, std::size_t skeletonInstanceIndex, const InstancedRenderable* instancedRenderable, UInt32 renderMask, const Recti& scissorBox)
|
||||
{
|
||||
std::size_t renderableIndex;
|
||||
RenderableData* renderableData = m_renderablePool.Allocate(renderableIndex);
|
||||
renderableData->renderable = instancedRenderable;
|
||||
renderableData->renderMask = renderMask;
|
||||
renderableData->scissorBox = scissorBox;
|
||||
renderableData->skeletonInstanceIndex = skeletonInstanceIndex;
|
||||
renderableData->worldInstanceIndex = worldInstanceIndex;
|
||||
|
||||
renderableData->onElementInvalidated.Connect(instancedRenderable->OnElementInvalidated, [=](InstancedRenderable* /*instancedRenderable*/)
|
||||
|
|
@ -159,6 +166,16 @@ namespace Nz
|
|||
return renderableIndex;
|
||||
}
|
||||
|
||||
std::size_t ForwardFramePipeline::RegisterSkeleton(SkeletonInstancePtr skeletonInstance)
|
||||
{
|
||||
std::size_t skeletonInstanceIndex;
|
||||
m_skeletonInstances.Allocate(skeletonInstanceIndex, std::move(skeletonInstance));
|
||||
|
||||
m_invalidatedSkeletonInstances.UnboundedSet(skeletonInstanceIndex);
|
||||
|
||||
return skeletonInstanceIndex;
|
||||
}
|
||||
|
||||
std::size_t ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
|
||||
{
|
||||
std::size_t viewerIndex;
|
||||
|
|
@ -191,10 +208,24 @@ namespace Nz
|
|||
|
||||
Graphics* graphics = Graphics::Instance();
|
||||
|
||||
// Destroy world instances at the end of the frame
|
||||
// Destroy instances at the end of the frame
|
||||
for (std::size_t skeletonInstanceIndex = m_removedSkeletonInstances.FindFirst(); skeletonInstanceIndex != m_removedSkeletonInstances.npos; skeletonInstanceIndex = m_removedSkeletonInstances.FindNext(skeletonInstanceIndex))
|
||||
{
|
||||
renderFrame.PushForRelease(std::move(*m_skeletonInstances.RetrieveFromIndex(skeletonInstanceIndex)));
|
||||
m_skeletonInstances.Free(skeletonInstanceIndex);
|
||||
}
|
||||
m_removedSkeletonInstances.Clear();
|
||||
|
||||
for (std::size_t viewerIndex = m_removedViewerInstances.FindFirst(); viewerIndex != m_removedViewerInstances.npos; viewerIndex = m_removedViewerInstances.FindNext(viewerIndex))
|
||||
{
|
||||
renderFrame.PushForRelease(std::move(*m_viewerPool.RetrieveFromIndex(viewerIndex)));
|
||||
m_viewerPool.Free(viewerIndex);
|
||||
}
|
||||
m_removedSkeletonInstances.Clear();
|
||||
|
||||
for (std::size_t worldInstanceIndex = m_removedWorldInstances.FindFirst(); worldInstanceIndex != m_removedWorldInstances.npos; worldInstanceIndex = m_removedWorldInstances.FindNext(worldInstanceIndex))
|
||||
{
|
||||
renderFrame.PushForRelease(*m_worldInstances.RetrieveFromIndex(worldInstanceIndex));
|
||||
renderFrame.PushForRelease(std::move(*m_worldInstances.RetrieveFromIndex(worldInstanceIndex)));
|
||||
m_worldInstances.Free(worldInstanceIndex);
|
||||
}
|
||||
m_removedWorldInstances.Clear();
|
||||
|
|
@ -216,6 +247,13 @@ namespace Nz
|
|||
|
||||
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);
|
||||
|
|
@ -277,6 +315,11 @@ namespace Nz
|
|||
visibleRenderable.scissorBox = renderableData.scissorBox;
|
||||
visibleRenderable.worldInstance = worldInstance.get();
|
||||
|
||||
if (renderableData.skeletonInstanceIndex != NoSkeletonInstance)
|
||||
visibleRenderable.skeletonInstance = m_skeletonInstances.RetrieveFromIndex(renderableData.skeletonInstanceIndex)->get();
|
||||
else
|
||||
visibleRenderable.skeletonInstance = nullptr;
|
||||
|
||||
visibilityHash = CombineHash(visibilityHash, std::hash<const void*>()(&renderableData));
|
||||
}
|
||||
|
||||
|
|
@ -423,11 +466,16 @@ namespace Nz
|
|||
m_renderablePool.Free(renderableIndex);
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterSkeleton(std::size_t skeletonIndex)
|
||||
{
|
||||
// Defer world instance release
|
||||
m_removedSkeletonInstances.UnboundedSet(skeletonIndex);
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterViewer(std::size_t viewerIndex)
|
||||
{
|
||||
m_viewerPool.Free(viewerIndex);
|
||||
m_invalidatedViewerInstances.Reset(viewerIndex);
|
||||
m_rebuildFrameGraph = true;
|
||||
// Defer world instance release
|
||||
m_removedViewerInstances.UnboundedSet(viewerIndex);
|
||||
}
|
||||
|
||||
void ForwardFramePipeline::UnregisterWorldInstance(std::size_t worldInstance)
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ namespace Nz
|
|||
lightUboView = it->second;
|
||||
|
||||
std::size_t previousCount = m_renderElements.size();
|
||||
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, m_renderElements, renderableData.scissorBox);
|
||||
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, renderableData.skeletonInstance, m_renderElements, renderableData.scissorBox);
|
||||
for (std::size_t i = previousCount; i < m_renderElements.size(); ++i)
|
||||
{
|
||||
const RenderElement* element = m_renderElements[i].get();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Nz
|
|||
UpdateVertices();
|
||||
}
|
||||
|
||||
void LinearSlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
void LinearSlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
{
|
||||
const auto& materialPass = m_material->GetPass(passIndex);
|
||||
if (!materialPass)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Nz
|
|||
UpdateAABB(aabb);
|
||||
}
|
||||
|
||||
void Model::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
void Model::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
{
|
||||
for (std::size_t i = 0; i < m_submeshes.size(); ++i)
|
||||
{
|
||||
|
|
@ -54,7 +54,7 @@ namespace Nz
|
|||
std::size_t indexCount = m_graphicalMesh->GetIndexCount(i);
|
||||
IndexType indexType = m_graphicalMesh->GetIndexType(i);
|
||||
|
||||
elements.emplace_back(std::make_unique<RenderSubmesh>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, indexCount, indexType, indexBuffer, vertexBuffer, scissorBox));
|
||||
elements.emplace_back(std::make_unique<RenderSubmesh>(GetRenderLayer(), materialPass, renderPipeline, worldInstance, skeletonInstance, indexCount, indexType, indexBuffer, vertexBuffer, scissorBox));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ namespace Nz
|
|||
nzsl::FieldOffsets skeletalStruct(nzsl::StructLayout::Std140);
|
||||
|
||||
PredefinedSkeletalData skeletalData;
|
||||
skeletalData.jointMatricesOffset = skeletalStruct.AddMatrixArray(nzsl::StructFieldType::Float1, 4, 4, true, 100);
|
||||
skeletalData.jointMatricesOffset = skeletalStruct.AddMatrixArray(nzsl::StructFieldType::Float1, 4, 4, true, MaxMatricesCount);
|
||||
|
||||
skeletalData.totalSize = skeletalStruct.GetAlignedSize();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// 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/SkeletonInstance.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/UploadPool.hpp>
|
||||
#include <Nazara/Utility/Joint.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SkeletonInstance::SkeletonInstance(std::shared_ptr<const Skeleton> skeleton) :
|
||||
m_skeleton(std::move(skeleton)),
|
||||
m_dataInvalided(true)
|
||||
{
|
||||
NazaraAssert(m_skeleton, "invalid skeleton");
|
||||
|
||||
PredefinedSkeletalData skeletalUboOffsets = PredefinedSkeletalData::GetOffsets();
|
||||
|
||||
m_skeletalDataBuffer = Graphics::Instance()->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, skeletalUboOffsets.totalSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
|
||||
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
|
||||
{
|
||||
m_dataInvalided = true;
|
||||
});
|
||||
}
|
||||
|
||||
SkeletonInstance::SkeletonInstance(SkeletonInstance&& skeletonInstance) noexcept :
|
||||
m_skeletalDataBuffer(std::move(skeletonInstance.m_skeletalDataBuffer)),
|
||||
m_skeleton(std::move(skeletonInstance.m_skeleton)),
|
||||
m_dataInvalided(skeletonInstance.m_dataInvalided)
|
||||
{
|
||||
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
|
||||
{
|
||||
m_dataInvalided = true;
|
||||
});
|
||||
}
|
||||
|
||||
void SkeletonInstance::UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder)
|
||||
{
|
||||
if (m_dataInvalided)
|
||||
{
|
||||
PredefinedSkeletalData skeletalUboOffsets = PredefinedSkeletalData::GetOffsets();
|
||||
|
||||
auto& allocation = uploadPool.Allocate(m_skeletalDataBuffer->GetSize());
|
||||
Matrix4f* matrices = AccessByOffset<Matrix4f*>(allocation.mappedPtr, skeletalUboOffsets.jointMatricesOffset);
|
||||
|
||||
for (std::size_t i = 0; i < m_skeleton->GetJointCount(); ++i)
|
||||
matrices[i] = m_skeleton->GetJoint(i)->GetSkinningMatrix();
|
||||
|
||||
builder.CopyBuffer(allocation, m_skeletalDataBuffer.get());
|
||||
|
||||
m_dataInvalided = false;
|
||||
}
|
||||
}
|
||||
|
||||
SkeletonInstance& SkeletonInstance::operator=(SkeletonInstance&& skeletonInstance) noexcept
|
||||
{
|
||||
m_skeletalDataBuffer = std::move(skeletonInstance.m_skeletalDataBuffer);
|
||||
m_skeleton = std::move(skeletonInstance.m_skeleton);
|
||||
m_dataInvalided = skeletonInstance.m_dataInvalided;
|
||||
|
||||
m_onSkeletonJointsInvalidated.Connect(m_skeleton->OnSkeletonJointsInvalidated, [this](const Skeleton*)
|
||||
{
|
||||
m_dataInvalided = true;
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ namespace Nz
|
|||
UpdateVertices();
|
||||
}
|
||||
|
||||
void SlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
void SlicedSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
{
|
||||
const auto& materialPass = m_material->GetPass(passIndex);
|
||||
if (!materialPass)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Nz
|
|||
UpdateVertices();
|
||||
}
|
||||
|
||||
void Sprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
void Sprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
{
|
||||
const auto& materialPass = m_material->GetPass(passIndex);
|
||||
if (!materialPass)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <Nazara/Graphics/SubmeshRenderer.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Graphics/RenderSubmesh.hpp>
|
||||
#include <Nazara/Graphics/SkeletonInstance.hpp>
|
||||
#include <Nazara/Graphics/ViewerInstance.hpp>
|
||||
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
|
||||
#include <Nazara/Renderer/RenderFrame.hpp>
|
||||
|
|
@ -30,10 +31,10 @@ namespace Nz
|
|||
const MaterialPass* currentMaterialPass = nullptr;
|
||||
const RenderPipeline* currentPipeline = nullptr;
|
||||
const ShaderBinding* currentShaderBinding = nullptr;
|
||||
const SkeletonInstance* currentSkeletonInstance = nullptr;
|
||||
const WorldInstance* currentWorldInstance = nullptr;
|
||||
Recti currentScissorBox = invalidScissorBox;
|
||||
RenderBufferView currentLightData;
|
||||
RenderBufferView currentSkeletalData;
|
||||
|
||||
auto FlushDrawCall = [&]()
|
||||
{
|
||||
|
|
@ -82,6 +83,12 @@ namespace Nz
|
|||
currentVertexBuffer = vertexBuffer;
|
||||
}
|
||||
|
||||
if (const SkeletonInstance* skeletonInstance = submesh.GetSkeletonInstance(); currentSkeletonInstance != skeletonInstance)
|
||||
{
|
||||
FlushDrawData();
|
||||
currentSkeletonInstance = skeletonInstance;
|
||||
}
|
||||
|
||||
if (const WorldInstance* worldInstance = &submesh.GetWorldInstance(); currentWorldInstance != worldInstance)
|
||||
{
|
||||
// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
|
||||
|
|
@ -96,12 +103,6 @@ namespace Nz
|
|||
currentLightData = renderState.lightData;
|
||||
}
|
||||
|
||||
if (currentSkeletalData != renderState.skeletalData)
|
||||
{
|
||||
FlushDrawData();
|
||||
currentSkeletalData = renderState.skeletalData;
|
||||
}
|
||||
|
||||
const Recti& scissorBox = submesh.GetScissorBox();
|
||||
const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox;
|
||||
if (currentScissorBox != targetScissorBox)
|
||||
|
|
@ -142,13 +143,15 @@ namespace Nz
|
|||
};
|
||||
}
|
||||
|
||||
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::SkeletalDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentSkeletalData)
|
||||
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::SkeletalDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentSkeletonInstance)
|
||||
{
|
||||
const auto& skeletalBuffer = currentSkeletonInstance->GetSkeletalBuffer();
|
||||
|
||||
auto& bindingEntry = m_bindingCache.emplace_back();
|
||||
bindingEntry.bindingIndex = bindingIndex;
|
||||
bindingEntry.content = ShaderBinding::UniformBufferBinding{
|
||||
currentSkeletalData.GetBuffer(),
|
||||
currentSkeletalData.GetOffset(), currentSkeletalData.GetSize()
|
||||
skeletalBuffer.get(),
|
||||
0, skeletalBuffer->GetSize()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,19 @@
|
|||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Renderer/UploadPool.hpp>
|
||||
#include <Nazara/Utility/Components/NodeComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
|
||||
#include <Nazara/Graphics/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
RenderSystem::RenderSystem(entt::registry& registry) :
|
||||
m_registry(registry),
|
||||
m_cameraConstructObserver(registry, entt::collector.group<CameraComponent, NodeComponent>()),
|
||||
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>()),
|
||||
m_lightConstructObserver(registry, entt::collector.group<LightComponent, NodeComponent>()),
|
||||
m_registry(registry),
|
||||
m_sharedSkeletonConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent, SharedSkeletonComponent>(entt::exclude<SkeletonComponent>)),
|
||||
m_skeletonConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent, SkeletonComponent>(entt::exclude<SharedSkeletonComponent>)),
|
||||
m_cameraEntityPool(8),
|
||||
m_graphicsEntityPool(1024),
|
||||
m_lightEntityPool(32)
|
||||
|
|
@ -30,6 +34,8 @@ namespace Nz
|
|||
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
|
||||
m_lightDestroyConnection = registry.on_destroy<LightComponent>().connect<&RenderSystem::OnLightDestroy>(this);
|
||||
m_nodeDestroyConnection = registry.on_destroy<NodeComponent>().connect<&RenderSystem::OnNodeDestroy>(this);
|
||||
m_sharedSkeletonDestroyConnection = registry.on_destroy<SharedSkeletonComponent>().connect<&RenderSystem::OnSharedSkeletonDestroy>(this);
|
||||
m_skeletonDestroyConnection = registry.on_destroy<SkeletonComponent>().connect<&RenderSystem::OnSkeletonDestroy>(this);
|
||||
|
||||
m_pipeline = std::make_unique<ForwardFramePipeline>();
|
||||
}
|
||||
|
|
@ -39,10 +45,6 @@ namespace Nz
|
|||
m_cameraConstructObserver.disconnect();
|
||||
m_graphicsConstructObserver.disconnect();
|
||||
m_lightConstructObserver.disconnect();
|
||||
m_cameraDestroyConnection.release();
|
||||
m_graphicsDestroyConnection.release();
|
||||
m_lightDestroyConnection.release();
|
||||
m_nodeDestroyConnection.release();
|
||||
}
|
||||
|
||||
void RenderSystem::Update(float /*elapsedTime*/)
|
||||
|
|
@ -157,6 +159,52 @@ namespace Nz
|
|||
|
||||
if (m_registry.try_get<LightComponent>(entity))
|
||||
OnLightDestroy(registry, entity);
|
||||
|
||||
if (m_registry.try_get<SharedSkeletonComponent>(entity))
|
||||
OnSharedSkeletonDestroy(registry, entity);
|
||||
|
||||
if (m_registry.try_get<SkeletonComponent>(entity))
|
||||
OnSkeletonDestroy(registry, entity);
|
||||
}
|
||||
|
||||
void RenderSystem::OnSharedSkeletonDestroy(entt::registry& registry, entt::entity entity)
|
||||
{
|
||||
assert(&m_registry == ®istry);
|
||||
|
||||
SharedSkeletonComponent& skeletonComponent = registry.get<SharedSkeletonComponent>(entity);
|
||||
Skeleton* skeleton = skeletonComponent.GetSkeleton().get();
|
||||
|
||||
auto skeletonInstanceIt = m_sharedSkeletonInstances.find(skeleton);
|
||||
assert(skeletonInstanceIt != m_sharedSkeletonInstances.end());
|
||||
|
||||
SharedSkeleton& sharedSkeleton = skeletonInstanceIt->second;
|
||||
assert(sharedSkeleton.useCount > 0);
|
||||
if (--sharedSkeleton.useCount == 0)
|
||||
{
|
||||
m_pipeline->UnregisterSkeleton(sharedSkeleton.skeletonInstanceIndex);
|
||||
m_sharedSkeletonInstances.erase(skeletonInstanceIt);
|
||||
}
|
||||
|
||||
auto it = m_graphicsEntities.find(entity);
|
||||
if (it == m_graphicsEntities.end())
|
||||
return;
|
||||
|
||||
GraphicsEntity* graphicsEntity = it->second;
|
||||
graphicsEntity->skeletonInstanceIndex = NoInstance;
|
||||
}
|
||||
|
||||
void RenderSystem::OnSkeletonDestroy(entt::registry& registry, entt::entity entity)
|
||||
{
|
||||
assert(&m_registry == ®istry);
|
||||
|
||||
auto it = m_graphicsEntities.find(entity);
|
||||
if (it == m_graphicsEntities.end())
|
||||
return;
|
||||
|
||||
GraphicsEntity* graphicsEntity = it->second;
|
||||
|
||||
m_pipeline->UnregisterSkeleton(graphicsEntity->skeletonInstanceIndex);
|
||||
graphicsEntity->skeletonInstanceIndex = NoInstance;
|
||||
}
|
||||
|
||||
void RenderSystem::UpdateInstances()
|
||||
|
|
@ -247,6 +295,7 @@ namespace Nz
|
|||
graphicsEntity->entity = entity;
|
||||
graphicsEntity->poolIndex = poolIndex;
|
||||
graphicsEntity->renderableIndices.fill(std::numeric_limits<std::size_t>::max());
|
||||
graphicsEntity->skeletonInstanceIndex = NoInstance; //< will be set in skeleton observer
|
||||
graphicsEntity->worldInstanceIndex = m_pipeline->RegisterWorldInstance(entityGfx.GetWorldInstance());
|
||||
graphicsEntity->onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, graphicsEntity](const Node* /*node*/)
|
||||
{
|
||||
|
|
@ -259,7 +308,7 @@ namespace Nz
|
|||
return;
|
||||
|
||||
const auto& renderableEntry = gfx->GetRenderableEntry(renderableIndex);
|
||||
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, gfx->GetScissorBox());
|
||||
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, graphicsEntity->skeletonInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, gfx->GetScissorBox());
|
||||
});
|
||||
|
||||
graphicsEntity->onRenderableDetach.Connect(entityGfx.OnRenderableDetach, [this, graphicsEntity](GraphicsComponent* gfx, std::size_t renderableIndex)
|
||||
|
|
@ -301,16 +350,7 @@ namespace Nz
|
|||
m_invalidatedGfxWorldNode.insert(graphicsEntity);
|
||||
|
||||
if (entityGfx.IsVisible())
|
||||
{
|
||||
for (std::size_t renderableIndex = 0; renderableIndex < LightComponent::MaxLightCount; ++renderableIndex)
|
||||
{
|
||||
const auto& renderableEntry = entityGfx.GetRenderableEntry(renderableIndex);
|
||||
if (!renderableEntry.renderable)
|
||||
continue;
|
||||
|
||||
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox());
|
||||
}
|
||||
}
|
||||
m_newlyVisibleGfxEntities.insert(graphicsEntity);
|
||||
|
||||
assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end());
|
||||
m_graphicsEntities.emplace(entity, graphicsEntity);
|
||||
|
|
@ -383,6 +423,46 @@ namespace Nz
|
|||
assert(m_lightEntities.find(entity) == m_lightEntities.end());
|
||||
m_lightEntities.emplace(entity, lightEntity);
|
||||
});
|
||||
|
||||
m_sharedSkeletonConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
GraphicsEntity* graphicsEntity = Retrieve(m_graphicsEntities, entity);
|
||||
|
||||
SharedSkeletonComponent& skeletonComponent = m_registry.get<SharedSkeletonComponent>(entity);
|
||||
const std::shared_ptr<Skeleton>& skeleton = skeletonComponent.GetSkeleton();
|
||||
|
||||
if (auto it = m_sharedSkeletonInstances.find(skeleton.get()); it == m_sharedSkeletonInstances.end())
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.useCount++;
|
||||
graphicsEntity->skeletonInstanceIndex = it->second.skeletonInstanceIndex;
|
||||
}
|
||||
});
|
||||
|
||||
m_skeletonConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
GraphicsEntity* graphicsEntity = Retrieve(m_graphicsEntities, entity);
|
||||
|
||||
SkeletonComponent& skeletonComponent = m_registry.get<SkeletonComponent>(entity);
|
||||
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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void RenderSystem::UpdateVisibility()
|
||||
|
|
@ -414,7 +494,7 @@ namespace Nz
|
|||
if (!renderableEntry.renderable)
|
||||
continue;
|
||||
|
||||
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox());
|
||||
graphicsEntity->renderableIndices[renderableIndex] = m_pipeline->RegisterRenderable(graphicsEntity->worldInstanceIndex, graphicsEntity->skeletonInstanceIndex, renderableEntry.renderable.get(), renderableEntry.renderMask, entityGfx.GetScissorBox());
|
||||
}
|
||||
}
|
||||
m_newlyVisibleGfxEntities.clear();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Nz
|
|||
{
|
||||
}
|
||||
|
||||
void TextSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
void TextSprite::BuildElement(std::size_t passIndex, const WorldInstance& worldInstance, const SkeletonInstance* skeletonInstance, std::vector<std::unique_ptr<RenderElement>>& elements, const Recti& scissorBox) const
|
||||
{
|
||||
const auto& materialPass = m_material->GetPass(passIndex);
|
||||
if (!materialPass)
|
||||
|
|
|
|||
|
|
@ -31,8 +31,6 @@ namespace Nz
|
|||
auto rigidBodyView = m_registry.view<RigidBody2DComponent>();
|
||||
for (auto [entity, rigidBodyComponent] : rigidBodyView.each())
|
||||
rigidBodyComponent.Destroy();
|
||||
|
||||
m_constructConnection.release();
|
||||
}
|
||||
|
||||
void Physics2DSystem::Update(float elapsedTime)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ namespace Nz
|
|||
auto rigidBodyView = m_registry.view<RigidBody3DComponent>();
|
||||
for (auto [entity, rigidBodyComponent] : rigidBodyView.each())
|
||||
rigidBodyComponent.Destroy();
|
||||
|
||||
m_constructConnection.release();
|
||||
}
|
||||
|
||||
void Physics3DSystem::Update(float elapsedTime)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Joint.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SharedSkeletonComponent::SharedSkeletonComponent(std::shared_ptr<Skeleton> skeleton) :
|
||||
SkeletonComponentBase(std::move(skeleton)),
|
||||
m_skeletonJointInvalidated(true)
|
||||
{
|
||||
SetupSkeleton();
|
||||
}
|
||||
|
||||
SharedSkeletonComponent::SharedSkeletonComponent(const SharedSkeletonComponent& sharedSkeletalComponent) :
|
||||
SkeletonComponentBase(sharedSkeletalComponent),
|
||||
m_attachedSkeleton(sharedSkeletalComponent.m_attachedSkeleton),
|
||||
m_skeletonJointInvalidated(true)
|
||||
{
|
||||
SetupSkeleton();
|
||||
}
|
||||
|
||||
SharedSkeletonComponent::SharedSkeletonComponent(SharedSkeletonComponent&& sharedSkeletalComponent) noexcept :
|
||||
SkeletonComponentBase(std::move(sharedSkeletalComponent)),
|
||||
m_attachedSkeleton(std::move(sharedSkeletalComponent.m_attachedSkeleton)),
|
||||
m_skeletonJointInvalidated(sharedSkeletalComponent.m_skeletonJointInvalidated)
|
||||
{
|
||||
SetupSkeleton();
|
||||
}
|
||||
|
||||
const Joint& SharedSkeletonComponent::GetAttachedJoint(std::size_t jointIndex) const
|
||||
{
|
||||
return *m_attachedSkeleton.GetJoint(jointIndex);
|
||||
}
|
||||
|
||||
SharedSkeletonComponent& SharedSkeletonComponent::operator=(const SharedSkeletonComponent& sharedSkeletalComponent)
|
||||
{
|
||||
SkeletonComponentBase::operator=(sharedSkeletalComponent);
|
||||
|
||||
m_attachedSkeleton = sharedSkeletalComponent.m_attachedSkeleton;
|
||||
m_skeletonJointInvalidated = true;
|
||||
SetupSkeleton();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SharedSkeletonComponent& SharedSkeletonComponent::operator=(SharedSkeletonComponent&& sharedSkeletalComponent) noexcept
|
||||
{
|
||||
SkeletonComponentBase::operator=(std::move(sharedSkeletalComponent));
|
||||
|
||||
m_attachedSkeleton = std::move(sharedSkeletalComponent.m_attachedSkeleton);
|
||||
m_skeletonJointInvalidated = sharedSkeletalComponent.m_skeletonJointInvalidated;
|
||||
SetupSkeleton();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void SharedSkeletonComponent::OnReferenceJointsInvalidated(const Skeleton* skeleton)
|
||||
{
|
||||
m_skeletonJointInvalidated = true;
|
||||
}
|
||||
|
||||
void SharedSkeletonComponent::SetSkeletonParent(Node* parent)
|
||||
{
|
||||
m_attachedSkeleton.GetRootJoint()->SetParent(parent);
|
||||
}
|
||||
|
||||
void SharedSkeletonComponent::SetupSkeleton()
|
||||
{
|
||||
assert(m_referenceSkeleton);
|
||||
m_attachedSkeleton = *m_referenceSkeleton;
|
||||
m_referenceSkeleton->OnSkeletonJointsInvalidated.Connect(this, &SharedSkeletonComponent::OnReferenceJointsInvalidated);
|
||||
}
|
||||
|
||||
void SharedSkeletonComponent::UpdateAttachedSkeletonJoints()
|
||||
{
|
||||
assert(m_referenceSkeleton->GetJointCount() == m_attachedSkeleton.GetJointCount());
|
||||
std::size_t jointCount = m_referenceSkeleton->GetJointCount();
|
||||
|
||||
// TODO: This will trigger a lot of invalidation which can be avoided
|
||||
for (std::size_t i = 0; i < jointCount; ++i)
|
||||
{
|
||||
const Joint* referenceJoint = m_referenceSkeleton->GetJoint(i);
|
||||
Joint* attachedJoint = m_attachedSkeleton.GetJoint(i);
|
||||
|
||||
attachedJoint->SetPosition(referenceJoint->GetPosition());
|
||||
attachedJoint->SetRotation(referenceJoint->GetRotation());
|
||||
attachedJoint->SetScale(referenceJoint->GetScale());
|
||||
}
|
||||
|
||||
m_skeletonJointInvalidated = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SkeletonComponent::SkeletonComponent(std::shared_ptr<Skeleton> skeleton) :
|
||||
SkeletonComponentBase(std::move(skeleton))
|
||||
{
|
||||
}
|
||||
|
||||
const Joint& SkeletonComponent::GetAttachedJoint(std::size_t jointIndex) const
|
||||
{
|
||||
return *m_referenceSkeleton->GetJoint(jointIndex);
|
||||
}
|
||||
|
||||
Node* SkeletonComponent::GetRootNode()
|
||||
{
|
||||
return m_referenceSkeleton->GetRootJoint();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Components/SkeletonComponentBase.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
|
@ -217,15 +217,15 @@ namespace Nz
|
|||
m_impl->joints = skeleton.m_impl->joints;
|
||||
|
||||
// Restore parent hierarchy
|
||||
const Node* firstJoint = skeleton.m_impl->joints.data();
|
||||
const Joint* firstJoint = skeleton.m_impl->joints.data();
|
||||
|
||||
std::size_t jointCount = skeleton.m_impl->joints.size();
|
||||
for (std::size_t i = 0; i < jointCount; ++i)
|
||||
{
|
||||
const Node* parent = skeleton.m_impl->joints[i].GetParent();
|
||||
const Joint* parent = SafeCast<const Joint*>(skeleton.m_impl->joints[i].GetParent());
|
||||
if (parent)
|
||||
{
|
||||
std::size_t parentIndex = SafeCast<std::size_t>(firstJoint - parent);
|
||||
std::size_t parentIndex = SafeCast<std::size_t>(parent - firstJoint);
|
||||
m_impl->joints[i].SetParent(m_impl->joints[parentIndex]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Systems/SkeletonSystem.hpp>
|
||||
#include <Nazara/Utility/Components/NodeComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SharedSkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Components/SkeletonComponent.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
SkeletonSystem::SkeletonSystem(entt::registry& registry) :
|
||||
m_registry(registry),
|
||||
m_sharedSkeletonConstructObserver(registry, entt::collector.group<NodeComponent, SharedSkeletonComponent>(entt::exclude<SkeletonComponent>)),
|
||||
m_skeletonConstructObserver(registry, entt::collector.group<NodeComponent, SkeletonComponent>(entt::exclude<SharedSkeletonComponent>))
|
||||
{
|
||||
}
|
||||
|
||||
SkeletonSystem::~SkeletonSystem()
|
||||
{
|
||||
m_sharedSkeletonConstructObserver.disconnect();
|
||||
m_skeletonConstructObserver.disconnect();
|
||||
}
|
||||
|
||||
void SkeletonSystem::Update(float /*elapsedTime*/)
|
||||
{
|
||||
m_sharedSkeletonConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
NodeComponent& entityNode = m_registry.get<NodeComponent>(entity);
|
||||
SharedSkeletonComponent& entitySkeleton = m_registry.get<SharedSkeletonComponent>(entity);
|
||||
|
||||
entitySkeleton.SetSkeletonParent(&entityNode);
|
||||
});
|
||||
|
||||
m_skeletonConstructObserver.each([&](entt::entity entity)
|
||||
{
|
||||
NodeComponent& entityNode = m_registry.get<NodeComponent>(entity);
|
||||
SkeletonComponent& entitySkeleton = m_registry.get<SkeletonComponent>(entity);
|
||||
|
||||
// TODO: When attaching for the first time, set the skeleton to the position of the node before attaching the node
|
||||
Node* skeletonRoot = entitySkeleton.GetRootNode();
|
||||
|
||||
entityNode.SetParent(entitySkeleton.GetRootNode());
|
||||
});
|
||||
|
||||
// Updated attached skeleton joints (TODO: Only do this if necessary)
|
||||
auto view = m_registry.view<NodeComponent, SharedSkeletonComponent>();
|
||||
for (auto entity : view)
|
||||
{
|
||||
auto& sharedSkeletonComponent = view.get<SharedSkeletonComponent>(entity);
|
||||
if (sharedSkeletonComponent.IsAttachedSkeletonOutdated())
|
||||
sharedSkeletonComponent.UpdateAttachedSkeletonJoints();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue