Graphics: Move skinning to a separate module

This commit is contained in:
SirLynix 2022-11-05 00:26:56 +01:00
parent 1205155466
commit 5502e51d71
7 changed files with 170 additions and 15 deletions

View File

@ -53,6 +53,14 @@ namespace Nz
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkeletalData.nzslb.h>
};
const UInt8 r_skinningDataModule[] = {
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkinningData.nzslb.h>
};
const UInt8 r_skinningLinearModule[] = {
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkinningLinear.nzslb.h>
};
const UInt8 r_viewerDataModule[] = {
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/ViewerData.nzslb.h>
};
@ -321,6 +329,8 @@ namespace Nz
RegisterEmbedShaderModule(r_mathCookTorrancePBRModule);
RegisterEmbedShaderModule(r_phongMaterialShader);
RegisterEmbedShaderModule(r_physicallyBasedMaterialShader);
RegisterEmbedShaderModule(r_skinningDataModule);
RegisterEmbedShaderModule(r_skinningLinearModule);
RegisterEmbedShaderModule(r_skeletalDataModule);
RegisterEmbedShaderModule(r_textureBlitShader);
RegisterEmbedShaderModule(r_viewerDataModule);

View File

@ -4,6 +4,7 @@ module BasicMaterial;
import InstanceData from Engine.InstanceData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
import SkinLinearPosition from Engine.SkinningLinear;
// Pass-specific options
option DepthPass: bool = false;
@ -175,23 +176,24 @@ fn billboardMain(input: VertIn) -> VertOut
fn main(input: VertIn) -> VertOut
{
let pos: vec3[f32];
const if (HasSkinning)
{
pos = vec3[f32](0.0, 0.0, 0.0);
let jointMatrices = array[mat4[f32]](
skeletalData.jointMatrices[input.jointIndices[0]],
skeletalData.jointMatrices[input.jointIndices[1]],
skeletalData.jointMatrices[input.jointIndices[2]],
skeletalData.jointMatrices[input.jointIndices[3]]
);
[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;
}
let skinningOutput = SkinLinearPosition(jointMatrices, input.jointWeights, input.pos);
pos = skinningOutput.position;
}
else
pos = input.pos;
let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0);
let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](pos, 1.0);

View File

@ -9,5 +9,5 @@ const MaxJointCount: u32 = u32(256); //< FIXME: Fix integral value types
[layout(std140)]
struct SkeletalData
{
JointMatrices: array[mat4[f32], MaxJointCount]
jointMatrices: array[mat4[f32], MaxJointCount]
}

View File

@ -0,0 +1,23 @@
[nzsl_version("1.0")]
module Engine.SkinningData;
[export]
struct SkinPositionOutput
{
position: vec3[f32]
}
[export]
struct SkinPositionNormalOutput
{
position: vec3[f32],
normal: vec3[f32]
}
[export]
struct SkinPositionNormalTangentOutput
{
position: vec3[f32],
normal: vec3[f32],
tangent: vec3[f32]
}

View File

@ -0,0 +1,35 @@
[nzsl_version("1.0")]
module Engine.SkinningLinear;
import * from Engine.SkinningData;
[export]
fn SkinLinearPosition(jointMatrices: array[mat4[f32], 4], jointWeights: vec4[f32], position: vec3[f32]) -> SkinPositionOutput
{
let skinMatrix = mat4[f32](0.0);
[unroll]
for i in 0 -> 4
skinMatrix += jointMatrices[i] * jointWeights[i];
let output: SkinPositionOutput;
output.position = (skinMatrix * vec4[f32](position, 1.0)).xyz;
return output;
}
[export]
fn SkinLinearPositionNormal(jointMatrices: array[mat4[f32], 4], jointWeights: vec4[f32], position: vec3[f32], normal: vec3[f32]) -> SkinPositionNormalOutput
{
let skinMatrix = mat4[f32](0.0);
[unroll]
for i in 0 -> 4
skinMatrix += jointMatrices[i] * jointWeights[i];
let inverseTransposeSkinMatrix = transpose(inverse(mat3[f32](skinMatrix)));
let output: SkinPositionNormalOutput;
output.position = (skinMatrix * vec4[f32](position, 1.0)).xyz;
output.normal = inverseTransposeSkinMatrix * normal;
return output;
}

View File

@ -6,6 +6,8 @@ import LightData from Engine.LightData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
import SkinLinearPosition, SkinLinearPositionNormal from Engine.SkinningLinear;
// Pass-specific options
option DepthPass: bool = false;
@ -33,13 +35,16 @@ option VertexPositionLoc: i32;
option VertexTangentLoc: i32 = -1;
option VertexUvLoc: i32 = -1;
option VertexJointIndicesLoc: i32 = -1;
option VertexJointWeightsLoc: i32 = -1;
const HasNormal = (VertexNormalLoc >= 0);
const HasVertexColor = (VertexColorLoc >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasTangent = (VertexTangentLoc >= 0);
const HasUV = (VertexUvLoc >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent && !DepthPass;
const HasSkinning = (VertexJointIndicesLoc >= 0 && VertexJointWeightsLoc >= 0);
[layout(std140)]
struct MaterialSettings
@ -272,6 +277,12 @@ struct VertIn
[cond(HasTangent), location(VertexTangentLoc)]
tangent: vec3[f32],
[cond(HasSkinning), location(VertexJointIndicesLoc)]
jointIndices: vec4[i32],
[cond(HasSkinning), location(VertexJointWeightsLoc)]
jointWeights: vec4[f32],
[cond(Billboard), location(BillboardCenterLocation)]
billboardCenter: vec3[f32],
@ -316,7 +327,38 @@ fn billboardMain(input: VertIn) -> VertToFrag
[entry(vert), cond(!Billboard)]
fn main(input: VertIn) -> VertToFrag
{
let worldPosition = instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
let pos: vec3[f32];
const if (HasNormal) let normal: vec3[f32];
const if (HasSkinning)
{
let jointMatrices = array[mat4[f32]](
skeletalData.jointMatrices[input.jointIndices[0]],
skeletalData.jointMatrices[input.jointIndices[1]],
skeletalData.jointMatrices[input.jointIndices[2]],
skeletalData.jointMatrices[input.jointIndices[3]]
);
const if (HasNormal)
{
let skinningOutput = SkinLinearPositionNormal(jointMatrices, input.jointWeights, input.pos, input.normal);
pos = skinningOutput.position;
normal = skinningOutput.normal;
}
else
{
let skinningOutput = SkinLinearPosition(jointMatrices, input.jointWeights, input.pos);
pos = skinningOutput.position;
}
}
else
{
pos = input.pos;
const if (HasNormal)
normal = input.normal;
}
let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0);
let output: VertToFrag;
output.worldPos = worldPosition.xyz;
@ -328,7 +370,7 @@ fn main(input: VertIn) -> VertToFrag
output.color = input.color;
const if (HasNormal)
output.normal = rotationMatrix * input.normal;
output.normal = rotationMatrix * normal;
const if (HasUV)
output.uv = input.uv;

View File

@ -6,6 +6,8 @@ import LightData from Engine.LightData;
import SkeletalData from Engine.SkeletalData;
import ViewerData from Engine.ViewerData;
import SkinLinearPosition, SkinLinearPositionNormal from Engine.SkinningLinear;
// Pass-specific options
option DepthPass: bool = false;
@ -35,12 +37,16 @@ option VertexPositionLoc: i32;
option VertexTangentLoc: i32 = -1;
option VertexUvLoc: i32 = -1;
option VertexJointIndicesLoc: i32 = -1;
option VertexJointWeightsLoc: i32 = -1;
const HasNormal = (VertexNormalLoc >= 0);
const HasVertexColor = (VertexColorLoc >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasTangent = (VertexTangentLoc >= 0);
const HasUV = (VertexUvLoc >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent && !DepthPass;
const HasSkinning = (VertexJointIndicesLoc >= 0 && VertexJointWeightsLoc >= 0);
[layout(std140)]
struct MaterialSettings
@ -260,6 +266,12 @@ struct VertIn
[cond(HasTangent), location(VertexTangentLoc)]
tangent: vec3[f32],
[cond(HasSkinning), location(VertexJointIndicesLoc)]
jointIndices: vec4[i32],
[cond(HasSkinning), location(VertexJointWeightsLoc)]
jointWeights: vec4[f32],
[cond(Billboard), location(BillboardCenterLocation)]
billboardCenter: vec3[f32],
@ -304,7 +316,38 @@ fn billboardMain(input: VertIn) -> VertToFrag
[entry(vert), cond(!Billboard)]
fn main(input: VertIn) -> VertToFrag
{
let worldPosition = instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
let pos: vec3[f32];
const if (HasNormal) let normal: vec3[f32];
const if (HasSkinning)
{
let jointMatrices = array[mat4[f32]](
skeletalData.jointMatrices[input.jointIndices[0]],
skeletalData.jointMatrices[input.jointIndices[1]],
skeletalData.jointMatrices[input.jointIndices[2]],
skeletalData.jointMatrices[input.jointIndices[3]]
);
const if (HasNormal)
{
let skinningOutput = SkinLinearPositionNormal(jointMatrices, input.jointWeights, input.pos, input.normal);
pos = skinningOutput.position;
normal = skinningOutput.normal;
}
else
{
let skinningOutput = SkinLinearPosition(jointMatrices, input.jointWeights, input.pos);
pos = skinningOutput.position;
}
}
else
{
pos = input.pos;
const if (HasNormal)
normal = input.normal;
}
let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0);
let output: VertToFrag;
output.worldPos = worldPosition.xyz;