19using namespace helios;
30 std::string leaf_texture;
32 helios_runtime_error(
"ERROR (PlantArchitecture): Leaf prototype texture file was not specified.");
36 helios_runtime_error(
"ERROR (PlantArchitecture): Leaf prototype texture file for compound leaf index " + std::to_string(compound_leaf_index) +
" was not found.");
46 std::vector<uint> UUIDs;
49 uint Ny = ceil(prototype_parameters->leaf_aspect_ratio.val() *
float(Nx));
55 const float dx = 1.f / float(Nx);
56 const float dy = prototype_parameters->leaf_aspect_ratio.val() / float(Ny);
58 std::vector<std::vector<vec3>> vertices;
61 for (
int j = 0; j <= Ny; j++) {
63 for (
int i = 0; i <= Nx; i++) {
65 const float x = float(i) * dx;
66 const float y = float(j) * dy - 0.5f * prototype_parameters->leaf_aspect_ratio.val();
76 float z_ycurve = prototype_parameters->
lateral_curvature.val() * powf(y / prototype_parameters->leaf_aspect_ratio.val(), 4);
81 z_petiole = fmin(0.1f, prototype_parameters->
petiole_roll.val() * powf(7.f * y / prototype_parameters->leaf_aspect_ratio.val(), 4) * exp(-70.f * (x))) -
88 z_wave = (2.f * fabs(y) * prototype_parameters->
wave_amplitude.val() * sinf((x + 0.5f *
float(j >= 0.5 * Ny)) *
M_PI / prototype_parameters->
wave_period.val()));
91 vertices.at(j).at(i) =
make_vec3(x, y_fold, z_fold + z_ycurve + z_wave + z_petiole);
100 if (x <= prototype_parameters->leaf_buckle_length.val() && x + dx > prototype_parameters->
leaf_buckle_length.val()) {
109 for (
int j = 0; j < Ny; j++) {
110 for (
int i = 0; i < Nx; i++) {
112 const float x = float(i) * dx;
113 const float y = float(j) * dy - 0.5f * prototype_parameters->leaf_aspect_ratio.val();
114 vec2 uv0(x, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
115 vec2 uv1(x + dx, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
116 vec2 uv2(x + dx, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
117 vec2 uv3(x, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
119 vec3 v0 = vertices.at(j).at(i);
120 vec3 v1 = vertices.at(j).at(i + 1);
121 vec3 v2 = vertices.at(j + 1).at(i + 1);
122 vec3 v3 = vertices.at(j + 1).at(i);
125 uint uuid1 = context_ptr->
addTriangle(v0, v1, v2, leaf_texture.c_str(), uv0, uv1, uv2);
127 UUIDs.push_back(uuid1);
133 uint uuid2 = context_ptr->
addTriangle(v0, v2, v3, leaf_texture.c_str(), uv0, uv2, uv3);
135 UUIDs.push_back(uuid2);
145 std::vector<uint> UUIDs_petiolule = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/PetiolulePrototype.obj").
string().c_str(),
make_vec3(0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
147 UUIDs.insert(UUIDs.end(), UUIDs_petiolule.begin(), UUIDs_petiolule.end());
150 prototype_parameters->leaf_aspect_ratio.resample();
174 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/AlmondFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
179void AlmondPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
181 if (phytomer->internode_length_max < 0.01) {
182 phytomer->setInternodeMaxRadius(0.005);
183 phytomer->setVegetativeBudState(BUD_DEAD);
184 phytomer->scaleLeafPrototypeScale(0.8);
185 phytomer->setFloralBudState(BUD_DEAD);
186 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 7;
196void AlmondPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
206 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/AlmondFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
211void ApplePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
213 if (phytomer->internode_length_max < 0.01) {
214 phytomer->setInternodeMaxRadius(0.005);
215 phytomer->setVegetativeBudState(BUD_DEAD);
216 phytomer->scaleLeafPrototypeScale(0.8);
217 phytomer->setFloralBudState(BUD_DEAD);
218 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 6;
222void ApplePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
227 float curve_magnitude = context_ptr->
randu(0.f, 0.2f);
229 std::vector<vec3> nodes;
231 nodes.push_back(
make_vec3(context_ptr->
randu(0.4f, 0.7f), 0, -0.25f * curve_magnitude));
232 nodes.push_back(
make_vec3(0.95, 0, -0.9f * curve_magnitude));
233 nodes.push_back(
make_vec3(1, 0, -curve_magnitude));
235 std::vector<float> radius;
236 radius.push_back(0.015);
237 radius.push_back(0.015);
238 radius.push_back(0.015);
239 radius.push_back(0.0);
241 std::vector<RGBcolor> colors;
242 colors.push_back(RGB::forestgreen);
243 colors.push_back(RGB::forestgreen);
244 colors.push_back(RGB::forestgreen);
245 colors.push_back(RGB::forestgreen);
252void AsparagusPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
255 if (shoot_node_index <= 2) {
256 phytomer->scaleLeafPrototypeScale(0.6);
257 phytomer->setVegetativeBudState(BUD_DEAD);
262 std::vector<uint> UUIDs;
270 std::vector<uint> UUIDs;
271 if (compound_leaf_index == 0) {
273 }
else if (compound_leaf_index < 0) {
289 std::vector<uint> UUIDs;
290 if (flower_is_open) {
299void BeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
301 if (shoot_node_index > 5 || phytomer->rank > 1) {
302 phytomer->setVegetativeBudState(BUD_DEAD);
304 phytomer->setFloralBudState(BUD_DEAD);
308 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
309 phytomer->scaleLeafPrototypeScale(leaf_scale);
312 if (phytomer->rank == 0) {
313 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
314 phytomer->scaleInternodeMaxLength(inode_scale);
331 std::string OBJ_file;
332 if (context_ptr->
randn() < 0.4) {
338 std::vector<uint> UUIDs = context_ptr->
loadOBJ(OBJ_file.c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
342void CapsicumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
344 if (shoot_node_index < 6 && phytomer->rank == 0) {
345 phytomer->setVegetativeBudState(BUD_DEAD);
346 phytomer->setFloralBudState(BUD_DEAD);
347 phytomer->removeLeaf();
350 if (phytomer->rank >= 2) {
351 phytomer->setVegetativeBudState(BUD_DEAD);
352 phytomer->setFloralBudState(BUD_DEAD);
356 float leaf_scale = std::min(1.f, 0.6f + 0.4f * shoot_node_index / 5.f);
357 phytomer->scaleLeafPrototypeScale(leaf_scale);
360 if (phytomer->rank == 0) {
361 float inode_scale = std::min(1.f, 0.05f + 0.95f * plant_age / 15.f);
362 phytomer->scaleInternodeMaxLength(inode_scale);
373 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/CowpeaLeaf_unifoliate.obj").
string().c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
380 std::vector<uint> UUIDs;
381 if (compound_leaf_index < 0) {
383 }
else if (compound_leaf_index == 0) {
393 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/CowpeaPod.obj").
string().c_str(),
make_vec3(0., 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
399 std::vector<uint> UUIDs;
400 if (flower_is_open) {
409void CowpeaPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
411 if (shoot_node_index > 5 || phytomer->rank > 1) {
412 phytomer->setVegetativeBudState(BUD_DEAD);
414 phytomer->setFloralBudState(BUD_DEAD);
418 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
419 phytomer->scaleLeafPrototypeScale(leaf_scale);
422 if (phytomer->rank == 0) {
423 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
424 phytomer->scaleInternodeMaxLength(inode_scale);
429float random_float(
float min,
float max) {
430 return min +
static_cast<float>(rand()) / (
static_cast<float>(RAND_MAX / (
max -
min)));
435 float distance = std::sqrt(std::pow(center1.
x - center2.
x, 2) + std::pow(center1.
y - center2.
y, 2) + std::pow(center1.
z - center2.
z, 2));
436 return distance < (radius1 + radius2);
443 float base_radius = 2.f;
444 float taper_factor = 0.6f;
445 float grape_radius = 0.25f;
447 std::vector<std::pair<helios::vec3, float>> grapes;
448 float z_step = height / num_grapes;
452 grapes.push_back({first_center, grape_radius});
455 int max_attempts = 100;
457 for (
int i = 1; i < num_grapes; ++i) {
458 float z = i * z_step;
460 float taper_radius = base_radius * (1.0f - taper_factor * (z / height));
464 while (!placed && attempts < max_attempts) {
466 int reference_idx = rand() % grapes.size();
467 const helios::vec3 &reference_center = grapes[reference_idx].first;
470 float angle = random_float(0, 2 *
M_PI);
471 float distance = random_float(1.2 * grape_radius, 1.3 * grape_radius);
474 helios::vec3 new_center(reference_center.
x + distance * cos(angle), reference_center.
y + distance * sin(angle), random_float(z - 0.5f * z_step, z + 0.5f * z_step));
477 float new_center_distance = std::sqrt(new_center.x * new_center.x + new_center.y * new_center.y);
478 if (new_center_distance > taper_radius) {
484 bool collision =
false;
485 for (
const auto &grape: grapes) {
486 if (spheres_overlap(new_center, grape_radius, grape.first, grape.second)) {
494 grapes.push_back({new_center, grape_radius});
502 std::vector<uint> UUIDs;
503 for (
const auto &grape: grapes) {
505 std::vector<uint> UUIDs_tmp = context_ptr->
addSphere(10, grape.first, grape.second,
make_RGBcolor(0.053, 0.076, 0.098));
506 UUIDs.insert(UUIDs.end(), UUIDs_tmp.begin(), UUIDs_tmp.end());
523void GrapevinePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
526 if (shoot_node_index >= 2) {
527 phytomer->setFloralBudState(BUD_DEAD);
529 if (phytomer->rank >= 1 && shoot_node_index >= 8) {
530 phytomer->setVegetativeBudState(BUD_DEAD);
532 if (phytomer->rank >= 2) {
533 phytomer->setVegetativeBudState(BUD_DEAD);
534 phytomer->setFloralBudState(BUD_DEAD);
553 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/MaizeTassel.obj").
string().c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
563void MaizePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
567 if (shoot_node_index <= 5) {
568 scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
569 phytomer->scaleInternodeMaxLength(scale);
570 }
else if (shoot_node_index >= phytomer->shoot_index.z - 5) {
571 scale = fmin(1.f, 0.65 + 0.35 *
float(phytomer->shoot_index.z - shoot_node_index) / 3.f);
574 phytomer->scaleLeafPrototypeScale(scale);
576 if (shoot_node_index > 8 && shoot_node_index < 12) {
577 phytomer->phytomer_parameters.inflorescence.flowers_per_peduncle = 1;
578 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeEarPrototype;
579 phytomer->phytomer_parameters.inflorescence.fruit_prototype_scale = 0.2;
580 phytomer->phytomer_parameters.peduncle.length = 0.05f;
581 phytomer->phytomer_parameters.peduncle.radius = 0.01;
582 phytomer->phytomer_parameters.peduncle.pitch = 5;
583 phytomer->setFloralBudState(BUD_ACTIVE);
585 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeTasselPrototype;
586 phytomer->setFloralBudState(BUD_DEAD);
600 UUIDs_upper.insert(UUIDs_upper.end(), UUIDs_lower.begin(), UUIDs_lower.end());
614 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/OliveFlower_open.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
619void OlivePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
622void OlivePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
624 if (phytomer->isdormant) {
625 if (phytomer->shoot_index.x < phytomer->shoot_index.y - 8) {
626 phytomer->setFloralBudState(BUD_DEAD);
632 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/PistachioNut.obj").
string().c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
638 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/OliveFlower_open.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
643void PistachioPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
646 if (shoot_node_index == 0) {
647 phytomer->setVegetativeBudState(BUD_DEAD);
648 phytomer->setFloralBudState(BUD_DEAD);
652void PistachioPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
654 if (phytomer->isdormant) {
655 if (phytomer->shoot_index.x <= phytomer->shoot_index.y - 4) {
656 phytomer->setFloralBudState(BUD_DORMANT);
662 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/PuncturevineFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
668 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/RedbudFlower_open.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
677void RedbudPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
680void RedbudPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
683 if (phytomer->isdormant) {
684 int Nchild_shoots =
randu(2, 4);
685 if (phytomer->shoot_index.x < phytomer->shoot_index.y - Nchild_shoots) {
686 phytomer->setVegetativeBudState(BUD_DEAD);
688 phytomer->setFloralBudState(BUD_DEAD);
699void RicePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
702 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
703 phytomer->scaleLeafPrototypeScale(scale);
706 phytomer->scaleInternodeMaxLength(scale);
709void ButterLettucePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
711 float fact = float(shoot_max_nodes - shoot_node_index) / float(shoot_max_nodes);
718 phytomer->rotateLeaf(0, 0, make_AxisRotation(-
deg2rad(60) * fact, 0, 0));
723 if (subdivisions <= 1) {
727 float panicle_height = 1;
728 float panicle_width = 0.08;
729 float width_seed = 0.08;
730 float height_seed = 0.25;
731 float seed_tilt = 50;
734 std::string seed_texture_file =
helios::resolvePluginAsset(
"plantarchitecture",
"assets/textures/SorghumSeed.jpeg").string().c_str();
735 RGBcolor stem_color(0.45, 0.55, 0.42);
737 std::vector<uint> UUIDs;
739 panicle_height -= 0.8 * height_seed;
741 std::vector<vec3> nodes_panicle;
742 std::vector<float> radius_panicle;
744 for (
int n = 0; n < subdivisions; n++) {
749 z = 0.5f * height_seed / float(subdivisions - 1);
750 }
else if (n == subdivisions - 1) {
751 z = (subdivisions - 1.5f) * height_seed /
float(subdivisions - 1);
753 z = n * height_seed / float(subdivisions - 1);
756 float angle = float(n) *
M_PI / float(subdivisions - 1);
757 float dr = std::fmax(0.f, 0.5f * width_seed * sin(angle));
759 nodes_panicle.push_back(
make_vec3(x, y, z));
760 radius_panicle.push_back(dr);
763 std::vector<uint> UUIDs_seed_ptype = context_ptr->
addTube(subdivisions, nodes_panicle, radius_panicle, seed_texture_file.c_str());
765 int Ntheta = ceil(6.f * panicle_height / height_seed);
766 int Nphi = ceil(2.f *
M_PI * panicle_width / width_seed);
768 for (
int j = 0; j < Nphi; j++) {
769 for (
int i = 0; i < Ntheta; i++) {
771 if (i == 0 && j == 0) {
775 std::vector<uint> UUIDs_copy = context_ptr->
copyPrimitive(UUIDs_seed_ptype);
778 float phi = 2.f *
M_PI * float(j + 0.5f *
float(i % 2)) / float(Nphi);
779 float theta = acos(1 - 2 *
float(i +
float(j) /
float(Nphi)) /
float(Ntheta));
780 float x = sin(theta) * cos(phi);
781 float y = sin(theta) * sin(phi);
782 float z = 0.5f + 0.5f * cos(theta);
784 x *= 0.5f * panicle_width;
785 y *= 0.5f * panicle_width;
788 float tilt = -
deg2rad(seed_tilt) * sqrtf(1.f - z / panicle_height);
794 UUIDs.insert(UUIDs.end(), UUIDs_copy.begin(), UUIDs_copy.end());
800 std::vector<uint> UUIDs_sphere = context_ptr->
addSphere(10,
make_vec3(0, 0, 0.5 * panicle_height), 0.5f, seed_texture_file.c_str());
802 UUIDs.insert(UUIDs.end(), UUIDs_sphere.begin(), UUIDs_sphere.end());
811void SorghumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
814 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
815 phytomer->scaleLeafPrototypeScale(scale);
818 phytomer->scaleInternodeMaxLength(scale);
828 std::vector<uint> UUIDs;
829 if (flower_is_open) {
838void SoybeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
840 if (shoot_node_index > 5 || phytomer->rank > 1) {
841 phytomer->setVegetativeBudState(BUD_DEAD);
843 phytomer->setFloralBudState(BUD_DEAD);
847 float leaf_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 15.f);
848 phytomer->scaleLeafPrototypeScale(leaf_scale);
851 float inode_scale = fmin(1.f, 0.1 + 0.9 * plant_age / 15.f);
852 phytomer->scaleInternodeMaxLength(inode_scale);
856 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/StrawberryFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
862 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/StrawberryFruit.obj").
string().c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
868 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/TomatoFruit.obj").
string().c_str(),
make_vec3(0., 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
874 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/TomatoFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0.75, nullrotation, RGB::black,
"ZUP",
true);
879void TomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
881 if (shoot_node_index < 8 && phytomer->rank == 0) {
882 phytomer->setFloralBudState(BUD_DEAD);
884 if (phytomer->rank > 1) {
885 phytomer->setFloralBudState(BUD_DEAD);
886 phytomer->setVegetativeBudState(BUD_DEAD);
890 float leaf_scale = fmin(1.f, 0.5 + 0.5 * plant_age / 10.f);
891 phytomer->scaleLeafPrototypeScale(leaf_scale);
894 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
895 phytomer->scaleInternodeMaxLength(inode_scale);
898void CherryTomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
900 if (shoot_node_index < 8 || phytomer->rank > 1) {
901 phytomer->setFloralBudState(BUD_DEAD);
902 phytomer->setVegetativeBudState(BUD_DEAD);
906 float leaf_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 15.f);
907 phytomer->scaleLeafPrototypeScale(leaf_scale);
910 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
911 phytomer->scaleInternodeMaxLength(inode_scale);
914void CherryTomatoPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
916 float pruning_height = 1.f;
917 float pruning_day = 101.f;
919 float plant_age = phytomer->parent_shoot_ptr->plantarchitecture_ptr->getPlantAge(phytomer->plantID);
921 if (phytomer->hasLeaf() && plant_age >= pruning_day) {
922 float height = phytomer->getInternodeNodePositions().at(0).z;
923 if (height < pruning_height) {
924 phytomer->removeLeaf();
936 std::vector<uint> UUIDs = context_ptr->
loadOBJ(
helios::resolvePluginAsset(
"plantarchitecture",
"assets/obj/AlmondFlower.obj").
string().c_str(),
make_vec3(0.0, 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
941void WalnutPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
944 if (shoot_node_index < 4) {
945 phytomer->setVegetativeBudState(BUD_DEAD);
946 phytomer->setFloralBudState(BUD_DEAD);
950void WalnutPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
959void WheatPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
962 float scale = std::fmin(1.f, 0.7f + 0.3f *
float(shoot_node_index) / 5.f);
963 phytomer->scaleLeafPrototypeScale(scale);
966 phytomer->scaleInternodeMaxLength(scale);