1.3.49
 
Loading...
Searching...
No Matches
walnut.cpp
1#include "CanopyGenerator.h"
2
3using namespace helios;
4using namespace std;
5
6
7std::vector<uint> leafPrototype(const WalnutCanopyParameters &params, std::minstd_rand0 generator, Context *context) {
8
9 int Nx = params.leaf_subdivisions.x;
10 int Ny = ceil(params.leaf_subdivisions.y * 0.5);
11
12 float dx = 1.f / float(Nx);
13 float dy = 0.5f / float(Ny);
14
15 std::uniform_real_distribution<float> unif_distribution;
16
17 std::vector<uint> UUIDs;
18
19 float fold = 0.1 * PI_F; // unif_distribution(generator)*0.3*PI_F;
20
21 for (int i = 0; i < Nx; i++) {
22 for (int j = 0; j < Ny; j++) {
23
24 float x = i * dx;
25 float y = j * dy;
26
27 float mag, z;
28
29 mag = sqrt(x * x + 2 * y * y);
30 z = y * sinf(fold);
31 vec3 v0(x, y, z);
32
33 mag = sqrt((x + dx) * (x + dx) + 2 * y * y);
34 z = y * sinf(fold);
35 vec3 v1(x + dx, y, z);
36
37 mag = sqrt((x + dx) * (x + dx) + 2 * (y + dy) * (y + dy));
38 z = (y + dy) * sinf(fold);
39 vec3 v2(x + dx, y + dy, z);
40
41 mag = sqrt(x * x + 2 * (y + dy) * (y + dy));
42 z = (y + dy) * sinf(fold);
43 vec3 v3(x, y + dy, z);
44
45 vec2 uv0(x, 0.5 + j * dy);
46 vec2 uv1(x + dx, 0.5 + j * dy);
47 vec2 uv2(x + dx, 0.5 + (j + 1) * dy);
48 vec2 uv3(x, 0.5 + (j + 1) * dy);
49
50 UUIDs.push_back(context->addTriangle(v0, v1, v2, params.leaf_texture_file.c_str(), uv0, uv1, uv2));
51 UUIDs.push_back(context->addTriangle(v0, v2, v3, params.leaf_texture_file.c_str(), uv0, uv2, uv3));
52
53 v0.y = -v0.y;
54 v1.y = -v1.y;
55 v2.y = -v2.y;
56 v3.y = -v3.y;
57
58 uv0 = make_vec2(x, 0.5 - j * dy);
59 uv1 = make_vec2(x + dx, 0.5 - j * dy);
60 uv2 = make_vec2(x + dx, 0.5 - (j + 1) * dy);
61 uv3 = make_vec2(x, 0.5 - (j + 1) * dy);
62
63 UUIDs.push_back(context->addTriangle(v0, v2, v1, params.leaf_texture_file.c_str(), uv0, uv2, uv1));
64 UUIDs.push_back(context->addTriangle(v0, v3, v2, params.leaf_texture_file.c_str(), uv0, uv3, uv2));
65 }
66 }
67
68 return UUIDs;
69}
70
71std::vector<uint> nutPrototype(const WalnutCanopyParameters params, Context *context) {
72
73 std::vector<uint> UUIDs = context->addSphere(params.fruit_subdivisions, make_vec3(0, 0, 0), 1, params.fruit_texture_file.c_str());
74
75 context->scalePrimitive(UUIDs, make_vec3(0.85, 0.85, 1));
76
77 return UUIDs;
78}
79
80uint addBranch(const vec3 p_start, const vec3 tan_start, const float r_start, const vec3 p_end, const vec3 tan_end, const float r_end, const uint Nsegs, const WalnutCanopyParameters params, std::minstd_rand0 generator, Context *context) {
81
82 uint ID;
83
84 std::vector<vec3> position;
85 std::vector<float> radius;
86
87 // int ikink = randu(1,Nsegs-2);
88
89 // vec3 pkink = spline_interp3( float(ikink)/float(Nsegs-1), p_start, tan_start, p_end, tan_end );
90 // vec3 tankink = 0.5*(tan_start+tan_end)+0.*make_vec3(getVariation(1.f,generator),getVariation(1.f,generator),getVariation(1.f,generator));
91
92 // for( int i=0; i<ikink; i++ ){
93
94 // position.push_back( spline_interp3( float(i)/float(Nsegs-1), p_start, tan_start, pkink, tankink ) );
95
96 // radius.push_back( r_start + float(i)/float(Nsegs-1)*(r_end-r_start) );
97
98 // }
99
100 // for( int i=ikink; i<Nsegs; i++ ){
101
102 // position.push_back( spline_interp3( float(i)/float(Nsegs-1), pkink, tankink, p_end, tan_end ) );
103
104 // radius.push_back( r_start + float(i)/float(Nsegs-1)*(r_end-r_start) );
105
106 // }
107
108 for (int i = 0; i < Nsegs; i++) {
109
110 position.push_back(spline_interp3(float(i) / float(Nsegs - 1), p_start, tan_start, p_end, tan_end));
111
112 radius.push_back(r_start + float(i) / float(Nsegs - 1) * (r_end - r_start));
113 }
114
115 radius.front() *= 1.3;
116
117 ID = context->addTubeObject(params.wood_subdivisions, position, radius, params.wood_texture_file.c_str());
118
119 return ID;
120}
121
122void branchRecursion(const std::vector<vec3> position_parent, const std::vector<float> radius_parent, uint level, uint max_levels, const std::vector<uint> leaf_prototype, const std::vector<uint> nut_prototype, std::vector<uint> &UUID_branch_plant,
123 std::vector<std::vector<uint>> &UUID_leaf_plant, std::vector<std::vector<uint>> &UUID_fruit_plant, const WalnutCanopyParameters params, std::minstd_rand0 generator, Context *context) {
124
125 std::uniform_real_distribution<float> unif_distribution;
126
127 if (level > max_levels) { // leaves and nuts
128
129 int Nleaves = 6;
130
131 for (int i = 0; i < Nleaves; i++) {
132
133 float u = 0.3 + 0.7 * float(i) / float(Nleaves - 1);
134
135 float downangle = 0.15 * PI_F + getVariation(0.1f * PI_F, generator);
136
137 vec3 r0 = interpolateTube(position_parent, u);
138 vec3 r1 = interpolateTube(position_parent, 0.98 * u);
139 vec3 dr = r1 - r0;
140
141 // float elevation = cart2sphere(dr).elevation;
142 float azimuth = cart2sphere(dr).azimuth + getVariation(0.2f * PI_F, generator);
143
144 float elevation = 0.25 * PI_F + getVariation(0.1f * PI_F, generator);
145
146 std::vector<uint> UUIDs = context->copyPrimitive(leaf_prototype);
147 UUID_leaf_plant.push_back(UUIDs);
148
149 context->scalePrimitive(UUIDs, make_vec3(params.leaf_length, 0.5 * params.leaf_length, 0.5 * params.leaf_length));
150
151 context->rotatePrimitive(UUIDs, elevation, "x");
152 context->rotatePrimitive(UUIDs, downangle, "y");
153 context->rotatePrimitive(UUIDs, -azimuth, "z");
154
155 context->translatePrimitive(UUIDs, r0 + 0.1 * params.leaf_length * make_vec3(cosf(-azimuth), sinf(-azimuth), -0.5 * sinf(downangle)));
156
157 UUIDs = context->copyPrimitive(leaf_prototype);
158 UUID_leaf_plant.push_back(UUIDs);
159
160 context->scalePrimitive(UUIDs, make_vec3(params.leaf_length, 0.5 * params.leaf_length, 0.5 * params.leaf_length));
161
162 context->rotatePrimitive(UUIDs, elevation, "x");
163 context->rotatePrimitive(UUIDs, downangle, "y");
164 context->rotatePrimitive(UUIDs, -azimuth + PI_F, "z");
165
166 context->translatePrimitive(UUIDs, r0 - 0.1 * params.leaf_length * make_vec3(cosf(-azimuth), sinf(-azimuth), -0.5 * sinf(downangle)));
167
168 if (i == Nleaves - 1) { // tip leaf
169
170 UUIDs = context->copyPrimitive(leaf_prototype);
171 UUID_leaf_plant.push_back(UUIDs);
172
173 context->scalePrimitive(UUIDs, make_vec3(params.leaf_length, 0.5 * params.leaf_length, 0.5 * params.leaf_length));
174
175 elevation = 0.25 * PI_F + getVariation(0.1f * PI_F, generator);
176
177 context->rotatePrimitive(UUIDs, elevation, "y");
178 context->rotatePrimitive(UUIDs, 0, "x");
179 context->rotatePrimitive(UUIDs, -azimuth + 0.5 * PI_F, "z");
180
181 context->translatePrimitive(UUIDs, r0 - 0. * params.leaf_length * make_vec3(sinf(-azimuth), cosf(-azimuth), 0));
182 }
183
184 // nut
185
186 if (params.fruit_radius > 0) {
187
188 float Rnut = unif_distribution(generator);
189
190 if (Rnut < 0.005) { // triplet
191
192 // uint objID = context->copyObject( nut_prototype );
193 // UUID_fruit_plant.push_back( context->getObjectPointer(objID)->getPrimitiveUUIDs() );
194
195 // context->getSphereObjectPointer(objID)->scale( params.fruit_radius );
196
197 // context->getObjectPointer(objID)->translate( r0 - params.fruit_radius*make_vec3( sinf(-azimuth), cosf(-azimuth), -0.65) );
198
199 std::vector<uint> nut_UUIDs = context->copyPrimitive(nut_prototype);
200 UUID_fruit_plant.push_back(nut_UUIDs);
201
202 context->scalePrimitive(nut_UUIDs, make_vec3(params.fruit_radius, params.fruit_radius, params.fruit_radius));
203
204 context->translatePrimitive(nut_UUIDs, r0 - params.fruit_radius * make_vec3(sinf(-azimuth), cosf(-azimuth), -0.65));
205 }
206 if (Rnut < 0.01) { // double
207
208 std::vector<uint> nut_UUIDs = context->copyPrimitive(nut_prototype);
209 UUID_fruit_plant.push_back(nut_UUIDs);
210
211 context->scalePrimitive(nut_UUIDs, make_vec3(params.fruit_radius, params.fruit_radius, params.fruit_radius));
212
213 context->translatePrimitive(nut_UUIDs, r0 - params.fruit_radius * make_vec3(2.f * sinf(-azimuth), 2.f * cosf(-azimuth), -0.85));
214 }
215 if (Rnut < 0.05) { // single
216
217 std::vector<uint> nut_UUIDs = context->copyPrimitive(nut_prototype);
218 UUID_fruit_plant.push_back(nut_UUIDs);
219
220 context->scalePrimitive(nut_UUIDs, make_vec3(params.fruit_radius, params.fruit_radius, params.fruit_radius));
221
222 context->translatePrimitive(nut_UUIDs, r0 - params.fruit_radius * make_vec3(sinf(-azimuth), cosf(-azimuth), -0.75));
223 }
224 }
225 }
226
227
228 } else { // branches
229
230 float L = 0;
231 int Nbranch;
232 if (level == 1) {
233 L = params.branch_length.x;
234 Nbranch = 8;
235 } else if (level == 2) {
236 L = params.branch_length.y;
237 Nbranch = 6;
238 } else if (level == 3) {
239 L = params.branch_length.z;
240 Nbranch = 4;
241 }
242
243 if (L == 0) {
244 return;
245 }
246
247 // int Nbranch = fmin(8,ceil(5*L));
248
249 // random azimuthal rotation of first new branch
250 float phi0 = 2 * PI_F * unif_distribution(generator);
251
252 for (int i = 0; i < Nbranch; i++) {
253
254 // phi0 += 0.45*PI_F*(1.f+getVariation(0.2,generator));
255 phi0 += 60 * PI_F / 180.f * (1.f + getVariation(0.3f, generator));
256
257 // new branch height as fraction of trunk height
258 float u = fmin(1.f, 0.2 + 0.8 * float(i + 1) / float(Nbranch) + getVariation(0.05f, generator));
259
260 // position of new branch base
261 vec3 pbase = interpolateTube(position_parent, u);
262 // vector pointing in direction of parent branch
263 vec3 nbase = pbase - interpolateTube(position_parent, 0.98 * u);
264
265 // unit vector perpendicular to parent branch
266 vec3 bnorm = cross(make_vec3(0, 1, 1), nbase);
267 bnorm.normalize();
268
269 // vector perpendicular to new branch
270 vec3 pvec1 = cross(bnorm, nbase);
271
272 // direction of new branch base - apply random rotation relative to parent
273 bnorm = rotatePointAboutLine(bnorm, make_vec3(0, 0, 0), pvec1, 0.1 * PI_F + 0.15 * PI_F * float(i) / float(Nbranch - 1));
274
275 // direction of new branch base - apply random rotation about parent
276 vec3 bnorm1 = rotatePointAboutLine(bnorm, make_vec3(0, 0, 0), nbase, phi0);
277 bnorm1.normalize();
278 vec3 bnorm2 = rotatePointAboutLine(bnorm, make_vec3(0, 0, 0), nbase, phi0 + PI_F + getVariation(0.5f, generator));
279 bnorm2.normalize();
280
281 float L1 = (0.5 + 0.5 * unif_distribution(generator)) * L;
282 float L2 = (0.5 + 0.5 * unif_distribution(generator)) * L;
283
284 // base radius of new branch
285 float rbase1 = 0.6 * interpolateTube(radius_parent, u);
286 float rbase2 = rbase1 * (0.4 + 0.6 * L2 / L);
287 rbase1 = rbase1 * (0.4 + 0.6 * L1 / L);
288
289 vec3 pend1 = bnorm1 + 0.2 * L1 * make_vec3(0, 0, 1);
290 pend1.normalize();
291 vec3 pend2 = bnorm2 + 0.2 * L2 * make_vec3(0, 0, 1);
292 pend2.normalize();
293
294 uint ID1 = addBranch(pbase, 0.5 * L1 * bnorm1, rbase1, pbase + pend1 * L1, L1 * make_vec3(0, 0, 1.f + getVariation(1, generator)), 0.15 * rbase1, 8, params, generator, context);
295 uint ID2 = addBranch(pbase, 0.5 * L2 * bnorm2, rbase2, pbase + pend2 * L2, L2 * make_vec3(0, 0, 1.f + getVariation(1, generator)), 0.15 * rbase2, 8, params, generator, context);
296
297 std::vector<uint> UUID = context->getObjectPointer(ID1)->getPrimitiveUUIDs();
298 UUID_branch_plant.insert(UUID_branch_plant.end(), UUID.begin(), UUID.end());
299 UUID = context->getObjectPointer(ID2)->getPrimitiveUUIDs();
300 UUID_branch_plant.insert(UUID_branch_plant.end(), UUID.begin(), UUID.end());
301
302 std::vector<vec3> pos_parent = context->getTubeObjectPointer(ID1)->getNodes();
303 std::vector<float> rad_parent = context->getTubeObjectPointer(ID1)->getNodeRadii();
304
305 branchRecursion(pos_parent, rad_parent, level + 1, max_levels, leaf_prototype, nut_prototype, UUID_branch_plant, UUID_leaf_plant, UUID_fruit_plant, params, generator, context);
306
307 pos_parent = context->getTubeObjectPointer(ID2)->getNodes();
308 rad_parent = context->getTubeObjectPointer(ID2)->getNodeRadii();
309
310 branchRecursion(pos_parent, rad_parent, level + 1, max_levels, leaf_prototype, nut_prototype, UUID_branch_plant, UUID_leaf_plant, UUID_fruit_plant, params, generator, context);
311 }
312 }
313}
314
315
317
318 std::vector<uint> leaf_prototype = leafPrototype(params, generator, context);
319
320 std::vector<uint> nut_prototype = nutPrototype(params, context);
321
322 std::vector<uint> UUIDs;
323 std::vector<uint> UUID_branch_plant;
324 std::vector<std::vector<uint>> UUID_leaf_plant;
325 std::vector<std::vector<std::vector<uint>>> UUID_fruit_plant;
326 UUID_fruit_plant.resize(1);
327
328 std::uniform_real_distribution<float> unif_distribution;
329
330 //------ trunk -------//
331
332 uint ID_trunk = addBranch(origin, make_vec3(0, 0, 1), params.trunk_radius, origin + make_vec3(unif_distribution(generator) * 3 * params.trunk_radius, unif_distribution(generator) * 3 * params.trunk_radius, params.trunk_height),
333 make_vec3(0, 0, 0.5 * params.trunk_height), 0.5 * params.trunk_radius, 8, params, generator, context);
334
335 UUID_trunk.push_back(context->getObjectPointer(ID_trunk)->getPrimitiveUUIDs());
336
337 std::vector<vec3> pos_trunk = context->getTubeObjectPointer(ID_trunk)->getNodes();
338 std::vector<float> rad_trunk = context->getTubeObjectPointer(ID_trunk)->getNodeRadii();
339
340 branchRecursion(pos_trunk, rad_trunk, 1, 3, leaf_prototype, nut_prototype, UUID_branch_plant, UUID_leaf_plant, UUID_fruit_plant.front(), params, generator, context);
341
342
343 context->deletePrimitive(leaf_prototype);
344 context->deletePrimitive(nut_prototype);
345
346 UUID_branch.push_back(UUID_branch_plant);
347 UUID_leaf.push_back(UUID_leaf_plant);
348 UUID_fruit.push_back(UUID_fruit_plant);
349
350 return UUID_leaf.size() - 1;
351}