Blender  V2.93
node_geo_mesh_primitive_uv_sphere.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "DNA_mesh_types.h"
18 #include "DNA_meshdata_types.h"
19 
20 #include "BKE_mesh.h"
21 
22 #include "UI_interface.h"
23 #include "UI_resources.h"
24 
25 #include "node_geometry_util.hh"
26 
28  {SOCK_INT, N_("Segments"), 32, 0.0f, 0.0f, 0.0f, 3, 1024},
29  {SOCK_INT, N_("Rings"), 16, 0.0f, 0.0f, 0.0f, 2, 1024},
30  {SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
31  {-1, ""},
32 };
33 
35  {SOCK_GEOMETRY, N_("Geometry")},
36  {-1, ""},
37 };
38 
39 namespace blender::nodes {
40 
41 static int sphere_vert_total(const int segments, const int rings)
42 {
43  return segments * (rings - 1) + 2;
44 }
45 
46 static int sphere_edge_total(const int segments, const int rings)
47 {
48  return segments * (rings * 2 - 1);
49 }
50 
51 static int sphere_corner_total(const int segments, const int rings)
52 {
53  const int quad_corners = 4 * segments * (rings - 2);
54  const int tri_corners = 3 * segments * 2;
55  return quad_corners + tri_corners;
56 }
57 
58 static int sphere_face_total(const int segments, const int rings)
59 {
60  const int quads = segments * (rings - 2);
61  const int triangles = segments * 2;
62  return quads + triangles;
63 }
64 
66  const float radius,
67  const int segments,
68  const int rings)
69 {
70  const float delta_theta = M_PI / rings;
71  const float delta_phi = (2 * M_PI) / segments;
72 
73  copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
74  normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
75 
76  int vert_index = 1;
77  float theta = delta_theta;
78  for (const int UNUSED(ring) : IndexRange(rings - 1)) {
79  float phi = 0.0f;
80  const float z = cosf(theta);
81  for (const int UNUSED(segment) : IndexRange(segments)) {
82  const float sin_theta = std::sin(theta);
83  const float x = sin_theta * std::cos(phi);
84  const float y = sin_theta * std::sin(phi);
85  copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
86  normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
87  phi += delta_phi;
88  vert_index++;
89  }
90  theta += delta_theta;
91  }
92 
93  copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
94  normal_float_to_short_v3(verts.last().no, float3(0.0f, 0.0f, -1.0f));
95 }
96 
98  const int segments,
99  const int rings)
100 {
101  int edge_index = 0;
102 
103  /* Add the edges connecting the top vertex to the first ring. */
104  const int first_vert_ring_index_start = 1;
105  for (const int segment : IndexRange(segments)) {
106  MEdge &edge = edges[edge_index++];
107  edge.v1 = 0;
108  edge.v2 = first_vert_ring_index_start + segment;
109  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
110  }
111 
112  int ring_vert_index_start = 1;
113  for (const int ring : IndexRange(rings - 1)) {
114  const int next_ring_vert_index_start = ring_vert_index_start + segments;
115 
116  /* Add the edges running along each ring. */
117  for (const int segment : IndexRange(segments)) {
118  MEdge &edge = edges[edge_index++];
119  edge.v1 = ring_vert_index_start + segment;
120  edge.v2 = ring_vert_index_start + ((segment + 1) % segments);
121  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
122  }
123 
124  /* Add the edges connecting to the next ring. */
125  if (ring < rings - 2) {
126  for (const int segment : IndexRange(segments)) {
127  MEdge &edge = edges[edge_index++];
128  edge.v1 = ring_vert_index_start + segment;
129  edge.v2 = next_ring_vert_index_start + segment;
130  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
131  }
132  }
133  ring_vert_index_start += segments;
134  }
135 
136  /* Add the edges connecting the last ring to the bottom vertex. */
137  const int last_vert_index = sphere_vert_total(segments, rings) - 1;
138  const int last_vert_ring_start = last_vert_index - segments;
139  for (const int segment : IndexRange(segments)) {
140  MEdge &edge = edges[edge_index++];
141  edge.v1 = last_vert_index;
142  edge.v2 = last_vert_ring_start + segment;
143  edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
144  }
145 }
146 
148  MutableSpan<MPoly> polys,
149  const int segments,
150  const int rings)
151 {
152  int loop_index = 0;
153  int poly_index = 0;
154 
155  /* Add the triangles connected to the top vertex. */
156  const int first_vert_ring_index_start = 1;
157  for (const int segment : IndexRange(segments)) {
158  MPoly &poly = polys[poly_index++];
159  poly.loopstart = loop_index;
160  poly.totloop = 3;
161  MLoop &loop_a = loops[loop_index++];
162  loop_a.v = 0;
163  loop_a.e = segment;
164  MLoop &loop_b = loops[loop_index++];
165  loop_b.v = first_vert_ring_index_start + segment;
166  loop_b.e = segments + segment;
167  MLoop &loop_c = loops[loop_index++];
168  loop_c.v = first_vert_ring_index_start + (segment + 1) % segments;
169  loop_c.e = (segment + 1) % segments;
170  }
171 
172  int ring_vert_index_start = 1;
173  int ring_edge_index_start = segments;
174  for (const int UNUSED(ring) : IndexRange(1, rings - 2)) {
175  const int next_ring_vert_index_start = ring_vert_index_start + segments;
176  const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
177  const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
178 
179  for (const int segment : IndexRange(segments)) {
180  MPoly &poly = polys[poly_index++];
181  poly.loopstart = loop_index;
182  poly.totloop = 4;
183 
184  MLoop &loop_a = loops[loop_index++];
185  loop_a.v = ring_vert_index_start + segment;
186  loop_a.e = ring_vertical_edge_index_start + segment;
187  MLoop &loop_b = loops[loop_index++];
188  loop_b.v = next_ring_vert_index_start + segment;
189  loop_b.e = next_ring_edge_index_start + segment;
190  MLoop &loop_c = loops[loop_index++];
191  loop_c.v = next_ring_vert_index_start + (segment + 1) % segments;
192  loop_c.e = ring_vertical_edge_index_start + (segment + 1) % segments;
193  MLoop &loop_d = loops[loop_index++];
194  loop_d.v = ring_vert_index_start + (segment + 1) % segments;
195  loop_d.e = ring_edge_index_start + segment;
196  }
197  ring_vert_index_start += segments;
198  ring_edge_index_start += segments * 2;
199  }
200 
201  /* Add the triangles connected to the bottom vertex. */
202  const int last_edge_ring_start = segments * (rings - 2) * 2 + segments;
203  const int bottom_edge_fan_start = last_edge_ring_start + segments;
204  const int last_vert_index = sphere_vert_total(segments, rings) - 1;
205  const int last_vert_ring_start = last_vert_index - segments;
206  for (const int segment : IndexRange(segments)) {
207  MPoly &poly = polys[poly_index++];
208  poly.loopstart = loop_index;
209  poly.totloop = 3;
210 
211  MLoop &loop_a = loops[loop_index++];
212  loop_a.v = last_vert_index;
213  loop_a.e = bottom_edge_fan_start + (segment + 1) % segments;
214  MLoop &loop_b = loops[loop_index++];
215  loop_b.v = last_vert_ring_start + (segment + 1) % segments;
216  loop_b.e = last_edge_ring_start + segment;
217  MLoop &loop_c = loops[loop_index++];
218  loop_c.v = last_vert_ring_start + segment;
219  loop_c.e = bottom_edge_fan_start + segment;
220  }
221 }
222 
223 static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
224 {
225  MeshComponent mesh_component;
227  OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
228  "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
229  MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
230 
231  int loop_index = 0;
232  const float dy = 1.0f / rings;
233 
234  for (const int i_segment : IndexRange(segments)) {
235  const float segment = static_cast<float>(i_segment);
236  uvs[loop_index++] = float2((segment + 0.5f) / segments, 0.0f);
237  uvs[loop_index++] = float2(segment / segments, dy);
238  uvs[loop_index++] = float2((segment + 1.0f) / segments, dy);
239  }
240 
241  for (const int i_ring : IndexRange(1, rings - 2)) {
242  const float ring = static_cast<float>(i_ring);
243  for (const int i_segment : IndexRange(segments)) {
244  const float segment = static_cast<float>(i_segment);
245  uvs[loop_index++] = float2(segment / segments, ring / rings);
246  uvs[loop_index++] = float2(segment / segments, (ring + 1.0f) / rings);
247  uvs[loop_index++] = float2((segment + 1.0f) / segments, (ring + 1.0f) / rings);
248  uvs[loop_index++] = float2((segment + 1.0f) / segments, ring / rings);
249  }
250  }
251 
252  for (const int i_segment : IndexRange(segments)) {
253  const float segment = static_cast<float>(i_segment);
254  uvs[loop_index++] = float2((segment + 0.5f) / segments, 1.0f);
255  uvs[loop_index++] = float2((segment + 1.0f) / segments, 1.0f - dy);
256  uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
257  }
258 
259  uv_attribute.apply_span_and_save();
260 }
261 
262 static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
263 {
264  Mesh *mesh = BKE_mesh_new_nomain(sphere_vert_total(segments, rings),
265  sphere_edge_total(segments, rings),
266  0,
267  sphere_corner_total(segments, rings),
268  sphere_face_total(segments, rings));
273 
274  calculate_sphere_vertex_data(verts, radius, segments, rings);
275 
276  calculate_sphere_edge_indices(edges, segments, rings);
277 
278  calculate_sphere_faces(loops, polys, segments, rings);
279 
280  calculate_sphere_uvs(mesh, segments, rings);
281 
283 
284  return mesh;
285 }
286 
288 {
289  const int segments_num = params.extract_input<int>("Segments");
290  const int rings_num = params.extract_input<int>("Rings");
291  if (segments_num < 3 || rings_num < 2) {
292  params.set_output("Geometry", GeometrySet());
293  return;
294  }
295 
296  const float radius = params.extract_input<float>("Radius");
297 
298  Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
299  params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
300 }
301 
302 } // namespace blender::nodes
303 
305 {
306  static bNodeType ntype;
307 
309  &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
313  nodeRegisterType(&ntype);
314 }
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:45
bool BKE_mesh_is_valid(struct Mesh *me)
struct Mesh * BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
Definition: mesh.c:877
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
#define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE
Definition: BKE_node.h:1410
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define M_PI
Definition: BLI_math_base.h:38
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED(x)
#define N_(msgid)
@ CD_PROP_FLOAT2
@ ME_EDGEDRAW
@ ME_EDGERENDER
@ SOCK_INT
@ SOCK_FLOAT
@ SOCK_GEOMETRY
_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
@ PROP_DISTANCE
Definition: RNA_types.h:135
ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t)
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name, const AttributeDomain domain, const CustomDataType data_type, const void *default_value=nullptr)
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
fn::GMutableSpan get_span_for_write_only()
static float verts[][3]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define cosf(x)
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
static void calculate_sphere_vertex_data(MutableSpan< MVert > verts, const float radius, const int segments, const int rings)
static void calculate_sphere_edge_indices(MutableSpan< MEdge > edges, const int segments, const int rings)
static int sphere_edge_total(const int segments, const int rings)
static int sphere_face_total(const int segments, const int rings)
static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
static Mesh * create_uv_sphere_mesh(const float radius, const int segments, const int rings)
static void calculate_sphere_faces(MutableSpan< MLoop > loops, MutableSpan< MPoly > polys, const int segments, const int rings)
static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
static int sphere_corner_total(const int segments, const int rings)
static int sphere_vert_total(const int segments, const int rings)
static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_out[]
static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_in[]
void register_node_type_geo_mesh_primitive_uv_sphere()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
static GeometrySet create_with_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
unsigned int v1
unsigned int v2
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
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327