Skip to content

Commit 44ad9ce

Browse files
committed
cleanup + basic floor avoidance
1 parent 45dc5e5 commit 44ad9ce

File tree

4 files changed

+175
-82
lines changed

4 files changed

+175
-82
lines changed

m_tree/source/tree_functions/BranchFunction.cpp

Lines changed: 128 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,112 @@
55
#include "source/utilities/NodeUtilities.hpp"
66
#include "source/utilities/GeometryUtilities.hpp"
77

8+
9+
using namespace Mtree;
10+
11+
namespace
12+
{
13+
void update_positions_rec(Node& node, const Vector3& position)
14+
{
15+
auto& info = static_cast<BranchFunction::BranchGrowthInfo&>(*node.growthInfo);
16+
info.position = position;
17+
18+
for (auto& child : node.children)
19+
{
20+
Vector3 child_position = position + node.direction * node.length * child->position_in_parent;
21+
update_positions_rec(child->node, child_position);
22+
}
23+
}
24+
25+
bool avoid_floor(const Vector3& node_position, Vector3& node_direction, float parent_length) // return true if branch should be terminated
26+
{
27+
if (node_direction.z() < 0)
28+
{
29+
node_direction[2] -= node_direction[2] * 2 / (2 + node_position.z());
30+
}
31+
return (node_position + node_direction).z() * parent_length * 4 < 0; // is node heading to floor too fast
32+
}
33+
34+
Vector3 get_main_child_direction(Node& parent, const Vector3& parent_position, const float up_attraction, const float flatness, const float randomness, const float resolution, bool& should_terminate)
35+
{
36+
Vector3 random_dir = Geometry::random_vec(flatness).normalized() + Vector3{ 0,0,1 } * up_attraction;
37+
Vector3 child_direction = parent.direction + random_dir * randomness / resolution;
38+
should_terminate = avoid_floor(parent_position, child_direction, parent.length);
39+
child_direction.normalize();
40+
return child_direction;
41+
}
42+
43+
Vector3 get_split_direction(const Node& parent, const Vector3& parent_position, const float up_attraction, const float flatness, const float resolution, const float angle)
44+
{
45+
Vector3 child_direction = Geometry::random_vec();
46+
child_direction = child_direction.cross(parent.direction) + Vector3{ 0,0,1 } *up_attraction * flatness;
47+
Vector3 flat_normal = Vector3{ 0,0,1 }.cross(parent.direction).cross(parent.direction).normalized();
48+
child_direction -= child_direction.dot(flat_normal) * flatness * flat_normal;
49+
avoid_floor(parent_position, child_direction, parent.length);
50+
child_direction = Geometry::lerp(parent.direction, child_direction, angle / 90); // TODO use slerp for correct angle
51+
child_direction.normalize();
52+
return child_direction;
53+
}
54+
55+
void mark_inactive(Node& node)
56+
{
57+
auto& info = static_cast<BranchFunction::BranchGrowthInfo&>(*node.growthInfo);
58+
info.inactive = true;
59+
}
60+
61+
bool propagate_inactive_rec(Node& node)
62+
{
63+
auto* info = dynamic_cast<BranchFunction::BranchGrowthInfo*>(node.growthInfo.get());
64+
65+
if (node.children.size() == 0 || info->inactive)
66+
return info->inactive;
67+
68+
bool inactive = false;
69+
for (size_t i = 0; i < node.children.size(); i++)
70+
{
71+
if (propagate_inactive_rec(node.children[i]->node))
72+
inactive = true;
73+
}
74+
info->inactive = inactive;
75+
return inactive;
76+
}
77+
}
78+
879
namespace Mtree
980
{
10-
void BranchFunction::apply_gravity(Node& node)
81+
void BranchFunction::apply_gravity_to_branch(Node& branch_origin)
1182
{
12-
update_weight_rec(node);
13-
apply_gravity_rec(node, Eigen::AngleAxisf::Identity());
83+
propagate_inactive_rec(branch_origin);
84+
update_weight_rec(branch_origin);
85+
apply_gravity_rec(branch_origin, Eigen::AngleAxisf::Identity());
86+
BranchGrowthInfo& info = static_cast<BranchGrowthInfo&>(*branch_origin.growthInfo);
87+
update_positions_rec(branch_origin, info.position);
1488
}
1589

16-
void BranchFunction::apply_gravity_rec(Node& node, Eigen::AngleAxisf previous_rotations)
90+
void BranchFunction::apply_gravity_rec(Node& node, Eigen::AngleAxisf curent_rotation)
1791
{
18-
float horizontality = 1-abs(node.direction.z());
1992
BranchGrowthInfo& info = static_cast<BranchGrowthInfo&>(*node.growthInfo);
20-
info.age += 1/resolution;
21-
float displacement = horizontality * std::pow(info.cumulated_weight, .5f) * gravity_strength / resolution / resolution / 1000 / (1+info.age);
22-
displacement *= std::exp(- std::abs(info.deviation_from_rest_pose / resolution * stiffness));
23-
info.deviation_from_rest_pose += displacement;
93+
if (!info.inactive || true)
94+
{
95+
float horizontality = 1 - abs(node.direction.z());
96+
info.age += 1 / resolution;
97+
float displacement = horizontality * std::pow(info.cumulated_weight, .5f) * gravity_strength / resolution / resolution / 1000 / (1 + info.age);
98+
displacement *= std::exp(-std::abs(info.deviation_from_rest_pose / resolution * stiffness));
99+
info.deviation_from_rest_pose += displacement;
24100

25-
Vector3 tangent = node.direction.cross(Vector3{0,0,-1}).normalized();
26-
Eigen::AngleAxisf rot{displacement, tangent};
27-
rot = rot * previous_rotations;
101+
Vector3 tangent = node.direction.cross(Vector3{ 0,0,-1 }).normalized();
102+
Eigen::AngleAxisf rot{ displacement, tangent };
103+
curent_rotation = rot * curent_rotation;
28104

29-
node.direction = rot * node.direction;
105+
node.direction = curent_rotation * node.direction;
106+
}
30107

31108
for (auto& child : node.children)
32109
{
33-
apply_gravity_rec(child->node, rot);
110+
apply_gravity_rec(child->node, curent_rotation);
34111
}
35112
}
36-
113+
37114
void BranchFunction::update_weight_rec(Node& node)
38115
{
39116
float node_weight = node.length;
@@ -48,54 +125,55 @@ namespace Mtree
48125
info->cumulated_weight = node_weight;
49126
}
50127

51-
52128
// grow extremity by one level (add one or more children)
53129
void BranchFunction::grow_node_once(Node& node, const int id, std::queue<std::reference_wrapper<Node>>& results)
54130
{
55131
bool break_branch = rand_gen.get_0_1() * resolution < break_chance;
56132
if (break_branch)
133+
{
134+
mark_inactive(node);
57135
return;
58-
59-
bool split = rand_gen.get_0_1() * resolution < split_proba; // should the node split into two children
136+
}
60137

61138
BranchGrowthInfo& info = static_cast<BranchGrowthInfo&>(*node.growthInfo);
62139
float factor_in_branch = info.current_length / info.desired_length;
63140

64-
Vector3 random_dir = Geometry::random_vec(flatness).normalized() + Vector3{0,0,1} * up_attraction;
65-
Vector3 child_direction = node.direction + random_dir * randomness.execute(factor_in_branch) / resolution;
66-
// child_direction += Vector3{0,0,1} * up_attraction / resolution / 50 * (1 - node.direction.z());
67-
child_direction.normalize();
68141
float child_radius = Geometry::lerp(info.origin_radius, info.origin_radius * end_radius, factor_in_branch);
69142
float child_length = std::min(1/resolution, info.desired_length - info.current_length);
70-
143+
bool should_terminate;
144+
Vector3 child_direction = get_main_child_direction(node, info.position, up_attraction, flatness, randomness.execute(factor_in_branch), resolution, should_terminate);
145+
146+
if (should_terminate)
147+
{
148+
mark_inactive(node);
149+
return;
150+
}
151+
71152
NodeChild child{ Node{child_direction, node.tangent, child_length, child_radius, id}, 1 };
72153
node.children.push_back(std::make_shared<NodeChild>(std::move(child)));
73154
auto& child_node = node.children.back()->node;
74155

75156
float current_length = info.current_length + child_length;
76-
BranchGrowthInfo child_info{info.desired_length, info.origin_radius, current_length};
157+
Vector3 child_position = info.position + child_direction * child_length;
158+
BranchGrowthInfo child_info{info.desired_length, info.origin_radius, child_position, current_length};
77159
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(child_info);
78160
if (current_length < info.desired_length)
79161
{
80162
results.push(std::ref<Node>(child_node));
81163
}
82164

165+
bool split = rand_gen.get_0_1() * resolution < split_proba; // should the node split into two children
83166
if (split)
84167
{
85-
child_direction = Geometry::random_vec();
86-
child_direction = child_direction.cross(node.direction) + Vector3{0,0,1} * up_attraction * flatness;
87-
Vector3 flat_normal = Vector3{ 0,0,1 }.cross(node.direction).cross(node.direction).normalized();
88-
child_direction -= child_direction.dot(flat_normal) * flatness * flat_normal;
89-
child_direction.normalize();
90-
child_direction = Geometry::lerp(node.direction, child_direction, split_angle/90);
91-
child_direction.normalize();
92-
child_radius = node.radius * split_radius;
168+
Vector3 split_child_direction = get_split_direction(node, info.position, up_attraction, flatness, resolution, split_angle);
169+
float split_child_radius = node.radius * split_radius;
93170

94-
NodeChild child{ Node{child_direction, node.tangent, child_length, child_radius, id}, rand_gen.get_0_1() };
171+
NodeChild child{ Node{split_child_direction, node.tangent, child_length, split_child_radius, id}, rand_gen.get_0_1() };
95172
node.children.push_back(std::make_shared<NodeChild>(std::move(child)));
96173
auto& child_node = node.children.back()->node;
97174

98-
BranchGrowthInfo child_info{ info.desired_length, info.origin_radius * split_radius, current_length };
175+
Vector3 split_child_position = info.position + split_child_direction * child_length;
176+
BranchGrowthInfo child_info{ info.desired_length, info.origin_radius * split_radius, split_child_position, current_length};
99177
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(child_info);
100178
if (current_length < info.desired_length)
101179
{
@@ -104,7 +182,7 @@ namespace Mtree
104182
}
105183
}
106184

107-
void BranchFunction::grow_origins(NodeUtilities::NodeSelection& origins, const int id)
185+
void BranchFunction::grow_origins(std::vector<std::reference_wrapper<Node>>& origins, const int id)
108186
{
109187
std::queue<std::reference_wrapper<Node>> extremities;
110188
for (auto& node_ref : origins)
@@ -114,49 +192,50 @@ namespace Mtree
114192
int batch_size = extremities.size();
115193
while (!extremities.empty())
116194
{
117-
batch_size --;
118-
auto& node = extremities.front().get();
119-
extremities.pop();
120-
grow_node_once(node, id, extremities);
121-
122195
if (batch_size == 0)
123196
{
124197
batch_size = extremities.size();
125198
for (auto& node_ref : origins)
126199
{
127-
apply_gravity(node_ref.get());
200+
apply_gravity_to_branch(node_ref.get());
128201
}
129202
}
203+
auto& node = extremities.front().get();
204+
extremities.pop();
205+
grow_node_once(node, id, extremities);
206+
batch_size --;
130207
}
131208
}
132209

210+
133211
// get the origins of the branches that will be created.
134212
// origins are created from the nodes made by the parent TreeFunction
135-
NodeUtilities::NodeSelection BranchFunction::get_origins(std::vector<Stem>& stems, const int id, const int parent_id)
213+
std::vector<std::reference_wrapper<Node>> BranchFunction::get_origins(std::vector<Stem>& stems, const int id, const int parent_id)
136214
{
137215
// get all nodes created by the parent TreeFunction, organised by branch
138216
NodeUtilities::BranchSelection selection = NodeUtilities::select_from_tree(stems, parent_id);
139-
NodeUtilities::NodeSelection origins;
217+
std::vector<std::reference_wrapper<Node>> origins;
140218

141219
float origins_dist = 1 / (branches_density + .001); // distance between two consecutive origins
142220

143-
for (auto& branch : selection) // iterating over parent branches
221+
for (auto& branch : selection) // parent branches
144222
{
145223
if (branch.size() == 0)
146224
{
147225
continue;
148226
}
149227

150-
float branch_length = NodeUtilities::get_branch_length(branch[0].get());
228+
float branch_length = NodeUtilities::get_branch_length(*branch[0].node);
151229
float absolute_start = start * branch_length; // the length at which we can start adding new branch origins
152230
float absolute_end = end * branch_length; // the length at which we stop adding new branch origins
153231
float current_length = 0;
154232
float dist_to_next_origin = absolute_start;
155-
Vector3 tangent = Geometry::get_orthogonal_vector(branch[0].get().direction);
233+
Vector3 tangent = Geometry::get_orthogonal_vector(branch[0].node->direction);
156234

157235
for (size_t node_index = 0; node_index<branch.size(); node_index++)
158236
{
159-
auto& node = branch[node_index].get();
237+
auto& node = *branch[node_index].node;
238+
Vector3 node_position = branch[node_index].node_position;
160239
if (node.children.size() == 0) // cant add children since it would "continue" the branch and not ad a split
161240
{
162241
continue;
@@ -192,7 +271,8 @@ namespace Mtree
192271
NodeChild child{Node{child_direction, node.tangent, 1/(resolution+0.001f), child_radius, id}, position_in_parent};
193272
node.children.push_back(std::make_shared<NodeChild>(std::move(child)));
194273
auto& child_node = node.children.back()->node;
195-
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(length.execute(factor), child_radius, child_node.length);
274+
Vector3 child_position = node_position + node.direction * node.length * position_in_parent;
275+
child_node.growthInfo = std::make_unique<BranchGrowthInfo>(length.execute(factor), child_radius, child_position, child_node.length, 0);
196276
origins.push_back(std::ref(child_node));
197277
position_in_parent += position_in_parent_step;
198278
if (i > 0)

m_tree/source/tree_functions/BranchFunction.hpp

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,6 @@ namespace Mtree
1111
{
1212
class BranchFunction : public TreeFunction
1313
{
14-
private:
15-
16-
class BranchGrowthInfo:public GrowthInfo
17-
{
18-
public:
19-
float desired_length;
20-
float current_length;
21-
float origin_radius;
22-
float cumulated_weight=0;
23-
float deviation_from_rest_pose;
24-
float age=0;
25-
BranchGrowthInfo(float desired_length, float origin_radius, float current_length=0, float deviation=0) :
26-
desired_length(desired_length), origin_radius(origin_radius),
27-
current_length(current_length), deviation_from_rest_pose(deviation){};
28-
};
29-
30-
31-
NodeUtilities::NodeSelection get_origins(std::vector<Stem>& stems, const int id, const int parent_id);
32-
33-
void grow_origins(NodeUtilities::NodeSelection&, const int id);
34-
35-
void grow_node_once(Node& node, const int id, std::queue<std::reference_wrapper<Node>>& results);
36-
37-
void apply_gravity(Node& node);
38-
39-
void apply_gravity_rec(Node& node, Eigen::AngleAxisf previous_rotations);
40-
41-
void update_weight_rec(Node& node);
42-
4314
public:
4415
float start;
4516
float end;
@@ -61,6 +32,38 @@ namespace Mtree
6132
float split_proba = .05f; // 0 < x
6233

6334
void execute(std::vector<Stem>& stems, int id, int parent_id) override;
35+
36+
class BranchGrowthInfo :public GrowthInfo
37+
{
38+
public:
39+
float desired_length;
40+
float current_length;
41+
float origin_radius;
42+
float cumulated_weight = 0;
43+
float deviation_from_rest_pose;
44+
float age = 0;
45+
bool inactive = false;
46+
Vector3 position;
47+
BranchGrowthInfo(float desired_length, float origin_radius, Vector3 position, float current_length = 0, float deviation = 0) :
48+
desired_length(desired_length), origin_radius(origin_radius),
49+
current_length(current_length), deviation_from_rest_pose(deviation),
50+
position(position) {};
51+
};
52+
53+
private:
54+
55+
std::vector<std::reference_wrapper<Node>> get_origins(std::vector<Stem>& stems, const int id, const int parent_id);
56+
57+
void grow_origins(std::vector<std::reference_wrapper<Node>>&, const int id);
58+
59+
void grow_node_once(Node& node, const int id, std::queue<std::reference_wrapper<Node>>& results);
60+
61+
void apply_gravity_to_branch(Node& node);
62+
63+
void apply_gravity_rec(Node& node, Eigen::AngleAxisf previous_rotations);
64+
65+
void update_weight_rec(Node& node);
66+
6467
};
6568

6669
}

m_tree/source/utilities/NodeUtilities.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ namespace Mtree
1919
return length;
2020
}
2121

22-
void select_from_tree_rec(BranchSelection& selection, Node& node, int id)
22+
void select_from_tree_rec(BranchSelection& selection, Node& node, const Vector3& node_position, int id)
2323
{
2424
if (node.creator_id == id)
2525
{
26-
selection[selection.size() - 1].push_back(std::ref(node));
26+
selection[selection.size() - 1].push_back(NodeSelectionElement{node, node_position});
2727
}
2828
bool first_child = true;
2929
for (auto& child : node.children)
@@ -33,7 +33,8 @@ namespace Mtree
3333
selection.emplace_back();
3434
}
3535
first_child = false;
36-
select_from_tree_rec(selection, child->node, id);
36+
Vector3 child_position = node_position + child->node.direction * child->position_in_parent * child->node.length;
37+
select_from_tree_rec(selection, child->node, child_position, id);
3738
}
3839
}
3940

@@ -43,7 +44,7 @@ namespace Mtree
4344
selection.emplace_back();
4445
for (Stem& stem : stems)
4546
{
46-
select_from_tree_rec(selection, stem.node, id);
47+
select_from_tree_rec(selection, stem.node, stem.position, id);
4748
}
4849
return selection;
4950
}

0 commit comments

Comments
 (0)