Blender V4.3
node_geo_mesh_primitive_ico_sphere.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "DNA_mesh_types.h"
6
7#include "BKE_lib_id.hh"
8#include "BKE_material.h"
9#include "BKE_mesh.hh"
10
11#include "GEO_randomize.hh"
12
13#include "bmesh.hh"
14
15#include "node_geometry_util.hh"
16
18
20{
21 b.add_input<decl::Float>("Radius")
22 .default_value(1.0f)
23 .min(0.0f)
25 .description("Distance from the generated points to the origin");
26 b.add_input<decl::Int>("Subdivisions")
27 .default_value(1)
28 .min(1)
29 .max(7)
30 .description("Number of subdivisions on top of the basic icosahedron");
31 b.add_output<decl::Geometry>("Mesh");
32 b.add_output<decl::Vector>("UV Map").field_on_all();
33}
34
35static Bounds<float3> calculate_bounds_ico_sphere(const float radius, const int subdivisions)
36{
37 const float delta_phi = (2.0f * M_PI) / 5.0f;
38 const float theta = std::cos(std::atan(0.5f));
39 const float ro = radius * std::sin(delta_phi);
40
41 float x_max = radius;
42 float x_min = -radius;
43 float y_max = radius;
44 float y_min = -radius;
45
46 if (subdivisions == 1) {
47 x_max = radius * theta;
48 x_min = -x_max;
49 y_max = ro * theta;
50 y_min = -y_max;
51 }
52 else if (subdivisions == 2) {
53 x_max = ro;
54 x_min = -x_max;
55 }
56
57 const float3 bounds_min(x_min, y_min, -radius);
58 const float3 bounds_max(x_max, y_max, radius);
59
60 return {bounds_min, bounds_max};
61}
62
63static Mesh *create_ico_sphere_mesh(const int subdivisions,
64 const float radius,
65 const std::optional<std::string> &uv_map_id)
66{
67 if (subdivisions >= 3) {
68 /* Most nodes don't need this because they internally use multi-threading which triggers
69 * lazy-threading without any extra code. */
71 }
72
73 const float4x4 transform = float4x4::identity();
74
75 const bool create_uv_map = bool(uv_map_id);
76
77 BMeshCreateParams bmesh_create_params{};
78 bmesh_create_params.use_toolflags = true;
79 const BMAllocTemplate allocsize = {0, 0, 0, 0};
80 BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
82 /* Make sure the associated boolean layers exists as well. Normally this would be done when
83 * adding a UV layer via python or when copying from Mesh, but when we 'manually' create the UV
84 * layer we need to make sure the boolean layers exist as well. */
86
89 "create_icosphere subdivisions=%i radius=%f matrix=%m4 calc_uvs=%b",
90 subdivisions,
91 std::abs(radius),
92 transform.ptr(),
93 create_uv_map);
94
96 params.calc_object_remap = false;
97 Mesh *mesh = reinterpret_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
99 BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
101
102 /* The code above generates a "UVMap" attribute. The code below renames that attribute, we don't
103 * have a simple utility for that yet though so there is some overhead right now. */
104 MutableAttributeAccessor attributes = mesh->attributes_for_write();
105 if (create_uv_map) {
106 const VArraySpan orig_uv_map = *attributes.lookup<float2>("UVMap");
107 SpanAttributeWriter<float2> uv_map = attributes.lookup_or_add_for_write_only_span<float2>(
108 *uv_map_id, AttrDomain::Corner);
109 uv_map.span.copy_from(orig_uv_map);
110 uv_map.finish();
111 }
112 attributes.remove("UVMap");
113
115
116 mesh->bounds_set_eager(calculate_bounds_ico_sphere(radius, subdivisions));
117
118 return mesh;
119}
120
122{
123 const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
124 const float radius = params.extract_input<float>("Radius");
125
126 std::optional<std::string> uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
127 "UV Map");
128
129 Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id);
130 params.set_output("Mesh", GeometrySet::from_mesh(mesh));
131}
132
133static void node_register()
134{
135 static blender::bke::bNodeType ntype;
136
138 &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY);
139 ntype.declare = node_declare;
142}
144
145} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(struct ID *id)
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:418
#define M_PI
@ ID_ME
@ CD_PROP_FLOAT2
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_DISTANCE
Definition RNA_types.hh:159
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
void BM_uv_map_ensure_select_and_pin_attrs(BMesh *bm)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t)
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:220
static Mesh * create_ico_sphere_mesh(const int subdivisions, const float radius, const std::optional< std::string > &uv_map_id)
static Bounds< float3 > calculate_bounds_ico_sphere(const float radius, const int subdivisions)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
CustomData ldata
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347