149 std::vector<uint> UUID_trunk_plant, UUID_branch_plant;
150 std::vector<std::vector<uint>> UUID_leaf_plant;
151 std::vector<std::vector<std::vector<uint>>> UUID_fruit_plant;
153 std::uniform_real_distribution<float> unif_distribution;
155 float canopy_rotation = params.canopy_rotation +
getVariation(params.canopy_rotation_spread, generator);
157 bool is_dead =
false;
158 if (params.dead_probability > 0) {
159 float random_draw = context->
randu();
160 is_dead = random_draw <= params.dead_probability;
165 float trunk_radius = std::max(1e-5f, params.trunk_radius +
getVariation(params.trunk_radius_spread, generator));
166 float trunk_height = std::max(0.f, params.trunk_height +
getVariation(params.trunk_height_spread, generator));
168 std::vector<float> rad_main;
169 rad_main.push_back(0.75f * trunk_radius);
170 rad_main.push_back(0.8f * trunk_radius);
171 rad_main.push_back(1.f * trunk_radius);
172 rad_main.push_back(0.7f * trunk_radius);
173 rad_main.push_back(0.95f * trunk_radius);
174 rad_main.push_back(0.1f * trunk_radius);
175 std::vector<vec3> pos_main;
176 pos_main.push_back(
make_vec3(0., 0., 0.0));
177 pos_main.push_back(
make_vec3(0, 0, 0.2f * trunk_height));
178 pos_main.push_back(
make_vec3(0, 0, 0.22f * trunk_height));
179 pos_main.push_back(
make_vec3(0, 0, 0.6f * trunk_height));
180 pos_main.push_back(
make_vec3(0, 0, 0.96f * trunk_height));
181 pos_main.push_back(
make_vec3(0., 0., trunk_height));
183 for (
uint i = 0; i < rad_main.size(); i++) {
184 pos_main.at(i) = pos_main.at(i) + origin;
187 int wood_subdivisions = std::max(3, params.wood_subdivisions +
getVariation(params.wood_subdivisions_spread, generator));
189 uint objID = context->
addTubeObject(wood_subdivisions, pos_main, rad_main, params.wood_texture_file.c_str());
191 if (enable_element_labels) {
197 float cordon_height = std::max(0.f, params.cordon_height +
getVariation(params.cordon_height_spread, generator));
198 float cordon_radius = std::max(1e-5f, params.cordon_radius +
getVariation(params.cordon_radius_spread, generator));
199 float cordon_length = std::max(0.f, params.cordon_length +
getVariation(params.cordon_length_spread, generator));
201 float diff = cordon_height - trunk_height;
203 float cost = cosf(canopy_rotation);
204 float sint = sinf(canopy_rotation);
206 int Ncord = 2 * wood_subdivisions;
210 std::vector<float> rad_cordw;
211 rad_cordw.push_back(cordon_radius);
212 std::vector<vec3> pos_cordw;
213 pos_cordw.push_back(
make_vec3(0.01f * cordon_length * cost, 0.01f * cordon_length * sint, 0.95 * trunk_height));
217 for (
int i = 1; i < Ncord; i++) {
218 float frac = float(i) / float(Ncord - 1);
219 vec3 n =
spline_interp3(frac, pos_cordw.front(), n_start,
make_vec3(cordon_length * cost, cordon_length * sint, trunk_height + diff), n_end);
220 pos_cordw.push_back(n);
221 rad_cordw.push_back(cordon_radius * (1.f - 0.6f * frac));
224 std::vector<vec3> tmp;
225 tmp.resize(pos_cordw.size());
226 for (
uint i = 0; i < pos_cordw.size(); i++) {
227 tmp.at(i) = pos_cordw.at(i) + origin;
230 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cordw, params.wood_texture_file.c_str());
234 std::vector<float> rad_corde;
235 rad_corde.push_back(cordon_radius);
236 std::vector<vec3> pos_corde;
237 pos_corde.push_back(
make_vec3(-0.01f * cordon_length * cost, -0.01f * cordon_length * sint, 0.95f * trunk_height));
239 n_end =
make_vec3(-0.5f * cordon_height, 0, 0);
241 for (
int i = 1; i < Ncord; i++) {
242 float frac = float(i) / float(Ncord - 1);
243 vec3 n =
spline_interp3(frac, pos_corde.front(), n_start,
make_vec3(-cordon_length * cost, -cordon_length * sint, trunk_height + diff), n_end);
244 pos_corde.push_back(n);
245 rad_corde.push_back(cordon_radius * (1.f - 0.6f * frac));
248 tmp.resize(pos_corde.size());
249 for (
uint i = 0; i < pos_corde.size(); i++) {
250 tmp.at(i) = pos_corde.at(i) + origin;
253 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_corde, params.wood_texture_file.c_str());
255 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
257 if (enable_element_labels) {
265 std::vector<uint> leaf_ptype = leafPrototype(params.leaf_subdivisions, params.leaf_texture_file.c_str(), context);
267 float shoot_length = std::max(0.f, params.shoot_length +
getVariation(params.shoot_length_spread, generator));
268 float shoot_radius = std::max(1e-5f, params.shoot_radius +
getVariation(params.shoot_radius_spread, generator));
269 uint shoots_per_cordon = std::max(
uint(0), params.shoots_per_cordon +
getVariation(params.shoots_per_cordon_spread, generator));
271 float height = cordon_height + shoot_length;
274 for (
uint c = 0; c < 2; c++) {
276 std::vector<float> rad_cord;
277 std::vector<vec3> pos_cord;
280 pos_cord = pos_cordw;
281 rad_cord = rad_cordw;
284 pos_cord = pos_corde;
285 rad_cord = rad_corde;
289 float dx = fabs(pos_cord.back().y - pos_cord.at(0).y) / (float(shoots_per_cordon));
292 for (
int j = 1; j < shoots_per_cordon + 1; j++) {
295 float frac_shoot = float(j) / float(shoots_per_cordon);
299 std::vector<float> rad_pshoot;
300 std::vector<vec3> pos_pshoot;
303 rad_pshoot.push_back(shoot_radius);
304 pos_pshoot.push_back(cane_base);
307 float phirot = (0.5f - unif_distribution(generator)) * 0.5f *
PI_F;
309 if (unif_distribution(generator) < 0.5) {
320 uint Nz = 2 * wood_subdivisions;
321 float dz = ((1 +
getVariation(0.1f, generator)) * height - cordon_height) / float(Nz);
323 float total_cordons_length = 2 * cordon_length;
330 float zfrac_mid = (cane_mid.
z - cane_base.
z) / (cane_end.
z - cane_base.
z);
333 for (
uint k = 1; k < Nz; k++) {
335 float zfrac = float(k) / float(Nz - 1);
338 if (zfrac < zfrac_mid) {
339 n =
spline_interp3(zfrac / zfrac_mid, cane_base, n_start, cane_mid, n_mid);
341 n =
spline_interp3((zfrac - zfrac_mid) / (1 - zfrac_mid), cane_mid, n_mid, cane_end, n_end);
344 pos_pshoot.push_back(n);
346 rad_pshoot.push_back(shoot_radius * (1.f - 0.5f *
float(k) /
float(Nz)));
349 rad_pshoot.back() = 0.0f;
351 std::vector<vec3> tmp;
352 tmp.resize(pos_pshoot.size());
353 for (
uint i = 0; i < pos_pshoot.size(); i++) {
354 tmp.at(i) = pos_pshoot.at(i) + origin;
357 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_pshoot, params.wood_texture_file.c_str());
359 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
360 if (enable_element_labels) {
370 float grape_radius = std::max(0.f, params.grape_radius +
getVariation(params.grape_radius_spread, generator));
371 float cluster_radius = std::max(0.f, params.cluster_radius +
getVariation(params.cluster_radius_spread, generator));
372 float cluster_height_max = std::max(0.f, params.cluster_height_max +
getVariation(params.cluster_height_max_spread, generator));
373 uint grape_subdivisions = std::max(3u, params.grape_subdivisions +
getVariation(params.grape_subdivisions_spread, generator));
374 std::vector<std::vector<uint>> UUID_grapes;
375 if (grape_radius > 0 && cluster_radius > 0) {
377 float fgrape = 0.035f + (cluster_height_max - 0.035) * unif_distribution(generator);
380 if (unif_distribution(generator) < 0.5) {
383 vec3 offset(sgn * (0.25f * cluster_radius +
getVariation(0.1f, generator)) * sint, sgn * (0.1f * cluster_radius +
getVariation(0.1f, generator)) * cost, 0.f);
384 UUID_grapes =
addGrapeCluster(p_grape + offset, grape_radius, cluster_radius, params.grape_color, grape_subdivisions);
386 UUID_fruit_plant.push_back(UUID_grapes);
389 if (params.leaf_width == 0) {
392 float leaf_width = std::max(0.f, params.leaf_width +
getVariation(params.leaf_width_spread, generator));
395 if (unif_distribution(generator) < 0.5) {
398 float leaf_spacing_fraction = std::max(0.f, params.leaf_spacing_fraction +
getVariation(params.leaf_spacing_fraction, generator));
401 while (lfrac > 0.5 * leaf_width && iter < 100) {
404 float lsize = fmaxf(leaf_width * (1.f - exp(-5.f * (1 - lfrac))), 0.1f * leaf_width);
410 vec3 leaf_offset =
rotatePointAboutLine(
make_vec3(
getVariation(0.1f * lsize, generator),
getVariation(0.75f * lsize, generator), 0),
make_vec3(0, 0, 0), parent_normal, flip *
PI_F +
getVariation(0.25f *
PI_F, generator));
413 if (
int(flip) % 2 == 0) {
419 float Rphi = -canopy_rotation - s * 0.5 *
PI_F * (1.f +
getVariation(0.4f, generator));
422 vec3 position = origin + pos_leaf + leaf_offset;
424 std::vector<uint> UUID_leaf = context->
copyPrimitive(leaf_ptype);
432 UUID_leaf_plant.push_back(UUID_leaf);
434 lfrac = lfrac - leaf_spacing_fraction * lsize * (1.f +
getVariation(0.25f, generator));
443 UUID_trunk.push_back(UUID_trunk_plant);
444 UUID_branch.push_back(UUID_branch_plant);
445 UUID_leaf.push_back(UUID_leaf_plant);
446 UUID_fruit.push_back(UUID_fruit_plant);
448 return UUID_leaf.size() - 1;
454 std::vector<uint> UUID_trunk_plant, UUID_branch_plant;
455 std::vector<std::vector<uint>> UUID_leaf_plant;
456 std::vector<std::vector<std::vector<uint>>> UUID_fruit_plant;
458 std::uniform_real_distribution<float> unif_distribution;
460 float canopy_rotation = params.canopy_rotation +
getVariation(params.canopy_rotation_spread, generator);
462 bool is_dead =
false;
463 if (params.dead_probability > 0) {
464 float random_draw = context->
randu();
465 is_dead = random_draw <= params.dead_probability;
470 float trunk_radius = std::max(1e-5f, params.trunk_radius +
getVariation(params.trunk_radius_spread, generator));
471 float trunk_height = std::max(0.f, params.trunk_height +
getVariation(params.trunk_height_spread, generator));
473 std::vector<float> rad_main;
474 rad_main.push_back(0.75f * trunk_radius);
475 rad_main.push_back(0.8f * trunk_radius);
476 rad_main.push_back(1.f * trunk_radius);
477 rad_main.push_back(0.7f * trunk_radius);
478 rad_main.push_back(0.95f * trunk_radius);
479 rad_main.push_back(0.1f * trunk_radius);
480 std::vector<vec3> pos_main;
481 pos_main.push_back(
make_vec3(0., 0., 0.0));
482 pos_main.push_back(
make_vec3(0, 0, 0.2f * trunk_height));
483 pos_main.push_back(
make_vec3(0, 0, 0.22f * trunk_height));
484 pos_main.push_back(
make_vec3(0, 0, 0.6f * trunk_height));
485 pos_main.push_back(
make_vec3(0, 0, 0.96f * trunk_height));
486 pos_main.push_back(
make_vec3(0., 0., trunk_height));
488 for (
uint i = 0; i < rad_main.size(); i++) {
489 pos_main.at(i) = pos_main.at(i) + origin;
492 int wood_subdivisions = std::max(3, params.wood_subdivisions +
getVariation(params.wood_subdivisions_spread, generator));
494 uint objID = context->
addTubeObject(wood_subdivisions, pos_main, rad_main, params.wood_texture_file.c_str());
499 float cordon_height = std::max(0.f, params.cordon_height +
getVariation(params.cordon_height_spread, generator));
500 float cordon_radius = std::max(1e-5f, params.cordon_radius +
getVariation(params.cordon_radius_spread, generator));
501 float cordon_spacing = std::max(0.f, params.cordon_spacing +
getVariation(params.cordon_spacing_spread, generator));
503 float diff = cordon_height - trunk_height;
505 float cost = cosf(canopy_rotation + 0.5f *
PI_F);
506 float sint = sinf(canopy_rotation + 0.5f *
PI_F);
508 std::vector<float> rad_crown;
509 rad_crown.push_back(0.6f * trunk_radius);
510 rad_crown.push_back(0.55f * trunk_radius);
511 rad_crown.push_back(0.5f * trunk_radius);
512 rad_crown.push_back(0.45f * trunk_radius);
513 rad_crown.push_back(0.4f * trunk_radius);
515 std::vector<vec3> pos_crownw;
516 pos_crownw.push_back(
make_vec3(0., 0., 0.95f * trunk_height));
517 pos_crownw.push_back(
make_vec3(0.05f * 0.5f * cordon_spacing * cost, 0.05f * 0.5f * cordon_spacing * sint, trunk_height));
518 pos_crownw.push_back(
make_vec3(0.25f * 0.5f * cordon_spacing * cost, 0.25f * 0.5f * cordon_spacing * sint, trunk_height + 0.1f * diff));
519 pos_crownw.push_back(
make_vec3(0.45f * 0.5f * cordon_spacing * cost, 0.45f * 0.5f * cordon_spacing * sint, trunk_height + 0.65f * diff));
520 pos_crownw.push_back(
make_vec3(0.75f * 0.5f * cordon_spacing * cost, 0.75f * 0.5f * cordon_spacing * sint, cordon_height));
522 for (
uint i = 0; i < rad_crown.size(); i++) {
523 pos_crownw.at(i) = pos_crownw.at(i) + origin;
526 objID = context->
addTubeObject(wood_subdivisions, pos_crownw, rad_crown, params.wood_texture_file.c_str());
528 UUID_trunk_plant.insert(UUID_trunk_plant.end(), U.begin(), U.end());
530 std::vector<vec3> pos_crowne;
531 pos_crowne.push_back(
make_vec3(0., 0., 0.95f * trunk_height));
532 pos_crowne.push_back(
make_vec3(-0.05f * 0.5f * cordon_spacing * cost, -0.05f * 0.5f * cordon_spacing * sint, trunk_height));
533 pos_crowne.push_back(
make_vec3(-0.25f * 0.5f * cordon_spacing * cost, -0.25f * 0.5f * cordon_spacing * sint, trunk_height + 0.1f * diff));
534 pos_crowne.push_back(
make_vec3(-0.45f * 0.5f * cordon_spacing * cost, -0.45f * 0.5f * cordon_spacing * sint, trunk_height + 0.65f * diff));
535 pos_crowne.push_back(
make_vec3(-0.75f * 0.5f * cordon_spacing * cost, -0.75f * 0.5f * cordon_spacing * sint, cordon_height));
537 for (
uint i = 0; i < rad_crown.size(); i++) {
538 pos_crowne.at(i) = pos_crowne.at(i) + origin;
541 objID = context->
addTubeObject(wood_subdivisions, pos_crowne, rad_crown, params.wood_texture_file.c_str());
543 UUID_trunk_plant.insert(UUID_trunk_plant.end(), U.begin(), U.end());
547 float cordon_length = std::max(0.f, params.cordon_length +
getVariation(params.cordon_length_spread, generator));
549 std::vector<float> rad_cord;
550 rad_cord.push_back(cordon_radius);
551 rad_cord.push_back(0.95f * cordon_radius);
552 rad_cord.push_back(0.9f * cordon_radius);
553 rad_cord.push_back(0.9f * cordon_radius);
554 rad_cord.push_back(0.9f * cordon_radius);
555 rad_cord.push_back(0.6f * cordon_radius);
556 rad_cord.push_back(0.2f * cordon_radius);
559 std::vector<vec3> pos_cordnw;
560 pos_cordnw.push_back(
make_vec3(0.7f * 0.5f * cordon_spacing * cost, 0.7f * 0.5f * cordon_spacing * sint, 0.99f * cordon_height));
561 pos_cordnw.push_back(
make_vec3(0.85f * 0.5f * cordon_spacing * cost + 0.025f * sint, 0.85f * 0.5f * cordon_spacing * sint + 0.025f * cost, cordon_height));
562 pos_cordnw.push_back(
make_vec3(0.95f * 0.5f * cordon_spacing * cost + 0.075f * sint, 0.95f * 0.5f * cordon_spacing * sint + 0.075f * cost, cordon_height));
563 pos_cordnw.push_back(
make_vec3(0.5f * cordon_spacing * cost + 0.12f * sint, 0.5f * cordon_spacing * sint + 0.12f * cost, cordon_height));
564 pos_cordnw.push_back(
make_vec3(0.5f * cordon_spacing * cost + 0.4f * cordon_length * sint, 0.5f * cordon_spacing * sint + 0.4f * cordon_length * cost, 0.94f * cordon_height));
565 pos_cordnw.push_back(
make_vec3(0.5f * cordon_spacing * cost + 0.8f * cordon_length * sint, 0.5f * cordon_spacing * sint + 0.8f * cordon_length * cost, 0.97f * cordon_height));
566 pos_cordnw.push_back(
make_vec3(0.5f * cordon_spacing * cost + cordon_length * sint, 0.5f * cordon_spacing * sint + cordon_length * cost, cordon_height));
568 std::vector<vec3> tmp;
569 tmp.resize(pos_cordnw.size());
570 for (
uint i = 0; i < pos_cordnw.size(); i++) {
571 tmp.at(i) = pos_cordnw.at(i) + origin;
574 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cord, params.wood_texture_file.c_str());
577 std::vector<vec3> pos_cordsw;
578 pos_cordsw.push_back(
make_vec3(0.7f * 0.5f * cordon_spacing * cost, 0.7f * 0.5f * cordon_spacing * sint, 0.99f * cordon_height));
579 pos_cordsw.push_back(
make_vec3(0.85f * 0.5f * cordon_spacing * cost - 0.025f * sint, 0.85f * 0.5f * cordon_spacing * sint - 0.025f * cost, cordon_height));
580 pos_cordsw.push_back(
make_vec3(0.95f * 0.5f * cordon_spacing * cost - 0.075f * sint, 0.95f * 0.5f * cordon_spacing * sint - 0.075f * cost, cordon_height));
581 pos_cordsw.push_back(
make_vec3(0.5f * cordon_spacing * cost - 0.12f * sint, 0.5f * cordon_spacing * sint - 0.12f * cost, cordon_height));
582 pos_cordsw.push_back(
make_vec3(0.5f * cordon_spacing * cost - 0.4f * cordon_length * sint, 0.5f * cordon_spacing * sint - 0.4f * cordon_length * cost, 0.94f * cordon_height));
583 pos_cordsw.push_back(
make_vec3(0.5f * cordon_spacing * cost - 0.8f * cordon_length * sint, 0.5f * cordon_spacing * sint - 0.8f * cordon_length * cost, 0.97f * cordon_height));
584 pos_cordsw.push_back(
make_vec3(0.5f * cordon_spacing * cost - cordon_length * sint, 0.5f * cordon_spacing * sint - cordon_length * cost, cordon_height));
586 tmp.resize(pos_cordsw.size());
587 for (
uint i = 0; i < pos_cordsw.size(); i++) {
588 tmp.at(i) = pos_cordsw.at(i) + origin;
591 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cord, params.wood_texture_file.c_str());
593 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
596 std::vector<vec3> pos_cordne;
597 pos_cordne.push_back(
make_vec3(-0.7f * 0.5f * cordon_spacing * cost, -0.7f * 0.5f * cordon_spacing * sint, 0.99f * cordon_height));
598 pos_cordne.push_back(
make_vec3(-0.85f * 0.5f * cordon_spacing * cost + 0.025f * sint, -0.85f * 0.5f * cordon_spacing * sint + 0.025f * cost, cordon_height));
599 pos_cordne.push_back(
make_vec3(-0.95f * 0.5f * cordon_spacing * cost + 0.075f * sint, -0.95f * 0.5f * cordon_spacing * sint + 0.075f * cost, cordon_height));
600 pos_cordne.push_back(
make_vec3(-0.5f * cordon_spacing * cost + 0.12f * sint, -0.5f * cordon_spacing * sint + 0.12f * cost, cordon_height));
601 pos_cordne.push_back(
make_vec3(-0.5f * cordon_spacing * cost + 0.4f * cordon_length * sint, -0.5f * cordon_spacing * sint + 0.4f * cordon_length * cost, 0.94f * cordon_height));
602 pos_cordne.push_back(
make_vec3(-0.5f * cordon_spacing * cost + 0.8f * cordon_length * sint, -0.5f * cordon_spacing * sint + 0.8f * cordon_length * cost, 0.97f * cordon_height));
603 pos_cordne.push_back(
make_vec3(-0.5f * cordon_spacing * cost + cordon_length * sint, -0.5f * cordon_spacing * sint + cordon_length * cost, cordon_height));
605 tmp.resize(pos_cordne.size());
606 for (
uint i = 0; i < pos_cordne.size(); i++) {
607 tmp.at(i) = pos_cordne.at(i) + origin;
610 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cord, params.wood_texture_file.c_str());
612 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
614 std::vector<vec3> pos_cordse;
615 pos_cordse.push_back(
make_vec3(-0.7f * 0.5f * cordon_spacing * cost, -0.7f * 0.5f * cordon_spacing * sint, 0.99f * cordon_height));
616 pos_cordse.push_back(
make_vec3(-0.85f * 0.5f * cordon_spacing * cost - 0.025f * sint, -0.85f * 0.5f * cordon_spacing * sint - 0.025f * cost, cordon_height));
617 pos_cordse.push_back(
make_vec3(-0.95f * 0.5f * cordon_spacing * cost - 0.075f * sint, -0.95f * 0.5f * cordon_spacing * sint - 0.075f * cost, cordon_height));
618 pos_cordse.push_back(
make_vec3(-0.5f * cordon_spacing * cost - 0.12f * sint, -0.5f * cordon_spacing * sint - 0.12f * cost, cordon_height));
619 pos_cordse.push_back(
make_vec3(-0.5f * cordon_spacing * cost - 0.4f * cordon_length * sint, -0.5f * cordon_spacing * sint - 0.4f * cordon_length * cost, 0.94f * cordon_height));
620 pos_cordse.push_back(
make_vec3(-0.5f * cordon_spacing * cost - 0.8f * cordon_length * sint, -0.5f * cordon_spacing * sint - 0.8f * cordon_length * cost, 0.97f * cordon_height));
621 pos_cordse.push_back(
make_vec3(-0.5f * cordon_spacing * cost - cordon_length * sint, -0.5f * cordon_spacing * sint - cordon_length * cost, cordon_height));
623 tmp.resize(pos_cordse.size());
624 for (
uint i = 0; i < pos_cordse.size(); i++) {
625 tmp.at(i) = pos_cordse.at(i) + origin;
628 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cord, params.wood_texture_file.c_str());
630 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
636 float shoot_length = std::max(0.f, params.shoot_length +
getVariation(params.shoot_length_spread, generator));
637 float shoot_radius = std::max(1e-5f, params.shoot_radius +
getVariation(params.shoot_radius_spread, generator));
638 uint shoots_per_cordon = std::max(0u, params.shoots_per_cordon +
getVariation(params.shoots_per_cordon_spread, generator));
639 float shoot_angle_base = params.shoot_angle_base +
getVariation(params.shoot_angle_base_spread, generator);
640 float shoot_angle_tip = params.shoot_angle_tip +
getVariation(params.shoot_angle_tip_spread, generator);
642 float height = cordon_height + shoot_length;
644 for (
uint d = 0; d < 2; d++) {
645 for (
uint c = 0; c < 2; c++) {
647 std::vector<vec3> pos_cord;
651 pos_cord = pos_cordsw;
653 pos_cord = pos_cordnw;
658 pos_cord = pos_cordse;
660 pos_cord = pos_cordne;
665 float dx = fabs(pos_cord.back().y - pos_cord.at(0).y) / (float(shoots_per_cordon));
667 for (
int j = 1; j < shoots_per_cordon + 1; j++) {
669 float frac_shoot = float(j) / float(shoots_per_cordon);
673 std::vector<float> rad_pshoot;
674 std::vector<vec3> pos_pshoot;
677 rad_pshoot.push_back(shoot_radius);
678 pos_pshoot.push_back(cane_base);
682 float phirot = 0.5f *
PI_F * (1 + (-0.5f + unif_distribution(generator)) * 1.0) + canopy_rotation;
683 if (unif_distribution(generator) < 0.5) {
696 theta0 = 0.5f *
PI_F * unif_distribution(generator);
698 theta0 = shoot_angle_base * (1.f + (-0.5 + unif_distribution(generator)) * 0.6);
700 float theta_end = shoot_angle_tip * (1.f + (-0.5 + unif_distribution(generator)) * 0.6);
702 uint Nz = 2 * wood_subdivisions;
703 float dz = ((1 +
getVariation(0.1f, generator)) * height - cordon_height) / float(Nz);
704 for (
uint k = 1; k < Nz; k++) {
710 rad_pshoot.push_back(shoot_radius);
713 rad_pshoot.back() = 0.0f;
715 std::vector<vec3> tmp;
716 tmp.resize(pos_pshoot.size());
717 for (
uint i = 0; i < pos_pshoot.size(); i++) {
718 tmp.at(i) = pos_pshoot.at(i) + origin;
721 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_pshoot, params.wood_texture_file.c_str());
723 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
731 float grape_radius = std::max(0.f, params.grape_radius +
getVariation(params.grape_radius_spread, generator));
732 float cluster_radius = std::max(0.f, params.cluster_radius +
getVariation(params.cluster_radius_spread, generator));
733 float cluster_height_max = std::max(0.f, params.cluster_height_max +
getVariation(params.cluster_height_max_spread, generator));
734 uint grape_subdivisions = std::max(0u, params.grape_subdivisions +
getVariation(params.grape_subdivisions_spread, generator));
735 std::vector<std::vector<uint>> UUID_grapes;
736 if (grape_radius > 0 && cluster_radius > 0) {
738 float fgrape = 0.035 + (cluster_height_max - 0.035) * unif_distribution(generator);
741 if (unif_distribution(generator) < 0.5) {
744 vec3 offset(sgn * (2.2 * cluster_radius +
getVariation(0.1f, generator)) * sint, sgn * (2 * cluster_radius +
getVariation(0.1f, generator)) * cost, 0.f);
746 UUID_grapes =
addGrapeCluster(p_grape + offset, grape_radius, cluster_radius, params.grape_color, grape_subdivisions);
748 UUID_fruit_plant.push_back(UUID_grapes);
751 if (params.leaf_width == 0) {
754 float leaf_width = std::max(0.f, params.leaf_width +
getVariation(params.leaf_width_spread, generator));
757 if (unif_distribution(generator) < 0.5) {
760 float leaf_spacing_fraction = std::max(0.f, params.leaf_spacing_fraction +
getVariation(params.leaf_spacing_fraction_spread, generator));
763 while (lfrac > 0.5 * leaf_width && iter < 100) {
766 float lsize = fmaxf(leaf_width * (1.f - exp(-5.f * (1 - lfrac))), 0.1 * leaf_width);
775 if (
int(flip) % 2 == 0) {
781 float Rphi = -canopy_rotation - s * 0.5f *
PI_F * (1.f +
getVariation(0.4f, generator));
784 vec3 position = origin + pos_leaf + leaf_offset;
794 lfrac = lfrac - leaf_spacing_fraction * lsize * (1.f +
getVariation(0.25f, generator));
804 UUID_trunk.push_back(UUID_trunk_plant);
805 UUID_branch.push_back(UUID_branch_plant);
806 UUID_leaf.push_back(UUID_leaf_plant);
807 UUID_fruit.push_back(UUID_fruit_plant);
809 return UUID_leaf.size() - 1;
814 float mean_shoot_angle = 0.1 *
PI_F;
817 std::vector<uint> UUID_trunk_plant, UUID_branch_plant;
818 std::vector<std::vector<uint>> UUID_leaf_plant;
819 std::vector<std::vector<std::vector<uint>>> UUID_fruit_plant;
821 std::uniform_real_distribution<float> unif_distribution;
823 float canopy_rotation = params.canopy_rotation +
getVariation(params.canopy_rotation_spread, generator);
825 float cost = cosf(canopy_rotation);
826 float sint = sinf(canopy_rotation);
828 bool is_dead =
false;
829 if (params.dead_probability > 0) {
830 float random_draw = context->
randu();
831 is_dead = random_draw <= params.dead_probability;
834 float cordon_length = std::max(0.f, params.cordon_length +
getVariation(params.cordon_length_spread, generator));
838 float trunk_radius = std::max(1e-5f, params.trunk_radius +
getVariation(params.trunk_radius_spread, generator));
839 float trunk_height = std::max(0.f, params.trunk_height +
getVariation(params.trunk_height_spread, generator));
841 std::vector<float> rad_main;
842 rad_main.push_back(0.75 * trunk_radius);
843 rad_main.push_back(0.8f * trunk_radius);
844 rad_main.push_back(1.f * trunk_radius);
845 rad_main.push_back(0.7f * trunk_radius);
846 rad_main.push_back(0.95f * trunk_radius);
847 rad_main.push_back(0.1 * trunk_radius);
848 std::vector<vec3> pos_main;
849 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, 0.0f));
850 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, 0.2f * trunk_height));
851 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, 0.22f * trunk_height));
852 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, 0.6f * trunk_height));
853 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, 0.96f * trunk_height));
854 pos_main.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius) * cost, (-cordon_length + 0.5f * trunk_radius) * sint, trunk_height));
856 for (
uint i = 0; i < rad_main.size(); i++) {
857 pos_main.at(i) = pos_main.at(i) + origin;
860 int wood_subdivisions = std::max(0, params.wood_subdivisions +
getVariation(params.wood_subdivisions_spread, generator));
862 uint objID = context->
addTubeObject(wood_subdivisions, pos_main, rad_main, params.wood_texture_file.c_str());
867 float cordon_height = std::max(0.f, params.cordon_height +
getVariation(params.cordon_height_spread, generator));
868 float cordon_radius = std::max(1e-5f, params.cordon_radius +
getVariation(params.cordon_radius_spread, generator));
870 float total_cordons_length = 2 * cordon_length;
872 float diff = cordon_height - trunk_height;
875 std::vector<float> rad_cord;
876 rad_cord.push_back(cordon_radius);
877 rad_cord.push_back(0.95 * cordon_radius);
878 rad_cord.push_back(0.9f * cordon_radius);
879 rad_cord.push_back(0.85f * cordon_radius);
880 rad_cord.push_back(0.8 * cordon_radius);
881 rad_cord.push_back(0.6 * cordon_radius);
882 rad_cord.push_back(0.2f * cordon_radius);
883 std::vector<vec3> pos_cord;
884 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.01f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.01f * total_cordons_length) * sint, 0.95f * trunk_height));
885 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.05f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.05f * total_cordons_length) * sint, trunk_height + 0.1f * diff));
886 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.15f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.15f * total_cordons_length) * sint, trunk_height + 0.65f * diff));
887 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.45f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.45f * total_cordons_length) * sint, trunk_height + 0.95f * diff));
888 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.6f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.6f * total_cordons_length) * sint, trunk_height + 1.05f * diff));
889 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 0.85f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 0.85f * total_cordons_length) * sint, trunk_height + diff));
890 pos_cord.push_back(
make_vec3((-cordon_length + 0.5f * trunk_radius + 1.0f * total_cordons_length) * cost, (-cordon_length + 0.5f * trunk_radius + 1.0f * total_cordons_length) * sint, trunk_height + diff));
892 std::vector<vec3> tmp;
893 tmp.resize(pos_cord.size());
894 for (
uint i = 0; i < pos_cord.size(); i++) {
895 tmp.at(i) = pos_cord.at(i) + origin;
898 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_cord, params.wood_texture_file.c_str());
905 float shoot_length = std::max(0.f, params.shoot_length +
getVariation(params.shoot_length_spread, generator));
906 float shoot_radius = std::max(1e-5f, params.shoot_radius +
getVariation(params.shoot_radius_spread, generator));
907 uint shoots_per_cordon = std::max(0u, params.shoots_per_cordon +
getVariation(params.shoots_per_cordon_spread, generator));
909 float height = cordon_height + shoot_length;
911 float dx = fabs(pos_cord.back().y - pos_cord.at(0).y) / (float(shoots_per_cordon));
913 for (
int j = 1; j < shoots_per_cordon + 1; j++) {
915 float frac_shoot = float(j) / float(shoots_per_cordon);
919 std::vector<float> rad_pshoot;
920 std::vector<vec3> pos_pshoot;
923 rad_pshoot.push_back(shoot_radius);
924 pos_pshoot.push_back(cane_base);
927 float phirot = (0.5f - unif_distribution(generator)) * 0.5 *
PI_F;
929 if (unif_distribution(generator) < 0.5) {
933 float theta0 = (0.3f - unif_distribution(generator)) * 0.6;
934 float theta_end = (0.1f - unif_distribution(generator)) * 0.2;
936 uint Nz = 2 * wood_subdivisions;
937 float dz = ((1 +
getVariation(0.1f, generator)) * height - cordon_height) / float(Nz);
938 for (
uint k = 1; k < Nz; k++) {
944 rad_pshoot.push_back(shoot_radius);
947 rad_pshoot.back() = 0.0f;
949 std::vector<vec3> tmp;
950 tmp.resize(pos_pshoot.size());
951 for (
uint i = 0; i < pos_pshoot.size(); i++) {
952 tmp.at(i) = pos_pshoot.at(i) + origin;
955 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_pshoot, params.wood_texture_file.c_str());
957 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
965 float grape_radius = std::max(0.f, params.grape_radius +
getVariation(params.grape_radius_spread, generator));
966 float cluster_radius = std::max(0.f, params.cluster_radius +
getVariation(params.cluster_radius_spread, generator));
967 float cluster_height_max = std::max(0.f, params.cluster_height_max +
getVariation(params.cluster_height_max_spread, generator));
968 uint grape_subdivisions = std::max(0u, params.grape_subdivisions +
getVariation(params.grape_subdivisions_spread, generator));
969 std::vector<std::vector<uint>> UUID_grapes;
970 if (grape_radius > 0 && cluster_radius > 0) {
972 float fgrape = 0.035 + (cluster_height_max - 0.035) * unif_distribution(generator);
975 if (unif_distribution(generator) < 0.5) {
978 vec3 offset(sgn * (2.2f * cluster_radius +
getVariation(0.1f, generator)) * sint, sgn * (2 * cluster_radius +
getVariation(0.1f, generator)) * cost, 0.f);
979 UUID_grapes =
addGrapeCluster(p_grape + offset, grape_radius, cluster_radius, params.grape_color, grape_subdivisions);
981 UUID_fruit_plant.push_back(UUID_grapes);
984 if (params.leaf_width == 0) {
987 float leaf_width = std::max(0.f, params.leaf_width +
getVariation(params.leaf_width_spread, generator));
990 if (unif_distribution(generator) < 0.5) {
993 float leaf_spacing_fraction = std::max(0.f, params.leaf_spacing_fraction +
getVariation(params.leaf_spacing_fraction_spread, generator));
996 while (lfrac > 0.5 * leaf_width && iter < 100) {
999 float lsize = fmaxf(leaf_width * (1.f - exp(-5.f * (1 - lfrac))), 0.1 * leaf_width);
1008 if (
int(flip) % 2 == 0) {
1014 float Rphi = -canopy_rotation - s * 0.5f *
PI_F * (1.f +
getVariation(0.4f, generator));
1017 vec3 position = origin + pos_leaf - leaf_offset;
1027 lfrac = lfrac - leaf_spacing_fraction * lsize * (1.f +
getVariation(0.25f, generator));
1035 UUID_trunk.push_back(UUID_trunk_plant);
1036 UUID_branch.push_back(UUID_branch_plant);
1037 UUID_leaf.push_back(UUID_leaf_plant);
1038 UUID_fruit.push_back(UUID_fruit_plant);
1040 return UUID_leaf.size() - 1;
1046 std::vector<uint> UUID_trunk_plant, UUID_branch_plant;
1047 std::vector<std::vector<uint>> UUID_leaf_plant;
1048 std::vector<std::vector<std::vector<uint>>> UUID_fruit_plant;
1050 std::uniform_real_distribution<float> unif_distribution;
1052 float canopy_rotation = params.canopy_rotation +
getVariation(params.canopy_rotation_spread, generator);
1054 float cost = cosf(canopy_rotation);
1055 float sint = sinf(canopy_rotation);
1057 bool is_dead =
false;
1058 if (params.dead_probability > 0) {
1059 float random_draw = context->
randu();
1060 is_dead = random_draw <= params.dead_probability;
1065 float trunk_radius = std::max(1e-5f, params.trunk_radius +
getVariation(params.trunk_radius_spread, generator));
1066 float trunk_height = std::max(0.f, params.trunk_height +
getVariation(params.trunk_height_spread, generator));
1068 std::vector<float> rad_main;
1069 rad_main.push_back(0.75 * trunk_radius);
1070 rad_main.push_back(0.8f * trunk_radius);
1071 rad_main.push_back(1.f * trunk_radius);
1072 rad_main.push_back(0.7f * trunk_radius);
1073 rad_main.push_back(0.95f * trunk_radius);
1074 rad_main.push_back(0.1 * trunk_radius);
1075 std::vector<vec3> pos_main;
1076 pos_main.push_back(
make_vec3(0., 0., 0.0));
1077 pos_main.push_back(
make_vec3(0, 0, 0.2f * trunk_height));
1078 pos_main.push_back(
make_vec3(0, 0, 0.22f * trunk_height));
1079 pos_main.push_back(
make_vec3(0, 0, 0.6f * trunk_height));
1080 pos_main.push_back(
make_vec3(0, 0, 0.96f * trunk_height));
1081 pos_main.push_back(
make_vec3(0., 0., trunk_height));
1083 for (
uint i = 0; i < rad_main.size(); i++) {
1084 pos_main.at(i) = pos_main.at(i) + origin;
1087 int wood_subdivisions = std::max(0, params.wood_subdivisions +
getVariation(params.wood_subdivisions_spread, generator));
1089 uint objID = context->
addTubeObject(wood_subdivisions, pos_main, rad_main, params.wood_texture_file.c_str());
1094 float cordon_height = std::max(0.f, params.cordon_height +
getVariation(params.cordon_height_spread, generator));
1096 float shoot_length = std::max(0.f, params.shoot_length +
getVariation(params.shoot_length_spread, generator));
1097 float shoot_radius = std::max(0.f, params.shoot_radius +
getVariation(params.shoot_radius_spread, generator));
1098 uint shoots_per_cordon = std::max(0u, params.shoots_per_cordon +
getVariation(params.shoots_per_cordon_spread, generator));
1102 for (
uint c = 0; c < 2; c++) {
1104 for (
int j = 1; j < shoots_per_cordon + 1; j++) {
1106 float frac_shoot = float(j) / float(shoots_per_cordon);
1108 float height = (cordon_height + shoot_length) * (1.f + 0.55 * (1 - frac_shoot));
1112 std::vector<float> rad_pshoot;
1113 std::vector<vec3> pos_pshoot;
1116 rad_pshoot.push_back(shoot_radius);
1117 pos_pshoot.push_back(cane_base);
1119 float theta0 = 0.5 *
PI_F * (1.f - float(j - 1) / float(shoots_per_cordon));
1120 float theta_end = (0.1f - unif_distribution(generator)) * 0.2;
1122 uint Nz = 2 * wood_subdivisions;
1123 float dz = ((1.f +
getVariation(0.1f, generator)) * height - cordon_height) / float(Nz);
1124 for (
uint k = 1; k < Nz; k++) {
1126 vec3 n =
rotatePoint(
make_vec3(0, 0, dz), (theta0 + (theta_end - theta0) *
float(k) /
float(Nz - 1)), canopy_rotation +
PI_F *
float(c));
1130 rad_pshoot.push_back(shoot_radius);
1133 rad_pshoot.back() = 0.0f;
1135 std::vector<vec3> tmp;
1136 tmp.resize(pos_pshoot.size());
1137 for (
uint i = 0; i < pos_pshoot.size(); i++) {
1138 tmp.at(i) = pos_pshoot.at(i) + origin;
1141 objID = context->
addTubeObject(wood_subdivisions, tmp, rad_pshoot, params.wood_texture_file.c_str());
1143 UUID_branch_plant.insert(UUID_branch_plant.end(), U.begin(), U.end());
1151 float grape_radius = std::max(0.f, params.grape_radius +
getVariation(params.grape_radius_spread, generator));
1152 float cluster_radius = std::max(0.f, params.cluster_radius +
getVariation(params.cluster_radius_spread, generator));
1153 float cluster_height_max = std::max(0.f, params.cluster_height_max +
getVariation(params.cluster_height_max_spread, generator));
1154 uint grape_subdivisions = std::max(0u, params.grape_subdivisions +
getVariation(params.grape_subdivisions_spread, generator));
1155 std::vector<std::vector<uint>> UUID_grapes;
1156 if (grape_radius > 0 && cluster_radius > 0) {
1158 float fgrape = 0.035 + (cluster_height_max - 0.035) * unif_distribution(generator);
1161 if (unif_distribution(generator) < 0.5) {
1164 vec3 offset(sgn * (2.2f * cluster_radius +
getVariation(0.1f, generator)) * sint, sgn * (2.f * cluster_radius +
getVariation(0.1f, generator)) * cost, 0.f);
1165 UUID_grapes =
addGrapeCluster(p_grape + offset, grape_radius, cluster_radius, params.grape_color, grape_subdivisions);
1167 UUID_fruit_plant.push_back(UUID_grapes);
1170 if (params.leaf_width == 0) {
1173 float leaf_width = std::max(0.f, params.leaf_width +
getVariation(params.leaf_width_spread, generator));
1176 if (unif_distribution(generator) < 0.5) {
1179 float leaf_spacing_fraction = std::max(0.f, params.leaf_spacing_fraction +
getVariation(params.leaf_spacing_fraction_spread, generator));
1182 while (lfrac > 0.5 * leaf_width && iter < 100) {
1185 float lsize = fmaxf(leaf_width * (1.f - exp(-5.f * (1 - lfrac))), 0.1 * leaf_width);
1194 if (
int(flip) % 2 == 0) {
1200 float Rphi = -canopy_rotation - s * 0.5 *
PI_F * (1.f +
getVariation(0.4f, generator));
1203 vec3 position = origin + pos_leaf - leaf_offset;
1213 lfrac = lfrac - leaf_spacing_fraction * lsize * (1.f +
getVariation(0.25f, generator));
1222 UUID_trunk.push_back(UUID_trunk_plant);
1223 UUID_branch.push_back(UUID_branch_plant);
1224 UUID_leaf.push_back(UUID_leaf_plant);
1225 UUID_fruit.push_back(UUID_fruit_plant);
1227 return UUID_leaf.size() - 1;