diff --git a/src/engine/physics/ik/ik-solver.hpp b/src/engine/physics/ik/ik-solver.hpp
deleted file mode 100644
index 7cf12ab..0000000
--- a/src/engine/physics/ik/ik-solver.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2023 Christopher J. Howard
- *
- * This file is part of Antkeeper source code.
- *
- * Antkeeper source code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Antkeeper source code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Antkeeper source code. If not, see .
- */
-
-#ifndef ANTKEEPER_PHYSICS_IK_SOLVER_HPP
-#define ANTKEEPER_PHYSICS_IK_SOLVER_HPP
-
-#include
-
-namespace physics {
-
-/**
- *
- */
-class ik_solver
-{
-public:
-
-};
-
-} // namespace physics
-
-#endif // ANTKEEPER_PHYSICS_IK_SOLVER_HPP
diff --git a/src/game/ant/ant-morphogenesis.cpp b/src/game/ant/ant-morphogenesis.cpp
index 4f0bf6e..775dcf4 100644
--- a/src/game/ant/ant-morphogenesis.cpp
+++ b/src/game/ant/ant-morphogenesis.cpp
@@ -130,6 +130,43 @@ void tag_vertices
}
}
+/**
+ * Calculates the total area of UV coordinates.
+ *
+ * @param vertex_data Vertex buffer data.
+ * @param uv_attribute Vertex UV attribute.
+ *
+ * @return Total UV area.
+ */
+float calculate_uv_area
+(
+ std::span vertex_data,
+ const gl::vertex_attribute& uv_attribute
+)
+{
+ std::byte* uv_data = vertex_data.data() + uv_attribute.offset;
+
+ float sum_area = 0.0f;
+
+ for (std::size_t i = 0; i + 2 < vertex_data.size(); i += 3)
+ {
+ const float* uv_data_a = reinterpret_cast(uv_data + uv_attribute.stride * i);
+ const float* uv_data_b = reinterpret_cast(uv_data + uv_attribute.stride * (i + 1));
+ const float* uv_data_c = reinterpret_cast(uv_data + uv_attribute.stride * (i + 2));
+
+ const float3 uva = {uv_data_a[0], uv_data_a[1], 0.0f};
+ const float3 uvb = {uv_data_b[0], uv_data_b[1], 0.0f};
+ const float3 uvc = {uv_data_c[0], uv_data_c[1], 0.0f};
+
+ const float3 uvab = uvb - uva;
+ const float3 uvac = uvc - uva;
+
+ sum_area += math::length(math::cross(uvab, uvac)) * 0.5f;
+ }
+
+ return sum_area;
+}
+
/**
* Calculates the bounds of vertex data.
*
@@ -166,28 +203,54 @@ void tag_vertices
return bounds;
}
+/**
+ * Calculates a scale factor which will give ant eyes the desired number of ommatidia.
+ *
+ * @param eye_uv_area Total UV area of a single eye.
+ * @param ommatidia_count Desired number of ommatidia.
+ *
+ * @return Ommatidia scale factor.
+ */
+[[nodiscard]] float calculate_ommatidia_scale(float eye_uv_area, float ommatidia_count)
+{
+ // Side length of hexagon tiles generated by the eye shader
+ constexpr float source_side_length = 1.0f / math::sqrt_3;
+
+ // Side length of hexagon tiles that will fill UV area
+ const float target_side_length = std::sqrt((eye_uv_area * 2.0f) / (3.0f * math::sqrt_3 * ommatidia_count));
+
+ return source_side_length / target_side_length;
+}
+
/**
* Generates an ant exoskeleton material.
*
- * @param pigmentation Ant pigmentation phene.
- * @param sculpturing Ant sculpturing phene.
+ * @param phenome Ant phenome.
+ * @param eye_uv_area Total UV area of a single eye.
*
* @return Generated ant exoskeleton material.
*/
[[nodiscard]] std::unique_ptr generate_ant_exoskeleton_material
(
- const ant_pigmentation_phene& pigmentation,
- const ant_sculpturing_phene& sculpturing
+ const ant_phenome& phenome,
+ float eye_uv_area
)
{
// Allocate copy of pigmentation material
- std::unique_ptr exoskeleton_material = std::make_unique(*pigmentation.material);
+ std::unique_ptr exoskeleton_material = std::make_unique(*phenome.pigmentation->material);
// Set roughness variable
- exoskeleton_material->set_variable("roughness", std::make_shared(1, sculpturing.roughness));
+ exoskeleton_material->set_variable("exoskeleton_roughness", std::make_shared(1, phenome.sculpturing->roughness));
// Set normal map variable
- exoskeleton_material->set_variable("normal_map", std::make_shared(1, sculpturing.normal_map));
+ exoskeleton_material->set_variable("exoskeleton_normal_map", std::make_shared(1, phenome.sculpturing->normal_map));
+
+ if (phenome.eyes->present)
+ {
+ // Set ommatidia scale variable
+ const float ommatidia_scale = calculate_ommatidia_scale(eye_uv_area, static_cast(phenome.eyes->ommatidia_count));
+ exoskeleton_material->set_variable("ommatidia_scale", std::make_shared(1, ommatidia_scale));
+ }
return exoskeleton_material;
}
@@ -196,9 +259,6 @@ void tag_vertices
std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
{
- // Generate exoskeleton material
- std::shared_ptr exoskeleton_material = generate_ant_exoskeleton_material(*phenome.pigmentation, *phenome.sculpturing);
-
// Get body part models
const render::model* mesosoma_model = phenome.mesosoma->model.get();
const render::model* legs_model = phenome.legs->model.get();
@@ -378,6 +438,7 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
// Get vertex attributes
const gl::vertex_attribute* position_attribute = nullptr;
+ const gl::vertex_attribute* uv_attribute = nullptr;
const gl::vertex_attribute* normal_attribute = nullptr;
const gl::vertex_attribute* tangent_attribute = nullptr;
const gl::vertex_attribute* bone_index_attribute = nullptr;
@@ -386,6 +447,10 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
{
position_attribute = &it->second;
}
+ if (auto it = vertex_attribute_map.find(render::vertex_attribute::uv); it != vertex_attribute_map.end())
+ {
+ uv_attribute = &it->second;
+ }
if (auto it = vertex_attribute_map.find(render::vertex_attribute::normal); it != vertex_attribute_map.end())
{
normal_attribute = &it->second;
@@ -715,6 +780,16 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
// Allocate model groups
model->get_groups().resize(1);
+ // Calculate UV area of a single eye
+ float eye_uv_area = 0.0f;
+ if (phenome.eyes->present)
+ {
+ 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);
+ }
+
+ // Generate exoskeleton material
+ std::shared_ptr exoskeleton_material = generate_ant_exoskeleton_material(phenome, eye_uv_area);
+
// Construct model group
render::model_group& model_group = model->get_groups()[0];
model_group.id = "exoskeleton";