1
1

Compare commits

...

72 Commits

Author SHA1 Message Date
21d774cef3 Fixes and cleanup after merge 2021-03-16 21:55:35 -04:00
7bb5c86c1e Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-16 21:29:58 -04:00
e05616fbac Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-16 21:22:31 -04:00
3861ee7f3f Rename function 2021-03-15 19:12:19 -04:00
109545755a Revert "Replace sphere with BMesh version"
This reverts commit 9f16e5ea3f.
2021-03-15 18:27:41 -04:00
e9d5b767e8 Revert "Use BMesh for cone, cylinder, and sphere"
This reverts commit 167a2d19a9.
2021-03-15 18:27:04 -04:00
e73fee563d Merge branch 'geometry-nodes-mesh-primitives' into geometry-nodes-mesh-primitives-slow 2021-03-15 18:16:01 -04:00
00a0c7943d Fix off-by-one error in the line node 2021-03-15 18:15:07 -04:00
167a2d19a9 Use BMesh for cone, cylinder, and sphere 2021-03-15 17:58:19 -04:00
9f16e5ea3f Replace sphere with BMesh version 2021-03-15 17:37:53 -04:00
b649f0ba7f Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-15 17:34:40 -04:00
977fc6e115 Add UVs to plane primitive 2021-03-15 17:34:20 -04:00
1cc876f325 Add UV attribute creation to cone node 2021-03-15 17:04:51 -04:00
f73bef57d9 Add UVs to sphere primitive 2021-03-15 15:34:15 -04:00
c97183258f Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-14 22:46:51 -04:00
630a163998 Use "Location" consistently 2021-03-14 22:28:21 -04:00
f65cca02b0 Remove unecessary checks for zero 2021-03-14 22:15:59 -04:00
3a45f35d7e Add plane primitive node 2021-03-14 22:10:46 -04:00
29e71774fe Remove extra assert 2021-03-14 08:40:44 -04:00
8892796e12 Merge branch 'master' into geometry-nodes-mesh-primitives 2021-03-14 08:27:21 -04:00
ec8bae2a59 Add line primitive node 2021-03-13 23:47:19 -05:00
5cd33108fc Cleanup: Remove unused includes, change switch to if 2021-03-13 21:46:12 -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
4 changed files with 552 additions and 65 deletions

View File

@@ -52,9 +52,7 @@ void transform_mesh(Mesh *mesh,
const float3 rotation,
const float3 scale);
Mesh *create_cylinder_or_cone_mesh(const float3 location,
const float3 rotation,
const float radius_top,
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
const float radius_bottom,
const float depth,
const int verts_num,

View File

@@ -17,14 +17,11 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "bmesh.h"
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_mesh_primitive_cone_in[] = {
@@ -191,46 +188,351 @@ static int face_total(const GeometryNodeMeshCircleFillType fill_type,
return face_total;
}
Mesh *create_cylinder_or_cone_mesh(const float3 location,
const float3 rotation,
const float radius_top,
static void calculate_uvs(Mesh *mesh,
const bool top_is_point,
const bool bottom_is_point,
const int verts_num,
const GeometryNodeMeshCircleFillType fill_type)
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
"uv", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
Array<float2> circle(verts_num);
float angle = 0.0f;
const float angle_delta = 2.0f * M_PI / static_cast<float>(verts_num);
for (const int i : IndexRange(verts_num)) {
circle[i].x = std::cos(angle) * 0.225f + 0.25f;
circle[i].y = std::sin(angle) * 0.225f + 0.25f;
angle += angle_delta;
}
int loop_index = 0;
if (!top_is_point) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
for (const int i : IndexRange(verts_num)) {
uvs[loop_index++] = circle[i];
}
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
uvs[loop_index++] = circle[i];
uvs[loop_index++] = circle[(i + 1) % verts_num];
uvs[loop_index++] = float2(0.25f, 0.25f);
}
}
}
/* Create side corners and faces. */
if (!top_is_point && !bottom_is_point) {
const float bottom = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ? 0.0f : 0.5f;
/* Quads connect the top and bottom. */
for (const int i : IndexRange(verts_num)) {
const float vert = static_cast<float>(i);
uvs[loop_index++] = float2(vert / verts_num, bottom);
uvs[loop_index++] = float2((vert + 1.0f) / verts_num, bottom);
uvs[loop_index++] = float2((vert + 1.0f) / verts_num, 1.0f);
uvs[loop_index++] = float2(vert / verts_num, 1.0f);
}
}
else {
/* Triangles connect the top and bottom section. */
if (!top_is_point) {
for (const int i : IndexRange(verts_num)) {
uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
uvs[loop_index++] = float2(0.75f, 0.25f);
uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
}
}
else {
BLI_assert(!bottom_is_point);
for (const int i : IndexRange(verts_num)) {
uvs[loop_index++] = circle[i];
uvs[loop_index++] = circle[(i + 1) % verts_num];
uvs[loop_index++] = float2(0.25f, 0.25f);
}
}
}
/* Create bottom corners and faces. */
if (!bottom_is_point) {
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) {
for (const int i : IndexRange(verts_num)) {
/* Go backwards because of reversed face normal. */
uvs[loop_index++] = circle[verts_num - 1 - i] + float2(0.5f, 0.0f);
}
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : IndexRange(verts_num)) {
uvs[loop_index++] = circle[i] + float2(0.5f, 0.0f);
uvs[loop_index++] = float2(0.75f, 0.25f);
uvs[loop_index++] = circle[(i + 1) % verts_num] + float2(0.5f, 0.0f);
}
}
}
uv_attribute.apply_span_and_save();
}
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)
{
float4x4 transform;
loc_eul_size_to_mat4(transform.values, location, rotation, float3(1));
const bool top_is_point = radius_top == 0.0f;
const bool bottom_is_point = 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 (top_is_point && bottom_is_point) {
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) {
const 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;
}
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {
Mesh *mesh = BKE_mesh_new_nomain(
vert_total(fill_type, verts_num, top_is_point, bottom_is_point),
edge_total(fill_type, verts_num, top_is_point, bottom_is_point),
0,
corner_total(fill_type, verts_num, top_is_point, bottom_is_point),
face_total(fill_type, verts_num, top_is_point, bottom_is_point)};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
face_total(fill_type, verts_num, top_is_point, bottom_is_point));
MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
const bool cap_end = (fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE);
const bool cap_tri = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN);
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
"create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
"cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
verts_num,
radius_bottom,
radius_top,
cap_end,
cap_tri,
depth,
transform.values,
true);
/* Calculate vertex positions. */
const int top_verts_start = 0;
const int bottom_verts_start = top_verts_start + (!top_is_point ? 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 (!top_is_point) {
copy_v3_v3(verts[top_verts_start + i].co, float3(x * radius_top, y * radius_top, depth));
}
if (!bottom_is_point) {
copy_v3_v3(verts[bottom_verts_start + i].co,
float3(x * radius_bottom, y * radius_bottom, -depth));
}
angle += angle_delta;
}
if (top_is_point) {
copy_v3_v3(verts[top_verts_start].co, float3(0.0f, 0.0f, depth));
}
if (bottom_is_point) {
copy_v3_v3(verts[bottom_verts_start].co, float3(0.0f, 0.0f, -depth));
}
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
BM_mesh_free(bm);
/* Add center vertices for the triangle fans at the end. */
const int top_center_vert_index = bottom_verts_start + (bottom_is_point ? 1 : verts_num);
const int bottom_center_vert_index = top_center_vert_index + (top_is_point ? 0 : 1);
if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
if (!top_is_point) {
copy_v3_v3(verts[top_center_vert_index].co, float3(0.0f, 0.0f, depth));
}
if (!bottom_is_point) {
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 = (!top_is_point &&
fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
top_edges_start + verts_num :
top_edges_start;
if (!top_is_point) {
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 + (!top_is_point ? verts_num : 0);
for (const int i : IndexRange(verts_num)) {
MEdge &edge = edges[connecting_edges_start + i];
edge.v1 = top_verts_start + (!top_is_point ? i : 0);
edge.v2 = bottom_verts_start + (!bottom_is_point ? i : 0);
}
/* Create bottom edges. */
const int bottom_edges_start = connecting_edges_start + verts_num;
const int bottom_fan_edges_start = (!bottom_is_point &&
fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) ?
bottom_edges_start + verts_num :
bottom_edges_start;
if (!bottom_is_point) {
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 (!top_is_point) {
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 (!top_is_point && !bottom_is_point) {
/* 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 (!top_is_point) {
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(!bottom_is_point);
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 (!bottom_is_point) {
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);
calculate_uvs(mesh, top_is_point, bottom_is_point, verts_num, fill_type);
BLI_assert(BKE_mesh_is_valid(mesh));
return mesh;
}
@@ -256,7 +558,10 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_cylinder_or_cone_mesh(
location, rotation, radius_top, radius_bottom, depth, verts_num, fill_type);
radius_top, radius_bottom, depth, verts_num, fill_type);
/* 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));
}

View File

@@ -79,8 +79,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
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(
location, rotation, radius, radius, depth, verts_num, fill_type);
Mesh *mesh = create_cylinder_or_cone_mesh(radius, radius, depth, verts_num, fill_type);
transform_mesh(mesh, location, rotation, float3(1));

View File

@@ -17,22 +17,19 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "bmesh.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_INT, N_("Rings"), 16, 0.0f, 0.0f, 0.0f, 2, 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, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
{SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
{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, ""},
};
@@ -67,34 +64,219 @@ static int sphere_face_total(const int segments, const int rings)
return quads + triangles;
}
static Mesh *create_uv_sphere_mesh_bmesh(const float3 location,
const float3 rotation,
static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float radius,
const int segments,
const int rings)
{
float4x4 transform;
loc_eul_size_to_mat4(transform.values, location, rotation, float3(radius));
const float delta_theta = M_PI / rings;
const float delta_phi = (2 * M_PI) / segments;
const BMeshCreateParams bmcp = {true};
const BMAllocTemplate allocsize = {sphere_vert_total(segments, rings),
sphere_edge_total(segments, rings),
sphere_corner_total(segments, rings),
sphere_face_total(segments, rings)};
BMesh *bm = BM_mesh_create(&allocsize, &bmcp);
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));
BMO_op_callf(bm,
BMO_FLAG_DEFAULTS,
"create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
segments,
rings,
radius,
transform.values,
true);
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 = std::sin(theta) * std::cos(phi);
const float y = std::sin(theta) * std::sin(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;
}
Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr);
BM_mesh_free(bm);
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(1, 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 void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
"uv", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
int loop_index = 0;
const float dy = 1.0f / rings;
for (const int i_segment : IndexRange(segments)) {
const float segment = static_cast<float>(i_segment);
uvs[loop_index++] = float2((segment + 0.5f) / segments, 0.0f);
uvs[loop_index++] = float2((segment + 1.0f) / segments, dy);
uvs[loop_index++] = float2(segment / segments, dy);
}
for (const int i_ring : IndexRange(1, rings - 2)) {
const float ring = static_cast<float>(i_ring);
for (const int i_segment : IndexRange(segments)) {
const float segment = static_cast<float>(i_segment);
uvs[loop_index++] = float2(segment / segments, ring / rings);
uvs[loop_index++] = float2((segment + 1.0f) / segments, ring / rings);
uvs[loop_index++] = float2((segment + 1.0f) / segments, (ring + 1.0f) / rings);
uvs[loop_index++] = float2(segment / segments, (ring + 1.0f) / rings);
}
}
for (const int i_segment : IndexRange(segments)) {
const float segment = static_cast<float>(i_segment);
uvs[loop_index++] = float2((segment + 0.5f) / segments, 1.0f);
uvs[loop_index++] = float2((segment + 1.0f) / segments, 1.0f - dy);
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
uv_attribute.apply_span_and_save();
}
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{mesh->mvert, mesh->totvert};
MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MPoly> polys{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);
calculate_sphere_uvs(mesh, segments, rings);
BLI_assert(BKE_mesh_is_valid(mesh));
return mesh;
}
@@ -103,7 +285,7 @@ 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) {
if (segments_num < 3 || rings_num < 2) {
params.set_output("Geometry", GeometrySet());
return;
}
@@ -112,7 +294,10 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
const float3 location = params.extract_input<float3>("Location");
const float3 rotation = params.extract_input<float3>("Rotation");
Mesh *mesh = create_uv_sphere_mesh_bmesh(location, rotation, radius, segments_num, rings_num);
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
transform_mesh(mesh, location, rotation, float3(1));
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}