29 #include <unordered_set>
47 std::byte* vertex_data,
48 std::size_t vertex_count,
53 std::size_t vertex_stride,
57 std::byte* position_data = vertex_data + position_attribute.
offset;
58 std::byte* normal_data = vertex_data + normal_attribute.
offset;
59 std::byte* tangent_data = vertex_data + tangent_attribute.
offset;
60 std::byte* bone_index_data = vertex_data + bone_index_attribute.
offset;
62 for (std::size_t i = 0;
i < vertex_count; ++
i)
65 std::uint16_t&
bone_index =
reinterpret_cast<std::uint16_t&
>(*(bone_index_data + vertex_stride *
i));
69 if (entry == reskin_map.end())
74 const auto& [new_bone_index, transform] = entry->second;
77 bone_index =
static_cast<std::uint16_t
>(new_bone_index);
80 float* px =
reinterpret_cast<float*
>(position_data + vertex_stride *
i);
83 float* nx =
reinterpret_cast<float*
>(normal_data + vertex_stride *
i);
86 float* tx =
reinterpret_cast<float*
>(tangent_data + vertex_stride *
i);
117 std::span<std::byte> vertex_data,
119 std::size_t vertex_stride,
120 std::uint16_t vertex_tag
123 std::byte* bone_index_data = vertex_data.data() + bone_index_attribute.
offset;
125 for (std::size_t i = 0;
i < vertex_data.size(); ++
i)
128 std::uint16_t* bone_indices =
reinterpret_cast<std::uint16_t*
>(bone_index_data + vertex_stride *
i);
131 bone_indices[3] = vertex_tag;
143 float calculate_uv_area
145 std::span<std::byte> vertex_data,
147 std::size_t vertex_stride
150 std::byte* uv_data = vertex_data.data() + uv_attribute.
offset;
152 float sum_area = 0.0f;
154 for (std::size_t i = 0;
i + 2 < vertex_data.size();
i += 3)
156 const float* uv_data_a =
reinterpret_cast<const float*
>(uv_data + vertex_stride *
i);
157 const float* uv_data_b =
reinterpret_cast<const float*
>(uv_data + vertex_stride * (
i + 1));
158 const float* uv_data_c =
reinterpret_cast<const float*
>(uv_data + vertex_stride * (
i + 2));
160 const math::fvec3 uva = {uv_data_a[0], uv_data_a[1], 0.0f};
161 const math::fvec3 uvb = {uv_data_b[0], uv_data_b[1], 0.0f};
162 const math::fvec3 uvc = {uv_data_c[0], uv_data_c[1], 0.0f};
184 const std::byte* vertex_data,
185 std::size_t vertex_count,
187 std::size_t vertex_stride
190 const std::byte* position_data = vertex_data + position_attribute.
offset;
193 for (std::size_t i = 0;
i < vertex_count; ++
i)
195 const float* px =
reinterpret_cast<const float*
>(position_data + vertex_stride *
i);
196 const float* py = px + 1;
197 const float* pz = py + 1;
213 [[nodiscard]]
float calculate_ommatidia_scale(
float eye_uv_area,
float ommatidia_count)
216 constexpr
float source_side_length = 1.0f / math::sqrt_3<float>;
219 const float target_side_length =
std::sqrt((eye_uv_area * 2.0f) / (3.0f * math::sqrt_3<float> * ommatidia_count));
221 return source_side_length / target_side_length;
232 [[nodiscard]] std::unique_ptr<render::material> generate_ant_exoskeleton_material
239 std::unique_ptr<render::material> exoskeleton_material = std::make_unique<render::material>(*phenome.
pigmentation->
material);
242 exoskeleton_material->set_variable(
"exoskeleton_roughness", std::make_shared<render::matvar_float>(1, phenome.
sculpturing->
roughness));
245 exoskeleton_material->set_variable(
"exoskeleton_normal_map", std::make_shared<render::matvar_texture_2d>(1, phenome.
sculpturing->
normal_map));
250 const float ommatidia_scale = calculate_ommatidia_scale(eye_uv_area,
static_cast<float>(phenome.
eyes->
ommatidia_count));
251 exoskeleton_material->set_variable(
"ommatidia_scale", std::make_shared<render::matvar_float>(1, ommatidia_scale));
254 return exoskeleton_material;
277 throw std::runtime_error(
"Ant phenome missing mesosoma model");
281 throw std::runtime_error(
"Ant phenome missing legs model");
285 throw std::runtime_error(
"Ant phenome missing head model");
287 if (!mandibles_model)
289 throw std::runtime_error(
"Ant phenome missing mandibles model");
293 throw std::runtime_error(
"Ant phenome missing antennae model");
297 throw std::runtime_error(
"Ant phenome missing waist model");
301 throw std::runtime_error(
"Ant phenome missing gaster model");
305 throw std::runtime_error(
"Ant phenome missing sting model");
309 throw std::runtime_error(
"Ant phenome missing eyes model");
313 throw std::runtime_error(
"Ant phenome missing ocelli model");
317 throw std::runtime_error(
"Ant phenome missing wings model");
334 std::size_t vertex_buffer_size = 0;
335 const std::size_t mesosoma_vbo_offset = vertex_buffer_size;
336 vertex_buffer_size += mesosoma_vbo->
size();
337 const std::size_t legs_vbo_offset = vertex_buffer_size;
338 vertex_buffer_size += legs_vbo->
size();
339 const std::size_t head_vbo_offset = vertex_buffer_size;
340 vertex_buffer_size += head_vbo->
size();
341 const std::size_t mandibles_vbo_offset = vertex_buffer_size;
342 vertex_buffer_size += mandibles_vbo->
size();
343 const std::size_t antennae_vbo_offset = vertex_buffer_size;
344 vertex_buffer_size += antennae_vbo->
size();
345 const std::size_t waist_vbo_offset = vertex_buffer_size;
346 vertex_buffer_size += waist_vbo->
size();
347 const std::size_t gaster_vbo_offset = vertex_buffer_size;
348 vertex_buffer_size += gaster_vbo->
size();
349 const std::size_t sting_vbo_offset = vertex_buffer_size;
352 vertex_buffer_size += sting_vbo->
size();
354 const std::size_t eyes_vbo_offset = vertex_buffer_size;
357 vertex_buffer_size += eyes_vbo->
size();
359 const std::size_t ocelli_vbo_offset = vertex_buffer_size;
362 vertex_buffer_size += ocelli_vbo->
size();
364 std::size_t wings_vbo_offset = vertex_buffer_size;
367 vertex_buffer_size += wings_vbo->
size();
371 std::vector<std::byte> vertex_buffer_data(vertex_buffer_size);
374 mesosoma_vbo->
read({vertex_buffer_data.data() + mesosoma_vbo_offset, mesosoma_vbo->
size()});
375 legs_vbo->
read({vertex_buffer_data.data() + legs_vbo_offset, legs_vbo->
size()});
376 head_vbo->
read({vertex_buffer_data.data() + head_vbo_offset, head_vbo->
size()});
377 mandibles_vbo->
read({vertex_buffer_data.data() + mandibles_vbo_offset, mandibles_vbo->
size()});
378 antennae_vbo->
read({vertex_buffer_data.data() + antennae_vbo_offset, antennae_vbo->
size()});
379 waist_vbo->
read({vertex_buffer_data.data() + waist_vbo_offset, waist_vbo->
size()});
380 gaster_vbo->
read({vertex_buffer_data.data() + gaster_vbo_offset, gaster_vbo->
size()});
383 sting_vbo->
read({vertex_buffer_data.data() + sting_vbo_offset, sting_vbo->
size()});
387 eyes_vbo->
read({vertex_buffer_data.data() + eyes_vbo_offset, eyes_vbo->
size()});
391 ocelli_vbo->
read({vertex_buffer_data.data() + ocelli_vbo_offset, ocelli_vbo->
size()});
395 wings_vbo->
read({vertex_buffer_data.data() + wings_vbo_offset, wings_vbo->
size()});
399 std::unique_ptr<render::model> model = std::make_unique<render::model>();
402 auto& model_vao = model->get_vertex_array();
403 model_vao = std::make_unique<gl::vertex_array>(mesosoma_model->
get_vertex_array()->attributes());
411 for (
const auto& attribute: model_vao->attributes())
413 switch (attribute.location)
416 position_attribute = &attribute;
419 uv_attribute = &attribute;
422 normal_attribute = &attribute;
425 tangent_attribute = &attribute;
428 bone_index_attribute = &attribute;
436 model->set_vertex_offset(0);
446 const std::uint32_t mesosoma_vertex_count = (mesosoma_model->
get_groups()).front().vertex_count;
447 const std::uint32_t legs_vertex_count = (legs_model->
get_groups()).front().vertex_count;
448 const std::uint32_t head_vertex_count = (head_model->
get_groups()).front().vertex_count;
449 const std::uint32_t mandibles_vertex_count = (mandibles_model->
get_groups()).front().vertex_count;
450 const std::uint32_t antennae_vertex_count = (antennae_model->
get_groups()).front().vertex_count;
451 const std::uint32_t waist_vertex_count = (waist_model->
get_groups()).front().vertex_count;
452 const std::uint32_t gaster_vertex_count = (gaster_model->
get_groups()).front().vertex_count;
453 const std::uint32_t sting_vertex_count = (phenome.
sting->
present) ? (sting_model->
get_groups()).front().vertex_count : 0;
454 const std::uint32_t eyes_vertex_count = (phenome.
eyes->
present) ? (eyes_model->
get_groups()).front().vertex_count : 0;
456 const std::uint32_t wings_vertex_count = (phenome.
wings->
present) ? wings_model->
get_groups().front().vertex_count : 0;
459 const ::skeleton& mesosoma_skeleton = phenome.
mesosoma->
model->get_skeleton();
460 const ::skeleton& legs_skeleton = phenome.
legs->
model->get_skeleton();
461 const ::skeleton& head_skeleton = phenome.
head->
model->get_skeleton();
462 const ::skeleton& mandibles_skeleton = phenome.
mandibles->
model->get_skeleton();
463 const ::skeleton& antennae_skeleton = phenome.
antennae->
model->get_skeleton();
464 const ::skeleton& waist_skeleton = phenome.
waist->
model->get_skeleton();
465 const ::skeleton& gaster_skeleton = phenome.
gaster->
model->get_skeleton();
466 const ::skeleton* sting_skeleton = (phenome.
sting->
present) ? &phenome.
sting->
model->get_skeleton() :
nullptr;
467 const ::skeleton* eyes_skeleton = (phenome.
eyes->
present) ? &phenome.
eyes->
model->get_skeleton() :
nullptr;
469 const ::skeleton* wings_skeleton = (phenome.
wings->
present) ? &phenome.
wings->
model->get_skeleton() :
nullptr;
504 gaster_to_body = waist_to_body;
510 sting_to_body = gaster_to_body * get_bone_transform(gaster_skeleton,
"sting_socket");
532 const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> legs_reskin_map
534 {*legs_skeleton.get_bone_index(
"procoxa_l"), {bones.
procoxa_l, &procoxa_l_to_body}},
535 {*legs_skeleton.get_bone_index(
"profemur_l"), {bones.
profemur_l, &procoxa_l_to_body}},
536 {*legs_skeleton.get_bone_index(
"protibia_l"), {bones.
protibia_l, &procoxa_l_to_body}},
537 {*legs_skeleton.get_bone_index(
"protarsomere1_l"), {bones.
protarsomere1_l, &procoxa_l_to_body}},
538 {*legs_skeleton.get_bone_index(
"protarsomere2_l"), {bones.
protarsomere1_l, &procoxa_l_to_body}},
539 {*legs_skeleton.get_bone_index(
"protarsomere3_l"), {bones.
protarsomere1_l, &procoxa_l_to_body}},
540 {*legs_skeleton.get_bone_index(
"protarsomere4_l"), {bones.
protarsomere1_l, &procoxa_l_to_body}},
541 {*legs_skeleton.get_bone_index(
"protarsomere5_l"), {bones.
protarsomere1_l, &procoxa_l_to_body}},
542 {*legs_skeleton.get_bone_index(
"procoxa_r"), {bones.
procoxa_r, &procoxa_r_to_body}},
543 {*legs_skeleton.get_bone_index(
"profemur_r"), {bones.
profemur_r, &procoxa_r_to_body}},
544 {*legs_skeleton.get_bone_index(
"protibia_r"), {bones.
protibia_r, &procoxa_r_to_body}},
545 {*legs_skeleton.get_bone_index(
"protarsomere1_r"), {bones.
protarsomere1_r, &procoxa_r_to_body}},
546 {*legs_skeleton.get_bone_index(
"protarsomere2_r"), {bones.
protarsomere1_r, &procoxa_r_to_body}},
547 {*legs_skeleton.get_bone_index(
"protarsomere3_r"), {bones.
protarsomere1_r, &procoxa_r_to_body}},
548 {*legs_skeleton.get_bone_index(
"protarsomere4_r"), {bones.
protarsomere1_r, &procoxa_r_to_body}},
549 {*legs_skeleton.get_bone_index(
"protarsomere5_r"), {bones.
protarsomere1_r, &procoxa_r_to_body}},
550 {*legs_skeleton.get_bone_index(
"mesocoxa_l"), {bones.
mesocoxa_l, &mesocoxa_l_to_body}},
551 {*legs_skeleton.get_bone_index(
"mesofemur_l"), {bones.
mesofemur_l, &mesocoxa_l_to_body}},
552 {*legs_skeleton.get_bone_index(
"mesotibia_l"), {bones.
mesotibia_l, &mesocoxa_l_to_body}},
553 {*legs_skeleton.get_bone_index(
"mesotarsomere1_l"), {bones.
mesotarsomere1_l, &mesocoxa_l_to_body}},
554 {*legs_skeleton.get_bone_index(
"mesotarsomere2_l"), {bones.
mesotarsomere1_l, &mesocoxa_l_to_body}},
555 {*legs_skeleton.get_bone_index(
"mesotarsomere3_l"), {bones.
mesotarsomere1_l, &mesocoxa_l_to_body}},
556 {*legs_skeleton.get_bone_index(
"mesotarsomere4_l"), {bones.
mesotarsomere1_l, &mesocoxa_l_to_body}},
557 {*legs_skeleton.get_bone_index(
"mesotarsomere5_l"), {bones.
mesotarsomere1_l, &mesocoxa_l_to_body}},
558 {*legs_skeleton.get_bone_index(
"mesocoxa_r"), {bones.
mesocoxa_r, &mesocoxa_r_to_body}},
559 {*legs_skeleton.get_bone_index(
"mesofemur_r"), {bones.
mesofemur_r, &mesocoxa_r_to_body}},
560 {*legs_skeleton.get_bone_index(
"mesotibia_r"), {bones.
mesotibia_r, &mesocoxa_r_to_body}},
561 {*legs_skeleton.get_bone_index(
"mesotarsomere1_r"), {bones.
mesotarsomere1_r, &mesocoxa_r_to_body}},
562 {*legs_skeleton.get_bone_index(
"mesotarsomere2_r"), {bones.
mesotarsomere1_r, &mesocoxa_r_to_body}},
563 {*legs_skeleton.get_bone_index(
"mesotarsomere3_r"), {bones.
mesotarsomere1_r, &mesocoxa_r_to_body}},
564 {*legs_skeleton.get_bone_index(
"mesotarsomere4_r"), {bones.
mesotarsomere1_r, &mesocoxa_r_to_body}},
565 {*legs_skeleton.get_bone_index(
"mesotarsomere5_r"), {bones.
mesotarsomere1_r, &mesocoxa_r_to_body}},
566 {*legs_skeleton.get_bone_index(
"metacoxa_l"), {bones.
metacoxa_l, &metacoxa_l_to_body}},
567 {*legs_skeleton.get_bone_index(
"metafemur_l"), {bones.
metafemur_l, &metacoxa_l_to_body}},
568 {*legs_skeleton.get_bone_index(
"metatibia_l"), {bones.
metatibia_l, &metacoxa_l_to_body}},
569 {*legs_skeleton.get_bone_index(
"metatarsomere1_l"), {bones.
metatarsomere1_l, &metacoxa_l_to_body}},
570 {*legs_skeleton.get_bone_index(
"metatarsomere2_l"), {bones.
metatarsomere1_l, &metacoxa_l_to_body}},
571 {*legs_skeleton.get_bone_index(
"metatarsomere3_l"), {bones.
metatarsomere1_l, &metacoxa_l_to_body}},
572 {*legs_skeleton.get_bone_index(
"metatarsomere4_l"), {bones.
metatarsomere1_l, &metacoxa_l_to_body}},
573 {*legs_skeleton.get_bone_index(
"metatarsomere5_l"), {bones.
metatarsomere1_l, &metacoxa_l_to_body}},
574 {*legs_skeleton.get_bone_index(
"metacoxa_r"), {bones.
metacoxa_r, &metacoxa_r_to_body}},
575 {*legs_skeleton.get_bone_index(
"metafemur_r"), {bones.
metafemur_r, &metacoxa_r_to_body}},
576 {*legs_skeleton.get_bone_index(
"metatibia_r"), {bones.
metatibia_r, &metacoxa_r_to_body}},
577 {*legs_skeleton.get_bone_index(
"metatarsomere1_r"), {bones.
metatarsomere1_r, &metacoxa_r_to_body}},
578 {*legs_skeleton.get_bone_index(
"metatarsomere2_r"), {bones.
metatarsomere1_r, &metacoxa_r_to_body}},
579 {*legs_skeleton.get_bone_index(
"metatarsomere3_r"), {bones.
metatarsomere1_r, &metacoxa_r_to_body}},
580 {*legs_skeleton.get_bone_index(
"metatarsomere4_r"), {bones.
metatarsomere1_r, &metacoxa_r_to_body}},
581 {*legs_skeleton.get_bone_index(
"metatarsomere5_r"), {bones.
metatarsomere1_r, &metacoxa_r_to_body}}
585 const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> head_reskin_map
587 {*head_skeleton.get_bone_index(
"head"), {bones.
head, &head_to_body}}
591 const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> mandibles_reskin_map
593 {*mandibles_skeleton.get_bone_index(
"mandible_l"), {bones.
mandible_l, &mandible_l_to_body}},
594 {*mandibles_skeleton.get_bone_index(
"mandible_r"), {bones.
mandible_r, &mandible_r_to_body}}
598 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> antennae_reskin_map
600 {*antennae_skeleton.get_bone_index(
"antennomere1_l"), {bones.
antennomere1_l, &antenna_l_to_body}},
601 {*antennae_skeleton.get_bone_index(
"antennomere2_l"), {bones.
antennomere2_l, &antenna_l_to_body}},
602 {*antennae_skeleton.get_bone_index(
"antennomere1_r"), {bones.
antennomere1_r, &antenna_r_to_body}},
603 {*antennae_skeleton.get_bone_index(
"antennomere2_r"), {bones.
antennomere2_r, &antenna_r_to_body}}
607 const std::string antennomere_l_name =
std::format(
"antennomere{}_l", i);
608 const std::string antennomere_r_name =
std::format(
"antennomere{}_r", i);
610 const hash::fnv1a32_t antennomere_l_key = hash::fnv1a32<char>(antennomere_l_name);
611 const hash::fnv1a32_t antennomere_r_key = hash::fnv1a32<char>(antennomere_r_name);
613 antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_l_key), std::tuple(bones.
antennomere2_l, &antenna_l_to_body));
614 antennae_reskin_map.emplace(*antennae_skeleton.get_bone_index(antennomere_r_key), std::tuple(bones.
antennomere2_r, &antenna_r_to_body));
618 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> waist_reskin_map;
621 waist_reskin_map.emplace(*waist_skeleton.get_bone_index(
"petiole"), std::tuple(*bones.
petiole, &waist_to_body));
625 waist_reskin_map.emplace(*waist_skeleton.get_bone_index(
"postpetiole"), std::tuple(*bones.
postpetiole, &waist_to_body));
630 const std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> gaster_reskin_map
632 {*gaster_skeleton.get_bone_index(
"gaster"), {bones.
gaster, &gaster_to_body}}
636 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> sting_reskin_map;
639 sting_reskin_map.emplace(*sting_skeleton->get_bone_index(
"sting"), std::tuple(*bones.
sting, &sting_to_body));
643 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> eyes_reskin_map;
646 eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index(
"eye_l"), std::tuple(bones.
head, &eye_l_to_body));
647 eyes_reskin_map.emplace(*eyes_skeleton->get_bone_index(
"eye_r"), std::tuple(bones.
head, &eye_r_to_body));
651 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> ocelli_reskin_map;
654 ocelli_reskin_map.emplace(*ocelli_skeleton->get_bone_index(
"ocellus_l"), std::tuple(bones.
head, &ocellus_l_to_body));
655 ocelli_reskin_map.emplace(*ocelli_skeleton->get_bone_index(
"ocellus_r"), std::tuple(bones.
head, &ocellus_r_to_body));
656 ocelli_reskin_map.emplace(*ocelli_skeleton->get_bone_index(
"ocellus_m"), std::tuple(bones.
head, &ocellus_m_to_body));
660 reskin_vertices(vertex_buffer_data.data() + legs_vbo_offset, legs_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), legs_reskin_map);
663 reskin_vertices(vertex_buffer_data.data() + head_vbo_offset, head_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), head_reskin_map);
666 reskin_vertices(vertex_buffer_data.data() + mandibles_vbo_offset, mandibles_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), mandibles_reskin_map);
669 reskin_vertices(vertex_buffer_data.data() + antennae_vbo_offset, antennae_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), antennae_reskin_map);
674 reskin_vertices(vertex_buffer_data.data() + waist_vbo_offset, waist_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), waist_reskin_map);
678 reskin_vertices(vertex_buffer_data.data() + gaster_vbo_offset, gaster_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), gaster_reskin_map);
683 reskin_vertices(vertex_buffer_data.data() + sting_vbo_offset, sting_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), sting_reskin_map);
689 reskin_vertices(vertex_buffer_data.data() + eyes_vbo_offset, eyes_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), eyes_reskin_map);
695 reskin_vertices(vertex_buffer_data.data() + ocelli_vbo_offset, ocelli_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), ocelli_reskin_map);
706 std::unordered_map<bone_index_type, std::tuple<bone_index_type, const math::transform<float>*>> wings_reskin_map;
707 wings_reskin_map.emplace(*wings_skeleton->get_bone_index(
"forewing_l"), std::tuple(*bones.
forewing_l, &forewing_l_to_body));
708 wings_reskin_map.emplace(*wings_skeleton->get_bone_index(
"forewing_r"), std::tuple(*bones.
forewing_r, &forewing_r_to_body));
709 wings_reskin_map.emplace(*wings_skeleton->get_bone_index(
"hindwing_l"), std::tuple(*bones.
hindwing_l, &hindwing_l_to_body));
710 wings_reskin_map.emplace(*wings_skeleton->get_bone_index(
"hindwing_r"), std::tuple(*bones.
hindwing_r, &hindwing_r_to_body));
712 reskin_vertices(vertex_buffer_data.data() + wings_vbo_offset, wings_vertex_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, model->get_vertex_stride(), wings_reskin_map);
718 tag_vertices({vertex_buffer_data.data() + eyes_vbo_offset, vertex_buffer_data.data() + eyes_vbo_offset + eyes_vertex_count}, *bone_index_attribute, model->get_vertex_stride(), 1);
722 auto& model_vbo = model->get_vertex_buffer();
726 model->get_groups().resize(phenome.
wings->
present ? 2 : 1);
729 float eye_uv_area = 0.0f;
732 eye_uv_area = calculate_uv_area({vertex_buffer_data.data() + eyes_vbo_offset, vertex_buffer_data.data() + eyes_vbo_offset + eyes_vertex_count / 2}, *uv_attribute, model->get_vertex_stride());
736 std::shared_ptr<render::material> exoskeleton_material = generate_ant_exoskeleton_material(phenome, eye_uv_area);
740 model_group.
id =
"exoskeleton";
741 model_group.
material = exoskeleton_material;
747 mandibles_vertex_count +
748 antennae_vertex_count +
750 gaster_vertex_count +
759 wings_group.
id =
"wings";
767 model->get_bounds() = calculate_bounds(vertex_buffer_data.data(), model_group.
vertex_count, *position_attribute, model->get_vertex_stride());
std::unique_ptr< render::model > ant_morphogenesis(const ant_phenome &phenome)
Generates a 3D model of an ant given its phenome.
void generate_ant_skeleton(skeleton &skeleton, ant_bone_set &bones, const ant_phenome &phenome)
Generates a skeleton for an ant model.
std::uint16_t bone_index_type
Bone index type.
Vertex buffer object (VBO).
constexpr std::size_t size() const noexcept
Returns the size of the buffer's data, in bytes.
void read(std::size_t offset, std::span< std::byte > data) const
Reads a subset of the buffer's data from the GL and returns it to the application.
const bone_transform_type & get_relative_transform(bone_index_type index) const
Returns the relative transform describing a bone pose.
const bone_transform_type & get_absolute_transform(bone_index_type index) const
Returns the absolute transform describing a bone pose.
const std::shared_ptr< gl::vertex_buffer > & get_vertex_buffer() const noexcept
Returns the vertex buffer associated with this model.
constexpr std::size_t get_vertex_stride() const noexcept
Returns the byte stride between consecutive elements within the vertex buffer.
const std::vector< model_group > & get_groups() const noexcept
Returns the model's model groups.
const std::shared_ptr< gl::vertex_array > & get_vertex_array() const noexcept
Returns the vertex array associated with this model.
Skeletal animation skeleton.
std::optional< bone_index_type > get_bone_index(hash::fnv1a32_t name) const
Finds the index of a bone from the bone's name.
const rest_pose & get_rest_pose() const noexcept
Returns the skeleton's rest pose.
format
Image and vertex formats.
@ static_draw
Data will be modified once, by the application, and used many times, for drawing commands.
@ triangle_list
Separate triangle primitives.
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
T length(const quaternion< T > &q)
Calculates the length of a quaternion.
constexpr vector< T, 3 > cross(const vector< T, 3 > &x, const vector< T, 3 > &y) noexcept
Calculates the cross product of two vectors.
vector< T, N > sqrt(const vector< T, N > &x)
Takes the square root of each element.
@ bone_index
Vertex bone indices (uvec4)
@ tangent
Vertex tangent (vec4)
@ normal
Vertex normal (vec3)
@ uv
Vertex UV texture coordinates (vec2)
@ position
Vertex position (vec3)
std::uint8_t total_antennomere_count
Total number of antennal segments per antenna.
std::shared_ptr< render::model > model
3D model of the antennae.
Set of bone indices for all possible bones in an ant skeleotn.
bone_index_type mandible_r
bone_index_type antennomere2_l
bone_index_type procoxa_r
bone_index_type protarsomere1_l
bone_index_type mesotarsomere1_l
std::optional< bone_index_type > hindwing_l
std::optional< bone_index_type > postpetiole
bone_index_type mesofemur_l
bone_index_type antennomere1_l
bone_index_type protibia_r
bone_index_type profemur_l
bone_index_type profemur_r
bone_index_type metatibia_r
bone_index_type mesotarsomere1_r
bone_index_type mesocoxa_l
std::optional< bone_index_type > forewing_l
bone_index_type mesotibia_r
bone_index_type mandible_l
std::optional< bone_index_type > sting
bone_index_type metafemur_l
std::optional< bone_index_type > forewing_r
bone_index_type mesocoxa_r
bone_index_type protarsomere1_r
bone_index_type mesofemur_r
bone_index_type metatibia_l
std::optional< bone_index_type > petiole
bone_index_type metacoxa_r
bone_index_type metatarsomere1_l
bone_index_type protibia_l
std::optional< bone_index_type > hindwing_r
bone_index_type antennomere2_r
bone_index_type metacoxa_l
bone_index_type procoxa_l
bone_index_type mesotibia_l
bone_index_type antennomere1_r
bone_index_type metafemur_r
bone_index_type metatarsomere1_r
std::shared_ptr< render::model > model
3D model of the eyes, if present.
std::uint32_t ommatidia_count
Number of ommatidia.
bool present
Indicates whether eyes are present.
std::shared_ptr< render::model > model
3D model of the gaster.
std::shared_ptr< render::model > model
3D model of the head.
std::shared_ptr< render::model > model
3D model of the legs.
std::shared_ptr< render::model > model
3D model of the mandibles.
std::shared_ptr< render::model > model
3D model of the mesosoma.
bool lateral_ocelli_present
Lateral ocelli present.
bool median_ocellus_present
Median ocellus present.
std::shared_ptr< render::model > model
3D model of the ocelli, if present.
Complete set of ant phenes.
const ant_sting_phene * sting
const ant_sculpturing_phene * sculpturing
const ant_mandibles_phene * mandibles
const ant_legs_phene * legs
const ant_pigmentation_phene * pigmentation
const ant_ocelli_phene * ocelli
const ant_antennae_phene * antennae
const ant_wings_phene * wings
const ant_waist_phene * waist
const ant_head_phene * head
const ant_eyes_phene * eyes
const ant_gaster_phene * gaster
const ant_mesosoma_phene * mesosoma
std::shared_ptr< render::material > material
Pigmentation material.
float roughness
Surface roughness.
std::shared_ptr< gl::texture_2d > normal_map
Surface culpturing normal map.
bool present
Indicates whether a sting present or not.
std::shared_ptr< render::model > model
3D model of the sting.
bool postpetiole_present
Postpetiole presence.
std::shared_ptr< render::model > model
3D model of the waist.
std::shared_ptr< render::model > model
3D model of the wings.
bool present
Wings presence.
n-dimensional axis-aligned rectangle.
void extend(const vector_type &point) noexcept
Extends the hyperrectangle to include a point.
32-bit FNV-1a hash value.
static constexpr vector infinity() noexcept
Returns a vector of infinities, where every element is equal to infinity.
Part of a model which is associated with exactly one material.
std::shared_ptr< render::material > material
gl::primitive_topology primitive_topology
std::uint32_t vertex_count
std::uint32_t first_vertex