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

655 lines
20 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 "game/system/terrain.hpp"
  20. #include "game/component/terrain.hpp"
  21. #include "game/component/camera.hpp"
  22. #include "geom/meshes/grid.hpp"
  23. #include "geom/mesh-functions.hpp"
  24. #include "geom/morton.hpp"
  25. #include "geom/quadtree.hpp"
  26. #include "gl/vertex-attribute.hpp"
  27. #include "math/quaternion-operators.hpp"
  28. #include "render/vertex-attribute.hpp"
  29. #include "utility/fundamental-types.hpp"
  30. #include <functional>
  31. #include <iostream>
  32. namespace game {
  33. namespace system {
  34. terrain::terrain(entity::registry& registry):
  35. updatable(registry),
  36. patch_side_length(0.0f),
  37. patch_subdivisions(0),
  38. patch_material(nullptr),
  39. elevation_function(nullptr),
  40. scene_collection(nullptr),
  41. patch_base_mesh(nullptr),
  42. patch_vertex_size(0),
  43. patch_vertex_stride(0),
  44. patch_vertex_data(nullptr)
  45. {
  46. // Specify vertex size and stride
  47. // (position + uv + normal + tangent + barycentric + target)
  48. patch_vertex_size = 3 + 2 + 3 + 4 + 3 + 3;
  49. patch_vertex_stride = patch_vertex_size * sizeof(float);
  50. // Init quadtee node sizes at each depth
  51. for (std::size_t i = 0; i <= quadtree_type::max_depth; ++i)
  52. quadtree_node_size[i] = 0.0f;
  53. registry.on_construct<component::terrain>().connect<&terrain::on_terrain_construct>(this);
  54. registry.on_update<component::terrain>().connect<&terrain::on_terrain_update>(this);
  55. registry.on_destroy<component::terrain>().connect<&terrain::on_terrain_destroy>(this);
  56. }
  57. terrain::~terrain()
  58. {
  59. registry.on_construct<component::terrain>().disconnect<&terrain::on_terrain_construct>(this);
  60. registry.on_update<component::terrain>().disconnect<&terrain::on_terrain_update>(this);
  61. registry.on_destroy<component::terrain>().disconnect<&terrain::on_terrain_destroy>(this);
  62. }
  63. void terrain::update(double t, double dt)
  64. {
  65. // Clear quadtree
  66. quadtree.clear();
  67. // For each camera
  68. this->registry.view<component::camera>().each
  69. (
  70. [&](entity::id camera_eid, const auto& camera)
  71. {
  72. if (!camera.object)
  73. return;
  74. const scene::camera& cam = *camera.object;
  75. // for (int i = 0; i < 8; ++i)
  76. // std::cout << "corner " << i << ": " << cam.get_view_frustum().get_corners()[i] << std::endl;
  77. geom::ray<float> rays[8];
  78. rays[0] = cam.pick({-1, -1});
  79. rays[1] = cam.pick({-1, 1});
  80. rays[2] = cam.pick({ 1, 1});
  81. rays[3] = cam.pick({ 1, -1});
  82. float3 ntl = rays[0].origin;
  83. float3 nbl = rays[1].origin;
  84. float3 nbr = rays[2].origin;
  85. float3 ntr = rays[3].origin;
  86. float3 ftl = rays[0].origin + rays[0].direction * (cam.get_clip_far() - cam.get_clip_near());
  87. float3 fbl = rays[1].origin + rays[1].direction * (cam.get_clip_far() - cam.get_clip_near());
  88. float3 fbr = rays[2].origin + rays[2].direction * (cam.get_clip_far() - cam.get_clip_near());
  89. float3 ftr = rays[3].origin + rays[3].direction * (cam.get_clip_far() - cam.get_clip_near());
  90. // for (int i = 0; i < 8; ++i)
  91. // std::cout << "ray or " << i << ": " << rays[i].origin << std::endl;
  92. geom::convex_hull<float> hull(6);
  93. hull.planes[0] = geom::plane<float>(ftl, fbl, nbl);
  94. hull.planes[1] = geom::plane<float>(ntr, nbr, fbr);
  95. hull.planes[2] = geom::plane<float>(fbl, fbr, nbr);
  96. hull.planes[3] = geom::plane<float>(ftl, ntl, ntr);
  97. hull.planes[4] = geom::plane<float>(ntl, nbl, nbr);
  98. hull.planes[5] = geom::plane<float>(ftr, fbr, fbl);
  99. geom::sphere<float> sphere;
  100. sphere.center = cam.get_translation();
  101. sphere.radius = cam.get_clip_far() * 0.25;
  102. //visit_quadtree(cam.get_view_frustum().get_bounds(), quadtree_type::root);
  103. visit_quadtree(sphere, quadtree_type::root);
  104. }
  105. );
  106. //std::cout << "qsize: " << quadtree.size() << std::endl;
  107. std::size_t qvis = 0;
  108. /// Toggle visibility of terrain scene objects
  109. for (auto it = patches.begin(); it != patches.end(); ++it)
  110. {
  111. bool active = (quadtree.contains(it->first) && quadtree.is_leaf(it->first));
  112. it->second->model_instance->set_active(active);
  113. if (active)
  114. ++qvis;
  115. }
  116. //std::cout << "qvis: " << qvis << std::endl;
  117. }
  118. void terrain::set_patch_side_length(float length)
  119. {
  120. patch_side_length = length;
  121. // Recalculate node sizes at each quadtree depth
  122. for (std::size_t i = 0; i <= quadtree_type::max_depth; ++i)
  123. {
  124. quadtree_node_size[i] = std::exp2(quadtree_type::max_depth - i) * patch_side_length;
  125. //std::cout << quadtree_node_size[i] << std::endl;
  126. }
  127. }
  128. void terrain::set_patch_subdivisions(std::size_t n)
  129. {
  130. patch_subdivisions = n;
  131. // Recalculate patch properties
  132. patch_cell_count = (patch_subdivisions + 1) * (patch_subdivisions + 1);
  133. patch_triangle_count = patch_cell_count * 4;
  134. // Resize patch vertex data buffer
  135. delete[] patch_vertex_data;
  136. patch_vertex_data = new float[patch_triangle_count * 3 * patch_vertex_size];
  137. // Resize patch buffers
  138. std::size_t vertex_buffer_row_size = patch_subdivisions + 4;
  139. std::size_t vertex_buffer_column_size = vertex_buffer_row_size * 2;
  140. patch_vertex_buffer.resize(vertex_buffer_row_size);
  141. for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
  142. patch_vertex_buffer[i].resize(vertex_buffer_column_size);
  143. rebuild_patch_base_mesh();
  144. }
  145. void terrain::set_patch_material(::render::material* material)
  146. {
  147. patch_material = material;
  148. }
  149. void terrain::set_elevation_function(const std::function<float(float, float)>& f)
  150. {
  151. elevation_function = f;
  152. }
  153. void terrain::set_scene_collection(scene::collection* collection)
  154. {
  155. scene_collection = collection;
  156. }
  157. void terrain::on_terrain_construct(entity::registry& registry, entity::id entity_id)
  158. {
  159. }
  160. void terrain::on_terrain_update(entity::registry& registry, entity::id entity_id)
  161. {
  162. }
  163. void terrain::on_terrain_destroy(entity::registry& registry, entity::id entity_id)
  164. {
  165. }
  166. float terrain::get_patch_size(quadtree_node_type node) const
  167. {
  168. return quadtree_node_size[quadtree_type::depth(node)];
  169. }
  170. float3 terrain::get_patch_center(quadtree_node_type node) const
  171. {
  172. const float node_size = get_patch_size(node);
  173. const float node_offset = quadtree_node_size[0] * -0.5f + node_size * 0.5f;
  174. // Extract node location from Morton location code
  175. quadtree_type::node_type node_location = quadtree_type::location(node);
  176. quadtree_type::node_type node_location_x;
  177. quadtree_type::node_type node_location_y;
  178. geom::morton::decode(node_location, node_location_x, node_location_y);
  179. return float3
  180. {
  181. node_offset + static_cast<float>(node_location_x) * node_size,
  182. 0.0f,
  183. node_offset + static_cast<float>(node_location_y) * node_size
  184. };
  185. }
  186. void terrain::rebuild_patch_base_mesh()
  187. {
  188. // Rebuild grid
  189. delete patch_base_mesh;
  190. patch_base_mesh = geom::meshes::grid_xy(1.0f, patch_subdivisions, patch_subdivisions);
  191. // Convert quads to triangle fans
  192. for (std::size_t i = 0; i < patch_base_mesh->get_faces().size(); ++i)
  193. {
  194. geom::mesh::face* face = patch_base_mesh->get_faces()[i];
  195. std::size_t edge_count = 1;
  196. for (geom::mesh::edge* edge = face->edge->next; edge != face->edge; edge = edge->next)
  197. ++edge_count;
  198. if (edge_count > 3)
  199. {
  200. geom::poke_face(*patch_base_mesh, face->index);
  201. --i;
  202. }
  203. }
  204. // Transform patch base mesh coordinates from XY plane to XZ plane
  205. const math::quaternion<float> xy_to_xz = math::quaternion<float>::rotate_x(math::half_pi<float>);
  206. for (geom::mesh::vertex* vertex: patch_base_mesh->get_vertices())
  207. {
  208. vertex->position = xy_to_xz * vertex->position;
  209. }
  210. }
  211. void terrain::visit_quadtree(const geom::bounding_volume<float>& volume, quadtree_node_type node)
  212. {
  213. const float root_offset = quadtree_node_size[0] * -0.5f;
  214. // Extract node depth
  215. quadtree_type::node_type node_depth = quadtree_type::depth(node);
  216. const float node_size = get_patch_size(node);
  217. const float3 node_center = get_patch_center(node);
  218. // Build node bounds AABB
  219. geom::aabb<float> node_bounds;
  220. node_bounds.min_point =
  221. {
  222. node_center.x() - node_size * 0.5f,
  223. quadtree_node_size[quadtree_type::max_depth] * -0.5f,
  224. node_center.z() - node_size * 0.5f
  225. };
  226. node_bounds.max_point =
  227. {
  228. node_bounds.min_point[0] + node_size,
  229. node_bounds.min_point[1] + quadtree_node_size[quadtree_type::max_depth],
  230. node_bounds.min_point[2] + node_size
  231. };
  232. // If volume intersects node
  233. if (volume.intersects(node_bounds))
  234. {
  235. // Subdivide leaf nodes
  236. if (quadtree.is_leaf(node))
  237. {
  238. quadtree.insert(quadtree_type::child(node, 0));
  239. for (quadtree_node_type i = 0; i < quadtree_type::children_per_node; ++i)
  240. {
  241. quadtree_node_type child = quadtree_type::child(node, i);
  242. if (patches.find(child) == patches.end())
  243. {
  244. patch* child_patch = generate_patch(child);
  245. patches[child] = child_patch;
  246. scene_collection->add_object(child_patch->model_instance);
  247. }
  248. }
  249. }
  250. // Visit children
  251. if (node_depth < quadtree_type::max_depth - 1)
  252. {
  253. for (quadtree_node_type i = 0; i < quadtree_type::children_per_node; ++i)
  254. visit_quadtree(volume, quadtree_type::child(node, i));
  255. }
  256. }
  257. }
  258. geom::mesh* terrain::generate_patch_mesh(quadtree_node_type node) const
  259. {
  260. // Extract node depth
  261. const quadtree_type::node_type node_depth = quadtree_type::depth(node);
  262. // Get size of node at depth
  263. const float node_size = quadtree_node_size[node_depth];
  264. // Extract node Morton location code and decode location
  265. const quadtree_type::node_type node_location = quadtree_type::location(node);
  266. quadtree_type::node_type node_location_x;
  267. quadtree_type::node_type node_location_y;
  268. geom::morton::decode(node_location, node_location_x, node_location_y);
  269. // Determine center of node
  270. const float node_offset = quadtree_node_size[0] * -0.5f + node_size * 0.5f;
  271. const float3 node_center =
  272. {
  273. node_offset + static_cast<float>(node_location_x) * node_size,
  274. 0.0f,
  275. node_offset + static_cast<float>(node_location_y) * node_size
  276. };
  277. // Copy patch base mesh
  278. geom::mesh* patch_mesh = new geom::mesh(*patch_base_mesh);
  279. // Modify patch mesh vertex positions
  280. for (geom::mesh::vertex* v: patch_mesh->get_vertices())
  281. {
  282. v->position.x() = node_center.x() + v->position.x() * node_size;
  283. v->position.z() = node_center.z() + v->position.z() * node_size;
  284. v->position.y() = elevation_function(v->position.x(), v->position.z());
  285. }
  286. return patch_mesh;
  287. }
  288. ::render::model* terrain::generate_patch_model(quadtree_node_type node) const
  289. {
  290. // Get size and position of patch
  291. const float patch_size = get_patch_size(node);
  292. const float3 patch_center = get_patch_center(node);
  293. // Calculate size of a patch cell
  294. const float cell_size = patch_size / static_cast<float>(patch_subdivisions + 1);
  295. const float half_cell_size = cell_size * 0.5f;
  296. // Init patch bounds
  297. geom::aabb<float> patch_bounds;
  298. patch_bounds.min_point.x() = patch_center.x() - patch_size * 0.5f;
  299. patch_bounds.min_point.y() = std::numeric_limits<float>::infinity();
  300. patch_bounds.min_point.z() = patch_center.z() - patch_size * 0.5f;
  301. patch_bounds.max_point.x() = patch_center.x() + patch_size * 0.5f;
  302. patch_bounds.max_point.y() = -std::numeric_limits<float>::infinity();
  303. patch_bounds.max_point.z() = patch_center.z() + patch_size * 0.5f;
  304. // Calculate positions of patch vertices and immediately neighboring vertices
  305. float3 first_vertex_position =
  306. {
  307. patch_bounds.min_point.x() - cell_size,
  308. patch_center.y(),
  309. patch_bounds.min_point.z() - cell_size
  310. };
  311. float3 vertex_position = first_vertex_position;
  312. for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
  313. {
  314. // For each column
  315. for (std::size_t j = 0; j < patch_vertex_buffer[i].size(); j += 2)
  316. {
  317. // Get elevation of vertex
  318. vertex_position.y() = elevation_function(vertex_position.x(), vertex_position.z());
  319. // Update patch bounds
  320. patch_bounds.min_point.y() = std::min(patch_bounds.min_point.y(), vertex_position.y());
  321. patch_bounds.max_point.y() = std::max(patch_bounds.max_point.y(), vertex_position.y());
  322. patch_vertex_buffer[i][j].position = vertex_position;
  323. vertex_position.x() += cell_size;
  324. }
  325. vertex_position.z() += cell_size;
  326. vertex_position.x() = first_vertex_position.x();
  327. }
  328. first_vertex_position.x() += cell_size * 0.5f;
  329. first_vertex_position.z() += cell_size * 0.5f;
  330. vertex_position = first_vertex_position;
  331. for (std::size_t i = 0; i < patch_vertex_buffer.size(); ++i)
  332. {
  333. // For each column
  334. for (std::size_t j = 1; j < patch_vertex_buffer[i].size(); j += 2)
  335. {
  336. // Get elevation of vertex
  337. vertex_position.y() = elevation_function(vertex_position.x(), vertex_position.z());
  338. // Update patch bounds
  339. patch_bounds.min_point.y() = std::min(patch_bounds.min_point.y(), vertex_position.y());
  340. patch_bounds.max_point.y() = std::max(patch_bounds.max_point.y(), vertex_position.y());
  341. patch_vertex_buffer[i][j].position = vertex_position;
  342. vertex_position.x() += cell_size;
  343. }
  344. vertex_position.z() += cell_size;
  345. vertex_position.x() = first_vertex_position.x();
  346. }
  347. // Calculate tangents, bitangents, and normals of patch vertices
  348. for (std::size_t i = 1; i < patch_vertex_buffer.size() - 1; ++i)
  349. {
  350. // For each column
  351. for (std::size_t j = 2; j < patch_vertex_buffer[i].size() - 3; ++j)
  352. {
  353. const float3& c = patch_vertex_buffer[i ][j ].position;
  354. const float3& n = patch_vertex_buffer[i+1][j ].position;
  355. const float3& s = patch_vertex_buffer[i-1][j ].position;
  356. const float3& e = patch_vertex_buffer[i ][j+2].position;
  357. const float3& w = patch_vertex_buffer[i ][j-2].position;
  358. const float3 tangent = math::normalize(float3{2.0f, (e.y() - w.y()) / cell_size, 0.0f});
  359. const float3 bitangent = math::normalize(float3{0.0f, (n.y() - s.y()) / cell_size, 2.0f});
  360. const float3 normal = math::cross(bitangent, tangent);
  361. const float bitangent_sign = std::copysign(1.0f, math::dot(math::cross(normal, tangent), bitangent));
  362. patch_vertex_buffer[i][j].uv.x() = (c.x() - patch_bounds.min_point.x()) / patch_size;
  363. patch_vertex_buffer[i][j].uv.y() = (c.z() - patch_bounds.min_point.z()) / patch_size;
  364. patch_vertex_buffer[i][j].normal = normal;
  365. patch_vertex_buffer[i][j].tangent = {tangent.x(), tangent.y(), tangent.z(), bitangent_sign};
  366. }
  367. }
  368. /*
  369. 0 subdivisions:
  370. +---+---+---+
  371. | |
  372. + +---+ +
  373. | | | |
  374. + +---+ +
  375. | |
  376. +---+---+---+
  377. 1 subdivision:
  378. +---+---+---+---+
  379. | |
  380. + +---+---+ +
  381. | | | | |
  382. + +---+---+ +
  383. | | | | |
  384. + +---+---+ +
  385. | |
  386. +---+---+---+---+
  387. 2 subdivisions:
  388. +---+---+---+---+---+
  389. | x x x x x | x
  390. + +---+---+---+ +
  391. | x | x | x | x | x | x
  392. + +---+---+---+ +
  393. | x | x | x | x | x | x
  394. + +---+---+---+ +
  395. | x | x | x | x | x | x
  396. + +---+---+---+ +
  397. | x x x x x | x
  398. +---+---+---+---+---+
  399. x x x x x x
  400. */
  401. // For each row
  402. float* v = patch_vertex_data;
  403. for (std::size_t i = 1; i < patch_vertex_buffer.size() - 2; ++i)
  404. {
  405. // For each column
  406. for (std::size_t j = 3; j < patch_vertex_buffer[i].size() - 4; j += 2)
  407. {
  408. // a---c
  409. // | x |
  410. // b---d
  411. const patch_vertex& x = patch_vertex_buffer[i ][j ];
  412. const patch_vertex& a = patch_vertex_buffer[i ][j-1];
  413. const patch_vertex& b = patch_vertex_buffer[i+1][j-1];
  414. const patch_vertex& c = patch_vertex_buffer[i ][j+1];
  415. const patch_vertex& d = patch_vertex_buffer[i+1][j+1];
  416. const float4& td = patch_vertex_buffer[i+1][j+1].tangent;
  417. auto add_triangle = [&v](const patch_vertex& a, const patch_vertex& b, const patch_vertex& c)
  418. {
  419. auto add_vertex = [&v](const patch_vertex& vertex, const float3& barycentric)
  420. {
  421. // Position
  422. *(v++) = vertex.position[0];
  423. *(v++) = vertex.position[1];
  424. *(v++) = vertex.position[2];
  425. // UV
  426. *(v++) = vertex.uv[0];
  427. *(v++) = vertex.uv[1];
  428. // Normal
  429. *(v++) = vertex.normal[0];
  430. *(v++) = vertex.normal[1];
  431. *(v++) = vertex.normal[2];
  432. /// Tangent
  433. *(v++) = vertex.tangent[0];
  434. *(v++) = vertex.tangent[1];
  435. *(v++) = vertex.tangent[2];
  436. *(v++) = vertex.tangent[3];
  437. // Barycentric
  438. *(v++) = barycentric[0];
  439. *(v++) = barycentric[1];
  440. *(v++) = barycentric[2];
  441. // Morph target (LOD transition)
  442. *(v++) = 0.0f;
  443. *(v++) = 0.0f;
  444. *(v++) = 0.0f;
  445. };
  446. add_vertex(a, float3{1, 0, 0});
  447. add_vertex(b, float3{0, 1, 0});
  448. add_vertex(c, float3{0, 0, 1});
  449. };
  450. add_triangle(x, a, b);
  451. add_triangle(x, b, d);
  452. add_triangle(x, d, c);
  453. add_triangle(x, c, a);
  454. // add_triangle(a, b, c);
  455. // add_triangle(c, b, d);
  456. }
  457. }
  458. // Allocate patch model
  459. ::render::model* patch_model = new ::render::model();
  460. // Get model VBO and VAO
  461. gl::vertex_buffer* vbo = patch_model->get_vertex_buffer();
  462. gl::vertex_array* vao = patch_model->get_vertex_array();
  463. // Resize model VBO and upload vertex data
  464. vbo->resize(patch_triangle_count * 3 * patch_vertex_stride, patch_vertex_data);
  465. std::size_t attribute_offset = 0;
  466. // Define position vertex attribute
  467. gl::vertex_attribute position_attribute;
  468. position_attribute.buffer = vbo;
  469. position_attribute.offset = attribute_offset;
  470. position_attribute.stride = patch_vertex_stride;
  471. position_attribute.type = gl::vertex_attribute_type::float_32;
  472. position_attribute.components = 3;
  473. attribute_offset += position_attribute.components * sizeof(float);
  474. // Define UV vertex attribute
  475. gl::vertex_attribute uv_attribute;
  476. uv_attribute.buffer = vbo;
  477. uv_attribute.offset = attribute_offset;
  478. uv_attribute.stride = patch_vertex_stride;
  479. uv_attribute.type = gl::vertex_attribute_type::float_32;
  480. uv_attribute.components = 2;
  481. attribute_offset += uv_attribute.components * sizeof(float);
  482. // Define normal vertex attribute
  483. gl::vertex_attribute normal_attribute;
  484. normal_attribute.buffer = vbo;
  485. normal_attribute.offset = attribute_offset;
  486. normal_attribute.stride = patch_vertex_stride;
  487. normal_attribute.type = gl::vertex_attribute_type::float_32;
  488. normal_attribute.components = 3;
  489. attribute_offset += normal_attribute.components * sizeof(float);
  490. // Define tangent vertex attribute
  491. gl::vertex_attribute tangent_attribute;
  492. tangent_attribute.buffer = vbo;
  493. tangent_attribute.offset = attribute_offset;
  494. tangent_attribute.stride = patch_vertex_stride;
  495. tangent_attribute.type = gl::vertex_attribute_type::float_32;
  496. tangent_attribute.components = 4;
  497. attribute_offset += tangent_attribute.components * sizeof(float);
  498. // Define barycentric vertex attribute
  499. gl::vertex_attribute barycentric_attribute;
  500. barycentric_attribute.buffer = vbo;
  501. barycentric_attribute.offset = attribute_offset;
  502. barycentric_attribute.stride = patch_vertex_stride;
  503. barycentric_attribute.type = gl::vertex_attribute_type::float_32;
  504. barycentric_attribute.components = 3;
  505. attribute_offset += barycentric_attribute.components * sizeof(float);
  506. // Define target vertex attribute
  507. gl::vertex_attribute target_attribute;
  508. target_attribute.buffer = vbo;
  509. target_attribute.offset = attribute_offset;
  510. target_attribute.stride = patch_vertex_stride;
  511. target_attribute.type = gl::vertex_attribute_type::float_32;
  512. target_attribute.components = 3;
  513. attribute_offset += target_attribute.components * sizeof(float);
  514. // Bind vertex attributes to VAO
  515. vao->bind(::render::vertex_attribute::position, position_attribute);
  516. vao->bind(::render::vertex_attribute::uv, uv_attribute);
  517. vao->bind(::render::vertex_attribute::normal, normal_attribute);
  518. vao->bind(::render::vertex_attribute::tangent, tangent_attribute);
  519. vao->bind(::render::vertex_attribute::barycentric, barycentric_attribute);
  520. vao->bind(::render::vertex_attribute::target, target_attribute);
  521. // Create model group
  522. ::render::model_group* patch_model_group = patch_model->add_group("terrain");
  523. patch_model_group->set_material(patch_material);
  524. patch_model_group->set_drawing_mode(gl::drawing_mode::triangles);
  525. patch_model_group->set_start_index(0);
  526. patch_model_group->set_index_count(patch_triangle_count * 3);
  527. // Set patch model bounds
  528. patch_model->set_bounds(patch_bounds);
  529. return patch_model;
  530. }
  531. terrain::patch* terrain::generate_patch(quadtree_node_type node)
  532. {
  533. patch* node_patch = new patch();
  534. node_patch->mesh = nullptr;//generate_patch_mesh(node);
  535. node_patch->model = generate_patch_model(node);
  536. node_patch->model_instance = new scene::model_instance(node_patch->model);
  537. return node_patch;
  538. }
  539. } // namespace system
  540. } // namespace game