19#include <glm/gtc/quaternion.hpp>
20#include <glm/mat4x4.hpp>
33 glm::ivec3 origin {0};
39 glm::vec3 position {};
40 glm::quat rotation {1.0f, 0.0f, 0.0f, 0.0f};
41 glm::vec3 velocity {};
42 glm::vec3 angular_velocity {};
45 uint32_t albedo_roughness = 0;
47 uint8_t reflectivity = 0;
56inline constexpr float k_max_debris_speed = 40.0f;
57inline constexpr float k_debris_cone_spread = 0.5f;
58inline constexpr float k_debris_max_spin = 8.0f;
61constexpr auto debrisBit(
const glm::ivec3& local) -> uint32_t {
62 return static_cast<uint32_t
>(local.x + (2 * local.y) + (4 * local.z));
66inline auto clusterDebris(std::span<const DebrisVoxel> voxels,
const glm::ivec3& jitter, Rng& rng,
float split_chance)
67 -> std::vector<DebrisCluster> {
74 std::vector<Entry> entries;
75 entries.reserve(voxels.size());
77 const glm::ivec3 shifted = v.voxel - jitter;
78 const glm::ivec3 cell {shifted.x >> 1, shifted.y >> 1, shifted.z >> 1};
79 entries.push_back({.cell = cell, .bit = debrisBit(shifted - (cell * 2)), .material = v.material});
81 std::ranges::sort(entries, [](
const Entry& a,
const Entry& b) {
82 if (a.cell.z != b.cell.z) {
83 return a.cell.z < b.cell.z;
85 if (a.cell.y != b.cell.y) {
86 return a.cell.y < b.cell.y;
88 if (a.cell.x != b.cell.x) {
89 return a.cell.x < b.cell.x;
94 std::vector<DebrisCluster> out;
95 for (
size_t first = 0; first < entries.size();) {
97 std::array<uint8_t, 8> material {};
99 while (last < entries.size() && entries[last].cell == entries[first].cell) {
100 present |= 1u << entries[last].bit;
101 material[entries[last].bit] = entries[last].material;
106 const auto count =
static_cast<uint32_t
>(std::popcount(present));
108 if (count > 1 && rng.chance(split_chance)) {
109 parts = (count > 2 && rng.chance(0.5f)) ? 3u : 2u;
111 std::array<uint32_t, 3> part_masks {};
112 for (uint32_t bit = 0; bit < 8; ++bit) {
113 if ((present & (1u << bit)) != 0) {
114 part_masks[parts == 1 ? 0 : rng.below(parts)] |= 1u << bit;
118 for (uint32_t p = 0; p < parts; ++p) {
119 if (part_masks[p] == 0) {
125 for (uint32_t bit = 0; bit < 8; ++bit) {
126 if ((part_masks[p] & (1u << bit)) == 0) {
130 for (uint32_t other = 0; other < 8; ++other) {
131 same += ((part_masks[p] & (1u << other)) != 0 && material[other] == material[bit]) ? 1 : 0;
133 if (same > best_count) {
135 best = material[bit];
140 .origin = (entries[first].cell * 2) + jitter,
141 .mask =
static_cast<uint8_t
>(part_masks[p]),
152inline auto debrisSpeed(
float energy,
float mass,
float scale) ->
float {
153 if (not(energy > 0.0f) || not(mass > 0.0f) || not(scale > 0.0f)) {
156 return std::min(std::sqrt(2.0f * energy / mass) * scale, k_max_debris_speed);
160inline auto debrisConeDirection(
const glm::vec3& axis,
Rng& rng,
float spread) -> glm::vec3 {
161 const glm::vec3 tilted = axis + (rng.direction() * spread);
162 const float length = glm::length(tilted);
163 return length > 1.0e-4f ? tilted / length : axis;
166TOAST_API
void stepDebris(
size_t steps);
168TOAST_API
void clearDebris();
Deterministic randomness for destruction.
@ present
Colour attachment output stage so the next use chains onto the acquire semaphore wait.
Definition gpu_sync.hpp:50
Definition fracture_random.hpp:99