1.3.49
 
Loading...
Searching...
No Matches
strawberry.cpp
1#include "CanopyGenerator.h"
2
3using namespace helios;
4using namespace std;
5
6std::vector<std::vector<uint>> strawberryCluster(const vec3 center, const StrawberryParameters &params, Context *context) {
7
8
9 std::vector<std::vector<uint>> U;
10
11 std::vector<vec3> nodes;
12 std::vector<float> radius;
13
14 nodes.push_back(center + make_vec3(0, 0, 0.6) * params.fruit_radius);
15 nodes.push_back(center + make_vec3(0, 0, 0.45) * params.fruit_radius);
16 nodes.push_back(center + make_vec3(0, 0, 0.3) * params.fruit_radius);
17 nodes.push_back(center + make_vec3(0, 0, 0.1) * params.fruit_radius);
18 nodes.push_back(center + make_vec3(0, 0, -0.2) * params.fruit_radius);
19 nodes.push_back(center + make_vec3(0, 0, -0.4) * params.fruit_radius);
20 nodes.push_back(center + make_vec3(0, 0, -0.5) * params.fruit_radius);
21
22 radius.push_back(1e-3 * params.fruit_radius);
23 radius.push_back(0.4 * params.fruit_radius);
24 radius.push_back(0.5 * params.fruit_radius);
25 radius.push_back(0.45 * params.fruit_radius);
26 radius.push_back(0.2 * params.fruit_radius);
27 radius.push_back(0.15 * params.fruit_radius);
28 radius.push_back(1e-3 * params.fruit_radius);
29
30 U.push_back(context->addTube(params.fruit_subdivisions, nodes, radius, params.fruit_texture_file.c_str()));
31
32 float azimuth = 2.f * PI_F * context->randu();
33
34 if (context->randu() < 0.75) {
35
36 std::vector<vec3> nodes2 = nodes;
37 for (int i = 0; i < nodes2.size(); i++) {
38 nodes2.at(i) = nodes2.at(i) = sphere2cart(make_SphericalCoord(1.5 * params.fruit_radius, 0, azimuth));
39 }
40
41 U.push_back(context->addTube(params.fruit_subdivisions, nodes2, radius, params.fruit_texture_file.c_str()));
42 }
43
44 if (context->randu() < 0.5) {
45
46 std::vector<vec3> nodes3 = nodes;
47 for (int i = 0; i < nodes3.size(); i++) {
48 nodes3.at(i) = nodes3.at(i) = sphere2cart(make_SphericalCoord(1.5 * params.fruit_radius, 0, azimuth + 0.5 * PI_F));
49 }
50
51 U.push_back(context->addTube(params.fruit_subdivisions, nodes3, radius, params.fruit_texture_file.c_str()));
52 }
53
54 return U;
55}
56
57std::vector<uint> leafPrototype(const StrawberryParameters &params, Context *context) {
58
59 int Nx = params.leaf_subdivisions.x;
60 int Ny = ceil(params.leaf_subdivisions.y * 0.5);
61
62 float dx = 1.f / float(Nx);
63 float dy = 0.5f / float(Ny);
64
65 std::vector<uint> UUIDs;
66
67 float a0 = 0.6;
68 float e0 = 0.4f;
69
70 for (int i = 0; i < Nx; i++) {
71 for (int j = 0; j < Ny; j++) {
72
73 float x = i * dx;
74 float y = j * dy;
75
76 float mag, z;
77
78 mag = sqrt(x * x + 2 * y * y);
79 z = a0 * mag / (e0 + mag);
80 vec3 v0(x, y, z);
81
82 mag = sqrt((x + dx) * (x + dx) + 2 * y * y);
83 z = a0 * mag / (e0 + mag);
84 vec3 v1(x + dx, y, z);
85
86 mag = sqrt((x + dx) * (x + dx) + 2 * (y + dy) * (y + dy));
87 z = a0 * mag / (e0 + mag);
88 vec3 v2(x + dx, y + dy, z);
89
90 mag = sqrt(x * x + 2 * (y + dy) * (y + dy));
91 z = a0 * mag / (e0 + mag);
92 vec3 v3(x, y + dy, z);
93
94 vec2 uv0(1.f - x, 0.5 + j * dy);
95 vec2 uv1(1.f - x - dx, 0.5 + j * dy);
96 vec2 uv2(1.f - x - dx, 0.5 + (j + 1) * dy);
97 vec2 uv3(1.f - x, 0.5 + (j + 1) * dy);
98
99 UUIDs.push_back(context->addTriangle(v0, v1, v2, params.leaf_texture_file.c_str(), uv0, uv1, uv2));
100 UUIDs.push_back(context->addTriangle(v0, v2, v3, params.leaf_texture_file.c_str(), uv0, uv2, uv3));
101
102 v0.y = -v0.y;
103 v1.y = -v1.y;
104 v2.y = -v2.y;
105 v3.y = -v3.y;
106
107 uv0 = make_vec2(1.f - x, 0.5 - j * dy);
108 uv1 = make_vec2(1.f - x - dx, 0.5 - j * dy);
109 uv2 = make_vec2(1.f - x - dx, 0.5 - (j + 1) * dy);
110 uv3 = make_vec2(1.f - x, 0.5 - (j + 1) * dy);
111
112 UUIDs.push_back(context->addTriangle(v0, v2, v1, params.leaf_texture_file.c_str(), uv0, uv2, uv1));
113 UUIDs.push_back(context->addTriangle(v0, v3, v2, params.leaf_texture_file.c_str(), uv0, uv3, uv2));
114 }
115 }
116
117 return UUIDs;
118}
119
120void strawberryShoot(const StrawberryParameters &params, const helios::vec3 base_position, const helios::vec3 base_direction, const float length, const float bend_angle, const std::vector<uint> &leaf_prototype,
121 std::vector<std::vector<uint>> &leaf_UUIDs, std::vector<uint> &branch_UUIDs, std::vector<std::vector<std::vector<uint>>> &fruit_UUIDs, Context *context) {
122
123 std::vector<uint> U;
124
125 std::vector<vec3> nodes;
126 std::vector<float> radius;
127 std::vector<RGBcolor> color;
128
129 int node_count = round(2 * length * params.stem_subdivisions);
130
131 vec3 dir = base_direction;
132 dir.normalize();
133
134 SphericalCoord base_angle = cart2sphere(dir);
135
136 nodes.push_back(base_position);
137 radius.push_back(params.stem_radius);
138 color.push_back(params.stem_color);
139
140 float theta = base_angle.elevation;
141 for (int i = 1; i < node_count; i++) {
142
143 float vfrac = float(i) / float(node_count - 1);
144
145 radius.push_back(params.stem_radius * params.plant_height * (1.f - 0.8 * vfrac));
146
147 vec3 position = nodes.back() + length / float(node_count - 1) * (sphere2cart(make_SphericalCoord(1, theta, base_angle.azimuth)));
148
149 theta -= bend_angle / float(node_count - 1);
150
151 nodes.push_back(position);
152
153 color.push_back(params.stem_color);
154 }
155
156 U = context->addTube(params.stem_subdivisions, nodes, radius, color);
157 branch_UUIDs.insert(branch_UUIDs.end(), U.begin(), U.end());
158
159 // tip leaf
160
161
162 U = context->copyPrimitive(leaf_prototype);
163
164 context->scalePrimitive(U, make_vec3(params.leaf_length, 0.8 * params.leaf_length, params.leaf_length));
165 context->rotatePrimitive(U, 0.75 * (0.6 * PI_F - theta), "y");
166 context->rotatePrimitive(U, -base_angle.azimuth + 0.5 * PI_F, "z");
167
168 context->translatePrimitive(U, nodes.back());
169
170 leaf_UUIDs.push_back(U);
171
172 // lateral leaves
173 U = context->copyPrimitive(leaf_prototype);
174
175 context->scalePrimitive(U, 0.8 * make_vec3(params.leaf_length, 0.8 * params.leaf_length, params.leaf_length));
176 context->rotatePrimitive(U, 0.75 * (0.6 * PI_F - theta), "y");
177 context->rotatePrimitive(U, -base_angle.azimuth - 0.05 * PI_F, "z");
178
179 context->translatePrimitive(U, nodes.back());
180
181 leaf_UUIDs.push_back(U);
182
183 U = context->copyPrimitive(leaf_prototype);
184
185 context->scalePrimitive(U, 0.8 * make_vec3(params.leaf_length, 0.8 * params.leaf_length, params.leaf_length));
186 context->rotatePrimitive(U, 0.75 * (0.6 * PI_F - theta), "y");
187 context->rotatePrimitive(U, -base_angle.azimuth + 1.05 * PI_F, "z");
188
189 context->translatePrimitive(U, nodes.back());
190
191 leaf_UUIDs.push_back(U);
192
193 // fruit
194
195 if (params.fruit_radius > 0 && context->randu() < params.clusters_per_stem) {
196
197 vec3 cluster_position = interpolateTube(nodes, 0.35) + sphere2cart(make_SphericalCoord(0.1 + 0.2 * context->randu(), 0, 2 * PI_F * context->randu()));
198
199 fruit_UUIDs.push_back(strawberryCluster(cluster_position, params, context));
200 }
201}
202
204
205 std::vector<std::vector<uint>> leaf_UUIDs;
206 std::vector<uint> branch_UUIDs;
207 std::vector<std::vector<std::vector<uint>>> fruit_UUIDs;
208
209 std::vector<uint> leaf_prototype = leafPrototype(params, context);
210
211 for (int i = 0; i < params.stems_per_plant; i++) {
212
213 vec3 position = origin + sphere2cart(make_SphericalCoord(0.1 * context->randu() * params.plant_height, 0, 2 * PI_F * context->randu()));
214
215 vec3 base_direction = sphere2cart(make_SphericalCoord(0.45 * PI_F - 0.15 * PI_F * float(i) / float(params.stems_per_plant - 1), 2 * PI_F * context->randu()));
216
217 float tip_angle = 0.3 * PI_F * float(i) / float(params.stems_per_plant - 1);
218
219 float length = (0.75 + 0.25 * float(params.stems_per_plant - 1 - i) / float(params.stems_per_plant - 1)) * params.plant_height * (0.9 + 0.2 * context->randu());
220
221 strawberryShoot(params, position, base_direction, length, tip_angle, leaf_prototype, leaf_UUIDs, branch_UUIDs, fruit_UUIDs, context);
222 }
223
224 context->deletePrimitive(leaf_prototype);
225
226 UUID_leaf.push_back(leaf_UUIDs);
227 UUID_branch.push_back(branch_UUIDs);
228 UUID_fruit.push_back(fruit_UUIDs);
229
230 return UUID_leaf.size() - 1;
231}