1.3.49
 
Loading...
Searching...
No Matches
CollisionDetection.h
Go to the documentation of this file.
1
16#ifndef COLLISION_DETECTION_H
17#define COLLISION_DETECTION_H
18
19#include <queue>
20#include <set>
21#include <unordered_map>
22#include <unordered_set>
23#include "Context.h"
24
35public:
36 // -------- CONE COLLISION STRUCTURES --------
37
47
51 struct AngularBins {
55
56 // Coverage data using packed bits for memory efficiency
57 std::vector<uint8_t> coverage_bits;
58 std::vector<float> depth_values;
59
60 AngularBins(int theta_div, int phi_div) : theta_divisions(theta_div), phi_divisions(phi_div) {
61 int total_bins = theta_div * phi_div;
62 coverage_bits.resize((total_bins + 7) / 8, 0); // Packed bits
63 depth_values.resize(total_bins, std::numeric_limits<float>::max());
64 angular_resolution = (2.0f * M_PI) / float(theta_div * phi_div);
65 }
66
67 // Fast bit operations for coverage testing
68 bool isCovered(int theta, int phi) const {
69 int index = theta * phi_divisions + phi;
70 return coverage_bits[index >> 3] & (1 << (index & 7));
71 }
72
73 void setCovered(int theta, int phi, float depth) {
74 int index = theta * phi_divisions + phi;
75 coverage_bits[index >> 3] |= (1 << (index & 7));
76 depth_values[index] = std::min(depth_values[index], depth);
77 }
78
79 void clear() {
80 std::fill(coverage_bits.begin(), coverage_bits.end(), 0);
81 std::fill(depth_values.begin(), depth_values.end(), std::numeric_limits<float>::max());
82 }
83 };
84
85 // -------- GENERIC RAY-TRACING STRUCTURES --------
86
90 struct RayQuery {
94 std::vector<uint> target_UUIDs;
95
96 RayQuery() : origin(0, 0, 0), direction(0, 0, 1), max_distance(-1.0f) {
97 }
98 RayQuery(const helios::vec3 &ray_origin, const helios::vec3 &ray_direction, float max_dist = -1.0f, const std::vector<uint> &targets = {}) : origin(ray_origin), direction(ray_direction), max_distance(max_dist), target_UUIDs(targets) {
99 }
100 };
101
116
129
134 static constexpr size_t WARP_SIZE = 32;
135 static constexpr size_t RAY_BATCH_SIZE = 1024;
136
141 struct RayPacket {
142 // Ray data (Structure-of-Arrays layout)
143 std::vector<helios::vec3> origins;
144 std::vector<helios::vec3> directions;
145 std::vector<float> max_distances;
146 std::vector<std::vector<uint>> target_UUIDs;
147
148 // Results (output)
149 std::vector<HitResult> results;
150
151 size_t ray_count = 0;
152
153 RayPacket() = default;
154
158 void reserve(size_t capacity) {
159 origins.reserve(capacity);
160 directions.reserve(capacity);
161 max_distances.reserve(capacity);
162 target_UUIDs.reserve(capacity);
163 results.reserve(capacity);
164 }
165
169 void addRay(const RayQuery &query) {
170 origins.push_back(query.origin);
171 directions.push_back(query.direction);
172 max_distances.push_back(query.max_distance);
173 target_UUIDs.push_back(query.target_UUIDs);
174 results.emplace_back(); // Initialize empty result
175 ray_count++;
176 }
177
181 void clear() {
182 origins.clear();
183 directions.clear();
184 max_distances.clear();
185 target_UUIDs.clear();
186 results.clear();
187 ray_count = 0;
188 }
189
193 [[nodiscard]] std::vector<RayQuery> toRayQueries() const {
194 std::vector<RayQuery> queries;
195 queries.reserve(ray_count);
196 for (size_t i = 0; i < ray_count; ++i) {
197 queries.emplace_back(origins[i], directions[i], max_distances[i], target_UUIDs[i]);
198 }
199 return queries;
200 }
201
205 [[nodiscard]] size_t getMemoryUsage() const {
206 size_t base_memory = (origins.size() + directions.size()) * sizeof(helios::vec3) + max_distances.size() * sizeof(float) + results.size() * sizeof(HitResult);
207
208 // Add memory for target UUIDs
209 for (const auto &targets: target_UUIDs) {
210 base_memory += targets.size() * sizeof(uint);
211 }
212
213 return base_memory;
214 }
215 };
216
221 struct RayStream {
222 std::vector<RayPacket> packets;
223 size_t current_packet = 0;
224 size_t total_rays = 0;
225
229 void addRays(const std::vector<RayQuery> &queries) {
230 for (const auto &query: queries) {
231 // Create new packet if current one is full
232 if (packets.empty() || packets.back().ray_count >= RAY_BATCH_SIZE) {
233 packets.emplace_back();
234 packets.back().reserve(RAY_BATCH_SIZE);
235 }
236
237 packets.back().addRay(query);
238 total_rays++;
239 }
240 }
241
245 [[nodiscard]] std::vector<HitResult> getAllResults() const {
246 std::vector<HitResult> all_results;
247 all_results.reserve(total_rays);
248
249 for (const auto &packet: packets) {
250 all_results.insert(all_results.end(), packet.results.begin(), packet.results.end());
251 }
252
253 return all_results;
254 }
255
259 void clear() {
260 packets.clear();
261 current_packet = 0;
262 total_rays = 0;
263 }
264
268 [[nodiscard]] size_t getMemoryUsage() const {
269 size_t total_memory = 0;
270 for (const auto &packet: packets) {
271 total_memory += packet.getMemoryUsage();
272 }
273 return total_memory;
274 }
275 };
276
285
290 explicit CollisionDetection(helios::Context *context);
291
296
297 // -------- PRIMITIVE/OBJECT COLLISION DETECTION --------
298
305 std::vector<uint> findCollisions(uint UUID, bool allow_spatial_culling = true);
306
313 std::vector<uint> findCollisions(const std::vector<uint> &UUIDs, bool allow_spatial_culling = true);
314
322 std::vector<uint> findCollisions(const std::vector<uint> &primitive_UUIDs, const std::vector<uint> &object_IDs, bool allow_spatial_culling = true);
323
333 std::vector<uint> findCollisions(const std::vector<uint> &query_UUIDs, const std::vector<uint> &query_object_IDs, const std::vector<uint> &target_UUIDs, const std::vector<uint> &target_object_IDs, bool allow_spatial_culling = true);
334
335 // -------- GENERIC RAY-TRACING INTERFACE --------
336
342 HitResult castRay(const RayQuery &ray_query);
343
352 HitResult castRay(const helios::vec3 &origin, const helios::vec3 &direction, float max_distance = -1.0f, const std::vector<uint> &target_UUIDs = {});
353
360 std::vector<HitResult> castRays(const std::vector<RayQuery> &ray_queries, RayTracingStats *stats = nullptr);
361
362 // -------- OPTIMIZATION METHODS --------
363
369 };
370
376
382
389 std::vector<HitResult> castRaysOptimized(const std::vector<RayQuery> &ray_queries, RayTracingStats *stats = nullptr);
390
391#ifdef HELIOS_CUDA_AVAILABLE
399 std::vector<HitResult> castRaysGPU(const std::vector<RayQuery> &ray_queries, RayTracingStats &stats);
400#endif
401
408 bool processRayStream(RayStream &ray_stream, RayTracingStats *stats = nullptr);
409
415 size_t soa_memory_bytes = 0;
416 size_t quantized_memory_bytes = 0;
417 float quantized_reduction_percent = 0.0f; // Reduction vs SoA
418 };
419 MemoryUsageStats getBVHMemoryUsage() const;
420
429 std::vector<std::vector<std::vector<std::vector<HitResult>>>> performGridRayIntersection(const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions, const std::vector<RayQuery> &ray_queries);
430
443 std::vector<std::vector<HitResult>> calculateVoxelPathLengths(const helios::vec3 &scan_origin, const std::vector<helios::vec3> &ray_directions, const std::vector<helios::vec3> &voxel_centers, const std::vector<helios::vec3> &voxel_sizes);
444
454 void calculateRayPathLengthsDetailed(const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions, const std::vector<helios::vec3> &ray_origins, const std::vector<helios::vec3> &ray_directions,
455 std::vector<HitResult> &hit_results);
456
457 // -------- CONE INTERSECTION QUERIES --------
458
468 OptimalPathResult findOptimalConePath(const helios::vec3 &apex, const helios::vec3 &centralAxis, float half_angle, float height = 0.0f, int initialSamples = 256);
469
470
471 // -------- GRID-BASED INTERSECTION --------
472
480 void calculateGridIntersection(const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions, const std::vector<uint> &UUIDs = {});
481
486 std::vector<std::vector<std::vector<std::vector<uint>>>> getGridCells();
487
495 std::vector<uint> getGridIntersections(int i, int j, int k);
496
497 // -------- VOXEL RAY PATH LENGTH CALCULATIONS --------
498
507 void calculateVoxelRayPathLengths(const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions, const std::vector<helios::vec3> &ray_origins, const std::vector<helios::vec3> &ray_directions);
508
515 void setVoxelTransmissionProbability(int P_denom, int P_trans, const helios::int3 &ijk);
516
523 void getVoxelTransmissionProbability(const helios::int3 &ijk, int &P_denom, int &P_trans) const;
524
530 void setVoxelRbar(float r_bar, const helios::int3 &ijk);
531
537 float getVoxelRbar(const helios::int3 &ijk) const;
538
546 void getVoxelRayHitCounts(const helios::int3 &ijk, int &hit_before, int &hit_after, int &hit_inside) const;
547
553 std::vector<float> getVoxelRayPathLengths(const helios::int3 &ijk) const;
554
558 void clearVoxelData();
559
560 // -------- FEATURE 4: COLLISION MINIMIZATION --------
561
569 int optimizeLayout(const std::vector<uint> &UUIDs, float learning_rate = 0.01f, int max_iterations = 1000);
570
571 // -------- SPATIAL OPTIMIZATION --------
572
580 std::vector<std::pair<uint, uint>> findCollisionsWithinDistance(const std::vector<uint> &query_UUIDs, const std::vector<uint> &target_UUIDs, float max_distance);
581
586 void setMaxCollisionDistance(float distance);
587
592 [[nodiscard]] float getMaxCollisionDistance() const;
593
601 std::vector<uint> filterGeometryByDistance(const helios::vec3 &query_center, float max_radius, const std::vector<uint> &candidate_UUIDs = {});
602
617 bool findNearestPrimitiveDistance(const helios::vec3 &origin, const helios::vec3 &direction, const std::vector<uint> &candidate_UUIDs, float &distance, helios::vec3 &obstacle_direction);
618
635 bool findNearestSolidObstacleInCone(const helios::vec3 &apex, const helios::vec3 &axis, float half_angle, float height, const std::vector<uint> &candidate_UUIDs, float &distance, helios::vec3 &obstacle_direction, int num_rays = 64);
636
638
655 bool findNearestSolidObstacleInCone(const helios::vec3 &apex, const helios::vec3 &axis, float half_angle, float height, const std::vector<uint> &candidate_UUIDs, const std::vector<uint> &plant_primitives, float &distance,
656 helios::vec3 &obstacle_direction, int num_rays = 64);
657
658
659 // -------- BVH MANAGEMENT --------
660
665 void buildBVH(const std::vector<uint> &UUIDs = {});
666
672 void updateBVH(const std::vector<uint> &UUIDs, bool force_rebuild = false);
673
678 void setStaticGeometry(const std::vector<uint> &UUIDs);
679
683 void rebuildBVH();
684
689
694
699
704
711 void buildStaticBVH();
712
721 void enableTreeBasedBVH(float isolation_distance = 5.0f);
722
726 void disableTreeBasedBVH();
727
732 [[nodiscard]] bool isTreeBasedBVHEnabled() const;
733
738
747 void registerTree(uint tree_object_id, const std::vector<uint> &tree_primitives);
748
756 void setStaticObstacles(const std::vector<uint> &obstacle_primitives);
757
769 std::vector<uint> getRelevantGeometryForTree(const helios::vec3 &query_position, const std::vector<uint> &query_primitives = {}, float max_distance = 15.0f);
770
775 [[nodiscard]] bool isBVHValid() const;
776
777 // -------- GPU ACCELERATION CONTROL --------
778
783
788
793 [[nodiscard]] bool isGPUAccelerationEnabled() const;
794
795 // -------- UTILITY METHODS --------
796
800 void disableMessages();
801
805 void enableMessages();
806
811 [[nodiscard]] size_t getPrimitiveCount() const;
812
819 void getBVHStatistics(size_t &node_count, size_t &leaf_count, size_t &max_depth) const;
820
825 static int selfTest(int argc, char **argv);
826
827private:
829 helios::Context *context;
830
832 bool gpu_acceleration_enabled;
833
835 bool printmessages;
836
837 // -------- THREAD-SAFE PRIMITIVE CACHE --------
838
842 struct CachedPrimitive {
844 std::vector<helios::vec3> vertices;
845
846 CachedPrimitive() : type(helios::PRIMITIVE_TYPE_TRIANGLE) {
847 }
848 CachedPrimitive(helios::PrimitiveType t, const std::vector<helios::vec3> &v) : type(t), vertices(v) {
849 }
850 };
851
853 std::unordered_map<uint, CachedPrimitive> primitive_cache;
854
858 void buildPrimitiveCache();
859
863 HitResult intersectPrimitiveThreadSafe(const helios::vec3 &origin, const helios::vec3 &direction, uint primitive_id, float max_distance);
864
868 bool triangleIntersect(const helios::vec3 &origin, const helios::vec3 &direction, const helios::vec3 &v0, const helios::vec3 &v1, const helios::vec3 &v2, float &distance);
869
870 bool patchIntersect(const helios::vec3 &origin, const helios::vec3 &direction, const helios::vec3 &v0, const helios::vec3 &v1, const helios::vec3 &v2, const helios::vec3 &v3, float &distance);
871
872 // -------- BVH DATA STRUCTURES --------
873
877 struct BVHNode {
878 helios::vec3 aabb_min;
879 helios::vec3 aabb_max;
880 uint left_child;
881 uint right_child;
882 uint primitive_start;
883 uint primitive_count;
884 bool is_leaf;
885
886 BVHNode() : aabb_min(0, 0, 0), aabb_max(0, 0, 0), left_child(0xFFFFFFFF), right_child(0xFFFFFFFF), primitive_start(0), primitive_count(0), is_leaf(false) {
887 }
888 };
889
894 struct BVHNodesSoA {
895 // Hot data: frequently accessed during traversal (cache-friendly grouping)
896 std::vector<helios::vec3> aabb_mins;
897 std::vector<helios::vec3> aabb_maxs;
898 std::vector<uint32_t> left_children;
899 std::vector<uint32_t> right_children;
900
901 // Cold data: accessed less frequently (separate for better cache utilization)
902 std::vector<uint32_t> primitive_starts;
903 std::vector<uint32_t> primitive_counts;
904 std::vector<uint8_t> is_leaf_flags;
905
906 // Metadata
907 size_t node_count = 0;
908
909 BVHNodesSoA() = default;
910
914 void reserve(size_t capacity) {
915 aabb_mins.reserve(capacity);
916 aabb_maxs.reserve(capacity);
917 left_children.reserve(capacity);
918 right_children.reserve(capacity);
919 primitive_starts.reserve(capacity);
920 primitive_counts.reserve(capacity);
921 is_leaf_flags.reserve(capacity);
922 }
923
927 void clear() {
928 aabb_mins.clear();
929 aabb_maxs.clear();
930 left_children.clear();
931 right_children.clear();
932 primitive_starts.clear();
933 primitive_counts.clear();
934 is_leaf_flags.clear();
935 node_count = 0;
936 }
937
941 [[nodiscard]] size_t getMemoryUsage() const {
942 return (aabb_mins.size() + aabb_maxs.size()) * sizeof(helios::vec3) + (left_children.size() + right_children.size() + primitive_starts.size() + primitive_counts.size()) * sizeof(uint32_t) + is_leaf_flags.size() * sizeof(uint8_t);
943 }
944 };
945
946
948 std::vector<BVHNode> bvh_nodes;
949
951 size_t next_available_node_index;
952
954 BVHNodesSoA bvh_nodes_soa;
955
958
960 std::vector<uint> primitive_indices;
961
963 std::unordered_map<uint, std::pair<helios::vec3, helios::vec3>> primitive_aabbs_cache;
964
966 std::unordered_set<uint> dirty_primitive_cache;
967
969 std::vector<std::vector<std::vector<std::vector<uint>>>> grid_cells;
970
972 helios::vec3 grid_center;
973 helios::vec3 grid_size;
974 helios::int3 grid_divisions;
975
976 // -------- VOXEL RAY STATISTICS DATA --------
977
979 std::vector<std::vector<std::vector<int>>> voxel_ray_counts;
980
982 std::vector<std::vector<std::vector<int>>> voxel_transmitted;
983
985 std::vector<std::vector<std::vector<float>>> voxel_path_lengths;
986
988 std::vector<std::vector<std::vector<int>>> voxel_hit_before;
989
991 std::vector<std::vector<std::vector<int>>> voxel_hit_after;
992
994 std::vector<std::vector<std::vector<int>>> voxel_hit_inside;
995
997 std::vector<std::vector<std::vector<std::vector<float>>>> voxel_individual_path_lengths;
998
999 // -------- OPTIMIZED FLAT ARRAY DATA (Structure-of-Arrays) --------
1000
1002 std::vector<int> voxel_ray_counts_flat;
1003 std::vector<int> voxel_transmitted_flat;
1004 std::vector<float> voxel_path_lengths_flat;
1005 std::vector<int> voxel_hit_before_flat;
1006 std::vector<int> voxel_hit_after_flat;
1007 std::vector<int> voxel_hit_inside_flat;
1008
1010 std::vector<float> voxel_individual_path_lengths_flat;
1011 std::vector<size_t> voxel_individual_path_offsets; // Start offset for each voxel
1012 std::vector<size_t> voxel_individual_path_counts; // Count for each voxel
1013
1015 bool use_flat_arrays;
1016
1018 bool voxel_data_initialized;
1019
1021 helios::vec3 voxel_grid_center;
1022 helios::vec3 voxel_grid_size;
1023 helios::int3 voxel_grid_divisions;
1024
1025 // -------- SPATIAL OPTIMIZATION DATA --------
1026
1028 float max_collision_distance;
1029
1031 std::unordered_map<uint, helios::vec3> primitive_centroids_cache;
1032
1033 // -------- GPU MEMORY POINTERS --------
1034
1036 void *d_bvh_nodes;
1037
1039 uint *d_primitive_indices;
1040
1042 bool gpu_memory_allocated;
1043
1045 std::set<uint> last_processed_uuids;
1046
1048 std::set<uint> last_processed_deleted_uuids;
1049
1051 std::set<uint> static_geometry_cache;
1052
1054 std::set<uint> last_bvh_geometry;
1055
1057 bool bvh_dirty;
1058
1060 bool soa_dirty;
1061
1063 bool automatic_bvh_rebuilds;
1064
1066 mutable bool batch_mode_skip_bvh_check;
1067
1068 // -------- HIERARCHICAL BVH DATA STRUCTURES --------
1069
1071 bool hierarchical_bvh_enabled;
1072
1074 std::vector<BVHNode> static_bvh_nodes;
1075
1077 std::vector<uint> static_bvh_primitives;
1078
1080 bool static_bvh_valid;
1081
1083 std::set<uint> last_static_bvh_geometry;
1084
1086 void updateHierarchicalBVH(const std::set<uint> &requested_geometry, bool force_rebuild);
1087
1088 // -------- TREE-BASED BVH DATA STRUCTURES --------
1089
1090 // Forward declaration
1091 struct TreeBVH;
1092
1094 bool tree_based_bvh_enabled;
1095
1097 float tree_isolation_distance;
1098
1100 std::unordered_map<uint, uint> object_to_tree_map;
1101
1103 std::vector<uint> static_obstacle_primitives;
1104
1106 struct ObstacleSpatialGrid {
1107 float cell_size;
1108 std::unordered_map<int64_t, std::vector<uint>> grid_cells;
1109
1110 [[nodiscard]] int64_t getGridKey(float x, float y) const {
1111 auto grid_x = static_cast<int32_t>(std::floor(x / cell_size));
1112 auto grid_y = static_cast<int32_t>(std::floor(y / cell_size));
1113 return (static_cast<int64_t>(grid_x) << 32) | static_cast<uint32_t>(grid_y);
1114 }
1115
1116 [[nodiscard]] std::vector<uint> getRelevantObstacles(const helios::vec3 &position, float radius) const;
1117 };
1118
1119 mutable ObstacleSpatialGrid obstacle_spatial_grid;
1120 bool obstacle_spatial_grid_initialized;
1121
1122 // -------- GAP DETECTION DATA STRUCTURES --------
1123
1127 struct RaySample {
1128 helios::vec3 direction;
1129 float distance;
1130 bool is_free;
1131 };
1132
1136 struct Gap {
1137 helios::vec3 center_direction;
1138 float angular_size;
1139 float angular_distance;
1140 float score;
1141 std::vector<int> sample_indices;
1142 };
1143
1147 struct SpatialHashGrid {
1148 struct Cell {
1149 std::vector<size_t> sample_indices;
1150 };
1151
1152 std::vector<std::vector<Cell>> grid;
1153 int theta_resolution;
1154 int phi_resolution;
1155 float theta_step;
1156 float phi_step;
1157
1158 explicit SpatialHashGrid(int theta_res = 32, int phi_res = 16) : theta_resolution(theta_res), phi_resolution(phi_res) {
1159 grid.resize(theta_resolution);
1160 for (auto &row: grid) {
1161 row.resize(phi_resolution);
1162 }
1163 theta_step = M_PI / theta_resolution;
1164 phi_step = 2.0f * M_PI / phi_resolution;
1165 }
1166
1167 void clear() {
1168 for (auto &row: grid) {
1169 for (auto &cell: row) {
1170 cell.sample_indices.clear();
1171 }
1172 }
1173 }
1174
1175 [[nodiscard]] std::pair<int, int> getGridIndex(const helios::vec3 &direction) const {
1176 // Convert direction to spherical coordinates
1177 float theta = acosf(std::max(-1.0f, std::min(1.0f, direction.z)));
1178 float phi = atan2f(direction.y, direction.x);
1179 if (phi < 0)
1180 phi += 2.0f * M_PI;
1181
1182 int theta_idx = std::min((int) (theta / theta_step), theta_resolution - 1);
1183 int phi_idx = std::min((int) (phi / phi_step), phi_resolution - 1);
1184
1185 return {theta_idx, phi_idx};
1186 }
1187
1188 void addSample(size_t sample_idx, const helios::vec3 &direction) {
1189 auto [theta_idx, phi_idx] = getGridIndex(direction);
1190 grid[theta_idx][phi_idx].sample_indices.push_back(sample_idx);
1191 }
1192
1193 [[nodiscard]] std::vector<size_t> getNearbyIndices(const helios::vec3 &direction, int radius = 1) const {
1194 auto [center_theta, center_phi] = getGridIndex(direction);
1195 std::vector<size_t> nearby_indices;
1196
1197 for (int dt = -radius; dt <= radius; dt++) {
1198 for (int dp = -radius; dp <= radius; dp++) {
1199 int theta_idx = center_theta + dt;
1200 int phi_idx = (center_phi + dp + phi_resolution) % phi_resolution;
1201
1202 if (theta_idx >= 0 && theta_idx < theta_resolution) {
1203 const auto &cell = grid[theta_idx][phi_idx];
1204 nearby_indices.insert(nearby_indices.end(), cell.sample_indices.begin(), cell.sample_indices.end());
1205 }
1206 }
1207 }
1208
1209 return nearby_indices;
1210 }
1211 };
1212
1216 struct TreeBVH {
1217 uint tree_object_id;
1218 helios::vec3 tree_center;
1219 float tree_radius;
1220 std::vector<BVHNode> nodes;
1221 std::vector<uint> primitive_indices;
1222 BVHNodesSoA soa_structure;
1223 bool soa_dirty;
1224
1225 TreeBVH() : tree_object_id(0), tree_center(0, 0, 0), tree_radius(0), soa_dirty(true) {
1226 }
1227
1228 void clear() {
1229 nodes.clear();
1230 primitive_indices.clear();
1231 soa_structure = BVHNodesSoA();
1232 soa_dirty = true;
1233 }
1234 };
1235
1237 std::unordered_map<uint, TreeBVH> tree_bvh_map;
1238
1239 // -------- PRIVATE HELPER METHODS --------
1240
1247 void ensureBVHCurrent();
1248
1255 void calculateAABB(const std::vector<uint> &primitives, helios::vec3 &aabb_min, helios::vec3 &aabb_max) const;
1256
1268 void buildBVHRecursive(uint node_index, size_t primitive_start, size_t primitive_count, int depth);
1269
1276 std::vector<uint> traverseBVH_CPU(const helios::vec3 &query_aabb_min, const helios::vec3 &query_aabb_max);
1277
1278#ifdef HELIOS_CUDA_AVAILABLE
1286 std::vector<uint> traverseBVH_GPU(const helios::vec3 &query_aabb_min, const helios::vec3 &query_aabb_max);
1287#endif
1288
1297 bool aabbIntersect(const helios::vec3 &min1, const helios::vec3 &max1, const helios::vec3 &min2, const helios::vec3 &max2);
1298
1309 bool rayAABBIntersect(const helios::vec3 &origin, const helios::vec3 &direction, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max, float &t_min, float &t_max) const;
1310
1322 uint32_t rayAABBIntersectSIMD(const helios::vec3 *ray_origins, const helios::vec3 *ray_directions, const helios::vec3 *aabb_mins, const helios::vec3 *aabb_maxs, float *t_mins, float *t_maxs, int count);
1323
1331 void traverseBVHSIMD(const helios::vec3 *ray_origins, const helios::vec3 *ray_directions, int count, HitResult *results);
1332
1336 void traverseBVHSIMDImpl(const helios::vec3 *ray_origins, const helios::vec3 *ray_directions, int count, HitResult *results);
1337
1345 bool coneAABBIntersect(const Cone &cone, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max);
1346
1355 bool coneAABBIntersectFast(const Cone &cone, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max);
1356
1367 bool coneAABBIntersect(const helios::vec3 &cone_origin, const helios::vec3 &cone_direction, float cone_angle, float max_distance, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max);
1368
1376 int countRayIntersections(const helios::vec3 &origin, const helios::vec3 &direction, float max_distance = -1.0f);
1377
1387 bool findNearestRayIntersection(const helios::vec3 &origin, const helios::vec3 &direction, const std::set<uint> &candidate_UUIDs, float &nearest_distance, float max_distance = -1.0f);
1388
1397 std::vector<helios::vec3> sampleDirectionsInCone(const helios::vec3 &apex, const helios::vec3 &central_axis, float half_angle, int num_samples);
1398
1399 // -------- GAP DETECTION HELPER METHODS --------
1400
1410 std::vector<Gap> detectGapsInCone(const helios::vec3 &apex, const helios::vec3 &central_axis, float half_angle, float height, int num_samples);
1411
1412
1421 std::vector<uint> getCandidatePrimitivesInCone(const helios::vec3 &apex, const helios::vec3 &central_axis, float half_angle, float height);
1422
1432 std::vector<uint> getCandidatesUsingSpatialGrid(const Cone &cone, const helios::vec3 &apex, const helios::vec3 &central_axis, float half_angle, float height);
1433
1440 float calculateGapAngularSize(const std::vector<RaySample> &gap_samples, const helios::vec3 &central_axis);
1441
1447 void scoreGapsByFishEyeMetric(std::vector<Gap> &gaps, const helios::vec3 &central_axis);
1448
1455 helios::vec3 findOptimalGapDirection(const std::vector<Gap> &gaps, const helios::vec3 &central_axis);
1456
1457 // -------- VOXEL RAY PATH LENGTH HELPER METHODS --------
1458
1465 void initializeVoxelData(const helios::vec3 &grid_center, const helios::vec3 &grid_size, const helios::int3 &grid_divisions);
1466
1472 void calculateVoxelRayPathLengths_CPU(const std::vector<helios::vec3> &ray_origins, const std::vector<helios::vec3> &ray_directions);
1473
1479 void calculateVoxelRayPathLengths_GPU(const std::vector<helios::vec3> &ray_origins, const std::vector<helios::vec3> &ray_directions);
1480
1486 bool validateVoxelIndices(const helios::int3 &ijk) const;
1487
1494 void calculateVoxelAABB(const helios::int3 &ijk, helios::vec3 &voxel_min, helios::vec3 &voxel_max) const;
1495
1502 std::vector<std::pair<helios::int3, float>> traverseVoxelGrid(const helios::vec3 &ray_origin, const helios::vec3 &ray_direction) const;
1503
1511 inline size_t flatIndex(int i, int j, int k) const {
1512 return static_cast<size_t>(i) * static_cast<size_t>(voxel_grid_divisions.y) * static_cast<size_t>(voxel_grid_divisions.z) + static_cast<size_t>(j) * static_cast<size_t>(voxel_grid_divisions.z) + static_cast<size_t>(k);
1513 }
1514
1520 inline size_t flatIndex(const helios::int3 &ijk) const {
1521 return flatIndex(ijk.x, ijk.y, ijk.z);
1522 }
1523
1524#ifdef HELIOS_CUDA_AVAILABLE
1528 void allocateGPUMemory();
1529
1533 void freeGPUMemory();
1534
1538 void transferBVHToGPU();
1539#endif
1540
1544 void markBVHDirty();
1545
1552 void incrementalUpdateBVH(const std::set<uint> &added_geometry, const std::set<uint> &removed_geometry, const std::set<uint> &final_geometry);
1553
1558 void updatePrimitiveAABBCache(uint uuid);
1559
1564 void optimizedRebuildBVH(const std::set<uint> &final_geometry);
1565
1571 bool validateUUIDs(const std::vector<uint> &UUIDs) const;
1572
1581 bool rayPrimitiveIntersection(const helios::vec3 &origin, const helios::vec3 &direction, uint primitive_UUID, float &distance) const;
1582
1589 void castRaysCPU(const std::vector<RayQuery> &ray_queries, std::vector<HitResult> &results, RayTracingStats &stats);
1590
1591#ifdef HELIOS_CUDA_AVAILABLE
1598 void castRaysGPU(const std::vector<RayQuery> &ray_queries, std::vector<HitResult> &results, RayTracingStats &stats);
1599#endif
1600
1601 // -------- OPTIMIZED RAY TRACING PRIVATE METHODS --------
1602
1606 void convertBVHLayout(BVHOptimizationMode from_mode, BVHOptimizationMode to_mode);
1607 void ensureOptimizedBVH(); // Populate optimized BVH structures on demand
1608
1612 std::vector<HitResult> castRaysSoA(const std::vector<RayQuery> &ray_queries, RayTracingStats &stats);
1613
1617 HitResult castRaySoATraversal(const RayQuery &query, RayTracingStats &stats);
1618
1623 HitResult castRayBVHTraversal(const RayQuery &query);
1624
1628 inline bool aabbIntersectSoA(const helios::vec3 &ray_origin, const helios::vec3 &ray_direction, float max_distance, size_t node_index) const;
1629
1634 bool rayAABBIntersect(const helios::vec3 &ray_origin, const helios::vec3 &ray_direction, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max) const;
1635
1639 HitResult intersectPrimitive(const RayQuery &query, uint primitive_id);
1640
1650 bool rayAABBIntersectPrimitive(const helios::vec3 &origin, const helios::vec3 &direction, const helios::vec3 &aabb_min, const helios::vec3 &aabb_max, float &distance);
1651
1652 // -------- RASTERIZATION-BASED COLLISION DETECTION --------
1653
1660 int calculateOptimalBinCount(float cone_half_angle, int geometry_count);
1661
1668 std::vector<uint> filterPrimitivesParallel(const Cone &cone, const std::vector<uint> &primitive_uuids);
1669
1676 void projectGeometryToBins(const Cone &cone, const std::vector<uint> &filtered_uuids, AngularBins &bins);
1677
1684 std::vector<Gap> findGapsInCoverageMap(const AngularBins &bins, const Cone &cone);
1685
1695 bool sphericalCoordsToBinIndices(float theta, float phi, const AngularBins &bins, int &theta_bin, int &phi_bin);
1696
1705 float cartesianToSphericalCone(const helios::vec3 &vector, const helios::vec3 &cone_axis, float &theta, float &phi);
1706
1713 void projectGeometryToBinsSerial(const Cone &cone, const std::vector<uint> &filtered_uuids, AngularBins &bins);
1714
1724 Gap floodFillGap(const AngularBins &bins, int start_theta, int start_phi, std::vector<std::vector<bool>> &visited, const Cone &cone);
1725
1734 float calculateBinSolidAngle(int theta_bin, int phi_bin, const AngularBins &bins, float cone_half_angle);
1735
1744 helios::vec3 binIndicesToCartesian(int theta_bin, int phi_bin, const AngularBins &bins, const Cone &cone);
1745
1754 void addUnoccupiedNeighbors(int theta, int phi, const AngularBins &bins, std::vector<std::vector<bool>> &visited, std::queue<std::pair<int, int>> &queue);
1755};
1756
1757#endif