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";