WIP: Geometry Nodes: Shperical Ico Sphere #116982

Draft
Iliya Katushenock wants to merge 48 commits from mod_moder/blender:new_ico_sphere_alg into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
1 changed files with 75 additions and 65 deletions
Showing only changes of commit 476389d581 - Show all commits

View File

@ -232,7 +232,51 @@ class TriangleRange {
}
};
static void base_ico_sphere_positions(const float radius, MutableSpan<float3> positions)
class SphericalIterator {
private:
float3 previous_;
float3 current_;
float product_;
public:
SphericalIterator(const float3 &begin, const float3 &next, const float product)
: previous_(begin), current_(next), product_(product)
{
BLI_assert(math::is_unit_scale(begin) && math::is_unit_scale(next));
}
static SphericalIterator between_points(const float3 from, const float3 &to, const int steps)
{
const float3 normal = math::normalize(math::cross_tri(float3(0.0f), from, to));
const math::AngleRadian rotation = math::angle_between<float>(from, to) / steps;
const float reflection_factor = math::cos(rotation) * 2.0f;
const math::AxisAngle axis(normal, rotation);
return SphericalIterator(
from, math::transform_point(math::to_quaternion(axis), from), reflection_factor);
}
SphericalIterator &operator++()
{
const float3 next = current_ * product_ - previous_;
previous_ = current_;
current_ = next;
return *this;
}
SphericalIterator operator++(int)
{
SphericalIterator copied_iterator = *this;
++(*this);
return copied_iterator;
}
float3 operator*() const
{
return current_;
}
};
static void base_ico_sphere_positions(MutableSpan<float3> positions)
{
SCOPED_TIMER_AVERAGED(__func__);
positions.first() = float3(0.0f, 0.0f, 1.0f);
@ -255,9 +299,9 @@ static void base_ico_sphere_positions(const float radius, MutableSpan<float3> po
positions.last() = float3(0.0f, 0.0f, -1.0f);
for (float3 &position : positions) {
position *= radius;
}
BLI_assert(std::all_of(positions.begin(), positions.end(), [](const float3 &pos) -> bool {
return math::is_unit_scale(pos);
}));
}
static Span<int2> base_edge_point_indices()
@ -356,27 +400,17 @@ static void interpolate_edge_points(const int edge_verts_num,
SCOPED_TIMER_AVERAGED(__func__);
const Span<int2> base_edge_points = base_edge_point_indices();
const float lerp_factor = 1.0f / (edge_verts_num + 1);
for (const int edge_i : IndexRange(base_edges_num)) {
MutableSpan<float3> verts = edge_verts.slice(edge_i * edge_verts_num, edge_verts_num);
const int2 edge = base_edge_points[edge_i];
const float3 vert_a = base_verts[edge[0]];
const float3 vert_b = base_verts[edge[1]];
const float3 &point_a = base_verts[edge[0]];
const float3 &point_b = base_verts[edge[1]];
const float3 normalized_a = math::normalize(point_a);
const float3 normalized_b = math::normalize(point_b);
const float3 normal = math::normalize(
math::cross_tri(float3(0.0f), normalized_a, normalized_b));
const math::AngleRadian rotation = math::angle_between<float>(normalized_a, normalized_b);
math::AngleRadian steps(0.0f);
SphericalIterator rotation = SphericalIterator::between_points(
vert_a, vert_b, edge_verts_num + 1);
for (float3 &vert : verts) {
steps += rotation * lerp_factor;
const math::AxisAngle axis(normal, steps);
vert = math::transform_point(math::to_quaternion(axis), point_a);
vert = *rotation;
rotation++;
}
}
}
@ -391,59 +425,28 @@ static void interpolate_face_points(const int line_subdiv,
const constexpr int left_righr_points = 2;
const TriangleRange inner_face_verts =
TriangleRange(line_subdiv - left_righr_points).drop_bottom(1);
const float edge_lerp_factor = 1.0f / (inner_face_verts.hight() + left_righr_points);
const int steps = inner_face_verts.hight() + left_righr_points;
for (const int face_i : IndexRange(base_faces_num)) {
const int3 face = base_face_points[face_i];
const float3 &point_a = base_verts[face[0]];
const float3 &point_b = base_verts[face[1]];
const float3 &point_c = base_verts[face[2]];
const float3 normalized_a = math::normalize(point_a);
const float3 normalized_b = math::normalize(point_b);
const float3 normalized_c = math::normalize(point_c);
const float3 normal_ac = math::normalize(
math::cross_tri(float3(0.0f), normalized_a, normalized_c));
const math::AngleRadian rotation_ac = math::angle_between<float>(normalized_a, normalized_c);
const float3 normal_bc = math::normalize(
math::cross_tri(float3(0.0f), normalized_b, normalized_c));
const math::AngleRadian rotation_bc = math::angle_between<float>(normalized_b, normalized_c);
math::AngleRadian steps_ac(0.0f);
math::AngleRadian steps_bc(0.0f);
const float3 &vert_a = base_verts[face[0]];
const float3 &vert_b = base_verts[face[1]];
const float3 &vert_c = base_verts[face[2]];
SphericalIterator rotation_ac = SphericalIterator::between_points(vert_a, vert_c, steps);
SphericalIterator rotation_bc = SphericalIterator::between_points(vert_b, vert_c, steps);
MutableSpan<float3> face_verts = faces_verts.slice(face_i * inner_face_verts.total(),
inner_face_verts.total());
for (const int y_index : IndexRange(inner_face_verts.hight())) {
const int r_y_index = inner_face_verts.hight() - 1 - y_index;
const float face_inner_factor = 1.0f / (r_y_index + left_righr_points);
MutableSpan<float3> level_verts = face_verts.slice(inner_face_verts.slice_at(y_index));
steps_ac += rotation_ac * edge_lerp_factor;
steps_bc += rotation_bc * edge_lerp_factor;
const math::AxisAngle axis_ac(normal_ac, steps_ac);
const math::AxisAngle axis_bc(normal_bc, steps_bc);
const float3 edge_point_a = math::transform_point(math::to_quaternion(axis_ac), point_a);
const float3 edge_point_b = math::transform_point(math::to_quaternion(axis_bc), point_b);
const float3 normalized_edge_a = math::normalize(edge_point_a);
const float3 normalized_edge_b = math::normalize(edge_point_b);
const float3 normal_c = math::normalize(
math::cross_tri(float3(0.0f), normalized_edge_a, normalized_edge_b));
const math::AngleRadian rotation_c = math::angle_between<float>(normalized_edge_a,
normalized_edge_b);
math::AngleRadian steps_c(0.0f);
SphericalIterator rotation_ab = SphericalIterator::between_points(
*rotation_ac, *rotation_bc, level_verts.size() + 1);
rotation_ac++;
rotation_bc++;
for (float3 &vert : level_verts) {
steps_c += rotation_c * face_inner_factor;
const math::AxisAngle axis_ac(normal_c, steps_c);
vert = math::transform_point(math::to_quaternion(axis_ac), edge_point_a);
vert = *rotation_ab;
rotation_ab++;
}
}
}
@ -818,7 +821,7 @@ static Mesh *ico_sphere(const int subdivisions, const float radius)
const IndexRange edge_points(vert_points.one_after_last(), base_edges_num * edge_verts_num);
const IndexRange face_points(edge_points.one_after_last(), face_verts_num * base_faces_num);
base_ico_sphere_positions(radius, positions.take_front(base_verts_num));
base_ico_sphere_positions(positions.take_front(base_verts_num));
interpolate_edge_points(
edge_verts_num, positions.slice(vert_points), positions.slice(edge_points));
@ -842,13 +845,20 @@ static Mesh *ico_sphere(const int subdivisions, const float radius)
const int face_i = i * 3;
const float3 normal = bke::mesh::face_normal_calc(positions,
corner_verts.slice(face_i, 3));
const float3 pos_a = math::normalize(positions[corner_verts[face_i]]);
const float3 pos_a = positions[corner_verts[face_i]];
return !math::is_equal(normal, pos_a, 0.4f);
});
bke::mesh_flip_faces(*mesh, normals_mask);
}
{
SCOPED_TIMER_AVERAGED("Scaling");
std::transform(positions.begin(), positions.end(), positions.begin(), [=](const float3 p) {
return p * radius;
});
}
BLI_assert(std::all_of(edges.cast<int>().begin(),
edges.cast<int>().end(),
[=](const int i) -> bool { return IndexRange(verts_num).contains(i); }));