Blender V5.0
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
6
7#include "DNA_mesh_types.h"
8
9#include "BKE_lib_id.hh"
10#include "BKE_material.hh"
11#include "BKE_mesh.hh"
12
13#include "GEO_randomize.hh"
14
15#include "bmesh.hh"
16
17#include "node_geometry_util.hh"
18
20
22{
23 b.add_input<decl::Float>("Radius")
24 .default_value(1.0f)
25 .min(0.0f)
27 .description("Distance from the generated points to the origin");
28 b.add_input<decl::Int>("Subdivisions")
29 .default_value(1)
30 .min(1)
31 .max(7)
32 .description("Number of subdivisions on top of the basic icosahedron");
33 b.add_output<decl::Geometry>("Mesh");
34 b.add_output<decl::Vector>("UV Map").field_on_all();
35}
36
37static Bounds<float3> calculate_bounds_ico_sphere(const float radius, const int subdivisions)
38{
39 const float delta_phi = (2.0f * M_PI) / 5.0f;
40 const float theta = std::cos(std::atan(0.5f));
41 const float ro = radius * std::sin(delta_phi);
42
43 float x_max = radius;
44 float x_min = -radius;
45 float y_max = radius;
46 float y_min = -radius;
47
48 if (subdivisions == 1) {
49 x_max = radius * theta;
50 x_min = -x_max;
51 y_max = ro * theta;
52 y_min = -y_max;
53 }
54 else if (subdivisions == 2) {
55 x_max = ro;
56 x_min = -x_max;
57 }
58
59 const float3 bounds_min(x_min, y_min, -radius);
60 const float3 bounds_max(x_max, y_max, radius);
61
62 return {bounds_min, bounds_max};
63}
64
65static Mesh *create_ico_sphere_mesh(const int subdivisions,
66 const float radius,
67 const std::optional<std::string> &uv_map_id)
68{
69 if (subdivisions >= 3) {
70 /* Most nodes don't need this because they internally use multi-threading which triggers
71 * lazy-threading without any extra code. */
73 }
74
76
77 const bool create_uv_map = bool(uv_map_id);
78
79 BMeshCreateParams bmesh_create_params{};
80 bmesh_create_params.use_toolflags = true;
81 const BMAllocTemplate allocsize = {0, 0, 0, 0};
82 BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
83 BM_data_layer_add_named(bm, &bm->ldata, CD_PROP_FLOAT2, "UVMap");
84 /* Make sure the associated boolean layers exists as well. Normally this would be done when
85 * adding a UV layer via python or when copying from Mesh, but when we 'manually' create the UV
86 * layer we need to make sure the boolean layers exist as well. */
88
91 "create_icosphere subdivisions=%i radius=%f matrix=%m4 calc_uvs=%b",
92 subdivisions,
93 std::abs(radius),
94 transform.ptr(),
95 create_uv_map);
96
98 params.calc_object_remap = false;
99 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
101 BM_mesh_bm_to_me(nullptr, bm, mesh, &params);
103
104 /* The code above generates a "UVMap" attribute. The code below renames that attribute, we don't
105 * have a simple utility for that yet though so there is some overhead right now. */
106 MutableAttributeAccessor attributes = mesh->attributes_for_write();
107 if (create_uv_map) {
108 const VArraySpan orig_uv_map = *attributes.lookup<float2>("UVMap");
110 *uv_map_id, AttrDomain::Corner);
111 uv_map.span.copy_from(orig_uv_map);
112 uv_map.finish();
113 }
114 attributes.remove("UVMap");
115
117
118 mesh->bounds_set_eager(calculate_bounds_ico_sphere(radius, subdivisions));
119
120 return mesh;
121}
122
124{
125 const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10);
126 const float radius = params.extract_input<float>("Radius");
127
128 std::optional<std::string> uv_map_id = params.get_output_anonymous_attribute_id_if_needed(
129 "UV Map");
130
131 Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius, uv_map_id);
132 params.set_output("Mesh", GeometrySet::from_mesh(mesh));
133}
134
135static void node_register()
136{
137 static blender::bke::bNodeType ntype;
138
139 geo_node_type_base(&ntype, "GeometryNodeMeshIcoSphere", GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE);
140 ntype.ui_name = "Ico Sphere";
141 ntype.ui_description = "Generate a spherical mesh that consists of equally sized triangles";
142 ntype.enum_name_legacy = "MESH_PRIMITIVE_ICO_SPHERE";
144 ntype.declare = node_declare;
147}
149
150} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(ID *id)
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:461
#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE
#define M_PI
@ CD_PROP_FLOAT2
#define NOD_REGISTER_NODE(REGISTER_FUNC)
@ PROP_DISTANCE
Definition RNA_types.hh:256
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const StringRef name)
void BM_uv_map_attr_pin_ensure_for_all_layers(BMesh *bm)
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(const int p, const float gamma_o, const float gamma_t)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
GAttributeReader lookup(const StringRef attribute_id) const
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:288
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)
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)