Add support for GPU skinning (WIP)

This commit is contained in:
SirLynix
2022-04-18 19:10:34 +02:00
committed by Jérôme Leclercq
parent 5d8ecd11df
commit 104f60f3e7
22 changed files with 667 additions and 141 deletions

View File

@@ -151,6 +151,16 @@ namespace Nz
options.defaultValues
});
FieldOffsets skeletalOffsets(StructLayout::Std140);
skeletalOffsets.AddMatrixArray(StructFieldType::Float1, 4, 4, true, 100);
settings.sharedUniformBlocks.push_back({
6,
"SkeletalData",
{},
ShaderStageType::Vertex
});
// Common data
settings.textures.push_back({
3,
@@ -160,9 +170,11 @@ namespace Nz
settings.sharedUniformBlocks.push_back(PredefinedInstanceData::GetUniformBlock(4, nzsl::ShaderStageType::Vertex));
settings.sharedUniformBlocks.push_back(PredefinedViewerData::GetUniformBlock(5, nzsl::ShaderStageType_All));
//settings.sharedUniformBlocks.push_back(PredefinedInstanceData::GetUniformBlock(6, nzsl::ShaderStageType::Vertex));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::InstanceDataUbo)] = 4;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::OverlayTexture)] = 3;
//settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::SkeletalDataUbo)] = 6;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::ViewerDataUbo)] = 5;
settings.shaders = options.shaders;
@@ -194,6 +206,14 @@ namespace Nz
config.optionValues[CRC32("UvLocation")] = locationIndex;
break;
case VertexComponent::JointIndices:
config.optionValues[CRC32("JointIndicesLocation")] = locationIndex;
break;
case VertexComponent::JointWeights:
config.optionValues[CRC32("JointWeightsLocation")] = locationIndex;
break;
case VertexComponent::Unused:
default:
break;

View File

@@ -13,8 +13,6 @@ namespace Nz
{
std::shared_ptr<GraphicalMesh> GraphicalMesh::BuildFromMesh(const Mesh& mesh)
{
assert(mesh.GetAnimationType() == AnimationType::Static);
const std::shared_ptr<RenderDevice>& renderDevice = Graphics::Instance()->GetRenderDevice();
std::shared_ptr<GraphicalMesh> gfxMesh = std::make_shared<GraphicalMesh>();

View File

@@ -47,9 +47,11 @@ namespace Nz
}
const auto& textureSettings = m_settings->GetTextures();
const auto& sharedUboSettings = m_settings->GetSharedUniformBlocks();
const auto& uboSettings = m_settings->GetUniformBlocks();
m_textures.resize(textureSettings.size());
m_sharedUniformBuffers.resize(sharedUboSettings.size());
m_uniformBuffers.reserve(uboSettings.size());
for (const auto& uniformBufferInfo : uboSettings)
@@ -68,6 +70,7 @@ namespace Nz
void MaterialPass::FillShaderBinding(std::vector<ShaderBinding::Binding>& bindings) const
{
const auto& textureSettings = m_settings->GetTextures();
const auto& sharedUboSettings = m_settings->GetSharedUniformBlocks();
const auto& uboSettings = m_settings->GetUniformBlocks();
// Textures
@@ -98,7 +101,22 @@ namespace Nz
});
}
// Shared UBO (TODO)
// Shared UBO
for (std::size_t i = 0; i < m_sharedUniformBuffers.size(); ++i)
{
const auto& sharedUboSlot = m_sharedUniformBuffers[i];
if (!sharedUboSlot.bufferView)
continue;
const auto& sharedUboSetting = sharedUboSettings[i];
bindings.push_back({
sharedUboSetting.bindingIndex,
ShaderBinding::UniformBufferBinding {
sharedUboSlot.bufferView.GetBuffer(), sharedUboSlot.bufferView.GetOffset(), sharedUboSlot.bufferView.GetSize()
}
});
}
// Owned UBO
for (std::size_t i = 0; i < m_uniformBuffers.size(); ++i)

View File

@@ -186,7 +186,7 @@ namespace Nz
options.phongTextureIndexes->emissive = settings.textures.size();
settings.textures.push_back({
7,
8,
"Emissive",
ImageType::E2D
});
@@ -195,7 +195,7 @@ namespace Nz
options.phongTextureIndexes->height = settings.textures.size();
settings.textures.push_back({
8,
9,
"Height",
ImageType::E2D
});
@@ -204,7 +204,7 @@ namespace Nz
options.phongTextureIndexes->normal = settings.textures.size();
settings.textures.push_back({
9,
10,
"Normal",
ImageType::E2D
});
@@ -213,7 +213,7 @@ namespace Nz
options.phongTextureIndexes->specular = settings.textures.size();
settings.textures.push_back({
10,
11,
"Specular",
ImageType::E2D
});
@@ -229,8 +229,8 @@ namespace Nz
options.defaultValues
});
settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(6, nzsl::ShaderStageType::Fragment));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 6;
settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(7, nzsl::ShaderStageType::Fragment));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 7;
settings.shaders = options.shaders;

View File

@@ -19,9 +19,13 @@ option ColorLocation: i32 = -1;
option PosLocation: i32;
option UvLocation: i32 = -1;
option JointIndicesLocation: i32 = -1;
option JointWeightsLocation: i32 = -1;
const HasVertexColor = (ColorLocation >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasUV = (UvLocation >= 0);
const HasSkinning = (JointIndicesLocation >= 0 && JointWeightsLocation >= 0);
[layout(std140)]
struct MaterialSettings
@@ -30,6 +34,14 @@ struct MaterialSettings
BaseColor: vec4[f32]
}
const MaxJointCount: u32 = u32(200); //< FIXME: Fix integral value types
[layout(std140)]
struct SkeletalData
{
JointMatrices: array[mat4[f32], MaxJointCount]
}
external
{
[binding(0)] settings: uniform[MaterialSettings],
@@ -38,6 +50,7 @@ external
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] skeletalData: uniform[SkeletalData]
}
// Fragment stage
@@ -92,6 +105,12 @@ struct VertIn
[cond(HasUV), location(UvLocation)]
uv: vec2[f32],
[cond(HasSkinning), location(JointIndicesLocation)]
jointIndices: vec4[i32],
[cond(HasSkinning), location(JointWeightsLocation)]
jointWeights: vec4[f32],
[cond(Billboard), location(BillboardCenterLocation)]
billboardCenter: vec3[f32],
@@ -143,8 +162,26 @@ fn billboardMain(input: VertIn) -> VertOut
[entry(vert), cond(!Billboard)]
fn main(input: VertIn) -> VertOut
{
let pos: vec3[f32];
const if (HasSkinning)
{
pos = vec3[f32](0.0, 0.0, 0.0);
[unroll]
for i in 0 -> 4
{
let jointIndex = input.jointIndices[i];
let jointWeight = input.jointWeights[i];
let jointMatrix = skeletalData.JointMatrices[jointIndex];
pos += (jointMatrix * vec4[f32](input.pos, 1.0)).xyz * jointWeight;
}
}
else
pos = input.pos;
let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](pos, 1.0);
const if (HasColor)
output.color = input.color;

View File

@@ -62,11 +62,11 @@ external
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] lightData: uniform[LightData],
[binding(7)] MaterialEmissiveMap: sampler2D[f32],
[binding(8)] MaterialHeightMap: sampler2D[f32],
[binding(9)] MaterialNormalMap: sampler2D[f32],
[binding(10)] MaterialSpecularMap: sampler2D[f32],
[binding(7)] lightData: uniform[LightData],
[binding(8)] MaterialEmissiveMap: sampler2D[f32],
[binding(9)] MaterialHeightMap: sampler2D[f32],
[binding(10)] MaterialNormalMap: sampler2D[f32],
[binding(11)] MaterialSpecularMap: sampler2D[f32],
}
struct VertToFrag

View File

@@ -33,6 +33,7 @@ namespace Nz
const WorldInstance* currentWorldInstance = nullptr;
Recti currentScissorBox = invalidScissorBox;
RenderBufferView currentLightData;
RenderBufferView currentSkeletalData;
auto FlushDrawCall = [&]()
{
@@ -95,6 +96,12 @@ 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)
@@ -135,6 +142,16 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::SkeletalDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentSkeletalData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::UniformBufferBinding{
currentSkeletalData.GetBuffer(),
currentSkeletalData.GetOffset(), currentSkeletalData.GetSize()
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
{
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();