dynamis-world 0.6.0

GPU-driven physics engine
Documentation
use crate::world::shape_pool::ShapePool;
use dynamis_layout::{
    AabbRecord, ColliderRecord, SHAPE_CAPSULE, SHAPE_CUBOID, SHAPE_CYLINDER, SHAPE_HEIGHTFIELD,
    SHAPE_HULL, SHAPE_MESH, SHAPE_NONE, SHAPE_PLANE, SHAPE_SPHERE,
};
use dynamis_math::{quat_mul, quat_rotate};
use dynamis_model::MAX_COLLIDERS_PER_BODY;

fn abs3(v: [f32; 3]) -> [f32; 3] {
    [v[0].abs(), v[1].abs(), v[2].abs()]
}

pub fn static_aabbs(
    position: [f32; 3],
    orientation: [f32; 4],
    colliders: &[ColliderRecord; MAX_COLLIDERS_PER_BODY],
    shapes: &ShapePool,
) -> [AabbRecord; MAX_COLLIDERS_PER_BODY] {
    let mut aabbs = [AabbRecord::empty(); MAX_COLLIDERS_PER_BODY];
    for (index, collider) in colliders.iter().enumerate() {
        if collider.kind == SHAPE_NONE {
            continue;
        }
        aabbs[index] = collider_aabb(position, orientation, collider, shapes);
    }
    aabbs
}

fn collider_aabb(
    position: [f32; 3],
    orientation: [f32; 4],
    collider: &ColliderRecord,
    shapes: &ShapePool,
) -> AabbRecord {
    let offset = quat_rotate(orientation, collider.local_offset);
    let center = [
        position[0] + offset[0],
        position[1] + offset[1],
        position[2] + offset[2],
    ];
    let rotation = quat_mul(orientation, collider.local_rotation);
    let extent = match collider.kind {
        SHAPE_PLANE => [1e6f32; 3],
        SHAPE_SPHERE => [collider.radius; 3],
        SHAPE_CUBOID => {
            let e = collider.half_extents;
            let ex = abs3(quat_rotate(rotation, [e[0], 0.0, 0.0]));
            let ey = abs3(quat_rotate(rotation, [0.0, e[1], 0.0]));
            let ez = abs3(quat_rotate(rotation, [0.0, 0.0, e[2]]));
            [
                ex[0] + ey[0] + ez[0],
                ex[1] + ey[1] + ez[1],
                ex[2] + ey[2] + ez[2],
            ]
        }
        SHAPE_CAPSULE | SHAPE_CYLINDER => {
            let axis = quat_rotate(rotation, [0.0, 1.0, 0.0]);
            [
                axis[0].abs() * collider.half_height + collider.radius,
                axis[1].abs() * collider.half_height + collider.radius,
                axis[2].abs() * collider.half_height + collider.radius,
            ]
        }
        SHAPE_HULL | SHAPE_MESH | SHAPE_HEIGHTFIELD => {
            let record = shapes.record_by_index(collider.source as usize);
            let mut min = [f32::MAX; 3];
            let mut max = [f32::MIN; 3];
            for vertex in &shapes.vertices[record.vertex_offset as usize
                ..(record.vertex_offset + record.vertex_count) as usize]
            {
                let rotated = quat_rotate(rotation, [vertex[0], vertex[1], vertex[2]]);
                for axis in 0..3 {
                    min[axis] = min[axis].min(rotated[axis]);
                    max[axis] = max[axis].max(rotated[axis]);
                }
            }
            [
                (max[0] - min[0]) * 0.5,
                (max[1] - min[1]) * 0.5,
                (max[2] - min[2]) * 0.5,
            ]
        }
        _ => [0.0; 3],
    };
    let s = collider.scale[0]
        .max(collider.scale[1])
        .max(collider.scale[2]);
    let scaled = [extent[0] * s, extent[1] * s, extent[2] * s];
    AabbRecord {
        min: [
            center[0] - scaled[0],
            center[1] - scaled[1],
            center[2] - scaled[2],
        ],
        _pad0: 0.0,
        max: [
            center[0] + scaled[0],
            center[1] + scaled[1],
            center[2] + scaled[2],
        ],
        _pad1: 0.0,
    }
}