rusting_engine 2.4.1

Vulkan 3D game engine with GPU-accelerated physics for massive physics-heavy scenes
#version 450
// XPBD cloth and soft bodies in one workgroup; src/runtime/gpu_cloth.rs
// packs the words and holds the bit-exact Rust reference (`step_on_cpu`);
// change both.
//
// Header words: 0 particle count, 1 distance color count, 2 substeps,
// 3 steps, 4 floor on, 5 substep h, 6 velocity kept per substep,
// 7..9 gravity, 10 floor height, 11 volume color count; offsets:
// 12 distance color table, 13 distance constraints, 14 particles,
// 15 volume color table, 16 volume constraints.
// Color table: color count + 1 starts into its constraints.
// Distance constraint: a, b, rest length, alpha (compliance / h^2).
// Volume constraint: four corners, rest volume, alpha.
// Particle: position xyz, velocity xyz, inverse mass, previous position xyz.
layout(local_size_x = 256) in;
#include <sim_math.glsl>
layout(set = 0, binding = 0) coherent buffer Data { uint words[]; };

const uint CONSTRAINT_WORDS = 4u;
const uint PARTICLE_WORDS = 10u;
const uint VOLUME_WORDS = 6u;
// 1 / 6 rounded to float (bits 0x3E2AAAAB), as `SIXTH` in gpu_cloth.rs.
// Written as that float's exact decimal value: the glslang that shaderc
// builds when no Vulkan SDK is installed cannot fold `uintBitsToFloat`
// in a constant.
const float SIXTH = 0.16666667163372039794921875;
const uvec3 OPPOSITE[4] = uvec3[4](uvec3(1u, 3u, 2u), uvec3(0u, 2u, 3u), uvec3(0u, 3u, 1u), uvec3(0u, 1u, 2u));

float word(uint index) { return uintBitsToFloat(words[index]); }
vec3 read3(uint index) { return vec3(word(index), word(index + 1u), word(index + 2u)); }
void write3(uint index, vec3 v) {
    words[index] = floatBitsToUint(v.x);
    words[index + 1u] = floatBitsToUint(v.y);
    words[index + 2u] = floatBitsToUint(v.z);
}
vec3 cross_of(vec3 a, vec3 b) {
    precise vec3 c = vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
    return c;
}
void sync() {
    memoryBarrierBuffer();
    barrier();
}

void main() {
    uint lane = gl_LocalInvocationID.x;
    uint count = words[0];
    uint colors = words[1];
    uint rounds = words[2] * words[3];
    bool has_floor = words[4] != 0u;
    float h = word(5u);
    float keep = word(6u);
    vec3 gravity = read3(7u);
    float floor_height = word(10u);
    uint color_base = words[12];
    uint constraint_base = words[13];
    uint particle_base = words[14];
    uint volume_colors = words[11];
    uint volume_table = words[15];
    uint volume_base = words[16];
    float inverse_h = sim_recip(h);

    for (uint round = 0u; round < rounds; round++) {
        for (uint i = lane; i < count; i += gl_WorkGroupSize.x) {
            uint p = particle_base + i * PARTICLE_WORDS;
            vec3 x = read3(p);
            write3(p + 7u, x);
            if (word(p + 6u) == 0.0) continue;
            precise vec3 v = read3(p + 3u) * keep + gravity * h;
            write3(p + 3u, v);
            precise vec3 moved = x + v * h;
            write3(p, moved);
        }
        sync();
        for (uint color = 0u; color < colors; color++) {
            uint end = words[color_base + color + 1u];
            for (uint k = words[color_base + color] + lane; k < end; k += gl_WorkGroupSize.x) {
                uint q = constraint_base + k * CONSTRAINT_WORDS;
                uint pa = particle_base + words[q] * PARTICLE_WORDS;
                uint pb = particle_base + words[q + 1u] * PARTICLE_WORDS;
                float rest = word(q + 2u);
                float alpha = word(q + 3u);
                float wa = word(pa + 6u);
                float wb = word(pb + 6u);
                vec3 xa = read3(pa);
                vec3 xb = read3(pb);
                precise float weight = wa + wb;
                precise vec3 delta = xa - xb;
                float distance = sim_length(delta);
                precise float denominator = weight + alpha;
                if (denominator == 0.0 || distance < 1e-9) continue;
                vec3 normal = sim_div(delta, distance);
                precise float lambda = -(distance - rest) * sim_recip(denominator);
                precise vec3 moved_a = xa + normal * (lambda * wa);
                precise vec3 moved_b = xb - normal * (lambda * wb);
                write3(pa, moved_a);
                write3(pb, moved_b);
            }
            sync();
        }
        for (uint color = 0u; color < volume_colors; color++) {
            uint end = words[volume_table + color + 1u];
            for (uint k = words[volume_table + color] + lane; k < end; k += gl_WorkGroupSize.x) {
                uint q = volume_base + k * VOLUME_WORDS;
                uint p[4];
                vec3 x[4];
                float w[4];
                for (uint j = 0u; j < 4u; j++) {
                    p[j] = particle_base + words[q + j] * PARTICLE_WORDS;
                    x[j] = read3(p[j]);
                    w[j] = word(p[j] + 6u);
                }
                float rest = word(q + 4u);
                float alpha = word(q + 5u);
                vec3 gradients[4];
                precise float weight = 0.0;
                for (uint j = 0u; j < 4u; j++) {
                    uvec3 o = OPPOSITE[j];
                    precise vec3 g = cross_of(x[o.y] - x[o.x], x[o.z] - x[o.x]) * SIXTH;
                    gradients[j] = g;
                    weight = weight + w[j] * sim_dot(g, g);
                }
                precise float denominator = weight + alpha;
                if (denominator == 0.0) continue;
                precise float volume = sim_dot(cross_of(x[1] - x[0], x[2] - x[0]), x[3] - x[0]) * SIXTH;
                precise float lambda = -(volume - rest) * sim_recip(denominator);
                for (uint j = 0u; j < 4u; j++) {
                    precise vec3 moved = x[j] + gradients[j] * (lambda * w[j]);
                    write3(p[j], moved);
                }
            }
            sync();
        }
        for (uint i = lane; i < count; i += gl_WorkGroupSize.x) {
            uint p = particle_base + i * PARTICLE_WORDS;
            if (word(p + 6u) == 0.0) continue;
            vec3 x = read3(p);
            vec3 previous = read3(p + 7u);
            if (has_floor && x.y < floor_height) {
                x = vec3(previous.x, floor_height, previous.z);
                write3(p, x);
            }
            precise vec3 velocity = (x - previous) * inverse_h;
            write3(p + 3u, velocity);
        }
        sync();
    }
}