💿🐜 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.

518 lines
18 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 "entity/systems/terrain.hpp"
  20. #include "entity/components/celestial-body.hpp"
  21. #include "entity/components/observer.hpp"
  22. #include "entity/components/terrain.hpp"
  23. #include "geom/meshes/grid.hpp"
  24. #include "geom/mesh-functions.hpp"
  25. #include "geom/morton.hpp"
  26. #include "geom/quadtree.hpp"
  27. #include "geom/spherical.hpp"
  28. #include "gl/vertex-attribute-type.hpp"
  29. #include "math/constants.hpp"
  30. #include "math/quaternion-operators.hpp"
  31. #include "renderer/vertex-attributes.hpp"
  32. #include "utility/fundamental-types.hpp"
  33. #include <functional>
  34. #include <iostream>
  35. namespace entity {
  36. namespace system {
  37. terrain::terrain(entity::registry& registry):
  38. updatable(registry),
  39. patch_subdivisions(0),
  40. patch_base_mesh(nullptr),
  41. patch_vertex_size(0),
  42. patch_vertex_count(0),
  43. patch_vertex_data(nullptr),
  44. patch_scene_collection(nullptr),
  45. max_error(0.0)
  46. {
  47. // Build set of quaternions to rotate quadtree cube coordinates into BCBF space according to face index
  48. face_rotations[0] = math::quaternion<double>::identity(); // +x
  49. face_rotations[1] = math::quaternion<double>::rotate_z(math::pi<double>); // -x
  50. face_rotations[2] = math::quaternion<double>::rotate_z( math::half_pi<double>); // +y
  51. face_rotations[3] = math::quaternion<double>::rotate_z(-math::half_pi<double>); // -y
  52. face_rotations[4] = math::quaternion<double>::rotate_y(-math::half_pi<double>); // +z
  53. face_rotations[5] = math::quaternion<double>::rotate_y( math::half_pi<double>); // -z
  54. // Specify vertex size and stride
  55. // (position + uv + normal + tangent + barycentric + target)
  56. patch_vertex_size = 3 + 2 + 3 + 4 + 3 + 3;
  57. patch_vertex_stride = patch_vertex_size * sizeof(float);
  58. // Init patch subdivisions to zero
  59. set_patch_subdivisions(0);
  60. registry.on_construct<component::terrain>().connect<&terrain::on_terrain_construct>(this);
  61. registry.on_destroy<component::terrain>().connect<&terrain::on_terrain_destroy>(this);
  62. }
  63. terrain::~terrain()
  64. {}
  65. void terrain::update(double t, double dt)
  66. {
  67. // Refine the level of detail of each terrain quadsphere
  68. registry.view<component::terrain, component::celestial_body>().each(
  69. [&](entity::id terrain_eid, const auto& terrain_component, const auto& terrain_body)
  70. {
  71. // Retrieve terrain quadsphere
  72. terrain_quadsphere* quadsphere = terrain_quadspheres[terrain_eid];
  73. // For each observer
  74. this->registry.view<component::observer>().each(
  75. [&](entity::id observer_eid, const auto& observer)
  76. {
  77. // Skip observers with invalid reference body
  78. if (!this->registry.has<component::celestial_body>(observer.reference_body_eid) ||
  79. !this->registry.has<component::terrain>(observer.reference_body_eid))
  80. return;
  81. // Get celestial body and terrain component of observer reference body
  82. const auto& reference_celestial_body = this->registry.get<component::celestial_body>(observer.reference_body_eid);
  83. const auto& reference_terrain = this->registry.get<component::terrain>(observer.reference_body_eid);
  84. // Calculate reference BCBF-space position of observer.
  85. //double3 observer_spherical = {reference_celestial_body.radius + observer.elevation, observer.latitude, observer.longitude};
  86. double3 observer_spherical = {observer.elevation, observer.latitude, observer.longitude};
  87. double3 observer_cartesian = geom::spherical::to_cartesian(observer_spherical);
  88. observer_cartesian = math::type_cast<double>(observer.camera->get_translation());
  89. /// @TODO Transform observer position into BCBF space of terrain body (use orbit component?)
  90. // For each terrain quadsphere face
  91. for (int i = 0; i < 6; ++i)
  92. {
  93. terrain_quadsphere_face& quadsphere_face = quadsphere->faces[i];
  94. // Get the quadsphere faces's quadtree
  95. quadtree_type& quadtree = quadsphere_face.quadtree;
  96. // Clear quadsphere face quadtree
  97. quadtree.clear();
  98. // For each node in the face quadtree
  99. for (auto node_it = quadtree.begin(); node_it != quadtree.end(); ++node_it)
  100. {
  101. quadtree_node_type node = *node_it;
  102. // Skip non leaf nodes
  103. if (!quadtree.is_leaf(node))
  104. continue;
  105. // Extract node depth
  106. quadtree_type::node_type node_depth = quadtree_type::depth(node);
  107. // Skip nodes at max depth level
  108. if (node_depth >= terrain_component.max_lod)
  109. continue;
  110. // Extract node location from Morton location code
  111. quadtree_type::node_type node_location = quadtree_type::location(node);
  112. quadtree_type::node_type node_location_x;
  113. quadtree_type::node_type node_location_y;
  114. geom::morton::decode(node_location, node_location_x, node_location_y);
  115. const double nodes_per_axis = std::exp2(node_depth);
  116. const double node_width = 2.0 / nodes_per_axis;
  117. // Determine node center on front face of unit BCBF cube.
  118. double3 center;
  119. center.y = -(nodes_per_axis * 0.5 * node_width) + node_width * 0.5;
  120. center.z = center.y;
  121. center.y += static_cast<double>(node_location_x) * node_width;
  122. center.z += static_cast<double>(node_location_y) * node_width;
  123. center.x = 1.0;
  124. // Rotate node center according to cube face
  125. /// @TODO Rather than rotating every center, "unrotate" observer position 6 times
  126. center = face_rotations[i] * center;
  127. // Project node center onto unit sphere
  128. double xx = center.x * center.x;
  129. double yy = center.y * center.y;
  130. double zz = center.z * center.z;
  131. center.x *= std::sqrt(std::max(0.0, 1.0 - yy * 0.5 - zz * 0.5 + yy * zz / 3.0));
  132. center.y *= std::sqrt(std::max(0.0, 1.0 - xx * 0.5 - zz * 0.5 + xx * zz / 3.0));
  133. center.z *= std::sqrt(std::max(0.0, 1.0 - xx * 0.5 - yy * 0.5 + xx * yy / 3.0));
  134. // Scale node center by body radius
  135. center *= terrain_body.radius;
  136. center.y -= terrain_body.radius;
  137. //center *= 50.0;
  138. const double horizontal_fov = observer.camera->get_fov();
  139. const double horizontal_resolution = 1920.0;
  140. const double distance = math::length(center - observer_cartesian);
  141. const double geometric_error = static_cast<double>(524288.0 / std::exp2(node_depth));
  142. const double screen_error = screen_space_error(horizontal_fov, horizontal_resolution, distance, geometric_error);
  143. if (screen_error > max_error)
  144. {
  145. //std::cout << screen_error << std::endl;
  146. quadtree.insert(quadtree_type::child(node, 0));
  147. }
  148. }
  149. }
  150. });
  151. });
  152. // Handle meshes and models for each terrain patch
  153. registry.view<component::terrain, component::celestial_body>().each(
  154. [&](entity::id terrain_eid, const auto& terrain_component, const auto& terrain_body)
  155. {
  156. // Retrieve terrain quadsphere
  157. terrain_quadsphere* quadsphere = terrain_quadspheres[terrain_eid];
  158. // For each terrain quadsphere face
  159. for (int i = 0; i < 6; ++i)
  160. {
  161. terrain_quadsphere_face& quadsphere_face = quadsphere->faces[i];
  162. const quadtree_type& quadtree = quadsphere_face.quadtree;
  163. // For each quadtree node
  164. for (auto node_it = quadtree.unordered_begin(); node_it != quadtree.unordered_end(); ++node_it)
  165. {
  166. quadtree_node_type node = *node_it;
  167. // Look up cached patch for this node
  168. auto patch_it = quadsphere_face.patches.find(node);
  169. // If there is no cached patch instance for this node
  170. if (patch_it == quadsphere_face.patches.end())
  171. {
  172. // Construct a terrain patch
  173. terrain_patch* patch = new terrain_patch();
  174. // Generate a patch mesh
  175. patch->mesh = generate_patch_mesh(i, *node_it, terrain_body.radius, terrain_component.elevation);
  176. //patch->mesh = generate_patch_mesh(i, *node_it, 50.0, terrain_component.elevation);
  177. // Generate a patch model
  178. patch->model = generate_patch_model(*patch->mesh, terrain_component.patch_material);
  179. // Construct patch model instance
  180. patch->model_instance = new scene::model_instance(patch->model);
  181. // Cache the terrain patch
  182. quadsphere_face.patches[node] = patch;
  183. // Add patch model instance to the patch scene collection
  184. if (patch_scene_collection)
  185. patch_scene_collection->add_object(patch->model_instance);
  186. }
  187. }
  188. // For each terrain pach
  189. for (auto patch_it = quadsphere_face.patches.begin(); patch_it != quadsphere_face.patches.end(); ++patch_it)
  190. {
  191. quadtree_node_type node = patch_it->first;
  192. // Set patch model instance active if its node is a leaf node, otherwise deactivate it
  193. bool active = (quadtree.contains(node) && quadtree.is_leaf(node));
  194. patch_it->second->model_instance->set_active(active);
  195. }
  196. }
  197. });
  198. }
  199. void terrain::set_patch_subdivisions(std::uint8_t n)
  200. {
  201. patch_subdivisions = n;
  202. // Rebuid patch base mesh
  203. {
  204. delete patch_base_mesh;
  205. patch_base_mesh = geom::meshes::grid_xy(2.0f, patch_subdivisions, patch_subdivisions);
  206. // Convert quads to triangle fans
  207. for (std::size_t i = 0; i < patch_base_mesh->get_faces().size(); ++i)
  208. {
  209. geom::mesh::face* face = patch_base_mesh->get_faces()[i];
  210. std::size_t edge_count = 1;
  211. for (geom::mesh::edge* edge = face->edge->next; edge != face->edge; edge = edge->next)
  212. ++edge_count;
  213. if (edge_count > 3)
  214. {
  215. geom::poke_face(*patch_base_mesh, face->index);
  216. --i;
  217. }
  218. }
  219. }
  220. // Transform patch base mesh coordinates to match the front face of a BCBF cube
  221. const math::quaternion<float> xy_to_zy = math::quaternion<float>::rotate_y(-math::half_pi<float>);
  222. for (geom::mesh::vertex* vertex: patch_base_mesh->get_vertices())
  223. {
  224. vertex->position = xy_to_zy * vertex->position;
  225. vertex->position.x = 1.0f;
  226. }
  227. // Recalculate number of vertices per patch
  228. patch_vertex_count = patch_base_mesh->get_faces().size() * 3;
  229. // Resize patch vertex data buffer
  230. delete[] patch_vertex_data;
  231. patch_vertex_data = new float[patch_vertex_count * patch_vertex_size];
  232. }
  233. void terrain::set_patch_scene_collection(scene::collection* collection)
  234. {
  235. patch_scene_collection = collection;
  236. }
  237. void terrain::set_max_error(double error)
  238. {
  239. max_error = error;
  240. }
  241. void terrain::on_terrain_construct(entity::registry& registry, entity::id entity_id, component::terrain& component)
  242. {
  243. terrain_quadsphere* quadsphere = new terrain_quadsphere();
  244. terrain_quadspheres[entity_id] = quadsphere;
  245. }
  246. void terrain::on_terrain_destroy(entity::registry& registry, entity::id entity_id)
  247. {
  248. // Find terrain quadsphere for the given entity ID
  249. auto quadsphere_it = terrain_quadspheres.find(entity_id);
  250. if (quadsphere_it != terrain_quadspheres.end())
  251. {
  252. terrain_quadsphere* quadsphere = quadsphere_it->second;
  253. // For each terrain quadsphere face
  254. for (int i = 0; i < 6; ++i)
  255. {
  256. terrain_quadsphere_face& quadsphere_face = quadsphere->faces[i];
  257. for (auto patch_it = quadsphere_face.patches.begin(); patch_it != quadsphere_face.patches.end(); ++patch_it)
  258. {
  259. terrain_patch* patch = patch_it->second;
  260. if (patch_scene_collection)
  261. patch_scene_collection->remove_object(patch->model_instance);
  262. delete patch->model_instance;
  263. delete patch->model;
  264. delete patch->mesh;
  265. delete patch;
  266. }
  267. }
  268. // Free terrain quadsphere
  269. delete quadsphere;
  270. }
  271. // Remove terrain quadsphere from the map
  272. terrain_quadspheres.erase(quadsphere_it);
  273. }
  274. geom::mesh* terrain::generate_patch_mesh(std::uint8_t face_index, quadtree_node_type node, double body_radius, const std::function<double(double, double)>& elevation) const
  275. {
  276. // Extract node depth
  277. const quadtree_type::node_type depth = quadtree_type::depth(node);
  278. // Extract node Morton location code and decode location
  279. const quadtree_type::node_type location = quadtree_type::location(node);
  280. quadtree_type::node_type location_x;
  281. quadtree_type::node_type location_y;
  282. geom::morton::decode(location, location_x, location_y);
  283. const double nodes_per_axis = std::exp2(depth);
  284. const double scale_yz = 1.0 / nodes_per_axis;
  285. const double node_width = 2.0 / nodes_per_axis;
  286. // Determine vertex offset according to node location
  287. double offset_y = -(nodes_per_axis * 0.5 * node_width) + node_width * 0.5;
  288. double offset_z = offset_y;
  289. offset_y += static_cast<double>(location_x) * node_width;
  290. offset_z += static_cast<double>(location_y) * node_width;
  291. // Copy base mesh
  292. geom::mesh* patch_mesh = new geom::mesh(*patch_base_mesh);
  293. // Modify patch mesh vertex positions
  294. for (geom::mesh::vertex* v: patch_mesh->get_vertices())
  295. {
  296. double3 position = math::type_cast<double>(v->position);
  297. // Offset and scale vertex position
  298. position.y *= scale_yz;
  299. position.z *= scale_yz;
  300. position.y += offset_y;
  301. position.z += offset_z;
  302. // Rotate according to cube face
  303. position = face_rotations[face_index] * position;
  304. // Project onto unit sphere
  305. //position = math::normalize(position);
  306. // Cartesian Spherical Cube projection (KSC)
  307. /// @see https://catlikecoding.com/unity/tutorials/cube-sphere/
  308. /// @see https://core.ac.uk/download/pdf/228552506.pdf
  309. double xx = position.x * position.x;
  310. double yy = position.y * position.y;
  311. double zz = position.z * position.z;
  312. position.x *= std::sqrt(std::max(0.0, 1.0 - yy * 0.5 - zz * 0.5 + yy * zz / 3.0));
  313. position.y *= std::sqrt(std::max(0.0, 1.0 - xx * 0.5 - zz * 0.5 + xx * zz / 3.0));
  314. position.z *= std::sqrt(std::max(0.0, 1.0 - xx * 0.5 - yy * 0.5 + xx * yy / 3.0));
  315. // Calculate latitude and longitude of vertex position
  316. const double latitude = std::atan2(position.z, std::sqrt(position.x * position.x + position.y * position.y));
  317. const double longitude = std::atan2(position.y, position.x);
  318. // Look up elevation at latitude and longitude and use to calculate radial distance
  319. const double radial_distance = body_radius + elevation(latitude, longitude);
  320. // Scale vertex position by radial distance
  321. position *= radial_distance;
  322. position.y -= body_radius;
  323. v->position = math::type_cast<float>(position);
  324. }
  325. return patch_mesh;
  326. }
  327. model* terrain::generate_patch_model(const geom::mesh& patch_mesh, material* patch_material) const
  328. {
  329. // Barycentric coordinates
  330. static const float3 barycentric[3] =
  331. {
  332. {1, 0, 0},
  333. {0, 1, 0},
  334. {0, 0, 1}
  335. };
  336. // Fill vertex data buffer
  337. float* v = patch_vertex_data;
  338. for (const geom::mesh::face* face: patch_mesh.get_faces())
  339. {
  340. const geom::mesh::vertex* a = face->edge->vertex;
  341. const geom::mesh::vertex* b = face->edge->next->vertex;
  342. const geom::mesh::vertex* c = face->edge->previous->vertex;
  343. const geom::mesh::vertex* face_vertices[] = {a, b, c};
  344. // Calculate facted normal
  345. float3 normal = math::normalize(math::cross(b->position - a->position, c->position - a->position));
  346. for (std::size_t i = 0; i < 3; ++i)
  347. {
  348. const geom::mesh::vertex* vertex = face_vertices[i];
  349. // Vertex position
  350. const float3& position = vertex->position;
  351. *(v++) = position.x;
  352. *(v++) = position.y;
  353. *(v++) = position.z;
  354. // Vertex UV coordinates (latitude, longitude)
  355. const float latitude = std::atan2(position.z, std::sqrt(position.x * position.x + position.y * position.y));
  356. const float longitude = std::atan2(position.y, position.x);
  357. *(v++) = latitude;
  358. *(v++) = longitude;
  359. // Vertex normal
  360. *(v++) = normal.x;
  361. *(v++) = normal.y;
  362. *(v++) = normal.z;
  363. /// @TODO Vertex tangent
  364. *(v++) = 0.0f;
  365. *(v++) = 0.0f;
  366. *(v++) = 0.0f;
  367. *(v++) = 0.0f;
  368. // Vertex barycentric coordinates
  369. *(v++) = barycentric[i].x;
  370. *(v++) = barycentric[i].y;
  371. *(v++) = barycentric[i].z;
  372. // Vertex morph target (LOD transition)
  373. *(v++) = 0.0f;
  374. *(v++) = 0.0f;
  375. *(v++) = 0.0f;
  376. }
  377. }
  378. // Get triangle count of patch mesh
  379. std::size_t patch_triangle_count = patch_mesh.get_faces().size();
  380. // Allocate patch model
  381. model* patch_model = new model();
  382. // Resize model VBO and upload vertex data
  383. gl::vertex_buffer* vbo = patch_model->get_vertex_buffer();
  384. vbo->resize(patch_triangle_count * 3 * patch_vertex_stride, patch_vertex_data);
  385. // Bind vertex attributes to model VAO
  386. gl::vertex_array* vao = patch_model->get_vertex_array();
  387. std::size_t offset = 0;
  388. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, patch_vertex_stride, 0);
  389. offset += 3;
  390. vao->bind_attribute(VERTEX_TEXCOORD_LOCATION, *vbo, 2, gl::vertex_attribute_type::float_32, patch_vertex_stride, sizeof(float) * offset);
  391. offset += 2;
  392. vao->bind_attribute(VERTEX_NORMAL_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, patch_vertex_stride, sizeof(float) * offset);
  393. offset += 3;
  394. vao->bind_attribute(VERTEX_TANGENT_LOCATION, *vbo, 4, gl::vertex_attribute_type::float_32, patch_vertex_stride, sizeof(float) * offset);
  395. offset += 4;
  396. vao->bind_attribute(VERTEX_BARYCENTRIC_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, patch_vertex_stride, sizeof(float) * offset);
  397. offset += 3;
  398. vao->bind_attribute(VERTEX_TARGET_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, patch_vertex_stride, sizeof(float) * offset);
  399. offset += 3;
  400. // Create model group
  401. model_group* patch_model_group = patch_model->add_group("terrain");
  402. patch_model_group->set_material(patch_material);
  403. patch_model_group->set_drawing_mode(gl::drawing_mode::triangles);
  404. patch_model_group->set_start_index(0);
  405. patch_model_group->set_index_count(patch_triangle_count * 3);
  406. // Calculate model bounds
  407. geom::aabb<float> bounds = geom::calculate_bounds(patch_mesh);
  408. patch_model->set_bounds(bounds);
  409. return patch_model;
  410. }
  411. double terrain::screen_space_error(double horizontal_fov, double horizontal_resolution, double distance, double geometric_error)
  412. {
  413. // Calculate view frustum width at given distance
  414. const double frustum_width = 2.0 * distance * std::tan(horizontal_fov * 0.5);
  415. return (geometric_error * horizontal_resolution) / frustum_width;
  416. }
  417. } // namespace system
  418. } // namespace entity