1
1

Compare commits

...

54 Commits

Author SHA1 Message Date
41238bba45 Add functional line node 2021-03-13 23:45:41 -05:00
0732e3de35 Merge branch 'geometry-nodes-mesh-primitives' into temp-geometry-nodes-mesh-primitive-line 2021-03-13 21:46:58 -05:00
5cd33108fc Cleanup: Remove unused includes, change switch to if 2021-03-13 21:46:12 -05:00
36397a721a Add boilerplate code for a line primitive 2021-03-13 18:04:07 -05:00
1173d1ca9e Cleanup: Spelling 2021-03-13 17:43:33 -05:00
f7a6dd7218 Cleanup: remove static 2021-03-13 17:39:09 -05:00
9934a71172 Cleanup, revert some changes 2021-03-13 17:31:39 -05:00
e46dcc499c Revert changes split to a separate patch
D10712
2021-03-13 17:29:43 -05:00
4be8061baf Rename and reorder variables for consistency 2021-03-13 17:27:57 -05:00
c20d7676fc Move cylinder / cone code to cone file 2021-03-13 17:22:15 -05:00
507fdd0e3e Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-13 17:16:32 -05:00
1e29f64987 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-13 15:17:53 -05:00
9b2b6674ba Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-13 09:14:22 -05:00
cec588d757 Fix issue with normals 2021-03-11 16:57:04 -05:00
3e5869e083 Use full "Fill Type" text 2021-03-11 15:50:32 -05:00
5f9bec93e6 Add working cone node based on cylinder code 2021-03-11 15:47:57 -05:00
167525dc8d Remove duplicate nodes 2021-03-11 08:38:05 -05:00
1d6764dddd Add ico sphere primitive 2021-03-10 16:10:53 -05:00
507b8fa527 Working cylinder node 2021-03-10 15:28:26 -05:00
91e42d81fe Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-10 12:03:23 -05:00
53daf2a0db Use 3x3 matrix for normal transformation 2021-03-09 09:18:35 -05:00
73d53b3bd8 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-08 22:48:47 -05:00
55fe91b83b Progress on cylinder node 2021-03-08 22:14:19 -05:00
94d826f6d6 Cleanup, add transformation 2021-03-08 21:36:56 -05:00
51b731d479 Add primitive cube node 2021-03-08 21:36:39 -05:00
5fa962c7f6 Expose transform operation and optimize normal transform 2021-03-08 21:35:58 -05:00
543783fc61 Add float3.is_zero() 2021-03-08 21:34:18 -05:00
a70a715f67 Fix build 2021-03-08 17:04:08 -05:00
1f95b07b32 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-08 16:56:18 -05:00
9b28ab0d0b Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-01 08:36:08 -06:00
83c87b6564 Start of Cylinder node, add distance float socket 2021-02-26 09:00:24 -06:00
50072596d1 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-25 22:43:12 -06:00
05aea4bb51 Fix issue with normals 2021-02-25 18:39:36 -06:00
f993a47248 remove extra whitespace 2021-02-25 18:03:33 -06:00
73b023bbab Remove asserts 2021-02-25 18:03:13 -06:00
95ecd5804d Fix index calculations 2021-02-25 18:02:41 -06:00
0c42b40aee Fix: Make output mesh valid, add a bunch of asserts 2021-02-25 17:26:50 -06:00
0084954ade Working sphere polygons 2021-02-25 14:56:03 -06:00
8464641e77 Sphere edges working 2021-02-25 13:37:37 -06:00
4f875a31c9 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-25 09:31:02 -06:00
46b8b36eff Broken sphere stuff 2021-02-25 06:59:39 -06:00
475f0f5ece Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-24 21:58:46 -06:00
9a501e1ece Continue working on sphere node 2021-02-24 08:48:14 -06:00
3915392560 Fix sphere node not registered 2021-02-24 08:17:42 -06:00
fdb116a0b6 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-23 23:12:03 -06:00
ca8d1900ff Shell for UV sphere code 2021-02-23 07:59:10 -06:00
edce7ee71d Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-22 23:46:43 -06:00
ffd63bc495 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-20 17:59:26 -06:00
fbf093dee1 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-20 17:22:16 -06:00
414747f40d Working circle primitive, except for rotation 2021-02-19 00:11:48 -06:00
e3995e5050 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-02-18 18:11:55 -06:00
6ac36103ea Working circle fill types (not triangle fan) 2021-02-18 12:23:17 -06:00
fcd7c0cfcc Merge branch 'master' into geometry-nodes-mesh-primitive-cube 2021-02-17 21:10:09 -06:00
93788a9b8d Initial broken implementation 2021-02-15 11:57:18 -06:00
18 changed files with 1678 additions and 4 deletions

View File

@@ -519,6 +519,17 @@ geometry_node_categories = [
NodeItem("GeometryNodeEdgeSplit"),
NodeItem("GeometryNodeSubdivideSmooth"),
NodeItem("GeometryNodeSubdivide"),
# These should be in a sub-menu, but that requires a refactor to build the add menu manually.
NodeItem("GeometryNodeMeshCube"),
NodeItem("GeometryNodeMeshCircle"),
NodeItem("GeometryNodeMeshUVSphere"),
NodeItem("GeometryNodeMeshIcoSphere"),
NodeItem("GeometryNodeMeshCylinder"),
NodeItem("GeometryNodeMeshCone"),
NodeItem("GeometryNodeMeshLine")
# NodeItem("GeometryNodeMeshPlane"),
# NodeItem("GeometryNodeMeshGrid"),
]),
GeometryNodeCategory("GEO_POINT", "Point", items=[
NodeItem("GeometryNodePointDistribute"),

View File

@@ -1374,6 +1374,13 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_SUBDIVIDE 1029
#define GEO_NODE_ATTRIBUTE_REMOVE 1030
#define GEO_NODE_ATTRIBUTE_CONVERT 1031
#define GEO_NODE_MESH_PRIMITIVE_CUBE 1032
#define GEO_NODE_MESH_PRIMITIVE_CIRCLE 1033
#define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE 1034
#define GEO_NODE_MESH_PRIMITIVE_CYLINDER 1035
#define GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE 1036
#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
/** \} */

View File

@@ -4806,6 +4806,13 @@ static void registerGeometryNodes()
register_node_type_geo_edge_split();
register_node_type_geo_is_viewport();
register_node_type_geo_join_geometry();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();
register_node_type_geo_mesh_primitive_cylinder();
register_node_type_geo_mesh_primitive_ico_sphere();
register_node_type_geo_mesh_primitive_line();
register_node_type_geo_mesh_primitive_uv_sphere();
register_node_type_geo_object_info();
register_node_type_geo_point_distribute();
register_node_type_geo_point_instance();

View File

@@ -174,6 +174,11 @@ struct float3 {
return len_squared_v3(*this);
}
bool is_zero() const
{
return this->x == 0.0f && this->y == 0.0f && this->z == 0.0f;
}
void reflect(const float3 &normal)
{
*this = this->reflected(normal);

View File

@@ -1234,6 +1234,28 @@ typedef struct NodeAttributeConvert {
int16_t domain;
} NodeAttributeConvert;
typedef struct NodeGeometryMeshCircle {
/* GeometryNodeMeshCircleFillType. */
uint8_t fill_type;
} NodeGeometryMeshCircle;
typedef struct NodeGeometryMeshCylinder {
/* GeometryNodeMeshCircleFillType. */
uint8_t fill_type;
} NodeGeometryMeshCylinder;
typedef struct NodeGeometryMeshCone {
/* GeometryNodeMeshCircleFillType. */
uint8_t fill_type;
} NodeGeometryMeshCone;
typedef struct NodeGeometryMeshLine {
/* GeometryNodeMeshLineMode. */
uint8_t mode;
/* GeometryNodeMeshLineCountMode. */
uint8_t count_mode;
} NodeGeometryMeshLine;
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -1710,6 +1732,22 @@ typedef enum GeometryNodePointsToVolumeResolutionMode {
GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1,
} GeometryNodePointsToVolumeResolutionMode;
typedef enum GeometryNodeMeshCircleFillType {
GEO_NODE_MESH_CIRCLE_FILL_NONE = 0,
GEO_NODE_MESH_CIRCLE_FILL_NGON = 1,
GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN = 2,
} GeometryNodeMeshCircleFillType;
typedef enum GeometryNodeMeshLineMode {
GEO_NODE_MESH_LINE_MODE_END_POINTS = 0,
GEO_NODE_MESH_LINE_MODE_OFFSET = 1,
} GeometryNodeMeshLineMode;
typedef enum GeometryNodeMeshLineCountMode {
GEO_NODE_MESH_LINE_COUNT_TOTAL = 0,
GEO_NODE_MESH_LINE_COUNT_RESOLUTION = 1,
} GeometryNodeMeshLineCountMode;
#ifdef __cplusplus
}
#endif

View File

@@ -398,6 +398,13 @@ static const EnumPropertyItem prop_shader_output_target_items[] = {
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem rna_node_geometry_mesh_circle_fill_type_items[] = {
{GEO_NODE_MESH_CIRCLE_FILL_NONE, "NONE", 0, "None", ""},
{GEO_NODE_MESH_CIRCLE_FILL_NGON, "NGON", 0, "N-Gon", ""},
{GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN, "TRIANGLE_FAN", 0, "Triangles", ""},
{0, NULL, 0, NULL, NULL},
};
#endif
#define ITEM_ATTRIBUTE \
@@ -9234,6 +9241,87 @@ static void def_geo_attribute_separate_xyz(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_mesh_circle(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCircle", "storage");
prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
RNA_def_property_ui_text(prop, "Fill Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_mesh_cylinder(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCylinder", "storage");
prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
RNA_def_property_ui_text(prop, "Fill Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_mesh_cone(StructRNA *srna)
{
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryMeshCone", "storage");
prop = RNA_def_property(srna, "fill_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_node_geometry_mesh_circle_fill_type_items);
RNA_def_property_ui_text(prop, "Fill Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_mesh_line(StructRNA *srna)
{
PropertyRNA *prop;
static EnumPropertyItem mode_items[] = {
{GEO_NODE_MESH_LINE_MODE_OFFSET,
"OFFSET",
0,
"Offset",
"Specify the offset from one vertex to the next"},
{GEO_NODE_MESH_LINE_MODE_END_POINTS,
"END_POINTS",
0,
"End Points",
"Specify the line's start and end points"},
{0, NULL, 0, NULL, NULL},
};
static EnumPropertyItem count_mode_items[] = {
{GEO_NODE_MESH_LINE_COUNT_TOTAL,
"TOTAL",
0,
"Count",
"Specify the total number of vertices"},
{GEO_NODE_MESH_LINE_COUNT_RESOLUTION,
"RESOLUTION",
0,
"Resolution",
"Specify the distance between vertices"},
{0, NULL, 0, NULL, NULL},
};
RNA_def_struct_sdna_from(srna, "NodeGeometryMeshLine", "storage");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "count_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, count_mode_items);
RNA_def_property_ui_text(prop, "Count Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)

View File

@@ -162,6 +162,13 @@ set(SRC
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_is_viewport.cc
geometry/nodes/node_geo_join_geometry.cc
geometry/nodes/node_geo_mesh_primitive_circle.cc
geometry/nodes/node_geo_mesh_primitive_cone.cc
geometry/nodes/node_geo_mesh_primitive_cube.cc
geometry/nodes/node_geo_mesh_primitive_cylinder.cc
geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
geometry/nodes/node_geo_mesh_primitive_line.cc
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
geometry/nodes/node_geo_point_instance.cc

View File

@@ -44,6 +44,13 @@ void register_node_type_geo_collection_info(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_is_viewport(void);
void register_node_type_geo_join_geometry(void);
void register_node_type_geo_mesh_primitive_circle(void);
void register_node_type_geo_mesh_primitive_cone(void);
void register_node_type_geo_mesh_primitive_cube(void);
void register_node_type_geo_mesh_primitive_cylinder(void);
void register_node_type_geo_mesh_primitive_ico_sphere(void);
void register_node_type_geo_mesh_primitive_line(void);
void register_node_type_geo_mesh_primitive_uv_sphere(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_point_distribute(void);
void register_node_type_geo_point_instance(void);

View File

@@ -301,6 +301,13 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separat
DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "ATTRIBUTE_CONVERT", AttributeConvert, "Attribute Convert", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
/* undefine macros */
#undef DefNode

View File

@@ -47,4 +47,15 @@ void update_attribute_input_socket_availabilities(bNode &node,
Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
const AttributeDomain domain);
void transform_mesh(Mesh *mesh,
const float3 translation,
const float3 rotation,
const float3 scale);
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
const float radius_bottom,
const float depth,
const int verts_num,
const GeometryNodeMeshCircleFillType fill_type);
} // namespace blender::nodes

View File

@@ -0,0 +1,247 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_circle_in[] = {
{SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
{SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_circle_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_mesh_primitive_circle_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
sizeof(NodeGeometryMeshCircle), __func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
node->storage = node_storage;
}
namespace blender::nodes {
static int circle_vert_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
{
switch (fill_type) {
case GEO_NODE_MESH_CIRCLE_FILL_NONE:
case GEO_NODE_MESH_CIRCLE_FILL_NGON:
return verts_num;
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
return verts_num + 1;
}
BLI_assert(false);
return 0;
}
static int circle_edge_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
{
switch (fill_type) {
case GEO_NODE_MESH_CIRCLE_FILL_NONE:
case GEO_NODE_MESH_CIRCLE_FILL_NGON:
return verts_num;
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
return verts_num * 2;
}
BLI_assert(false);
return 0;
}
static int circle_corner_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
{
switch (fill_type) {
case GEO_NODE_MESH_CIRCLE_FILL_NONE:
return 0;
case GEO_NODE_MESH_CIRCLE_FILL_NGON:
return verts_num;
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
return verts_num * 3;
}
BLI_assert(false);
return 0;
}
static int circle_face_total(const GeometryNodeMeshCircleFillType fill_type, const int verts_num)
{
switch (fill_type) {
case GEO_NODE_MESH_CIRCLE_FILL_NONE:
return 0;
case GEO_NODE_MESH_CIRCLE_FILL_NGON:
return 1;
case GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN:
return verts_num;
}
BLI_assert(false);
return 0;
}
static Mesh *create_circle_mesh(const float radius,
const int verts_num,
const GeometryNodeMeshCircleFillType fill_type)
{
Mesh *mesh = BKE_mesh_new_nomain(circle_vert_total(fill_type, verts_num),
circle_edge_total(fill_type, verts_num),
0,
circle_corner_total(fill_type, verts_num),
circle_face_total(fill_type, verts_num));
MutableSpan<MVert> verts = MutableSpan<MVert>(mesh->mvert, mesh->totvert);
MutableSpan<MLoop> loops = MutableSpan<MLoop>(mesh->mloop, mesh->totloop);
MutableSpan<MEdge> edges = MutableSpan<MEdge>(mesh->medge, mesh->totedge);
MutableSpan<MPoly> polys = MutableSpan<MPoly>(mesh->mpoly, mesh->totpoly);
float angle = 0.0f;
const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
for (MVert &vert : verts) {
copy_v3_v3(vert.co, float3(std::cos(angle) * radius, std::sin(angle) * radius, 0.0f));
angle += angle_delta;
}
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
copy_v3_v3(verts.last().co, float3(0));
}
/* Point all vertex normals in the up direction. */
short up_normal[3] = {0, 0, SHRT_MAX};
for (MVert &vert : verts) {
copy_v3_v3_short(vert.no, up_normal);
}
/* Create outer edges. */
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[i];
edge.v1 = i;
edge.v2 = (i + 1) % verts_num;
}
/* Set loose edge flags. */
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[i];
edge.flag |= ME_LOOSEEDGE;
}
}
/* Create triangle fan edges. */
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[verts_num + i];
edge.v1 = verts_num;
edge.v2 = i;
}
}
/* Create corners and faces. */
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
MPoly &poly = polys[0];
poly.loopstart = 0;
poly.totloop = loops.size();
for (const int i : IndexRange(verts_num)) {
MLoop &loop = loops[i];
loop.e = i;
loop.v = i;
}
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[i];
poly.loopstart = 3 * i;
poly.totloop = 3;
MLoop &loop_a = loops[3 * i];
loop_a.e = i;
loop_a.v = i;
MLoop &loop_b = loops[3 * i + 1];
loop_b.e = verts_num + ((i + 1) % verts_num);
loop_b.v = (i + 1) % verts_num;
MLoop &loop_c = loops[3 * i + 2];
loop_c.e = verts_num + i;
loop_c.v = verts_num;
}
}
BLI_assert(BKE_mesh_is_valid(mesh));
return mesh;
}
static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage;
const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
storage.fill_type;
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.set_output("Geometry", GeometrySet());
return;
}
const float radius = params.extract_input<float>("Radius");
const float3 location = params.extract_input<float3>("Location");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
BLI_assert(BKE_mesh_is_valid(mesh));
if (!location.is_zero() || !rotation.is_zero()) {
transform_mesh(mesh, location, rotation, float3(1));
}
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_circle()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_circle_in, geo_node_mesh_primitive_circle_out);
node_type_init(&ntype, geo_node_mesh_primitive_circle_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec;
ntype.draw_buttons = geo_node_mesh_primitive_circle_layout;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,493 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_cone_in[] = {
{SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
{SOCK_FLOAT, N_("Radius Top"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_FLOAT, N_("Radius Bottom"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_FLOAT, N_("Depth"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_cone_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_mesh_primitive_cone_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
sizeof(NodeGeometryMeshCone), __func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
node->storage = node_storage;
}
namespace blender::nodes {
static int vert_total(const GeometryNodeMeshCircleFillType fill_type,
const int verts_num,
const bool use_top,
const bool use_bottom)
{
int vert_total = 0;
if (use_top) {
vert_total += verts_num;
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
vert_total++;
}
}
else {
vert_total++;
}
if (use_bottom) {
vert_total += verts_num;
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
vert_total++;
}
}
else {
vert_total++;
}
return vert_total;
}
static int edge_total(const GeometryNodeMeshCircleFillType fill_type,
const int verts_num,
const bool use_top,
const bool use_bottom)
{
if (!use_top && !use_bottom) {
return 1;
}
int edge_total = 0;
if (use_top) {
edge_total += verts_num;
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
edge_total += verts_num;
}
}
edge_total += verts_num;
if (use_bottom) {
edge_total += verts_num;
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
edge_total += verts_num;
}
}
return edge_total;
}
static int corner_total(const GeometryNodeMeshCircleFillType fill_type,
const int verts_num,
const bool use_top,
const bool use_bottom)
{
if (!use_top && !use_bottom) {
return 0;
}
int corner_total = 0;
if (use_top) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
corner_total += verts_num;
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
corner_total += verts_num * 3;
}
}
if (use_top && use_bottom) {
corner_total += verts_num * 4;
}
else {
corner_total += verts_num * 3;
}
if (use_bottom) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
corner_total += verts_num;
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
corner_total += verts_num * 3;
}
}
return corner_total;
}
static int face_total(const GeometryNodeMeshCircleFillType fill_type,
const int verts_num,
const bool use_top,
const bool use_bottom)
{
if (!use_top && !use_bottom) {
return 0;
}
int face_total = 0;
if (use_top) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
face_total++;
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
face_total += verts_num;
}
}
face_total += verts_num;
if (use_bottom) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
face_total++;
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
face_total += verts_num;
}
}
return face_total;
}
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
const float radius_bottom,
const float depth,
const int verts_num,
const GeometryNodeMeshCircleFillType fill_type)
{
const bool use_top = radius_top != 0.0f;
const bool use_bottom = radius_bottom != 0.0f;
/* Handle the case of a line / single point before everything else to avoid
* the need to check for it later. */
if (!use_top && !use_bottom) {
const bool single_vertex = depth == 0.0f;
Mesh *mesh = BKE_mesh_new_nomain(single_vertex ? 1 : 2, single_vertex ? 0 : 1, 0, 0, 0);
copy_v3_v3(mesh->mvert[0].co, float3(0.0f, 0.0f, depth));
if (single_vertex) {
short up[3] = {0, 0, SHRT_MAX};
copy_v3_v3_short(mesh->mvert[0].no, up);
return mesh;
}
copy_v3_v3(mesh->mvert[1].co, float3(0.0f, 0.0f, -depth));
mesh->medge[0].v1 = 0;
mesh->medge[0].v2 = 1;
mesh->medge[0].flag |= ME_LOOSEEDGE;
BKE_mesh_calc_normals(mesh);
return mesh;
}
Mesh *mesh = BKE_mesh_new_nomain(vert_total(fill_type, verts_num, use_top, use_bottom),
edge_total(fill_type, verts_num, use_top, use_bottom),
0,
corner_total(fill_type, verts_num, use_top, use_bottom),
face_total(fill_type, verts_num, use_top, use_bottom));
MutableSpan<MVert> verts = MutableSpan<MVert>(mesh->mvert, mesh->totvert);
MutableSpan<MEdge> edges = MutableSpan<MEdge>(mesh->medge, mesh->totedge);
MutableSpan<MLoop> loops = MutableSpan<MLoop>(mesh->mloop, mesh->totloop);
MutableSpan<MPoly> polys = MutableSpan<MPoly>(mesh->mpoly, mesh->totpoly);
/* Calculate vertex positions. */
const int top_verts_start = 0;
const int bottom_verts_start = top_verts_start + (use_top ? verts_num : 1);
float angle = 0.0f;
const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
for (const int i : IndexRange(verts_num)) {
const float x = std::cos(angle);
const float y = std::sin(angle);
if (use_top) {
copy_v3_v3(verts[top_verts_start + i].co, float3(x * radius_top, y * radius_top, depth));
}
if (use_bottom) {
copy_v3_v3(verts[bottom_verts_start + i].co,
float3(x * radius_bottom, y * radius_bottom, -depth));
}
angle += angle_delta;
}
if (!use_top) {
copy_v3_v3(verts[top_verts_start].co, float3(0.0f, 0.0f, depth));
}
if (!use_bottom) {
copy_v3_v3(verts[bottom_verts_start].co, float3(0.0f, 0.0f, -depth));
}
/* Add center vertices for the triangle fans at the end. */
const int top_center_vert_index = bottom_verts_start + (use_bottom ? verts_num : 1);
const int bottom_center_vert_index = top_center_vert_index + (use_top ? 1 : 0);
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
if (use_top) {
copy_v3_v3(verts[top_center_vert_index].co, float3(0.0f, 0.0f, depth));
}
if (use_bottom) {
copy_v3_v3(verts[bottom_center_vert_index].co, float3(0.0f, 0.0f, -depth));
}
}
/* Create top edges. */
const int top_edges_start = 0;
const int top_fan_edges_start = (use_top &&
fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
top_edges_start + verts_num :
top_edges_start;
if (use_top) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[top_edges_start + i];
edge.v1 = top_verts_start + i;
edge.v2 = top_verts_start + (i + 1) % verts_num;
}
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[top_fan_edges_start + i];
edge.v1 = top_center_vert_index;
edge.v2 = top_verts_start + i;
}
}
}
/* Create connecting edges. */
const int connecting_edges_start = top_fan_edges_start + (use_top ? verts_num : 0);
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[connecting_edges_start + i];
edge.v1 = top_verts_start + (use_top ? i : 0);
edge.v2 = bottom_verts_start + (use_bottom ? i : 0);
}
/* Create bottom edges. */
const int bottom_edges_start = connecting_edges_start + verts_num;
const int bottom_fan_edges_start = (use_bottom &&
fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
bottom_edges_start + verts_num :
bottom_edges_start;
if (use_bottom) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[bottom_edges_start + i];
edge.v1 = bottom_verts_start + i;
edge.v2 = bottom_verts_start + (i + 1) % verts_num;
}
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[bottom_fan_edges_start + i];
edge.v1 = bottom_center_vert_index;
edge.v2 = bottom_verts_start + i;
}
}
}
/* Create top corners and faces. */
int loop_index = 0;
int poly_index = 0;
if (use_top) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = verts_num;
for (const int i : IndexRange(verts_num)) {
MLoop &loop = loops[loop_index++];
loop.v = top_verts_start + i;
loop.e = top_edges_start + i;
}
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = top_verts_start + i;
loop_a.e = top_edges_start + i;
MLoop &loop_b = loops[loop_index++];
loop_b.v = top_verts_start + (i + 1) % verts_num;
loop_b.e = top_fan_edges_start + (i + 1) % verts_num;
MLoop &loop_c = loops[loop_index++];
loop_c.v = top_center_vert_index;
loop_c.e = top_fan_edges_start + i;
}
}
}
/* Create side corners and faces. */
if (use_top && use_bottom) {
/* Quads connect the top and bottom. */
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 4;
MLoop &loop_a = loops[loop_index++];
loop_a.v = top_verts_start + i;
loop_a.e = connecting_edges_start + i;
MLoop &loop_b = loops[loop_index++];
loop_b.v = bottom_verts_start + i;
loop_b.e = bottom_edges_start + i;
MLoop &loop_c = loops[loop_index++];
loop_c.v = bottom_verts_start + (i + 1) % verts_num;
loop_c.e = connecting_edges_start + (i + 1) % verts_num;
MLoop &loop_d = loops[loop_index++];
loop_d.v = top_verts_start + (i + 1) % verts_num;
loop_d.e = top_edges_start + i;
}
}
else {
/* Triangles connect the top and bottom section. */
if (use_top) {
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = top_verts_start + i;
loop_a.e = connecting_edges_start + i;
MLoop &loop_b = loops[loop_index++];
loop_b.v = bottom_verts_start;
loop_b.e = connecting_edges_start + (i + 1) % verts_num;
MLoop &loop_c = loops[loop_index++];
loop_c.v = top_verts_start + (i + 1) % verts_num;
loop_c.e = top_edges_start + i;
}
}
else {
BLI_assert(use_bottom);
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = bottom_verts_start + i;
loop_a.e = bottom_edges_start + i;
MLoop &loop_b = loops[loop_index++];
loop_b.v = bottom_verts_start + (i + 1) % verts_num;
loop_b.e = connecting_edges_start + (i + 1) % verts_num;
MLoop &loop_c = loops[loop_index++];
loop_c.v = top_verts_start;
loop_c.e = connecting_edges_start + i;
}
}
}
/* Create bottom corners and faces. */
if (use_bottom) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = verts_num;
for (const int i : IndexRange(verts_num)) {
/* Go backwards to reverse surface normal. */
MLoop &loop = loops[loop_index++];
loop.v = bottom_verts_start + verts_num - 1 - i;
loop.e = bottom_edges_start + verts_num - 1 - (i + 1) % verts_num;
}
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = bottom_verts_start + i;
loop_a.e = bottom_fan_edges_start + i;
MLoop &loop_b = loops[loop_index++];
loop_b.v = bottom_center_vert_index;
loop_b.e = bottom_fan_edges_start + (i + 1) % verts_num;
MLoop &loop_c = loops[loop_index++];
loop_c.v = bottom_verts_start + (i + 1) % verts_num;
loop_c.e = bottom_edges_start + i;
}
}
}
BKE_mesh_calc_normals(mesh);
return mesh;
}
static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage;
const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
storage.fill_type;
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.set_output("Geometry", GeometrySet());
return;
}
const float radius_top = params.extract_input<float>("Radius Top");
const float radius_bottom = params.extract_input<float>("Radius Bottom");
const float depth = params.extract_input<float>("Depth");
const float3 location = params.extract_input<float3>("Location");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_cylinder_or_cone_mesh(
radius_top, radius_bottom, depth, verts_num, fill_type);
BLI_assert(BKE_mesh_is_valid(mesh));
/* Transform the mesh so that the base of the cone is at the origin. */
transform_mesh(mesh, location + float3(0.0f, 0.0f, depth), rotation, float3(1));
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_cone()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_cone_in, geo_node_mesh_primitive_cone_out);
node_type_init(&ntype, geo_node_mesh_primitive_cone_init);
node_type_storage(
&ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec;
ntype.draw_buttons = geo_node_mesh_primitive_cone_layout;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,84 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "bmesh.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_cube_in[] = {
{SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_cube_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static Mesh *create_cube_mesh(const float3 location, const float3 rotation, const float size)
{
float4x4 transform;
loc_eul_size_to_mat4(transform.values, location, rotation, float3(size));
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {8, 12, 24, 6};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
"create_cube matrix=%m4 size=%f calc_uvs=%b",
transform.values,
size,
true);
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, NULL);
BM_mesh_free(bm);
return mesh;
}
static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
{
const float size = params.extract_input<float>("Size");
const float3 location = params.extract_input<float3>("Translation");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_cube_mesh(location, rotation, size);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_cube()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_cube_in, geo_node_mesh_primitive_cube_out);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,108 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_cylinder_in[] = {
{SOCK_INT, N_("Vertices"), 32, 0.0f, 0.0f, 0.0f, 3, 4096},
{SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_FLOAT, N_("Depth"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_cylinder_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE);
}
static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
sizeof(NodeGeometryMeshCylinder), __func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
node->storage = node_storage;
}
namespace blender::nodes {
static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage;
const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType)
storage.fill_type;
const int verts_num = params.extract_input<int>("Vertices");
if (verts_num < 3) {
params.set_output("Geometry", GeometrySet());
return;
}
const float radius = params.extract_input<float>("Radius");
const float depth = params.extract_input<float>("Depth");
const float3 location = params.extract_input<float3>("Location");
const float3 rotation = params.extract_input<float3>("Rotation");
/* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */
Mesh *mesh = create_cylinder_or_cone_mesh(radius, radius, depth, verts_num, fill_type);
if (!location.is_zero() || !rotation.is_zero()) {
transform_mesh(mesh, location, rotation, float3(1));
}
BLI_assert(BKE_mesh_is_valid(mesh));
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_cylinder()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_cylinder_in, geo_node_mesh_primitive_cylinder_out);
node_type_init(&ntype, geo_node_mesh_primitive_cylinder_init);
node_type_storage(
&ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec;
ntype.draw_buttons = geo_node_mesh_primitive_cylinder_layout;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,92 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "bmesh.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_ico_sphere_in[] = {
{SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_INT, N_("Subdivisions"), 1, 0, 0, 0, 0, 7},
{SOCK_VECTOR, N_("Translation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_ico_sphere_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static Mesh *create_ico_sphere_mesh(const float3 location,
const float3 rotation,
const int subdivisions,
const float radius)
{
float4x4 transform;
loc_eul_size_to_mat4(transform.values, location, rotation, float3(1.0f));
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {0, 0, 0, 0};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
"create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
subdivisions,
radius,
transform.values,
true);
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, NULL);
BM_mesh_free(bm);
return mesh;
}
static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
{
/* Anything above 8 is not likely to be purposeful and will be very slow. */
const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 8);
const float radius = params.extract_input<float>("Radius");
const float3 location = params.extract_input<float3>("Translation");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_ico_sphere_mesh(location, rotation, subdivisions, radius);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_ico_sphere()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_ico_sphere_in, geo_node_mesh_primitive_ico_sphere_out);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,184 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_map.hh"
#include "BLI_math_matrix.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_line_in[] = {
{SOCK_INT, N_("Count"), 10, 0.0f, 0.0f, 0.0f, 1, 10000},
{SOCK_FLOAT, N_("Resolution"), 1.0f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR,
N_("Start Location"),
0.0f,
0.0f,
0.0f,
1.0f,
-FLT_MAX,
FLT_MAX,
PROP_TRANSLATION},
{SOCK_VECTOR, N_("End Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Offset"), 1.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_line_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
static void geo_node_mesh_primitive_line_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
if (RNA_enum_get(ptr, "mode") == GEO_NODE_MESH_LINE_MODE_END_POINTS) {
uiItemR(layout, ptr, "count_mode", 0, "", ICON_NONE);
}
}
static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
sizeof(NodeGeometryMeshLine), __func__);
node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
node->storage = node_storage;
}
static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node)
{
bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first;
bNodeSocket *resolution_socket = count_socket->next;
bNodeSocket *start_socket = resolution_socket->next;
bNodeSocket *end_socket = start_socket->next;
bNodeSocket *offset_socket = end_socket->next;
const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)node->storage;
const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
storage.count_mode;
nodeSetSocketAvailability(end_socket, mode == GEO_NODE_MESH_LINE_MODE_END_POINTS);
nodeSetSocketAvailability(resolution_socket,
mode == GEO_NODE_MESH_LINE_MODE_END_POINTS &&
count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION);
nodeSetSocketAvailability(count_socket,
mode == GEO_NODE_MESH_LINE_MODE_OFFSET ||
count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL);
nodeSetSocketAvailability(offset_socket, mode == GEO_NODE_MESH_LINE_MODE_OFFSET);
}
namespace blender::nodes {
static void fill_edge_data(MutableSpan<MEdge> edges)
{
for (const int i : edges.index_range()) {
edges[i].v1 = i;
edges[i].v2 = i + 1;
edges[i].flag |= ME_LOOSEEDGE;
}
}
static Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
{
Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0);
MutableSpan<MVert> verts = MutableSpan<MVert>(mesh->mvert, mesh->totvert);
MutableSpan<MEdge> edges = MutableSpan<MEdge>(mesh->medge, mesh->totedge);
short normal[3];
normal_float_to_short_v3(normal, delta.normalized());
float3 co = start;
for (const int i : verts.index_range()) {
copy_v3_v3(verts[i].co, co);
copy_v3_v3_short(verts[i].no, normal);
co += delta;
}
fill_edge_data(edges);
return mesh;
}
static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
{
const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage;
const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode;
const GeometryNodeMeshLineCountMode count_mode = (const GeometryNodeMeshLineCountMode)
storage.count_mode;
Mesh *mesh = nullptr;
const float3 start = params.extract_input<float3>("Start Location");
if (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) {
const float3 end = params.extract_input<float3>("End Location");
const float3 total_delta = end - start;
int count;
float3 delta;
if (count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION) {
const float resolution = params.extract_input<float>("Resolution");
count = total_delta.length() / resolution;
delta = total_delta.normalized() * resolution;
}
else if (count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL) {
count = params.extract_input<int>("Count");
delta = total_delta / count;
}
if (count > 0) {
mesh = create_line_mesh(start, delta, count);
}
}
else if (mode == GEO_NODE_MESH_LINE_MODE_OFFSET) {
const float3 delta = params.extract_input<float3>("Offset");
const int count = params.extract_input<int>("Count");
mesh = create_line_mesh(start, delta, count);
}
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_line()
{
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Line", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_line_in, geo_node_mesh_primitive_line_out);
node_type_init(&ntype, geo_node_mesh_primitive_line_init);
node_type_update(&ntype, geo_node_mesh_primitive_line_update);
node_type_storage(
&ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec;
ntype.draw_buttons = geo_node_mesh_primitive_line_layout;
nodeRegisterType(&ntype);
}

View File

@@ -0,0 +1,278 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_in[] = {
{SOCK_INT, N_("Segments"), 32, 0.0f, 0.0f, 0.0f, 3, 1024},
{SOCK_INT, N_("Rings"), 16, 0.0f, 0.0f, 0.0f, 3, 1024},
{SOCK_FLOAT, N_("Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_VECTOR, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{-1, ""},
};
static bNodeSocketTemplate geo_node_mesh_primitive_uv_sphere_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
static int sphere_vert_total(const int segments, const int rings)
{
return segments * (rings - 1) + 2;
}
static int sphere_edge_total(const int segments, const int rings)
{
return segments * (rings * 2 - 1);
}
static int sphere_corner_total(const int segments, const int rings)
{
const int quad_corners = 4 * segments * (rings - 2);
const int tri_corners = 3 * segments * 2;
return quad_corners + tri_corners;
}
static int sphere_face_total(const int segments, const int rings)
{
const int quads = segments * (rings - 2);
const int triangles = segments * 2;
return quads + triangles;
}
static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float radius,
const int segments,
const int rings)
{
const float delta_theta = M_PI / rings;
const float delta_phi = (2 * M_PI) / segments;
copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
int vert_index = 1;
float theta = delta_theta;
for (const int UNUSED(ring) : IndexRange(rings - 1)) {
float phi = 0.0f;
const float z = cosf(theta);
for (const int UNUSED(segment) : IndexRange(segments)) {
const float x = sinf(theta) * cosf(phi);
const float y = sinf(theta) * sinf(phi);
copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
phi += delta_phi;
vert_index++;
}
theta += delta_theta;
}
copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
normal_float_to_short_v3(verts.last().no, float3(0.0f, 0.0f, -1.0f));
}
static void calculate_sphere_edge_indices(MutableSpan<MEdge> edges,
const int segments,
const int rings)
{
int edge_index = 0;
/* Add the edges connecting the top vertex to the first ring. */
const int first_vert_ring_index_start = 1;
for (const int segment : IndexRange(segments)) {
MEdge &edge = edges[edge_index++];
edge.v1 = 0;
edge.v2 = first_vert_ring_index_start + segment;
}
int ring_vert_index_start = 1;
for (const int ring : IndexRange(rings - 1)) {
const int next_ring_vert_index_start = ring_vert_index_start + segments;
/* Add the edges running along each ring. */
for (const int segment : IndexRange(segments)) {
MEdge &edge_in_ring = edges[edge_index++];
edge_in_ring.v1 = ring_vert_index_start + segment;
edge_in_ring.v2 = ring_vert_index_start + ((segment + 1) % segments);
}
/* Add the edges connecting to the next ring. */
if (ring < rings - 2) {
for (const int segment : IndexRange(segments)) {
MEdge &edge_to_next_ring = edges[edge_index++];
edge_to_next_ring.v1 = ring_vert_index_start + segment;
edge_to_next_ring.v2 = next_ring_vert_index_start + segment;
}
}
ring_vert_index_start += segments;
}
/* Add the edges connecting the last ring to the bottom vertex. */
const int last_vert_index = sphere_vert_total(segments, rings) - 1;
const int last_vert_ring_start = last_vert_index - segments;
for (const int segment : IndexRange(segments)) {
MEdge &edge = edges[edge_index++];
edge.v1 = last_vert_index;
edge.v2 = last_vert_ring_start + segment;
}
}
static void calculate_sphere_faces(MutableSpan<MLoop> loops,
MutableSpan<MPoly> polys,
const int segments,
const int rings)
{
int loop_index = 0;
int poly_index = 0;
/* Add the triangles conntected to the top vertex. */
const int first_vert_ring_index_start = 1;
for (const int segment : IndexRange(segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = 0;
loop_a.e = segment;
MLoop &loop_b = loops[loop_index++];
loop_b.v = first_vert_ring_index_start + segment;
loop_b.e = segments + segment;
MLoop &loop_c = loops[loop_index++];
loop_c.v = first_vert_ring_index_start + (segment + 1) % segments;
loop_c.e = (segment + 1) % segments;
}
int ring_vert_index_start = 1;
int ring_edge_index_start = segments;
for (const int UNUSED(ring) : IndexRange(rings - 2)) {
const int next_ring_vert_index_start = ring_vert_index_start + segments;
const int next_ring_edge_index_start = ring_edge_index_start + segments * 2;
const int ring_vertical_edge_index_start = ring_edge_index_start + segments;
for (const int segment : IndexRange(segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 4;
MLoop &loop_a = loops[loop_index++];
loop_a.v = ring_vert_index_start + segment;
loop_a.e = ring_vertical_edge_index_start + segment;
MLoop &loop_b = loops[loop_index++];
loop_b.v = next_ring_vert_index_start + segment;
loop_b.e = next_ring_edge_index_start + segment;
MLoop &loop_c = loops[loop_index++];
loop_c.v = next_ring_vert_index_start + ((segment + 1) % segments);
loop_c.e = ring_vertical_edge_index_start + ((segment + 1) % segments);
MLoop &loop_d = loops[loop_index++];
loop_d.v = ring_vert_index_start + ((segment + 1) % segments);
loop_d.e = ring_edge_index_start + segment;
}
ring_vert_index_start += segments;
ring_edge_index_start += segments * 2;
}
/* Add the triangles connected to the bottom vertex. */
const int last_edge_ring_start = segments * (rings - 2) * 2 + segments;
const int bottom_edge_fan_start = last_edge_ring_start + segments;
const int last_vert_index = sphere_vert_total(segments, rings) - 1;
const int last_vert_ring_start = last_vert_index - segments;
for (const int segment : IndexRange(segments)) {
MPoly &poly = polys[poly_index++];
poly.loopstart = loop_index;
poly.totloop = 3;
MLoop &loop_a = loops[loop_index++];
loop_a.v = last_vert_index;
loop_a.e = bottom_edge_fan_start + ((segment + 1) % segments);
MLoop &loop_b = loops[loop_index++];
loop_b.v = last_vert_ring_start + (segment + 1) % segments;
loop_b.e = last_edge_ring_start + segment;
MLoop &loop_c = loops[loop_index++];
loop_c.v = last_vert_ring_start + segment;
loop_c.e = bottom_edge_fan_start + segment;
}
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
{
Mesh *mesh = BKE_mesh_new_nomain(sphere_vert_total(segments, rings),
sphere_edge_total(segments, rings),
0,
sphere_corner_total(segments, rings),
sphere_face_total(segments, rings));
MutableSpan<MVert> verts = MutableSpan<MVert>(mesh->mvert, mesh->totvert);
MutableSpan<MEdge> edges = MutableSpan<MEdge>(mesh->medge, mesh->totedge);
MutableSpan<MLoop> loops = MutableSpan<MLoop>(mesh->mloop, mesh->totloop);
MutableSpan<MPoly> polys = MutableSpan<MPoly>(mesh->mpoly, mesh->totpoly);
calculate_sphere_vertex_data(verts, radius, segments, rings);
calculate_sphere_edge_indices(edges, segments, rings);
calculate_sphere_faces(loops, polys, segments, rings);
BLI_assert(BKE_mesh_is_valid(mesh));
return mesh;
}
static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
{
const int segments_num = params.extract_input<int>("Segments");
const int rings_num = params.extract_input<int>("Rings");
if (segments_num < 3 || rings_num < 3) {
params.set_output("Geometry", GeometrySet());
return;
}
const float radius = params.extract_input<float>("Radius");
const float3 location = params.extract_input<float3>("Location");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
BLI_assert(BKE_mesh_is_valid(mesh));
if (!location.is_zero() || !rotation.is_zero()) {
transform_mesh(mesh, location, rotation, float3(1));
}
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
} // namespace blender::nodes
void register_node_type_geo_mesh_primitive_uv_sphere()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_uv_sphere_in, geo_node_mesh_primitive_uv_sphere_out);
ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec;
nodeRegisterType(&ntype);
}

View File

@@ -57,10 +57,10 @@ static bool use_translate(const float3 rotation, const float3 scale)
return true;
}
static void transform_mesh(Mesh *mesh,
const float3 translation,
const float3 rotation,
const float3 scale)
void transform_mesh(Mesh *mesh,
const float3 translation,
const float3 rotation,
const float3 scale)
{
/* Use only translation if rotation and scale are zero. */
if (use_translate(rotation, scale)) {