|
|
@ -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<std::byte> 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<const float*>(uv_data + uv_attribute.stride * i); |
|
|
|
const float* uv_data_b = reinterpret_cast<const float*>(uv_data + uv_attribute.stride * (i + 1)); |
|
|
|
const float* uv_data_c = reinterpret_cast<const float*>(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<float>; |
|
|
|
|
|
|
|
// 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<float> * 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<render::material> 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<render::material> exoskeleton_material = std::make_unique<render::material>(*pigmentation.material); |
|
|
|
std::unique_ptr<render::material> exoskeleton_material = std::make_unique<render::material>(*phenome.pigmentation->material); |
|
|
|
|
|
|
|
// Set roughness variable
|
|
|
|
exoskeleton_material->set_variable("roughness", std::make_shared<render::material_float>(1, sculpturing.roughness)); |
|
|
|
exoskeleton_material->set_variable("exoskeleton_roughness", std::make_shared<render::material_float>(1, phenome.sculpturing->roughness)); |
|
|
|
|
|
|
|
// Set normal map variable
|
|
|
|
exoskeleton_material->set_variable("normal_map", std::make_shared<render::material_texture_2d>(1, sculpturing.normal_map)); |
|
|
|
exoskeleton_material->set_variable("exoskeleton_normal_map", std::make_shared<render::material_texture_2d>(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<float>(phenome.eyes->ommatidia_count)); |
|
|
|
exoskeleton_material->set_variable("ommatidia_scale", std::make_shared<render::material_float>(1, ommatidia_scale)); |
|
|
|
} |
|
|
|
|
|
|
|
return exoskeleton_material; |
|
|
|
} |
|
|
@ -196,9 +259,6 @@ void tag_vertices |
|
|
|
|
|
|
|
std::unique_ptr<render::model> ant_morphogenesis(const ant_phenome& phenome) |
|
|
|
{ |
|
|
|
// Generate exoskeleton material
|
|
|
|
std::shared_ptr<render::material> 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<render::material> 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"; |
|
|
|