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))) -
91 const float wave_phase = (x + prototype_parameters->
wave_period.val() * float(j >= 0.5 * Ny)) *
M_PI / prototype_parameters->
wave_period.val();
92 z_wave = 2.f * fabs(y) * prototype_parameters->
wave_amplitude.val() * sinf(wave_phase);
95 vertices.at(j).at(i) =
make_vec3(x, y_fold, z_fold + z_ycurve + z_petiole);
97 float rot_angle = 0.f;
107 if (x <= prototype_parameters->leaf_buckle_length.val() && x + dx > prototype_parameters->
leaf_buckle_length.val()) {
120 vertices.at(j).at(i).x += z_wave * sinf(rot_angle);
121 vertices.at(j).at(i).z += z_wave * cosf(rot_angle);
126 for (
int j = 0; j < Ny; j++) {
127 for (
int i = 0; i < Nx; i++) {
129 const float x = float(i) * dx;
130 const float y = float(j) * dy - 0.5f * prototype_parameters->leaf_aspect_ratio.val();
131 vec2 uv0(x, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
132 vec2 uv1(x + dx, (y + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
133 vec2 uv2(x + dx, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
134 vec2 uv3(x, (y + dy + 0.5f * prototype_parameters->leaf_aspect_ratio.val()) / prototype_parameters->leaf_aspect_ratio.val());
136 vec3 v0 = vertices.at(j).at(i);
137 vec3 v1 = vertices.at(j).at(i + 1);
138 vec3 v2 = vertices.at(j + 1).at(i + 1);
139 vec3 v3 = vertices.at(j + 1).at(i);
142 uint uuid1 = context_ptr->
addTriangle(v0, v1, v2, leaf_texture.c_str(), uv0, uv1, uv2);
144 UUIDs.push_back(uuid1);
150 uint uuid2 = context_ptr->
addTriangle(v0, v2, v3, leaf_texture.c_str(), uv0, uv2, uv3);
152 UUIDs.push_back(uuid2);
162 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);
164 UUIDs.insert(UUIDs.end(), UUIDs_petiolule.begin(), UUIDs_petiolule.end());
167 prototype_parameters->leaf_aspect_ratio.resample();
191 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);
196void AlmondPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
198 if (phytomer->internode_length_max < 0.01) {
199 phytomer->setInternodeMaxRadius(0.005);
200 phytomer->setVegetativeBudState(BUD_DEAD);
201 phytomer->scaleLeafPrototypeScale(0.8);
202 phytomer->setFloralBudState(BUD_DEAD);
203 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 7;
213void AlmondPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
223 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);
228void ApplePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
230 if (phytomer->internode_length_max < 0.01) {
231 phytomer->setInternodeMaxRadius(0.005);
232 phytomer->setVegetativeBudState(BUD_DEAD);
233 phytomer->scaleLeafPrototypeScale(0.8);
234 phytomer->setFloralBudState(BUD_DEAD);
235 phytomer->parent_shoot_ptr->shoot_parameters.max_nodes_per_season = 6;
239void ApplePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
244 float curve_magnitude = context_ptr->
randu(0.f, 0.2f);
246 std::vector<vec3> nodes;
248 nodes.push_back(
make_vec3(context_ptr->
randu(0.4f, 0.7f), 0, -0.25f * curve_magnitude));
249 nodes.push_back(
make_vec3(0.95, 0, -0.9f * curve_magnitude));
250 nodes.push_back(
make_vec3(1, 0, -curve_magnitude));
252 std::vector<float> radius;
253 radius.push_back(0.015);
254 radius.push_back(0.015);
255 radius.push_back(0.015);
256 radius.push_back(0.0);
258 std::vector<RGBcolor> colors;
259 colors.push_back(RGB::forestgreen);
260 colors.push_back(RGB::forestgreen);
261 colors.push_back(RGB::forestgreen);
262 colors.push_back(RGB::forestgreen);
269void AsparagusPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
272 if (shoot_node_index <= 2) {
273 phytomer->scaleLeafPrototypeScale(0.6);
274 phytomer->setVegetativeBudState(BUD_DEAD);
279 std::vector<uint> UUIDs;
287 std::vector<uint> UUIDs;
288 if (compound_leaf_index == 0) {
290 }
else if (compound_leaf_index < 0) {
306 std::vector<uint> UUIDs;
307 if (flower_is_open) {
316void BeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
318 if (shoot_node_index > 5 || phytomer->rank > 1) {
319 phytomer->setVegetativeBudState(BUD_DEAD);
321 phytomer->setFloralBudState(BUD_DEAD);
325 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
326 phytomer->scaleLeafPrototypeScale(leaf_scale);
329 if (phytomer->rank == 0) {
330 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
331 phytomer->scaleInternodeMaxLength(inode_scale);
348 std::string OBJ_file;
349 if (context_ptr->
randn() < 0.4) {
355 std::vector<uint> UUIDs = context_ptr->
loadOBJ(OBJ_file.c_str(),
make_vec3(0., 0, 0), 0, nullrotation, RGB::black,
"ZUP",
true);
359void CapsicumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
361 if (shoot_node_index < 6 && phytomer->rank == 0) {
362 phytomer->setVegetativeBudState(BUD_DEAD);
363 phytomer->setFloralBudState(BUD_DEAD);
364 phytomer->removeLeaf();
367 if (phytomer->rank >= 2) {
368 phytomer->setVegetativeBudState(BUD_DEAD);
369 phytomer->setFloralBudState(BUD_DEAD);
373 float leaf_scale = std::min(1.f, 0.6f + 0.4f * shoot_node_index / 5.f);
374 phytomer->scaleLeafPrototypeScale(leaf_scale);
377 if (phytomer->rank == 0) {
378 float inode_scale = std::min(1.f, 0.05f + 0.95f * plant_age / 15.f);
379 phytomer->scaleInternodeMaxLength(inode_scale);
390 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);
397 std::vector<uint> UUIDs;
398 if (compound_leaf_index < 0) {
400 }
else if (compound_leaf_index == 0) {
410 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);
416 std::vector<uint> UUIDs;
417 if (flower_is_open) {
426void CowpeaPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
428 if (shoot_node_index > 5 || phytomer->rank > 1) {
429 phytomer->setVegetativeBudState(BUD_DEAD);
431 phytomer->setFloralBudState(BUD_DEAD);
435 float leaf_scale = fmin(1.f, 0.6 + 0.4 * plant_age / 8.f);
436 phytomer->scaleLeafPrototypeScale(leaf_scale);
439 if (phytomer->rank == 0) {
440 float inode_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 10.f);
441 phytomer->scaleInternodeMaxLength(inode_scale);
446float random_float(
float min,
float max) {
447 return min +
static_cast<float>(rand()) / (
static_cast<float>(RAND_MAX) / (
max -
min));
452 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));
453 return distance < (radius1 + radius2);
460 float base_radius = 2.f;
461 float taper_factor = 0.6f;
462 float grape_radius = 0.25f;
464 std::vector<std::pair<helios::vec3, float>> grapes;
465 float z_step = height / num_grapes;
469 grapes.push_back({first_center, grape_radius});
472 int max_attempts = 100;
474 for (
int i = 1; i < num_grapes; ++i) {
475 float z = i * z_step;
477 float taper_radius = base_radius * (1.0f - taper_factor * (z / height));
481 while (!placed && attempts < max_attempts) {
483 int reference_idx = rand() % grapes.size();
484 const helios::vec3 &reference_center = grapes[reference_idx].first;
487 float angle = random_float(0, 2 *
M_PI);
488 float distance = random_float(1.2 * grape_radius, 1.3 * grape_radius);
491 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));
494 float new_center_distance = std::sqrt(new_center.x * new_center.x + new_center.y * new_center.y);
495 if (new_center_distance > taper_radius) {
501 bool collision =
false;
502 for (
const auto &grape: grapes) {
503 if (spheres_overlap(new_center, grape_radius, grape.first, grape.second)) {
511 grapes.push_back({new_center, grape_radius});
519 std::vector<uint> UUIDs;
520 for (
const auto &grape: grapes) {
522 std::vector<uint> UUIDs_tmp = context_ptr->
addSphere(10, grape.first, grape.second,
make_RGBcolor(0.053, 0.076, 0.098));
523 UUIDs.insert(UUIDs.end(), UUIDs_tmp.begin(), UUIDs_tmp.end());
540void GrapevinePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
543 if (shoot_node_index >= 2) {
544 phytomer->setFloralBudState(BUD_DEAD);
546 if (phytomer->rank >= 1 && shoot_node_index >= 8) {
547 phytomer->setVegetativeBudState(BUD_DEAD);
549 if (phytomer->rank >= 2) {
550 phytomer->setVegetativeBudState(BUD_DEAD);
551 phytomer->setFloralBudState(BUD_DEAD);
570 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);
580void MaizePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
584 if (shoot_node_index <= 5) {
585 scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
586 phytomer->scaleInternodeMaxLength(scale);
587 }
else if (shoot_node_index >= phytomer->shoot_index.z - 5) {
588 scale = fmin(1.f, 0.65 + 0.35 *
float(phytomer->shoot_index.z - shoot_node_index) / 3.f);
591 phytomer->scaleLeafPrototypeScale(scale);
593 if (shoot_node_index > 8 && shoot_node_index < 12) {
594 phytomer->phytomer_parameters.inflorescence.flowers_per_peduncle = 1;
595 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeEarPrototype;
596 phytomer->phytomer_parameters.inflorescence.fruit_prototype_scale = 0.2;
597 phytomer->phytomer_parameters.peduncle.length = 0.05f;
598 phytomer->phytomer_parameters.peduncle.radius = 0.01;
599 phytomer->phytomer_parameters.peduncle.pitch = 5;
600 phytomer->setFloralBudState(BUD_ACTIVE);
602 phytomer->phytomer_parameters.inflorescence.fruit_prototype_function = MaizeTasselPrototype;
603 phytomer->setFloralBudState(BUD_DEAD);
617 UUIDs_upper.insert(UUIDs_upper.end(), UUIDs_lower.begin(), UUIDs_lower.end());
631 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);
636void OlivePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
639void OlivePhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
641 if (phytomer->isdormant) {
642 if (phytomer->shoot_index.x < phytomer->shoot_index.y - 8) {
643 phytomer->setFloralBudState(BUD_DEAD);
649 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);
655 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);
660void PistachioPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
663 if (shoot_node_index == 0) {
664 phytomer->setVegetativeBudState(BUD_DEAD);
665 phytomer->setFloralBudState(BUD_DEAD);
669void PistachioPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
671 if (phytomer->isdormant) {
672 if (phytomer->shoot_index.x <= phytomer->shoot_index.y - 4) {
673 phytomer->setFloralBudState(BUD_DORMANT);
679 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);
685 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);
694void RedbudPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
697void RedbudPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
700 if (phytomer->isdormant) {
701 int Nchild_shoots =
randu(2, 4);
702 if (phytomer->shoot_index.x < phytomer->shoot_index.y - Nchild_shoots) {
703 phytomer->setVegetativeBudState(BUD_DEAD);
705 phytomer->setFloralBudState(BUD_DEAD);
716void RicePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
719 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
720 phytomer->scaleLeafPrototypeScale(scale);
723 phytomer->scaleInternodeMaxLength(scale);
726void ButterLettucePhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
728 float fact = float(shoot_max_nodes - shoot_node_index) / float(shoot_max_nodes);
735 phytomer->rotateLeaf(0, 0, make_AxisRotation(-
deg2rad(60) * fact, 0, 0));
740 if (subdivisions <= 1) {
744 float panicle_height = 1;
745 float panicle_width = 0.08;
746 float width_seed = 0.08;
747 float height_seed = 0.25;
748 float seed_tilt = 50;
751 std::string seed_texture_file =
helios::resolvePluginAsset(
"plantarchitecture",
"assets/textures/SorghumSeed.jpeg").string().c_str();
752 RGBcolor stem_color(0.45, 0.55, 0.42);
754 std::vector<uint> UUIDs;
756 panicle_height -= 0.8 * height_seed;
758 std::vector<vec3> nodes_panicle;
759 std::vector<float> radius_panicle;
761 for (
int n = 0; n < subdivisions; n++) {
766 z = 0.5f * height_seed / float(subdivisions - 1);
767 }
else if (n == subdivisions - 1) {
768 z = (subdivisions - 1.5f) * height_seed /
float(subdivisions - 1);
770 z = n * height_seed / float(subdivisions - 1);
773 float angle = float(n) *
M_PI / float(subdivisions - 1);
774 float dr = std::fmax(0.f, 0.5f * width_seed * sin(angle));
776 nodes_panicle.push_back(
make_vec3(x, y, z));
777 radius_panicle.push_back(dr);
780 std::vector<uint> UUIDs_seed_ptype = context_ptr->
addTube(subdivisions, nodes_panicle, radius_panicle, seed_texture_file.c_str());
782 int Ntheta = ceil(6.f * panicle_height / height_seed);
783 int Nphi = ceil(2.f *
M_PI * panicle_width / width_seed);
785 for (
int j = 0; j < Nphi; j++) {
786 for (
int i = 0; i < Ntheta; i++) {
788 if (i == 0 && j == 0) {
792 std::vector<uint> UUIDs_copy = context_ptr->
copyPrimitive(UUIDs_seed_ptype);
795 float phi = 2.f *
M_PI * float(j + 0.5f *
float(i % 2)) / float(Nphi);
796 float theta = acos(1 - 2 *
float(i +
float(j) /
float(Nphi)) /
float(Ntheta));
797 float x = sin(theta) * cos(phi);
798 float y = sin(theta) * sin(phi);
799 float z = 0.5f + 0.5f * cos(theta);
801 x *= 0.5f * panicle_width;
802 y *= 0.5f * panicle_width;
805 float tilt = -
deg2rad(seed_tilt) * sqrtf(1.f - z / panicle_height);
811 UUIDs.insert(UUIDs.end(), UUIDs_copy.begin(), UUIDs_copy.end());
817 std::vector<uint> UUIDs_sphere = context_ptr->
addSphere(10,
make_vec3(0, 0, 0.5 * panicle_height), 0.5f, seed_texture_file.c_str());
819 UUIDs.insert(UUIDs.end(), UUIDs_sphere.begin(), UUIDs_sphere.end());
828void SorghumPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
831 float scale = fmin(1.f, 0.7 + 0.3 *
float(shoot_node_index) / 5.f);
832 phytomer->scaleLeafPrototypeScale(scale);
835 phytomer->scaleInternodeMaxLength(scale);
842 const bool is_flag_leaf = (shoot_max_nodes > 0 && shoot_node_index + 1 == shoot_max_nodes);
844 phytomer->rotatePetiole(0, make_AxisRotation(
deg2rad(25.f), 0.f, 0.f));
855 std::vector<uint> UUIDs;
856 if (flower_is_open) {
865void SoybeanPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
867 if (shoot_node_index > 5 || phytomer->rank > 1) {
868 phytomer->setVegetativeBudState(BUD_DEAD);
870 phytomer->setFloralBudState(BUD_DEAD);
874 float leaf_scale = fmin(1.f, 0.2 + 0.8 * plant_age / 15.f);
875 phytomer->scaleLeafPrototypeScale(leaf_scale);
878 float inode_scale = fmin(1.f, 0.1 + 0.9 * plant_age / 15.f);
879 phytomer->scaleInternodeMaxLength(inode_scale);
883 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);
889 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);
895 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);
901 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);
906void TomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
908 if (shoot_node_index < 8 && phytomer->rank == 0) {
909 phytomer->setFloralBudState(BUD_DEAD);
911 if (phytomer->rank > 1) {
912 phytomer->setFloralBudState(BUD_DEAD);
913 phytomer->setVegetativeBudState(BUD_DEAD);
917 float leaf_scale = fmin(1.f, 0.5 + 0.5 * plant_age / 10.f);
918 phytomer->scaleLeafPrototypeScale(leaf_scale);
921 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
922 phytomer->scaleInternodeMaxLength(inode_scale);
925void CherryTomatoPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
927 if (shoot_node_index < 8 || phytomer->rank > 1) {
928 phytomer->setFloralBudState(BUD_DEAD);
929 phytomer->setVegetativeBudState(BUD_DEAD);
933 float leaf_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 15.f);
934 phytomer->scaleLeafPrototypeScale(leaf_scale);
937 float inode_scale = fmin(1.f, 0.7 + 0.3 * plant_age / 10.f);
938 phytomer->scaleInternodeMaxLength(inode_scale);
941void CherryTomatoPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
943 float pruning_height = 1.f;
944 float pruning_day = 101.f;
946 float plant_age = phytomer->parent_shoot_ptr->plantarchitecture_ptr->getPlantAge(phytomer->plantID);
948 if (phytomer->hasLeaf() && plant_age >= pruning_day) {
949 float height = phytomer->getInternodeNodePositions().at(0).z;
950 if (height < pruning_height) {
951 phytomer->removeLeaf();
963 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);
968void WalnutPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
971 if (shoot_node_index < 4) {
972 phytomer->setVegetativeBudState(BUD_DEAD);
973 phytomer->setFloralBudState(BUD_DEAD);
977void WalnutPhytomerCallbackFunction(std::shared_ptr<Phytomer> phytomer) {
986void WheatPhytomerCreationFunction(std::shared_ptr<Phytomer> phytomer,
uint shoot_node_index,
uint parent_shoot_node_index,
uint shoot_max_nodes,
float plant_age) {
989 float scale = std::fmin(1.f, 0.7f + 0.3f *
float(shoot_node_index) / 5.f);
990 phytomer->scaleLeafPrototypeScale(scale);
993 phytomer->scaleInternodeMaxLength(scale);