diff options
author | reduz <reduzio@gmail.com> | 2020-12-16 11:07:08 -0300 |
---|---|---|
committer | reduz <reduzio@gmail.com> | 2020-12-16 14:32:04 -0300 |
commit | bf77016c8a3cc9a8ff4c57c0fc32a4255006391b (patch) | |
tree | 0b4a378b86c7a3d6e20534e99460e05384ace298 /servers/rendering/renderer_rd/shaders | |
parent | c514cc58224e5c973ac8be7bb6db7023d5c25906 (diff) |
Reimplement skeletons and blend shapes
Uses compute shaders, which only once, on demand, and all in parallel.
Diffstat (limited to 'servers/rendering/renderer_rd/shaders')
-rw-r--r-- | servers/rendering/renderer_rd/shaders/SCsub | 1 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/skeleton.glsl | 199 |
2 files changed, 200 insertions, 0 deletions
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub index 1fe43b25f6..cb62882deb 100644 --- a/servers/rendering/renderer_rd/shaders/SCsub +++ b/servers/rendering/renderer_rd/shaders/SCsub @@ -41,3 +41,4 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("particles.glsl") env.RD_GLSL("particles_copy.glsl") env.RD_GLSL("sort.glsl") + env.RD_GLSL("skeleton.glsl") diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl new file mode 100644 index 0000000000..b19f5a9ad3 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -0,0 +1,199 @@ +#[compute] + +#version 450 + +VERSION_DEFINES + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(set = 0, binding = 1, std430) buffer restrict writeonly DstVertexData { + uint data[]; +} +dst_vertices; + +layout(set = 0, binding = 2, std430) buffer restrict readonly BlendShapeWeights { + float data[]; +} +blend_shape_weights; + +layout(set = 1, binding = 0, std430) buffer restrict readonly SrcVertexData { + uint data[]; +} +src_vertices; + +layout(set = 1, binding = 1, std430) buffer restrict readonly BoneWeightData { + uint data[]; +} +src_bone_weights; + +layout(set = 1, binding = 2, std430) buffer restrict readonly BlendShapeData { + uint data[]; +} +src_blend_shapes; + +layout(set = 2, binding = 0, std430) buffer restrict readonly SkeletonData { + vec4 data[]; +} +bone_transforms; + +layout(push_constant, binding = 0, std430) uniform Params { + bool has_normal; + bool has_tangent; + bool has_skeleton; + bool has_blend_shape; + + uint vertex_count; + uint vertex_stride; + uint skin_stride; + uint skin_weight_offset; + + uint blend_shape_count; + bool normalized_blend_shapes; + uint pad0; + uint pad1; +} +params; + +vec4 decode_abgr_2_10_10_10(uint base) { + uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3); + return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0; +} + +uint encode_abgr_2_10_10_10(vec4 base) { + uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30); + return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w; +} + +void main() { + uint index = gl_GlobalInvocationID.x; + if (index >= params.vertex_count) { + return; + } + + uint src_offset = index * params.vertex_stride; + +#ifdef MODE_2D + vec2 vertex = uintBitsToFloat(uvec2(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1])); +#else + vec3 vertex; + vec3 normal; + vec4 tangent; + + vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2])); + + src_offset += 3; + + if (params.has_normal) { + normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb; + src_offset++; + } + + if (params.has_tangent) { + tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]); + } + + if (params.has_blend_shape) { + float blend_total = 0.0; + vec3 blend_vertex = vec3(0.0); + vec3 blend_normal = vec3(0.0); + vec3 blend_tangent = vec3(0.0); + + for (uint i = 0; i < params.blend_shape_count; i++) { + float w = blend_shape_weights.data[i]; + if (w > 0.0001) { + uint base_offset = (params.vertex_count * i + index) * params.vertex_stride; + + blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w; + + base_offset += 3; + + if (params.has_normal) { + blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w; + base_offset++; + } + + if (params.has_tangent) { + blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb; + } + + blend_total += w; + } + } + + if (params.normalized_blend_shapes) { + vertex = (1.0 - blend_total) * vertex; + normal = (1.0 - blend_total) * normal; + tangent.rgb = (1.0 - blend_total) * tangent.rgb; + } + + vertex += blend_vertex; + normal += normalize(normal + blend_normal); + tangent.rgb += normalize(tangent.rgb + blend_tangent); + } + + if (params.has_skeleton) { + uint skin_offset = params.skin_stride * index; + + uvec2 bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + uvec2 bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + uvec2 bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + uvec2 weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + vec2 weights_01 = unpackUnorm2x16(weights.x); + vec2 weights_23 = unpackUnorm2x16(weights.y); + + mat4 m = mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + + if (params.skin_weight_offset == 4) { + //using 8 bones/weights + skin_offset = params.skin_stride * index + 2; + + bones = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + bones_01 = uvec2(bones.x & 0xFFFF, bones.x >> 16) * 3; //pre-add xform offset + bones_23 = uvec2(bones.y & 0xFFFF, bones.y >> 16) * 3; + + skin_offset += params.skin_weight_offset; + + weights = uvec2(src_bone_weights.data[skin_offset + 0], src_bone_weights.data[skin_offset + 1]); + + weights_01 = unpackUnorm2x16(weights.x); + weights_23 = unpackUnorm2x16(weights.y); + + m += mat4(bone_transforms.data[bones_01.x], bone_transforms.data[bones_01.x + 1], bone_transforms.data[bones_01.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.x; + m += mat4(bone_transforms.data[bones_01.y], bone_transforms.data[bones_01.y + 1], bone_transforms.data[bones_01.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_01.y; + m += mat4(bone_transforms.data[bones_23.x], bone_transforms.data[bones_23.x + 1], bone_transforms.data[bones_23.x + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.x; + m += mat4(bone_transforms.data[bones_23.y], bone_transforms.data[bones_23.y + 1], bone_transforms.data[bones_23.y + 2], vec4(0.0, 0.0, 0.0, 1.0)) * weights_23.y; + } + + //reverse order because its transposed + vertex = (vec4(vertex, 1.0) * m).xyz; + normal = normalize((vec4(normal, 0.0) * m).xyz); + tangent.xyz = normalize((vec4(tangent.xyz, 0.0) * m).xyz); + } + + uint dst_offset = index * params.vertex_stride; + + uvec3 uvertex = floatBitsToUint(vertex); + dst_vertices.data[dst_offset + 0] = uvertex.x; + dst_vertices.data[dst_offset + 1] = uvertex.y; + dst_vertices.data[dst_offset + 2] = uvertex.z; + + dst_offset += 3; + + if (params.has_normal) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0)); + dst_offset++; + } + + if (params.has_tangent) { + dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent); + } + +#endif +} |