0ad/binaries/data/mods/mod/shaders/glsl/compute_skinning.cs
Vladislav Belov abf444d91c
Reduces vertex maximum stride to 16
https://wikis.khronos.org/opengl/Vertex_Specification_Best_Practices

> The alignment of any attribute's data should be no less than 4 bytes.

But to make it a bit safer for older drivers we prefer to use 16 bytes
alignment (vec4) for now to match std140.
2026-07-12 17:54:26 +02:00

105 lines
2.5 KiB
C#

#version 430
#include "common/compute.h"
const int MAX_INFLUENCES = 4;
BEGIN_DRAW_TEXTURES
NO_DRAW_TEXTURES
END_DRAW_TEXTURES
BEGIN_DRAW_UNIFORMS
UNIFORM(float, vertexCount)
// offset.x - input vertex offset
// offset.y - input skinning data offset
// offset.z - output position offset
// offset.w - output packed normal and tangent offset
UNIFORM(vec4, offset)
END_DRAW_UNIFORMS
BEGIN_UNIFORM_BUFFER(SkinningMatrices)
mat4 skinBlendMatrices[MAX_BONES];
END_UNIFORM_BUFFER
struct Vertex
{
vec4 tangent;
vec4 normal;
vec4 position;
};
STORAGE_BUFFER(0) restrict readonly buffer InputVertices
{
Vertex vertices[];
};
STORAGE_BUFFER(1) restrict readonly buffer SkinData
{
uvec2 skinDatas[];
};
STORAGE_BUFFER(2) writeonly buffer OutputPositions
{
vec4 outputPositions[];
};
STORAGE_BUFFER(3) writeonly buffer OutputNormalsTangents
{
uvec4 outputPackedNT[];
};
uvec4 getSkinJoints(in uvec2 skinData)
{
return uvec4(unpackUnorm4x8(skinData.y) * 255.0);
}
vec4 getSkinWeights(in uvec2 skinData)
{
return unpackUnorm4x8(skinData.x);
}
uvec4 packNormalTangent(in vec3 normal, in vec3 tangent, in float weight)
{
return uvec4(
packHalf2x16(normal.xy), packHalf2x16(vec2(normal.z, 0.0)),
packHalf2x16(tangent.xy), packHalf2x16(vec2(tangent.z, weight)));
}
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
void main()
{
uint index = gl_GlobalInvocationID.x;
if (index >= vertexCount)
return;
uvec4 offsets = uvec4(offset);
Vertex vertex = vertices[index + offsets[0]];
uvec2 skinData = skinDatas[index + offsets[1]];
vec3 localPosition = vertex.position.xyz;
vec3 localNormal = vertex.normal.xyz;
vec3 localTangent = vertex.tangent.xyz;
uvec4 skinJoints = getSkinJoints(skinData);
vec4 skinWeights = getSkinWeights(skinData);
vec3 transformedPosition = vec3(0.0);
vec3 transformedNormal = vec3(0.0);
vec3 transformedTangent = vec3(0.0);
for (uint i = 0; i < MAX_INFLUENCES; ++i)
{
uint joint = skinJoints[i];
if (joint != 0xFF)
{
mat4 matrix = skinBlendMatrices[joint];
transformedPosition += vec3(matrix * vec4(localPosition, 1.0)) * skinWeights[i];
transformedNormal += vec3(matrix * vec4(localNormal, 0.0)) * skinWeights[i];
transformedTangent += vec3(matrix * vec4(localTangent, 0.0)) * skinWeights[i];
}
}
transformedNormal = normalize(transformedNormal);
transformedTangent = normalize(transformedTangent);
outputPositions[index + offsets[2]] = vec4(transformedPosition, 0.0);
outputPackedNT[index + offsets[3]] = packNormalTangent(transformedNormal, transformedTangent, vertex.tangent.w);
}