mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
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.
105 lines
2.5 KiB
C#
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);
|
|
}
|