Compare commits
39 Commits
asset-shel
...
bevelv2
Author | SHA1 | Date | |
---|---|---|---|
7501d46648 | |||
4b2e119f48 | |||
049eea594c | |||
785729bb46 | |||
fe40d51180 | |||
12263df09f | |||
63e0bd1da6 | |||
60dccd4e6f | |||
e737fe7061 | |||
5cea3e5500 | |||
0a7fea09d3 | |||
2ce0bb1358 | |||
58b6976a27 | |||
cb83c88bf9 | |||
a41a1bfc49 | |||
fc8f9e4204 | |||
6df669a0bd | |||
c5049d3ad1 | |||
0a35a7bd31 | |||
5070ffda47 | |||
e4abaa6748 | |||
bb20c44bac | |||
05cc4cd004 | |||
845d525099 | |||
2bc4a34343 | |||
7826cd74ba | |||
f789cf6ac3 | |||
d22cfad960 | |||
3b2bc5d146 | |||
81341d1e94 | |||
ba8dd18d34 | |||
b9a93465a0 | |||
1f31645a1a | |||
62c97f107c | |||
3556fa2742 | |||
cae7778db7 | |||
b13451f3c3 | |||
38fadd7fc4 | |||
b0875a588b |
@@ -381,6 +381,7 @@ class NODE_MT_geometry_node_GEO_MESH_OPERATIONS(Menu):
|
||||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeBevelMesh")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeDualMesh")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToCurves")
|
||||
node_add_menu.add_node_type(layout, "GeometryNodeEdgePathsToSelection")
|
||||
|
@@ -1372,6 +1372,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
/** \name Texture Nodes
|
||||
* \{ */
|
||||
|
||||
#define GEO_NODE_BEVEL_MESH 1400
|
||||
#define TEX_NODE_OUTPUT 401
|
||||
#define TEX_NODE_CHECKER 402
|
||||
#define TEX_NODE_TEXTURE 403
|
||||
|
110
source/blender/blenlib/BLI_mesh_inset.hh
Normal file
110
source/blender/blenlib/BLI_mesh_inset.hh
Normal file
@@ -0,0 +1,110 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*
|
||||
* This header file contains a C++ interface to a 3D mesh inset algorithm
|
||||
* which is based on a 2D Straight Skeleton construction.
|
||||
*/
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
|
||||
namespace blender::meshinset {
|
||||
|
||||
/*
|
||||
* This is the library interface to a function that can inset
|
||||
* contours (closed sequences of vertices) of a 3D mesh.
|
||||
* For generality, the mesh is specified by #Span of faces,
|
||||
* where each face has the sequence of vertex indices that
|
||||
* are traversed in CCW order to form the face.
|
||||
* The indices given the position in a #Span of #float3 entries,
|
||||
* which are 3D coordinates.
|
||||
*
|
||||
* An "inset" of a contour by a given amount is conceptually
|
||||
* formed as follows: offset each edge of the contour on its left
|
||||
* side by the specified amount, shortening and joining up each
|
||||
* offset edge with its neighbor offset edges. If the contour
|
||||
* forms a face, this is typically known as a "face inset".
|
||||
* However, that conceptual description fails to describe what
|
||||
* to do if an offset edge shortens so much that it vanishes,
|
||||
* or if advancing intersection points of offset edges collide
|
||||
* into offset edges from another part of the contour (or another
|
||||
* contour).
|
||||
*
|
||||
* An algorithm called the "Straight Skeleton Algorithm"
|
||||
* (see https://wikipedia.org/wiki/Straight_skeleton)
|
||||
* deals with such complications, and is what is used in this
|
||||
* library routine. That algorithm regards each edge of the
|
||||
* contour as a wavefront that advances at a constant speed,
|
||||
* dealing with topological changes as wavefront edges collapse
|
||||
* or crash into opposite ones. The Straight Skeleton is what
|
||||
* remains if you advance the wavefronts as far as they can go,
|
||||
* but we can stop at any particular amount of advancement to
|
||||
* achieve an inset by that amount.
|
||||
*
|
||||
* However, the Straight Skeleton Algorithm is a 2D algorithm,
|
||||
* doesn't deal with internal geometry. This library function
|
||||
* is adapted to work in 3D and "flow over" internal geometry
|
||||
* as the wavefronts advance.
|
||||
*
|
||||
* Also, an extra feature of this library is to allow the advancing
|
||||
* wavefronts to raise (along face normals) at a given slope.
|
||||
* Users like this as an option to a "face inset" function.
|
||||
*
|
||||
* Usage:
|
||||
* Populate a #MeshInset_Input structure with the mesh
|
||||
* (vertex coordinates and faces), the contours to inset
|
||||
* (vertex indices forming closed loops to inset),
|
||||
* and the amount to inset and the slope.
|
||||
* Pass this to #mesh_inset_calc, and receive a #MeshInset_Result
|
||||
* as output.
|
||||
* The #MeshInset_Result has a new mesh, also give by vertex
|
||||
* coordinates and faces. It also has some data to help understand
|
||||
* how to map the output back to the input:
|
||||
* TODO: Document the extras when this interface finally settles down.
|
||||
*/
|
||||
|
||||
/** #MeshInset_Input is the input structure for #mesh_inset_calc. */
|
||||
class MeshInset_Input {
|
||||
public:
|
||||
/** The vertices. Can be a superset of the needed vertices. */
|
||||
Span<float3> vert;
|
||||
/** The faces, each a CCW ordering of vertex indices. */
|
||||
Span<Vector<int>> face;
|
||||
/** The contours to inset; ints are vert indices; contour is on left side of implied edges. */
|
||||
Span<Vector<int>> contour;
|
||||
float inset_amount;
|
||||
float slope;
|
||||
bool need_ids;
|
||||
};
|
||||
|
||||
/** #MeshInset_Result is the output structure for #mesh_inset_calc. */
|
||||
class MeshInset_Result {
|
||||
public:
|
||||
/** The output vertices. A subset (perhaps) of input vertices, plus some new ones. */
|
||||
Array<float3> vert;
|
||||
/** The output faces, each a CCW ordering of the output vertices. */
|
||||
Array<Vector<int>> face;
|
||||
/** The output contours -- where the input contours ended up. */
|
||||
Array<Vector<int>> contour;
|
||||
/** Maps output vertex indices to input vertex indices, -1 if there is none. */
|
||||
Array<int> orig_vert;
|
||||
/** Maps output faces tot input faces that they were part of. */
|
||||
Array<int> orig_face;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate a mesh inset -- the offset of a set of contours, dealing with collisions.
|
||||
*
|
||||
* \param input: a #MeshInset_Input containing a mesh, contours to offet, and offset parameters.
|
||||
* \return a #MeshInset_Result giving a new mesh and data to relate the output to the input.
|
||||
*/
|
||||
MeshInset_Result mesh_inset_calc(const MeshInset_Input &input);
|
||||
|
||||
} // namespace blender::meshinset
|
@@ -115,6 +115,7 @@ set(SRC
|
||||
intern/math_vector_inline.c
|
||||
intern/memory_utils.c
|
||||
intern/mesh_boolean.cc
|
||||
intern/mesh_inset.cc
|
||||
intern/mesh_intersect.cc
|
||||
intern/noise.c
|
||||
intern/noise.cc
|
||||
@@ -303,6 +304,7 @@ set(SRC
|
||||
BLI_memory_utils.hh
|
||||
BLI_mempool.h
|
||||
BLI_mesh_boolean.hh
|
||||
BLI_mesh_inset.hh
|
||||
BLI_mesh_intersect.hh
|
||||
BLI_mmap.h
|
||||
BLI_multi_value_map.hh
|
||||
@@ -514,6 +516,7 @@ if(WITH_GTESTS)
|
||||
tests/BLI_memiter_test.cc
|
||||
tests/BLI_memory_utils_test.cc
|
||||
tests/BLI_mesh_boolean_test.cc
|
||||
tests/BLI_mesh_inset_test.cc
|
||||
tests/BLI_mesh_intersect_test.cc
|
||||
tests/BLI_multi_value_map_test.cc
|
||||
tests/BLI_path_util_test.cc
|
||||
|
3455
source/blender/blenlib/intern/mesh_inset.cc
Normal file
3455
source/blender/blenlib/intern/mesh_inset.cc
Normal file
File diff suppressed because it is too large
Load Diff
393
source/blender/blenlib/tests/BLI_mesh_inset_test.cc
Normal file
393
source/blender/blenlib/tests/BLI_mesh_inset_test.cc
Normal file
@@ -0,0 +1,393 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_mesh_inset.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
namespace blender::meshinset {
|
||||
|
||||
namespace test {
|
||||
|
||||
class SpecArrays {
|
||||
public:
|
||||
Array<float3> vert;
|
||||
Array<Vector<int>> face;
|
||||
Array<Vector<int>> contour;
|
||||
};
|
||||
|
||||
/* The spec should have the form:
|
||||
* #verts #faces #contours
|
||||
* <float> <float> <float> [#verts lines]
|
||||
* <int> <int> ... <int> [#faces lines]
|
||||
* <int> <int> ... <int> [#contours lines]
|
||||
*/
|
||||
static SpecArrays fill_input_from_string(const char *spec)
|
||||
{
|
||||
SpecArrays ans;
|
||||
std::istringstream ss(spec);
|
||||
std::string line;
|
||||
getline(ss, line);
|
||||
std::istringstream hdrss(line);
|
||||
int nverts, nfaces, ncontours;
|
||||
hdrss >> nverts >> nfaces >> ncontours;
|
||||
if (nverts == 0) {
|
||||
return SpecArrays();
|
||||
}
|
||||
ans.vert = Array<float3>(nverts);
|
||||
ans.face = Array<Vector<int>>(nfaces);
|
||||
ans.contour = Array<Vector<int>>(ncontours);
|
||||
int i = 0;
|
||||
while (i < nverts && getline(ss, line)) {
|
||||
std::istringstream iss(line);
|
||||
float x, y, z;
|
||||
iss >> x >> y >> z;
|
||||
ans.vert[i] = float3(x, y, z);
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (i < nfaces && getline(ss, line)) {
|
||||
std::istringstream fss(line);
|
||||
int v;
|
||||
while (fss >> v) {
|
||||
ans.face[i].append(v);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
while (i < ncontours && getline(ss, line)) {
|
||||
std::istringstream css(line);
|
||||
int v;
|
||||
while (css >> v) {
|
||||
ans.contour[i].append(v);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
class InputHolder {
|
||||
SpecArrays spec_arrays_;
|
||||
|
||||
public:
|
||||
MeshInset_Input input;
|
||||
|
||||
InputHolder(const char *spec, float amount)
|
||||
{
|
||||
spec_arrays_ = fill_input_from_string(spec);
|
||||
input.vert = spec_arrays_.vert.as_span();
|
||||
input.face = spec_arrays_.face.as_span();
|
||||
input.contour = spec_arrays_.contour.as_span();
|
||||
input.inset_amount = amount;
|
||||
input.slope = 0.5f;
|
||||
input.need_ids = false;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(mesh_inset, Tri)
|
||||
{
|
||||
const char *spec = R"(3 1 1
|
||||
0.0 0.0 0.0
|
||||
1.0 0.0 0.0
|
||||
0.5 0.5 0.0
|
||||
0 1 2
|
||||
0 1 2
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.1);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 6);
|
||||
EXPECT_EQ(out1.face.size(), 4);
|
||||
|
||||
InputHolder in2(spec, 0.3);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
EXPECT_EQ(out2.vert.size(), 4);
|
||||
EXPECT_EQ(out2.face.size(), 3);
|
||||
}
|
||||
|
||||
/* An asymmetrical quadrilateral. */
|
||||
TEST(mesh_inset, Quad)
|
||||
{
|
||||
const char *spec = R"(4 1 1
|
||||
-1.0 -1.0 0.0
|
||||
1.1 -1.0 0.0
|
||||
0.9 0.9 0.0
|
||||
-0.5 1.0 0.0
|
||||
0 1 2 3
|
||||
0 1 2 3
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.3);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 8);
|
||||
EXPECT_EQ(out1.face.size(), 5);
|
||||
|
||||
InputHolder in2(spec, .85);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
EXPECT_EQ(out2.vert.size(), 8);
|
||||
EXPECT_EQ(out2.face.size(), 5);
|
||||
|
||||
InputHolder in3(spec, .88);
|
||||
MeshInset_Result out3 = mesh_inset_calc(in3.input);
|
||||
EXPECT_EQ(out3.vert.size(), 6);
|
||||
EXPECT_EQ(out3.face.size(), 4);
|
||||
}
|
||||
|
||||
TEST(mesh_inset, Square)
|
||||
{
|
||||
const char *spec = R"(4 1 1
|
||||
0.0 0.0 0.0
|
||||
1.0 0.0 0.0
|
||||
1.0 1.0 0.0
|
||||
0.0 1.0 0.0
|
||||
0 1 2 3
|
||||
0 1 2 3
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.4);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 8);
|
||||
EXPECT_EQ(out1.face.size(), 5);
|
||||
|
||||
InputHolder in2(spec, 0.51);
|
||||
in2.input.slope = 0.5f;
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
/* Note: current code wants all 3-valence vertices in
|
||||
* straight skeleton, so the center doesn't collapse to
|
||||
* a single vertex, but rather two vertices with a zero
|
||||
* length edge between them. */
|
||||
EXPECT_EQ(out2.vert.size(), 6);
|
||||
EXPECT_EQ(out2.face.size(), 4);
|
||||
/* The last two verts should be in the center, with height 0.25. */
|
||||
const float3 &v4 = out2.vert[4];
|
||||
const float3 &v5 = out2.vert[5];
|
||||
EXPECT_NEAR(v4.x, 0.5, 1e-5);
|
||||
EXPECT_NEAR(v4.y, 0.5, 1e-5);
|
||||
EXPECT_NEAR(v4.z, 0.25, 1e-5);
|
||||
EXPECT_NEAR(v5.x, 0.5, 1e-5);
|
||||
EXPECT_NEAR(v5.y, 0.5, 1e-5);
|
||||
EXPECT_NEAR(v5.z, 0.25, 1e-5);
|
||||
}
|
||||
|
||||
TEST(mesh_inset, Pentagon)
|
||||
{
|
||||
const char *spec = R"(5 1 1
|
||||
0.0 0.0 0.0
|
||||
1.0 0.0 0.0
|
||||
1.0 1.0 0.0
|
||||
0.5 1.5 0.0
|
||||
0.0 1.0 0.0
|
||||
0 1 2 3 4
|
||||
0 1 2 3 4
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.2);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 10);
|
||||
EXPECT_EQ(out1.face.size(), 6);
|
||||
|
||||
InputHolder in2(spec, 1.0);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
/* Because code wants all valence-3 vertices in the skeleton,
|
||||
* there is a zero-length edge in this output. */
|
||||
EXPECT_EQ(out2.vert.size(), 8);
|
||||
EXPECT_EQ(out2.face.size(), 5);
|
||||
}
|
||||
|
||||
TEST(mesh_inset, Hexagon)
|
||||
{
|
||||
const char *spec = R"(6 1 1
|
||||
0.0 1.0 0.0
|
||||
0.125 0.0 0.0
|
||||
0.625 -0.75 0.0
|
||||
1.5 -1.0 0.0
|
||||
2.875 0.0 0.0
|
||||
3.0 1.0 0.0
|
||||
0 1 2 3 4 5
|
||||
0 1 2 3 4 5
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.4);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 12);
|
||||
EXPECT_EQ(out1.face.size(), 7);
|
||||
|
||||
InputHolder in2(spec, 0.67);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
EXPECT_EQ(out2.vert.size(), 12);
|
||||
EXPECT_EQ(out2.face.size(), 7);
|
||||
|
||||
InputHolder in3(spec, 0.85);
|
||||
MeshInset_Result out3 = mesh_inset_calc(in3.input);
|
||||
EXPECT_EQ(out3.vert.size(), 12);
|
||||
EXPECT_EQ(out3.face.size(), 7);
|
||||
|
||||
InputHolder in4(spec, 0.945);
|
||||
MeshInset_Result out4 = mesh_inset_calc(in4.input);
|
||||
EXPECT_EQ(out4.vert.size(), 12);
|
||||
EXPECT_EQ(out4.face.size(), 7);
|
||||
|
||||
InputHolder in5(spec, 0.97);
|
||||
MeshInset_Result out5 = mesh_inset_calc(in5.input);
|
||||
EXPECT_EQ(out5.vert.size(), 10);
|
||||
EXPECT_EQ(out5.face.size(), 6);
|
||||
}
|
||||
|
||||
TEST(mesh_inset, Splitter)
|
||||
{
|
||||
const char *spec = R"(5 1 1
|
||||
0.0 0.0 0.0
|
||||
1.5 0.1 0.0
|
||||
1.75 0.8 0.0
|
||||
0.8 0.6 0.0
|
||||
0.0 1.0 0.0
|
||||
0 1 2 3 4
|
||||
0 1 2 3 4
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.25);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 10);
|
||||
EXPECT_EQ(out1.face.size(), 6);
|
||||
|
||||
InputHolder in2(spec, 0.29);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
EXPECT_EQ(out2.vert.size(), 12);
|
||||
EXPECT_EQ(out2.face.size(), 7);
|
||||
|
||||
InputHolder in3(spec, 0.40);
|
||||
MeshInset_Result out3 = mesh_inset_calc(in3.input);
|
||||
EXPECT_EQ(out3.vert.size(), 8);
|
||||
EXPECT_EQ(out3.face.size(), 5);
|
||||
}
|
||||
|
||||
TEST(mesh_inset, Flipper)
|
||||
{
|
||||
const char *spec = R"(20 1 1
|
||||
0.0 0.0 0.0
|
||||
1.5 0.0 0.0
|
||||
1.375 0.025 0.0
|
||||
1.25 0.06 0.0
|
||||
1.125 0.11 0.0
|
||||
1.0 0.2 0.0
|
||||
1.0 1.0 0.0
|
||||
0.79 1.0 0.0
|
||||
0.75 0.95 0.0
|
||||
0.71 1.0 0.0
|
||||
0.585 1.0 0.0
|
||||
0.55 0.9 0.0
|
||||
0.515 1.0 0.0
|
||||
0.38 1.0 0.0
|
||||
0.35 0.85 0.0
|
||||
0.32 1.0 0.0
|
||||
0.175 1.0 0.0
|
||||
0.15 0.8 0.0
|
||||
0.125 1.0 0.0
|
||||
0.0 1.0 0.0
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.01);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 40);
|
||||
EXPECT_EQ(out1.face.size(), 21);
|
||||
|
||||
InputHolder in2(spec, 0.06);
|
||||
MeshInset_Result out2 = mesh_inset_calc(in2.input);
|
||||
EXPECT_EQ(out2.vert.size(), 40);
|
||||
EXPECT_EQ(out2.face.size(), 21);
|
||||
|
||||
InputHolder in3(spec, 0.07);
|
||||
MeshInset_Result out3 = mesh_inset_calc(in3.input);
|
||||
EXPECT_EQ(out3.vert.size(), 40);
|
||||
EXPECT_EQ(out3.face.size(), 21);
|
||||
|
||||
InputHolder in4(spec, 0.08);
|
||||
MeshInset_Result out4 = mesh_inset_calc(in4.input);
|
||||
EXPECT_EQ(out4.vert.size(), 40);
|
||||
EXPECT_EQ(out4.face.size(), 21);
|
||||
|
||||
InputHolder in5(spec, 0.087);
|
||||
MeshInset_Result out5 = mesh_inset_calc(in5.input);
|
||||
EXPECT_EQ(out5.vert.size(), 40);
|
||||
EXPECT_EQ(out5.face.size(), 21);
|
||||
|
||||
InputHolder in6(spec, 0.0878);
|
||||
MeshInset_Result out6 = mesh_inset_calc(in6.input);
|
||||
EXPECT_EQ(out6.vert.size(), 40);
|
||||
EXPECT_EQ(out6.face.size(), 21);
|
||||
|
||||
InputHolder in7(spec, 0.11);
|
||||
MeshInset_Result out7 = mesh_inset_calc(in7.input);
|
||||
EXPECT_EQ(out7.vert.size(), 42);
|
||||
EXPECT_EQ(out7.face.size(), 22);
|
||||
|
||||
InputHolder in8(spec, 0.24);
|
||||
MeshInset_Result out8 = mesh_inset_calc(in8.input);
|
||||
EXPECT_EQ(out8.vert.size(), 42);
|
||||
EXPECT_EQ(out8.face.size(), 22);
|
||||
|
||||
InputHolder in9(spec, 0.255);
|
||||
MeshInset_Result out9 = mesh_inset_calc(in9.input);
|
||||
EXPECT_EQ(out9.vert.size(), 42);
|
||||
EXPECT_EQ(out9.face.size(), 22);
|
||||
|
||||
InputHolder in10(spec, 0.30);
|
||||
MeshInset_Result out10 = mesh_inset_calc(in10.input);
|
||||
EXPECT_EQ(out10.vert.size(), 40);
|
||||
EXPECT_EQ(out10.face.size(), 21);
|
||||
|
||||
InputHolder in11(spec, 0.35);
|
||||
MeshInset_Result out11 = mesh_inset_calc(in11.input);
|
||||
EXPECT_EQ(out11.vert.size(), 38);
|
||||
EXPECT_EQ(out11.face.size(), 20);
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(mesh_inset, Grid)
|
||||
{
|
||||
const char *spec = R"(16 9 1
|
||||
0.0 0.0 0.0
|
||||
1.0 0.0 0.0
|
||||
2.0 0.0 0.0
|
||||
3.0 0.0 0.0
|
||||
0.0 1.0 0.0
|
||||
1.0 1.0 0.0
|
||||
2.0 1.0 0.0
|
||||
3.0 1.0 0.0
|
||||
0.0 2.0 0.0
|
||||
1.0 2.0 0.0
|
||||
2.0 2.0 0.0
|
||||
3.0 2.0 0.0
|
||||
0.0 3.0 0.0
|
||||
1.0 3.0 0.0
|
||||
2.0 3.0 0.0
|
||||
3.0 3.0 0.0
|
||||
0 1 5 4
|
||||
1 2 6 5
|
||||
2 3 7 6
|
||||
4 5 9 8
|
||||
5 6 10 9
|
||||
6 7 11 10
|
||||
8 9 13 12
|
||||
9 10 14 13
|
||||
10 11 15 14
|
||||
0 1 2 3 7 11 15 14 13 12 8 4
|
||||
)";
|
||||
|
||||
InputHolder in1(spec, 0.5);
|
||||
MeshInset_Result out1 = mesh_inset_calc(in1.input);
|
||||
EXPECT_EQ(out1.vert.size(), 28);
|
||||
EXPECT_EQ(out1.face.size(), 21);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace blender::meshinset
|
@@ -1339,6 +1339,11 @@ typedef struct NodeGeometryExtrudeMesh {
|
||||
uint8_t mode;
|
||||
} NodeGeometryExtrudeMesh;
|
||||
|
||||
typedef struct NodeGeometryBevelMesh {
|
||||
/* GeometryNodeBevelMode */
|
||||
uint8_t mode;
|
||||
} NodeGeometryBevelMesh;
|
||||
|
||||
typedef struct NodeGeometryObjectInfo {
|
||||
/* GeometryNodeTransformSpace. */
|
||||
uint8_t transform_space;
|
||||
@@ -2228,6 +2233,12 @@ typedef enum GeometryNodeExtrudeMeshMode {
|
||||
GEO_NODE_EXTRUDE_MESH_FACES = 2,
|
||||
} GeometryNodeExtrudeMeshMode;
|
||||
|
||||
typedef enum GeometryNodeBevelMeshMode {
|
||||
GEO_NODE_BEVEL_MESH_VERTICES = 0,
|
||||
GEO_NODE_BEVEL_MESH_EDGES = 1,
|
||||
GEO_NODE_BEVEL_MESH_FACES = 2,
|
||||
} GeometryNodeBevelMeshMode;
|
||||
|
||||
typedef enum FunctionNodeRotateEulerType {
|
||||
FN_NODE_ROTATE_EULER_TYPE_EULER = 0,
|
||||
FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE = 1,
|
||||
|
@@ -9628,6 +9628,27 @@ static void def_geo_extrude_mesh(StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_geo_bevel_mesh(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static const EnumPropertyItem mode_items[] = {
|
||||
{GEO_NODE_BEVEL_MESH_VERTICES, "VERTICES", 0, "Vertices", ""},
|
||||
{GEO_NODE_BEVEL_MESH_EDGES, "EDGES", 0, "Edges", ""},
|
||||
{GEO_NODE_BEVEL_MESH_FACES, "FACES", 0, "Faces", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryBevelMesh", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "mode");
|
||||
RNA_def_property_enum_items(prop, mode_items);
|
||||
RNA_def_property_enum_default(prop, GEO_NODE_BEVEL_MESH_FACES);
|
||||
RNA_def_property_ui_text(prop, "Mode", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_geo_distribute_points_in_volume(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
@@ -283,6 +283,7 @@ DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToStri
|
||||
DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "Add the values of an evaluated field together and output the running total for each element")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "Retrieve the number of elements in a geometry for each attribute domain")
|
||||
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC",AttributeStatistic, "Attribute Statistic","Calculate statistics about a data set from a field evaluated on a geometry")
|
||||
DefNode(GeometryNode, GEO_NODE_BEVEL_MESH, def_geo_bevel_mesh, "BEVEL_MESH", BevelMesh, "Bevel Mesh", "")
|
||||
DefNode(GeometryNode, GEO_NODE_BLUR_ATTRIBUTE, def_geo_blur_attribute, "BLUR_ATTRIBUTE", BlurAttribute, "Blur Attribute", "Mix attribute values of neighboring elements")
|
||||
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "Calculate the limits of a geometry's positions and generate a box mesh with those dimensions")
|
||||
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture,"CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "Store the result of a field on a geometry and output the data as a node socket. Allows remembering or interpolating data as the geometry changes, such as positions before deformation")
|
||||
|
@@ -29,6 +29,7 @@ set(SRC
|
||||
nodes/node_geo_attribute_capture.cc
|
||||
nodes/node_geo_attribute_domain_size.cc
|
||||
nodes/node_geo_attribute_statistic.cc
|
||||
nodes/node_geo_bevel_mesh.cc
|
||||
nodes/node_geo_blur_attribute.cc
|
||||
nodes/node_geo_boolean.cc
|
||||
nodes/node_geo_bounding_box.cc
|
||||
|
@@ -14,6 +14,7 @@ void register_geometry_nodes()
|
||||
register_node_type_geo_attribute_capture();
|
||||
register_node_type_geo_attribute_domain_size();
|
||||
register_node_type_geo_attribute_statistic();
|
||||
register_node_type_geo_bevel_mesh();
|
||||
register_node_type_geo_blur_attribute();
|
||||
register_node_type_geo_boolean();
|
||||
register_node_type_geo_bounding_box();
|
||||
|
@@ -11,6 +11,7 @@ void register_node_type_geo_attribute_capture();
|
||||
void register_node_type_geo_attribute_domain_size();
|
||||
void register_node_type_geo_attribute_separate_xyz();
|
||||
void register_node_type_geo_attribute_statistic();
|
||||
void register_node_type_geo_bevel_mesh();
|
||||
void register_node_type_geo_blur_attribute();
|
||||
void register_node_type_geo_boolean();
|
||||
void register_node_type_geo_bounding_box();
|
||||
|
2022
source/blender/nodes/geometry/nodes/node_geo_bevel_mesh.cc
Normal file
2022
source/blender/nodes/geometry/nodes/node_geo_bevel_mesh.cc
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user