Blender  V3.3
node_geo_mesh_primitive_uv_sphere.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "DNA_mesh_types.h"
6 #include "DNA_meshdata_types.h"
7 
8 #include "BKE_material.h"
9 #include "BKE_mesh.h"
10 
11 #include "UI_interface.h"
12 #include "UI_resources.h"
13 
14 #include "node_geometry_util.hh"
15 
17 
19 {
20  b.add_input<decl::Int>(N_("Segments"))
21  .default_value(32)
22  .min(3)
23  .max(1024)
24  .description(N_("Horizontal resolution of the sphere"));
25  b.add_input<decl::Int>(N_("Rings"))
26  .default_value(16)
27  .min(2)
28  .max(1024)
29  .description(N_("The number of horizontal rings"));
30  b.add_input<decl::Float>(N_("Radius"))
31  .default_value(1.0f)
32  .min(0.0f)
33  .subtype(PROP_DISTANCE)
34  .description(N_("Distance from the generated points to the origin"));
35  b.add_output<decl::Geometry>(N_("Mesh"));
36 }
37 
38 static int sphere_vert_total(const int segments, const int rings)
39 {
40  return segments * (rings - 1) + 2;
41 }
42 
43 static int sphere_edge_total(const int segments, const int rings)
44 {
45  return segments * (rings * 2 - 1);
46 }
47 
48 static int sphere_corner_total(const int segments, const int rings)
49 {
50  const int quad_corners = 4 * segments * (rings - 2);
51  const int tri_corners = 3 * segments * 2;
52  return quad_corners + tri_corners;
53 }
54 
55 static int sphere_face_total(const int segments, const int rings)
56 {
57  const int quads = segments * (rings - 2);
58  const int triangles = segments * 2;
59  return quads + triangles;
60 }
61 
67  MutableSpan<float3> vert_normals,
68  const float radius,
69  const int segments,
70  const int rings)
71 {
72  const float delta_theta = M_PI / rings;
73  const float delta_phi = (2.0f * M_PI) / segments;
74 
75  Array<float, 64> segment_cosines(segments + 1);
76  for (const int segment : IndexRange(1, segments)) {
77  const float phi = segment * delta_phi;
78  segment_cosines[segment] = std::cos(phi);
79  }
80  Array<float, 64> segment_sines(segments + 1);
81  for (const int segment : IndexRange(1, segments)) {
82  const float phi = segment * delta_phi;
83  segment_sines[segment] = std::sin(phi);
84  }
85 
86  copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
87  vert_normals.first() = float3(0.0f, 0.0f, 1.0f);
88 
89  int vert_index = 1;
90  for (const int ring : IndexRange(1, rings - 1)) {
91  const float theta = ring * delta_theta;
92  const float sin_theta = std::sin(theta);
93  const float z = std::cos(theta);
94  for (const int segment : IndexRange(1, segments)) {
95  const float x = sin_theta * segment_cosines[segment];
96  const float y = sin_theta * segment_sines[segment];
97  copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
98  vert_normals[vert_index] = float3(x, y, z);
99  vert_index++;
100  }
101  }
102 
103  copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
104  vert_normals.last() = float3(0.0f, 0.0f, -1.0f);
105 }
106 
108  const int segments,
109  const int rings)
110 {
111  int edge_index = 0;
112 
113  /* Add the edges connecting the top vertex to the first ring. */
114  const int first_vert_ring_index_start = 1;
115  for (const int segment : IndexRange(segments)) {
116  MEdge &edge = edges[edge_index++];
117  edge.v1 = 0;
118  edge.v2 = first_vert_ring_index_start + segment;
119  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
120  }
121 
122  int ring_vert_index_start = 1;
123  for (const int ring : IndexRange(rings - 1)) {
124  const int next_ring_vert_index_start = ring_vert_index_start + segments;
125 
126  /* Add the edges running along each ring. */
127  for (const int segment : IndexRange(segments)) {
128  MEdge &edge = edges[edge_index++];
129  edge.v1 = ring_vert_index_start + segment;
130  edge.v2 = ring_vert_index_start + ((segment + 1) % segments);
131  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
132  }
133 
134  /* Add the edges connecting to the next ring. */
135  if (ring < rings - 2) {
136  for (const int segment : IndexRange(segments)) {
137  MEdge &edge = edges[edge_index++];
138  edge.v1 = ring_vert_index_start + segment;
139  edge.v2 = next_ring_vert_index_start + segment;
140  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
141  }
142  }
143  ring_vert_index_start += segments;
144  }
145 
146  /* Add the edges connecting the last ring to the bottom vertex. */
147  const int last_vert_index = sphere_vert_total(segments, rings) - 1;
148  const int last_vert_ring_start = last_vert_index - segments;
149  for (const int segment : IndexRange(segments)) {
150  MEdge &edge = edges[edge_index++];
151  edge.v1 = last_vert_index;
152  edge.v2 = last_vert_ring_start + segment;
153  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
154  }
155 }
156 
157 BLI_NOINLINE static void calculate_sphere_faces(MutableSpan<MPoly> polys, const int segments)
158 {
159  int loop_index = 0;
160 
161  /* Add the triangles connected to the top vertex. */
162  for (MPoly &poly : polys.take_front(segments)) {
163  poly.loopstart = loop_index;
164  poly.totloop = 3;
165  loop_index += 3;
166  }
167 
168  /* Add the middle quads. */
169  for (MPoly &poly : polys.drop_front(segments).drop_back(segments)) {
170  poly.loopstart = loop_index;
171  poly.totloop = 4;
172  loop_index += 4;
173  }
174 
175  /* Add the triangles connected to the bottom vertex. */
176  for (MPoly &poly : polys.take_back(segments)) {
177  poly.loopstart = loop_index;
178  poly.totloop = 3;
179  loop_index += 3;
180  }
181 }
182 
184  const int segments,
185  const int rings)
186 {
187  int loop_index = 0;
188  auto segment_next_or_first = [&](const int segment) {
189  return segment == segments - 1 ? 0 : segment + 1;
190  };
191 
192  /* Add the triangles connected to the top vertex. */
193  const int first_vert_ring_index_start = 1;
194  for (const int segment : IndexRange(segments)) {
195  const int segment_next = segment_next_or_first(segment);
196 
197  MLoop &loop_a = loops[loop_index++];
198  loop_a.v = 0;
199  loop_a.e = segment;
200  MLoop &loop_b = loops[loop_index++];
201  loop_b.v = first_vert_ring_index_start + segment;
202  loop_b.e = segments + segment;
203  MLoop &loop_c = loops[loop_index++];
204  loop_c.v = first_vert_ring_index_start + segment_next;
205  loop_c.e = segment_next;
206  }
207 
208  int ring_vert_index_start = 1;
209  int ring_edge_index_start = segments;
210  for ([[maybe_unused]] const int ring : IndexRange(1, rings - 2)) {
211  const int next_ring_vert_index_start = ring_vert_index_start + segments;
212  const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
213  const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
214 
215  for (const int segment : IndexRange(segments)) {
216  const int segment_next = segment_next_or_first(segment);
217 
218  MLoop &loop_a = loops[loop_index++];
219  loop_a.v = ring_vert_index_start + segment;
220  loop_a.e = ring_vertical_edge_index_start + segment;
221  MLoop &loop_b = loops[loop_index++];
222  loop_b.v = next_ring_vert_index_start + segment;
223  loop_b.e = next_ring_edge_index_start + segment;
224  MLoop &loop_c = loops[loop_index++];
225  loop_c.v = next_ring_vert_index_start + segment_next;
226  loop_c.e = ring_vertical_edge_index_start + segment_next;
227  MLoop &loop_d = loops[loop_index++];
228  loop_d.v = ring_vert_index_start + segment_next;
229  loop_d.e = ring_edge_index_start + segment;
230  }
231  ring_vert_index_start += segments;
232  ring_edge_index_start += segments * 2;
233  }
234 
235  /* Add the triangles connected to the bottom vertex. */
236  const int last_edge_ring_start = segments * (rings - 2) * 2 + segments;
237  const int bottom_edge_fan_start = last_edge_ring_start + segments;
238  const int last_vert_index = sphere_vert_total(segments, rings) - 1;
239  const int last_vert_ring_start = last_vert_index - segments;
240  for (const int segment : IndexRange(segments)) {
241  const int segment_next = segment_next_or_first(segment);
242 
243  MLoop &loop_a = loops[loop_index++];
244  loop_a.v = last_vert_index;
245  loop_a.e = bottom_edge_fan_start + segment_next;
246  MLoop &loop_b = loops[loop_index++];
247  loop_b.v = last_vert_ring_start + segment_next;
248  loop_b.e = last_edge_ring_start + segment;
249  MLoop &loop_c = loops[loop_index++];
250  loop_c.v = last_vert_ring_start + segment;
251  loop_c.e = bottom_edge_fan_start + segment;
252  }
253 }
254 
255 BLI_NOINLINE static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
256 {
258 
260  "uv_map", ATTR_DOMAIN_CORNER);
261  MutableSpan<float2> uvs = uv_attribute.span;
262 
263  int loop_index = 0;
264  const float dy = 1.0f / rings;
265 
266  const float segments_inv = 1.0f / segments;
267 
268  for (const int i_segment : IndexRange(segments)) {
269  const float segment = static_cast<float>(i_segment);
270  uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 0.0f);
271  uvs[loop_index++] = float2(segment * segments_inv, dy);
272  uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, dy);
273  }
274 
275  for (const int i_ring : IndexRange(1, rings - 2)) {
276  const float ring = static_cast<float>(i_ring);
277  for (const int i_segment : IndexRange(segments)) {
278  const float segment = static_cast<float>(i_segment);
279  uvs[loop_index++] = float2(segment * segments_inv, ring / rings);
280  uvs[loop_index++] = float2(segment * segments_inv, (ring + 1.0f) / rings);
281  uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, (ring + 1.0f) / rings);
282  uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, ring / rings);
283  }
284  }
285 
286  for (const int i_segment : IndexRange(segments)) {
287  const float segment = static_cast<float>(i_segment);
288  uvs[loop_index++] = float2((segment + 0.5f) * segments_inv, 1.0f);
289  uvs[loop_index++] = float2((segment + 1.0f) * segments_inv, 1.0f - dy);
290  uvs[loop_index++] = float2(segment * segments_inv, 1.0f - dy);
291  }
292 
293  uv_attribute.finish();
294 }
295 
296 static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
297 {
298  Mesh *mesh = BKE_mesh_new_nomain(sphere_vert_total(segments, rings),
299  sphere_edge_total(segments, rings),
300  0,
301  sphere_corner_total(segments, rings),
302  sphere_face_total(segments, rings));
308 
310  1024 < segments * rings,
311  [&]() {
313  calculate_sphere_vertex_data(verts, vert_normals, radius, segments, rings);
315  },
316  [&]() { calculate_sphere_edge_indices(edges, segments, rings); },
317  [&]() { calculate_sphere_faces(polys, segments); },
318  [&]() { calculate_sphere_corners(loops, segments, rings); },
319  [&]() { calculate_sphere_uvs(mesh, segments, rings); });
320 
321  return mesh;
322 }
323 
325 {
326  const int segments_num = params.extract_input<int>("Segments");
327  const int rings_num = params.extract_input<int>("Rings");
328  if (segments_num < 3 || rings_num < 2) {
329  if (segments_num < 3) {
330  params.error_message_add(NodeWarningType::Info, TIP_("Segments must be at least 3"));
331  }
332  if (rings_num < 3) {
333  params.error_message_add(NodeWarningType::Info, TIP_("Rings must be at least 3"));
334  }
335  params.set_default_remaining_outputs();
336  return;
337  }
338 
339  const float radius = params.extract_input<float>("Radius");
340 
341  Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
342  params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
343 }
344 
345 } // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc
346 
348 {
350 
351  static bNodeType ntype;
352 
356  nodeRegisterType(&ntype);
357 }
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
General operations, lookup, etc. for materials.
void BKE_id_material_eval_ensure_default_slot(struct ID *id)
Definition: material.c:784
float(* BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3]
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.cc:991
void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh)
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
#define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE
Definition: BKE_node.h:1393
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define BLI_NOINLINE
#define M_PI
Definition: BLI_math_base.h:20
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define TIP_(msgid)
@ ME_EDGEDRAW
@ ME_EDGERENDER
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
in reality light always falls off quadratically Particle Info
@ PROP_DISTANCE
Definition: RNA_types.h:149
ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t)
constexpr MutableSpan take_back(const int64_t n) const
Definition: BLI_span.hh:631
constexpr MutableSpan drop_back(const int64_t n) const
Definition: BLI_span.hh:609
constexpr MutableSpan drop_front(const int64_t n) const
Definition: BLI_span.hh:598
constexpr T & last(const int64_t n=0) const
Definition: BLI_span.hh:680
constexpr T & first() const
Definition: BLI_span.hh:670
constexpr MutableSpan take_front(const int64_t n) const
Definition: BLI_span.hh:620
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Segment< FEdge *, Vec3r > segment
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:311
int segments_num(const int points_num, const bool cyclic)
Definition: BKE_curves.hh:462
MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
static int sphere_edge_total(const int segments, const int rings)
static int sphere_vert_total(const int segments, const int rings)
static int sphere_corner_total(const int segments, const int rings)
static BLI_NOINLINE void calculate_sphere_faces(MutableSpan< MPoly > polys, const int segments)
static BLI_NOINLINE void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
static BLI_NOINLINE void calculate_sphere_corners(MutableSpan< MLoop > loops, const int segments, const int rings)
static Mesh * create_uv_sphere_mesh(const float radius, const int segments, const int rings)
static int sphere_face_total(const int segments, const int rings)
static BLI_NOINLINE void calculate_sphere_vertex_data(MutableSpan< MVert > verts, MutableSpan< float3 > vert_normals, const float radius, const int segments, const int rings)
static BLI_NOINLINE void calculate_sphere_edge_indices(MutableSpan< MEdge > edges, const int segments, const int rings)
void parallel_invoke(Functions &&...functions)
Definition: BLI_task.hh:99
vec_base< float, 3 > float3
vec_base< float, 2 > float2
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void register_node_type_geo_mesh_primitive_uv_sphere()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
static GeometrySet create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
unsigned int e
unsigned int v
struct MEdge * medge
struct MVert * mvert
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)