Blender V4.5
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.hh"
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
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);
81 BM_data_layer_add_named(bm, &bm->ldata, CD_PROP_FLOAT2, "UVMap");
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 = BKE_id_new_nomain<Mesh>(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");
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
137 geo_node_type_base(&ntype, "GeometryNodeMeshIcoSphere", GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE);
138 ntype.ui_name = "Ico Sphere";
139 ntype.ui_description = "Generate a spherical mesh that consists of equally sized triangles";
140 ntype.enum_name_legacy = "MESH_PRIMITIVE_ICO_SPHERE";
142 ntype.declare = node_declare;
145}
147
148} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(ID *id)
#define NODE_CLASS_GEOMETRY
Definition BKE_node.hh:447
#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:244
void BM_uv_map_attr_select_and_pin_ensure(BMesh *bm)
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const StringRef name)
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, eCustomDataType data_type)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:217
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:226
std::string ui_description
Definition BKE_node.hh:232
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
NodeDeclareFunction declare
Definition BKE_node.hh:355
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)