Toast Engine
Loading...
Searching...
No Matches
debris.hpp
Go to the documentation of this file.
1
7
8#pragma once
9
10#include "fracture_random.hpp"
11
12#include <algorithm>
13#include <array>
14#include <bit>
15#include <cmath>
16#include <cstddef>
17#include <cstdint>
18#include <glm/glm.hpp>
19#include <glm/gtc/quaternion.hpp>
20#include <glm/mat4x4.hpp>
21#include <span>
22#include <toast/export.hpp>
23#include <vector>
24
25namespace physics {
26
28 glm::ivec3 voxel {0};
29 uint8_t material = 0;
30};
31
33 glm::ivec3 origin {0};
34 uint8_t mask = 0;
35 uint8_t material = 0;
36};
37
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 {};
43 uint8_t mask = 0;
44 uint8_t material = 0;
45 uint32_t albedo_roughness = 0;
46 uint8_t metallic = 0;
47 uint8_t reflectivity = 0;
48};
49
51 glm::vec3 start {};
52 glm::vec3 end {};
53 float energy = 0.0f;
54};
55
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;
59
60[[nodiscard]]
61constexpr auto debrisBit(const glm::ivec3& local) -> uint32_t {
62 return static_cast<uint32_t>(local.x + (2 * local.y) + (4 * local.z));
63}
64
65[[nodiscard]]
66inline auto clusterDebris(std::span<const DebrisVoxel> voxels, const glm::ivec3& jitter, Rng& rng, float split_chance)
67 -> std::vector<DebrisCluster> {
68 struct Entry {
69 glm::ivec3 cell;
70 uint32_t bit;
71 uint8_t material;
72 };
73
74 std::vector<Entry> entries;
75 entries.reserve(voxels.size());
76 for (const DebrisVoxel& v : voxels) {
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});
80 }
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;
84 }
85 if (a.cell.y != b.cell.y) {
86 return a.cell.y < b.cell.y;
87 }
88 if (a.cell.x != b.cell.x) {
89 return a.cell.x < b.cell.x;
90 }
91 return a.bit < b.bit;
92 });
93
94 std::vector<DebrisCluster> out;
95 for (size_t first = 0; first < entries.size();) {
96 size_t last = first;
97 std::array<uint8_t, 8> material {};
98 uint32_t present = 0;
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;
102 ++last;
103 }
104
105 // a block sometimes breaks into 2 or 3 smaller pieces
106 const auto count = static_cast<uint32_t>(std::popcount(present));
107 uint32_t parts = 1;
108 if (count > 1 && rng.chance(split_chance)) {
109 parts = (count > 2 && rng.chance(0.5f)) ? 3u : 2u;
110 }
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;
115 }
116 }
117
118 for (uint32_t p = 0; p < parts; ++p) {
119 if (part_masks[p] == 0) {
120 continue;
121 }
122 // most common material of the part
123 uint8_t best = 0;
124 int best_count = 0;
125 for (uint32_t bit = 0; bit < 8; ++bit) {
126 if ((part_masks[p] & (1u << bit)) == 0) {
127 continue;
128 }
129 int same = 0;
130 for (uint32_t other = 0; other < 8; ++other) {
131 same += ((part_masks[p] & (1u << other)) != 0 && material[other] == material[bit]) ? 1 : 0;
132 }
133 if (same > best_count) {
134 best_count = same;
135 best = material[bit];
136 }
137 }
138 out.push_back(
140 .origin = (entries[first].cell * 2) + jitter,
141 .mask = static_cast<uint8_t>(part_masks[p]),
142 .material = best,
143 }
144 );
145 }
146 first = last;
147 }
148 return out;
149}
150
151[[nodiscard]]
152inline auto debrisSpeed(float energy, float mass, float scale) -> float {
153 if (not(energy > 0.0f) || not(mass > 0.0f) || not(scale > 0.0f)) {
154 return 0.0f;
155 }
156 return std::min(std::sqrt(2.0f * energy / mass) * scale, k_max_debris_speed);
157}
158
159[[nodiscard]]
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;
164}
165
166TOAST_API void stepDebris(size_t steps);
167
168TOAST_API void clearDebris();
169
170}
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 debris.hpp:50
Definition debris.hpp:32
Definition debris.hpp:38
Definition debris.hpp:27
Definition fracture_random.hpp:99