💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

484 lines
14 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "subterrain-system.hpp"
  20. #include "ecs/components/model-component.hpp"
  21. #include "ecs/components/cavity-component.hpp"
  22. #include "ecs/entity.hpp"
  23. #include "renderer/model.hpp"
  24. #include "renderer/material.hpp"
  25. #include "geom/mesh-functions.hpp"
  26. #include "renderer/vertex-attributes.hpp"
  27. #include "rasterizer/vertex-attribute-type.hpp"
  28. #include "rasterizer/drawing-mode.hpp"
  29. #include "rasterizer/vertex-buffer.hpp"
  30. #include "resources/resource-manager.hpp"
  31. #include "geom/marching-cubes.hpp"
  32. #include "geom/intersection.hpp"
  33. #include "utility/fundamental-types.hpp"
  34. #include <array>
  35. #include <limits>
  36. namespace ecs {
  37. /**
  38. * An octree containing cubes for the marching cubes algorithm.
  39. */
  40. struct cube_tree
  41. {
  42. public:
  43. cube_tree(const geom::aabb<float>& bounds, int max_depth);
  44. ~cube_tree();
  45. const bool is_leaf() const;
  46. const geom::aabb<float>& get_bounds() const;
  47. /// Subdivides all nodes intersecting with a region to the max depth.
  48. void subdivide_max(const geom::aabb<float>& region);
  49. /// Fills a list with all leaf nodes that intersect with a region.
  50. void query_leaves(std::list<cube_tree*>& nodes, const geom::aabb<float>& region);
  51. void visit_leaves(const geom::aabb<float>& region, const std::function<void(cube_tree&)>& f);
  52. /// Counts then number of nodes in the octree.
  53. std::size_t size() const;
  54. cube_tree* children[8];
  55. float3 corners[8];
  56. float distances[8];
  57. const int max_depth;
  58. const int depth;
  59. const geom::aabb<float> bounds;
  60. private:
  61. cube_tree(const geom::aabb<float>& bounds, int max_depth, int depth);
  62. void subdivide();
  63. };
  64. cube_tree::cube_tree(const geom::aabb<float>& bounds, int max_depth):
  65. cube_tree(bounds, max_depth, 0)
  66. {}
  67. cube_tree::cube_tree(const geom::aabb<float>& bounds, int max_depth, int depth):
  68. bounds(bounds),
  69. max_depth(max_depth),
  70. depth(depth)
  71. {
  72. corners[0] = {bounds.min_point.x, bounds.min_point.y, bounds.min_point.z};
  73. corners[1] = {bounds.max_point.x, bounds.min_point.y, bounds.min_point.z};
  74. corners[2] = {bounds.max_point.x, bounds.max_point.y, bounds.min_point.z};
  75. corners[3] = {bounds.min_point.x, bounds.max_point.y, bounds.min_point.z};
  76. corners[4] = {bounds.min_point.x, bounds.min_point.y, bounds.max_point.z};
  77. corners[5] = {bounds.max_point.x, bounds.min_point.y, bounds.max_point.z};
  78. corners[6] = {bounds.max_point.x, bounds.max_point.y, bounds.max_point.z};
  79. corners[7] = {bounds.min_point.x, bounds.max_point.y, bounds.max_point.z};
  80. for (int i = 0; i < 8; ++i)
  81. {
  82. children[i] = nullptr;
  83. distances[i] = -std::numeric_limits<float>::infinity();
  84. // For outside normals
  85. //distances[i] = std::numeric_limits<float>::infinity();
  86. }
  87. }
  88. cube_tree::~cube_tree()
  89. {
  90. for (cube_tree* child: children)
  91. delete child;
  92. }
  93. void cube_tree::subdivide_max(const geom::aabb<float>& region)
  94. {
  95. if (depth != max_depth && aabb_aabb_intersection(bounds, region))
  96. {
  97. if (is_leaf())
  98. subdivide();
  99. for (cube_tree* child: children)
  100. child->subdivide_max(region);
  101. }
  102. }
  103. void cube_tree::query_leaves(std::list<cube_tree*>& nodes, const geom::aabb<float>& region)
  104. {
  105. if (aabb_aabb_intersection(bounds, region))
  106. {
  107. if (is_leaf())
  108. {
  109. nodes.push_back(this);
  110. }
  111. else
  112. {
  113. for (cube_tree* child: children)
  114. child->query_leaves(nodes, region);
  115. }
  116. }
  117. }
  118. void cube_tree::visit_leaves(const geom::aabb<float>& region, const std::function<void(cube_tree&)>& f)
  119. {
  120. if (aabb_aabb_intersection(bounds, region))
  121. {
  122. if (is_leaf())
  123. {
  124. f(*this);
  125. }
  126. else
  127. {
  128. for (cube_tree* child: children)
  129. child->visit_leaves(region, f);
  130. }
  131. }
  132. }
  133. std::size_t cube_tree::size() const
  134. {
  135. std::size_t node_count = 1;
  136. if (!is_leaf())
  137. {
  138. for (cube_tree* child: children)
  139. node_count += child->size();
  140. }
  141. return node_count;
  142. }
  143. inline const bool cube_tree::is_leaf() const
  144. {
  145. return (children[0] == nullptr);
  146. }
  147. inline const geom::aabb<float>& cube_tree::get_bounds() const
  148. {
  149. return bounds;
  150. }
  151. void cube_tree::subdivide()
  152. {
  153. const float3 center = (bounds.min_point + bounds.max_point) * 0.5f;
  154. for (int i = 0; i < 8; ++i)
  155. {
  156. geom::aabb<float> child_bounds;
  157. for (int j = 0; j < 3; ++j)
  158. {
  159. child_bounds.min_point[j] = std::min<float>(corners[i][j], center[j]);
  160. child_bounds.max_point[j] = std::max<float>(corners[i][j], center[j]);
  161. }
  162. children[i] = new cube_tree(child_bounds, max_depth, depth + 1);
  163. }
  164. }
  165. subterrain_system::subterrain_system(ecs::registry& registry, ::resource_manager* resource_manager):
  166. entity_system(registry),
  167. resource_manager(resource_manager)
  168. {
  169. // Load subterrain materials
  170. subterrain_inside_material = resource_manager->load<material>("subterrain-inside.mtl");
  171. subterrain_inside_material = resource_manager->load<material>("subterrain-outside.mtl");
  172. // Allocate subterrain model
  173. subterrain_model = new model();
  174. // Create inside model group
  175. subterrain_inside_group = subterrain_model->add_group("inside");
  176. subterrain_inside_group->set_material(resource_manager->load<material>("subterrain-inside.mtl"));
  177. subterrain_inside_group->set_drawing_mode(drawing_mode::triangles);
  178. subterrain_inside_group->set_start_index(0);
  179. subterrain_inside_group->set_index_count(0);
  180. // Create outside model group
  181. subterrain_outside_group = subterrain_model->add_group("outside");
  182. subterrain_outside_group->set_material(resource_manager->load<material>("subterrain-outside.mtl"));
  183. subterrain_outside_group->set_drawing_mode(drawing_mode::triangles);
  184. subterrain_outside_group->set_start_index(0);
  185. subterrain_outside_group->set_index_count(0);
  186. // Determine vertex size (position, normal, barycentric)
  187. subterrain_model_vertex_size = 3 + 3 + 3;
  188. subterrain_model_vertex_stride = subterrain_model_vertex_size * sizeof(float);
  189. // Bind vertex attributes
  190. vertex_buffer* vbo = subterrain_model->get_vertex_buffer();
  191. vertex_array* vao = subterrain_model->get_vertex_array();
  192. std::size_t offset = 0;
  193. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, vertex_attribute_type::float_32, subterrain_model_vertex_stride, 0);
  194. offset += 3;
  195. vao->bind_attribute(VERTEX_NORMAL_LOCATION, *vbo, 3, vertex_attribute_type::float_32, subterrain_model_vertex_stride, sizeof(float) * offset);
  196. offset += 3;
  197. vao->bind_attribute(VERTEX_BARYCENTRIC_LOCATION, *vbo, 3, vertex_attribute_type::float_32, subterrain_model_vertex_stride, sizeof(float) * offset);
  198. offset += 3;
  199. // Calculate adjusted bounds to fit isosurface resolution
  200. //isosurface_resolution = 0.325f;
  201. isosurface_resolution = 0.5f;
  202. float ideal_volume_size = 200.0f;
  203. int octree_depth = std::floor(std::log(ideal_volume_size / isosurface_resolution) / std::log(2)) + 1;
  204. float adjusted_volume_size = std::pow(2.0f, octree_depth) * isosurface_resolution;
  205. // Set subterrain bounds
  206. subterrain_bounds.min_point = float3{-0.5f, -1.0f, -0.5f} * adjusted_volume_size;
  207. subterrain_bounds.max_point = float3{ 0.5f, 0.0f, 0.5f} * adjusted_volume_size;
  208. // Set subterrain model bounds
  209. subterrain_model->set_bounds(subterrain_bounds);
  210. // Allocate cube tree
  211. cube_tree = new ecs::cube_tree(subterrain_bounds, octree_depth);
  212. // Allocate mesh
  213. subterrain_mesh = new geom::mesh();
  214. first_run = true;
  215. }
  216. subterrain_system::~subterrain_system()
  217. {
  218. delete subterrain_model;
  219. delete subterrain_mesh;
  220. }
  221. void subterrain_system::update(double t, double dt)
  222. {
  223. if (first_run)
  224. {
  225. first_run = false;
  226. //auto subterrain_entity = registry.create();
  227. //registry.assign<model_component>(subterrain_entity, subterrain_model);
  228. subterrain_model_instance = new scene::model_instance(subterrain_model);
  229. collection->add_object(subterrain_model_instance);
  230. }
  231. bool digging = false;
  232. registry.view<cavity_component>().each(
  233. [this, &digging](ecs::entity entity, auto& cavity)
  234. {
  235. this->dig(cavity.position, cavity.radius);
  236. this->registry.destroy(entity);
  237. digging = true;
  238. });
  239. if (digging)
  240. {
  241. //std::cout << "regenerating subterrain mesh...\n";
  242. regenerate_subterrain_mesh();
  243. //std::cout << "regenerating subterrain mesh... done\n";
  244. //std::cout << "regenerating subterrain model...\n";
  245. regenerate_subterrain_model();
  246. //std::cout << "regenerating subterrain model... done\n";
  247. }
  248. }
  249. void subterrain_system::set_scene(scene::collection* collection)
  250. {
  251. this->collection = collection;
  252. }
  253. void subterrain_system::regenerate_subterrain_mesh()
  254. {
  255. delete subterrain_mesh;
  256. subterrain_mesh = new geom::mesh();
  257. subterrain_vertices.clear();
  258. subterrain_triangles.clear();
  259. subterrain_vertex_map.clear();
  260. //std::cout << "marching...\n";
  261. merged = 0;
  262. march(cube_tree);
  263. //std::cout << "merged " << merged << " vertices\n";
  264. //std::cout << "marching...done\n";
  265. //std::cout << "vertex count: " << subterrain_vertices.size() << std::endl;
  266. //std::cout << "triangle count: " << subterrain_triangles.size() << std::endl;
  267. //std::cout << "creating mesh...\n";
  268. create_triangle_mesh(*subterrain_mesh, subterrain_vertices, subterrain_triangles);
  269. //std::cout << "creating mesh... done\n";
  270. }
  271. void subterrain_system::march(ecs::cube_tree* node)
  272. {
  273. if (!node->is_leaf())
  274. {
  275. for (ecs::cube_tree* child: node->children)
  276. march(child);
  277. return;
  278. }
  279. else if (node->depth != node->max_depth)
  280. {
  281. return;
  282. }
  283. // Get node bounds
  284. const geom::aabb<float>& bounds = node->get_bounds();
  285. // Polygonize cube
  286. float vertex_buffer[12 * 3];
  287. std::uint_fast8_t vertex_count;
  288. std::int_fast8_t triangle_buffer[5 * 3];
  289. std::uint_fast8_t triangle_count;
  290. const float* corners = &node->corners[0][0];
  291. const float* distances = &node->distances[0];
  292. geom::mc::polygonize(vertex_buffer, &vertex_count, triangle_buffer, &triangle_count, corners, distances);
  293. // Remap local vertex buffer indices (0-11) to mesh vertex indices
  294. std::uint_fast32_t vertex_remap[12];
  295. for (int i = 0; i < vertex_count; ++i)
  296. {
  297. const float3& vertex = reinterpret_cast<const float3&>(vertex_buffer[i * 3]);
  298. if (auto it = subterrain_vertex_map.find(vertex); it != subterrain_vertex_map.end())
  299. {
  300. vertex_remap[i] = it->second;
  301. ++merged;
  302. }
  303. else
  304. {
  305. vertex_remap[i] = subterrain_vertices.size();
  306. subterrain_vertex_map[vertex] = subterrain_vertices.size();
  307. subterrain_vertices.push_back(vertex);
  308. }
  309. }
  310. // Add triangles
  311. for (std::uint_fast32_t i = 0; i < triangle_count; ++i)
  312. {
  313. subterrain_triangles.push_back(
  314. {
  315. vertex_remap[triangle_buffer[i * 3]],
  316. vertex_remap[triangle_buffer[i * 3 + 1]],
  317. vertex_remap[triangle_buffer[i * 3 + 2]]
  318. });
  319. }
  320. }
  321. void subterrain_system::regenerate_subterrain_model()
  322. {
  323. float3* face_normals = new float3[subterrain_mesh->get_faces().size()];
  324. calculate_face_normals(face_normals, *subterrain_mesh);
  325. static const float3 barycentric_coords[3] =
  326. {
  327. float3{1, 0, 0},
  328. float3{0, 1, 0},
  329. float3{0, 0, 1}
  330. };
  331. float* vertex_data = new float[subterrain_model_vertex_size * subterrain_mesh->get_faces().size() * 3];
  332. float* v = vertex_data;
  333. for (std::size_t i = 0; i < subterrain_mesh->get_faces().size(); ++i)
  334. {
  335. geom::mesh::face* face = subterrain_mesh->get_faces()[i];
  336. geom::mesh::edge* ab = face->edge;
  337. geom::mesh::edge* bc = face->edge->next;
  338. geom::mesh::edge* ca = face->edge->previous;
  339. geom::mesh::vertex* a = ab->vertex;
  340. geom::mesh::vertex* b = bc->vertex;
  341. geom::mesh::vertex* c = ca->vertex;
  342. geom::mesh::vertex* vertices[3] = {a, b, c};
  343. for (std::size_t j = 0; j < 3; ++j)
  344. {
  345. geom::mesh::vertex* vertex = vertices[j];
  346. float3 n = {0, 0, 0};
  347. geom::mesh::edge* start = vertex->edge;
  348. geom::mesh::edge* edge = start;
  349. do
  350. {
  351. if (edge->face)
  352. {
  353. n += face_normals[edge->face->index];
  354. }
  355. edge = edge->previous->symmetric;
  356. }
  357. while (edge != start);
  358. n = math::normalize(n);
  359. //float3 n = reinterpret_cast<const float3&>(face_normals[i * 3]);
  360. *(v++) = vertex->position[0];
  361. *(v++) = vertex->position[1];
  362. *(v++) = vertex->position[2];
  363. *(v++) = n[0];
  364. *(v++) = n[1];
  365. *(v++) = n[2];
  366. *(v++) = barycentric_coords[j][0];
  367. *(v++) = barycentric_coords[j][1];
  368. *(v++) = barycentric_coords[j][2];
  369. }
  370. }
  371. // Resized VBO and upload vertex data
  372. vertex_buffer* vbo = subterrain_model->get_vertex_buffer();
  373. vbo->resize(subterrain_mesh->get_faces().size() * 3 * subterrain_model_vertex_stride, vertex_data);
  374. // Deallocate vertex data
  375. delete[] face_normals;
  376. delete[] vertex_data;
  377. // Update model groups
  378. subterrain_inside_group->set_index_count(subterrain_mesh->get_faces().size() * 3);
  379. subterrain_outside_group->set_index_count(subterrain_mesh->get_faces().size() * 3);
  380. }
  381. void subterrain_system::dig(const float3& position, float radius)
  382. {
  383. // Construct region containing the cavity sphere
  384. geom::aabb<float> region = {position, position};
  385. for (int i = 0; i < 3; ++i)
  386. {
  387. region.min_point[i] -= radius + isosurface_resolution;
  388. region.max_point[i] += radius + isosurface_resolution;
  389. }
  390. // Subdivide the octree to the maximum depth within the region
  391. cube_tree->subdivide_max(region);
  392. // Query all octree leaf nodes within the region
  393. std::list<ecs::cube_tree*> nodes;
  394. cube_tree->visit_leaves(region,
  395. [&position, radius](ecs::cube_tree& node)
  396. {
  397. for (int i = 0; i < 8; ++i)
  398. {
  399. // For outside normals (also set node initial distance to +infinity)
  400. //float distance = math::length(node->corners[i] - position) - radius;
  401. // if (distance < node->distances[i])
  402. float distance = radius - math::length(node.corners[i] - position);
  403. if (distance > node.distances[i])
  404. node.distances[i] = distance;
  405. }
  406. });
  407. }
  408. } // namespace ecs