Merge branch 'SP3-17-animation-system' of https://github.com/SHADE-DP/SHADE_Y3 into SP3-17-animation-system

This commit is contained in:
Kah Wei 2023-01-18 15:12:03 +08:00
commit 6c6e3bfe28
19 changed files with 158 additions and 101 deletions

View File

@ -0,0 +1,8 @@
- VertexShader: 47911992
FragmentShader: 46377769
SubPass: G-Buffer Write
Properties:
data.color: {x: 1, y: 1, z: 1, w: 1}
data.textureIndex: 58303057
data.alpha: 0
data.beta: {x: 1, y: 1, z: 1}

View File

@ -0,0 +1,3 @@
Name: AnimatedBag
ID: 117923942
Type: 7

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -67,7 +67,7 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
const std::vector<Channel>& GetChannels() const noexcept { return channels; }
int GetTicksPerSecond() const noexcept { return ticksPerSecond; }
float GetTotalTime() const noexcept { return totalTime; }
float GetTotalTime() const noexcept { return totalTime/(float)ticksPerSecond; }
private:
/*---------------------------------------------------------------------------------*/

View File

@ -7,25 +7,7 @@ namespace SHADE
{
SHRigAsset::~SHRigAsset()
{
if (root == nullptr)
{
return;
}
std::queue<SHRigNode*> nodeQueue;
nodeQueue.push(root);
while(!nodeQueue.empty())
{
auto curr = nodeQueue.front();
nodeQueue.pop();
for (auto child : curr->children)
{
nodeQueue.push(child);
}
delete curr;
}
if (root != nullptr)
delete[] root;
}
}

View File

@ -176,8 +176,8 @@ namespace SHADE
std::queue<std::pair<SHRigNode*, NodeTemp*>> nodeQueue;
nodeQueue.emplace(std::make_pair(nodePool, dst));
auto depthPtr = nodePool + 1;
auto depthTempPtr = dst + 1;
SHRigNode* depthPtr = nodePool + 1;
NodeTemp* depthTempPtr = dst + 1;
while(!nodeQueue.empty())
{
@ -239,16 +239,19 @@ namespace SHADE
bone.name.resize(info.charCount);
file.read(bone.name.data(), info.charCount);
file.read(reinterpret_cast<char*>(&bone.offset), sizeof(SHMatrix));
uint32_t weightCount;
file.read(reinterpret_cast<char*>(&weightCount), sizeof(uint32_t));
bone.weights.resize(weightCount);
file.read(reinterpret_cast<char*>(bone.weights.data()), sizeof(BoneWeight) * weightCount);
bone.weights.resize(info.weightCount);
file.read(reinterpret_cast<char*>(bone.weights.data()), sizeof(BoneWeight) * info.weightCount);
}
data.VertexBoneIndices.resize(header.vertexCount);
data.VertexBoneWeights.resize(header.vertexCount);
//for (auto& weight : data.VertexBoneWeights)
//{
// weight = { -0.1f };
//}
for (uint32_t boneIndex{0}; boneIndex < bones.size(); ++boneIndex)
{
auto const& bone = bones[boneIndex];
@ -263,6 +266,7 @@ namespace SHADE
{
boneIndices[j] = boneIndex;
boneWeight[j] = weight.weight;
break;
}
}
}

View File

@ -37,40 +37,50 @@ namespace SHADE
/* SHBatch - Constructors/Destructors */
/*-----------------------------------------------------------------------------------*/
SHBatch::SHBatch(Handle<SHVkPipeline> pipeline)
: pipeline{ pipeline }
: pipeline{ pipeline }
{
if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
// Check the pipeline and flag it depending on whether or not it is animated
isAnimated = checkIfIsAnimatedPipeline(pipeline);
// Mark all as dirty
setAllDirtyFlags();
}
SHBatch::SHBatch(SHBatch&& rhs)
: device { rhs.device }
, pipeline { rhs.pipeline }
, referencedMatInstances { std::move(rhs.referencedMatInstances) }
, matBufferDirty { std::move(rhs.matBufferDirty) }
, subBatches { std::move(rhs.subBatches) }
, isDirty { std::move(rhs.isDirty) }
, drawData { std::move(rhs.drawData) }
, transformData { std::move(rhs.transformData) }
, instancedIntegerData { std::move(rhs.instancedIntegerData) }
, matPropsData { std::move(rhs.matPropsData) }
, matPropsDataSize { rhs.matPropsDataSize }
, singleMatPropAlignedSize { rhs.singleMatPropAlignedSize }
, singleMatPropSize { rhs.singleMatPropSize }
, isCPUBuffersDirty { rhs.isCPUBuffersDirty }
, drawDataBuffer { rhs.drawDataBuffer }
, transformDataBuffer { rhs.transformDataBuffer }
, instancedIntegerBuffer { rhs.instancedIntegerBuffer }
, matPropsBuffer { rhs.matPropsBuffer }
, instanceDataDescSet { rhs.instanceDataDescSet }
: device { rhs.device }
, isAnimated { rhs.isAnimated }
, pipeline { rhs.pipeline }
, referencedMatInstances { std::move(rhs.referencedMatInstances) }
, matBufferDirty { std::move(rhs.matBufferDirty) }
, subBatches { std::move(rhs.subBatches) }
, isDirty { std::move(rhs.isDirty) }
, drawData { std::move(rhs.drawData) }
, transformData { std::move(rhs.transformData) }
, instancedIntegerData { std::move(rhs.instancedIntegerData) }
, matPropsData { std::move(rhs.matPropsData) }
, matPropsDataSize { rhs.matPropsDataSize }
, singleMatPropAlignedSize { rhs.singleMatPropAlignedSize }
, singleMatPropSize { rhs.singleMatPropSize }
, boneMatrixData { std::move(rhs.boneMatrixData) }
, boneMatrixIndices { std::move(rhs.boneMatrixIndices) }
, isCPUBuffersDirty { rhs.isCPUBuffersDirty }
, drawDataBuffer { rhs.drawDataBuffer }
, transformDataBuffer { rhs.transformDataBuffer }
, instancedIntegerBuffer { rhs.instancedIntegerBuffer }
, matPropsBuffer { rhs.matPropsBuffer }
, boneMatrixBuffer { rhs.boneMatrixBuffer }
, boneMatrixFirstIndexBuffer { rhs.boneMatrixFirstIndexBuffer }
, instanceDataDescSet { rhs.instanceDataDescSet }
{
rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {};
rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {};
rhs.boneMatrixBuffer = {};
rhs.boneMatrixFirstIndexBuffer = {};
rhs.instanceDataDescSet = {};
}
@ -79,31 +89,38 @@ namespace SHADE
if (this == &rhs)
return *this;
device = rhs.device ;
pipeline = rhs.pipeline ;
referencedMatInstances = std::move(rhs.referencedMatInstances);
matBufferDirty = std::move(rhs.matBufferDirty) ;
subBatches = std::move(rhs.subBatches) ;
isDirty = std::move(rhs.isDirty) ;
drawData = std::move(rhs.drawData) ;
transformData = std::move(rhs.transformData) ;
instancedIntegerData = std::move(rhs.instancedIntegerData) ;
matPropsData = std::move(rhs.matPropsData) ;
matPropsDataSize = rhs.matPropsDataSize ;
singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ;
singleMatPropSize = rhs.singleMatPropSize ;
isCPUBuffersDirty = rhs.isCPUBuffersDirty ;
drawDataBuffer = rhs.drawDataBuffer ;
transformDataBuffer = rhs.transformDataBuffer ;
instancedIntegerBuffer = rhs.instancedIntegerBuffer ;
matPropsBuffer = rhs.matPropsBuffer ;
instanceDataDescSet = rhs.instanceDataDescSet ;
device = rhs.device ;
isAnimated = rhs.isAnimated ;
pipeline = rhs.pipeline ;
referencedMatInstances = std::move(rhs.referencedMatInstances);
matBufferDirty = std::move(rhs.matBufferDirty) ;
subBatches = std::move(rhs.subBatches) ;
isDirty = std::move(rhs.isDirty) ;
drawData = std::move(rhs.drawData) ;
transformData = std::move(rhs.transformData) ;
instancedIntegerData = std::move(rhs.instancedIntegerData) ;
matPropsData = std::move(rhs.matPropsData) ;
matPropsDataSize = rhs.matPropsDataSize ;
singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ;
singleMatPropSize = rhs.singleMatPropSize ;
boneMatrixData = std::move(rhs.boneMatrixData) ;
boneMatrixIndices = std::move(rhs.boneMatrixIndices) ;
isCPUBuffersDirty = rhs.isCPUBuffersDirty ;
drawDataBuffer = rhs.drawDataBuffer ;
transformDataBuffer = rhs.transformDataBuffer ;
instancedIntegerBuffer = rhs.instancedIntegerBuffer ;
matPropsBuffer = rhs.matPropsBuffer ;
boneMatrixBuffer = rhs.boneMatrixBuffer ;
boneMatrixFirstIndexBuffer = rhs.boneMatrixFirstIndexBuffer ;
instanceDataDescSet = rhs.instanceDataDescSet ;
// Unset values
rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {};
rhs.drawDataBuffer = {};
rhs.transformDataBuffer = {};
rhs.instancedIntegerBuffer = {};
rhs.matPropsBuffer = {};
rhs.boneMatrixBuffer = {};
rhs.boneMatrixFirstIndexBuffer = {};
rhs.instanceDataDescSet = {};
return *this;
@ -363,25 +380,27 @@ namespace SHADE
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
for (auto rendId : subBatch.Renderables)
{
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
auto* renderable = SHComponentManager::GetComponent<SHRenderable>(rendId);
instancedIntegerData.emplace_back(SHInstancedIntegerData
{
rendId,
renderable->GetLightLayer()
}
);
}
rendId,
renderable->GetLightLayer()
});
}
// Transfer to GPU
if (instancedIntegerBuffer[frameIndex] && !drawData.empty())
instancedIntegerBuffer[frameIndex]->WriteToMemory(instancedIntegerData.data(), static_cast<uint32_t>(instancedIntegerData.size() * sizeof(SHInstancedIntegerData)), 0, 0);
}
void SHBatch::UpdateAnimationBuffer(uint32_t frameIndex)
{
// Ignore if not animated batch
if (!isAnimated)
return;
// Frame Index check
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
@ -392,6 +411,9 @@ namespace SHADE
// Reset Animation Matrix Data
boneMatrixData.clear();
// Add the first identity matrix into the bone matrix data
boneMatrixData.emplace_back(SHMatrix::Identity); // This kills the GPU
// Populate on the CPU
for (auto& subBatch : subBatches)
for (auto rendId : subBatch.Renderables)
@ -402,6 +424,7 @@ namespace SHADE
const auto& MATRICES = animator->GetBoneMatrices();
boneMatrixData.insert(boneMatrixData.end(), MATRICES.cbegin(), MATRICES.cend());
}
// We don't have to account for missing animators or reset indices as the renderable list are not updated at this point
}
// Update GPU Buffers
@ -446,10 +469,19 @@ namespace SHADE
// - EID data
instancedIntegerData.reserve(numTotalElements);
instancedIntegerData.clear();
// - Bone Data
if (isAnimated)
{
boneMatrixData.clear();
boneMatrixIndices.clear();
boneMatrixIndices.reserve(numTotalElements);
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
// Add the first identity matrix into the bone matrix data
boneMatrixData.emplace_back(SHMatrix::Identity);
}
// - Material Properties Data
auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING);
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
descMappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH),
@ -469,10 +501,6 @@ namespace SHADE
matPropsDataSize = matPropTotalBytes;
}
}
// - Bone Data
boneMatrixData.clear();
boneMatrixIndices.clear();
boneMatrixIndices.reserve(numTotalElements);
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
@ -548,12 +576,20 @@ namespace SHADE
}
// Bone Data
auto animator = SHComponentManager::GetComponent_s<SHAnimatorComponent>(rendId);
if (animator)
if (isAnimated)
{
boneMatrixIndices.emplace_back(static_cast<uint32_t>(boneMatrixData.size()));
const auto& BONE_MATRICES = animator->GetBoneMatrices();
boneMatrixData.insert(boneMatrixData.end(), BONE_MATRICES.cbegin(), BONE_MATRICES.cend());
auto animator = SHComponentManager::GetComponent_s<SHAnimatorComponent>(rendId);
if (animator)
{
boneMatrixIndices.emplace_back(static_cast<uint32_t>(boneMatrixData.size()));
const auto& BONE_MATRICES = animator->GetBoneMatrices();
boneMatrixData.insert(boneMatrixData.end(), BONE_MATRICES.cbegin(), BONE_MATRICES.cend());
}
else
{
// Take the first matrix which is always identity
boneMatrixIndices.emplace_back(static_cast<uint32_t>(0));
}
}
}
}
@ -590,7 +626,7 @@ namespace SHADE
"Batch Instance Data Buffer"
);
// - Bone Matrix Indices
if (!boneMatrixIndices.empty())
if (isAnimated && !boneMatrixIndices.empty())
{
const uint32_t BMI_DATA_BYTES = static_cast<uint32_t>(boneMatrixIndices.size() * sizeof(uint32_t));
SHVkUtil::EnsureBufferAndCopyHostVisibleData
@ -625,7 +661,7 @@ namespace SHADE
// Bind all required objects before drawing
std::vector<uint32_t> dynamicOffset{ 0 };
if (!boneMatrixData.empty())
if (isAnimated && !boneMatrixData.empty())
{
dynamicOffset.emplace_back(0);
}
@ -633,7 +669,7 @@ namespace SHADE
cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0);
if (boneMatrixFirstIndexBuffer[frameIndex])
if (isAnimated && boneMatrixFirstIndexBuffer[frameIndex])
{
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::BONE_MATRIX_FIRST_INDEX, boneMatrixFirstIndexBuffer[frameIndex], 0);
}
@ -706,7 +742,9 @@ namespace SHADE
layoutTypes = PreDefDescLayoutType::MATERIAL_AND_BONES;
}
if (matPropsData || !boneMatrixData.empty())
const bool MUST_BUILD_BONE_DESC = isAnimated && !boneMatrixData.empty();
if (matPropsData || MUST_BUILD_BONE_DESC)
{
// Make sure that we have a descriptor set if we don't already have one
if (!instanceDataDescSet[frameIndex])
@ -756,7 +794,7 @@ namespace SHADE
}
/* Animation Bone Data */
if (!boneMatrixData.empty())
if (MUST_BUILD_BONE_DESC)
{
// Update GPU Buffers
const uint32_t BONE_MTX_DATA_BYTES = static_cast<uint32_t>(boneMatrixData.size() * sizeof(SHMatrix));
@ -786,4 +824,22 @@ namespace SHADE
);
}
}
bool SHBatch::checkIfIsAnimatedPipeline(Handle<SHVkPipeline> pipeline)
{
if (!pipeline || !pipeline->GetPipelineLayout())
return false;
// Grab the pipeline descriptor set layouts
auto pipelineDescLayouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline();
// Check if they contain the material and bones layout, that indicates it is
using GfxPreDef = SHGraphicsPredefinedData;
using GfxPreDefType = GfxPreDef::PredefinedDescSetLayoutTypes;
const Handle<SHVkDescriptorSetLayout> BONE_DESC_SET_LAYOUT = GfxPreDef::GetPredefinedDescSetLayouts(GfxPreDefType::MATERIAL_AND_BONES)[0];
return std::find_if(pipelineDescLayouts.begin(), pipelineDescLayouts.end(), [BONE_DESC_SET_LAYOUT](Handle<SHVkDescriptorSetLayout> layout)
{
return BONE_DESC_SET_LAYOUT == layout;
}) != pipelineDescLayouts.end();
}
}

View File

@ -97,6 +97,7 @@ namespace SHADE
bool IsEmpty() const noexcept { return subBatches.empty(); }
Handle<SHVkBuffer> GetTransformBuffer(uint32_t frameIndex) const noexcept;
Handle<SHVkBuffer> GetMDIBuffer(uint32_t frameIndex) const noexcept;
bool IsAnimated() const noexcept { return isAnimated; }
private:
/*---------------------------------------------------------------------------------*/
@ -111,6 +112,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/
// Resources
Handle<SHVkLogicalDevice> device;
// Config
bool isAnimated; // Whether the material supports animation
// Batch Properties
Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
@ -126,7 +129,7 @@ namespace SHADE
Byte matPropsDataSize = 0;
Byte singleMatPropAlignedSize = 0;
Byte singleMatPropSize = 0;
std::vector<SHMatrix> boneMatrixData;
std::vector<SHMatrix> boneMatrixData; // 0th element is always an identity matrix
std::vector<uint32_t> boneMatrixIndices;
bool isCPUBuffersDirty = true;
// GPU Buffers
@ -143,5 +146,6 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
void setAllDirtyFlags();
void rebuildDescriptorSetBuffers(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
static bool checkIfIsAnimatedPipeline(Handle<SHVkPipeline> pipeline);
};
}