Skip to content

Commit 3e05284

Browse files
authored
Smooth By Normals (#776)
* SmoothByNormals compiles * added ForVert * tests pass * added bindings * stupid formatting... * fix typo * small fix * aligned weights
1 parent c9ec169 commit 3e05284

16 files changed

+221
-39
lines changed

bindings/c/include/manifoldc.h

+2
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ ManifoldManifold *manifold_mirror(void *mem, ManifoldManifold *m, float nx,
139139
float ny, float nz);
140140
ManifoldManifold *manifold_warp(void *mem, ManifoldManifold *m,
141141
ManifoldVec3 (*fun)(float, float, float));
142+
ManifoldManifold *manifold_smooth_by_normals(void *mem, ManifoldManifold *m,
143+
int normalIdx);
142144
ManifoldManifold *manifold_smooth_out(void *mem, ManifoldManifold *m,
143145
float minSharpAngle, float minSmoothness);
144146
ManifoldManifold *manifold_refine(void *mem, ManifoldManifold *m, int refine);

bindings/c/manifoldc.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,12 @@ ManifoldMeshGL *manifold_level_set_seq_context(
300300
return level_set_context(mem, sdf, bounds, edge_length, level, true, ctx);
301301
}
302302

303+
ManifoldManifold *manifold_smooth_by_normals(void *mem, ManifoldManifold *m,
304+
int normalIdx) {
305+
auto smoothed = from_c(m)->SmoothByNormals(normalIdx);
306+
return to_c(new (mem) Manifold(smoothed));
307+
}
308+
303309
ManifoldManifold *manifold_smooth_out(void *mem, ManifoldManifold *m,
304310
float minSharpAngle,
305311
float minSmoothness) {

bindings/python/examples/all_apis.py

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def all_manifold():
7070
b = m.bounding_box()
7171
m = m.calculate_curvature(4, 5)
7272
m = m.calculate_normals(0)
73+
m = m.smooth_by_normals(0)
7374
m = Manifold.compose([m, m.translate((5, 0, 0))])
7475
m = Manifold.cube((1, 1, 1))
7576
m = Manifold.cylinder(1, 1)

bindings/python/manifold3d.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ NB_MODULE(manifold3d, m) {
318318
.def("calculate_normals", &Manifold::CalculateNormals,
319319
nb::arg("normal_idx"), nb::arg("min_sharp_angle") = 60,
320320
manifold__calculate_normals__normal_idx__min_sharp_angle)
321+
.def("smooth_by_normals", &Manifold::SmoothByNormals,
322+
nb::arg("normal_idx"), manifold__smooth_by_normals__normal_idx)
321323
.def("smooth_out", &Manifold::SmoothOut, nb::arg("min_sharp_angle") = 60,
322324
nb::arg("min_smoothness") = 0,
323325
manifold__smooth_out__min_sharp_angle__min_smoothness)

bindings/wasm/bindings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ EMSCRIPTEN_BINDINGS(whatever) {
144144
.function("_GetMeshJS", &js::GetMeshJS)
145145
.function("refine", &Manifold::Refine)
146146
.function("refineToLength", &Manifold::RefineToLength)
147+
.function("smoothByNormals", &Manifold::SmoothByNormals)
147148
.function("smoothOut", &Manifold::SmoothOut)
148149
.function("_Warp", &man_js::Warp)
149150
.function("_SetProperties", &man_js::SetProperties)

bindings/wasm/examples/public/examples.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export const examples = {
221221
const radius = 30;
222222
const offset = 20;
223223
const wiggles = 12;
224-
const sharpness = 0.8;
224+
const sharpness = 0.6;
225225
const n = 50;
226226

227227
const positions = [];

bindings/wasm/examples/worker.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ suite('Examples', () => {
116116
test('Scallop', async () => {
117117
const result = await runExample('Scallop');
118118
expect(result.genus).to.equal(0, 'Genus');
119-
expect(result.volume).to.be.closeTo(41100, 100, 'Volume');
120-
expect(result.surfaceArea).to.be.closeTo(7790, 10, 'Surface Area');
119+
expect(result.volume).to.be.closeTo(41500, 100, 'Volume');
120+
expect(result.surfaceArea).to.be.closeTo(7880, 10, 'Surface Area');
121121
});
122122

123123
test('Torus Knot', async () => {

bindings/wasm/examples/worker.ts

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const manifoldMemberFunctions = [
7171
'mirror',
7272
'calculateCurvature',
7373
'calculateNormals',
74+
'smoothByNormals',
7475
'smoothOut',
7576
'refine',
7677
'refineToLength',

bindings/wasm/manifold-encapsulated-types.d.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,20 @@ export class Manifold {
562562
/**
563563
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
564564
* geometry will remain unchanged until Refine or RefineToLength is called to
565-
* interpolate the surface.
565+
* interpolate the surface. This version uses the supplied vertex normal
566+
* properties to define the tangent vectors.
567+
*
568+
* @param normalIdx The first property channel of the normals. NumProp must be
569+
* at least normalIdx + 3. Any vertex where multiple normals exist and don't
570+
* agree will result in a sharp edge.
571+
*/
572+
smoothByNormals(normalIdx: number): Manifold;
573+
574+
/**
575+
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
576+
* geometry will remain unchanged until Refine or RefineToLength is called to
577+
* interpolate the surface. This version uses the geometry of the triangles
578+
* and pseudo-normals to define the tangent vectors.
566579
*
567580
* @param minSharpAngle degrees, default 60. Any edges with angles greater
568581
* than this value will remain sharp. The rest will be smoothed to G1

samples/src/scallop.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Manifold Scallop() {
2525
constexpr float radius = 3;
2626
constexpr float offset = 2;
2727
constexpr int wiggles = 12;
28-
constexpr float sharpness = 0.8;
28+
constexpr float sharpness = 0.6;
2929

3030
Mesh scallop;
3131
std::vector<Smoothness> sharpenedEdges;

src/manifold/include/manifold.h

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ class Manifold {
245245
int, std::function<void(float*, glm::vec3, const float*)>) const;
246246
Manifold CalculateCurvature(int gaussianIdx, int meanIdx) const;
247247
Manifold CalculateNormals(int normalIdx, float minSharpAngle = 60) const;
248+
Manifold SmoothByNormals(int normalIdx) const;
248249
Manifold SmoothOut(float minSharpAngle = 60, float minSmoothness = 0) const;
249250
Manifold Refine(int) const;
250251
Manifold RefineToLength(float) const;

src/manifold/src/impl.h

+25
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,29 @@ struct Manifold::Impl {
6666
const std::vector<float>& propertyTolerance = {},
6767
bool hasFaceIDs = false);
6868

69+
inline void ForVert(int halfedge, std::function<void(int halfedge)> func) {
70+
int current = halfedge;
71+
do {
72+
func(current);
73+
current = NextHalfedge(halfedge_[current].pairedHalfedge);
74+
} while (current != halfedge);
75+
}
76+
77+
template <typename T>
78+
void ForVert(int halfedge, std::function<T(int halfedge)> transform,
79+
std::function<void(int halfedge, const T& here, const T& next)>
80+
binaryOp) {
81+
T here = transform(halfedge);
82+
int current = halfedge;
83+
do {
84+
const int nextHalfedge = NextHalfedge(halfedge_[current].pairedHalfedge);
85+
const T next = transform(nextHalfedge);
86+
binaryOp(current, here, next);
87+
here = next;
88+
current = nextHalfedge;
89+
} while (current != halfedge);
90+
}
91+
6992
void CreateFaces(const std::vector<float>& propertyTolerance = {});
7093
void RemoveUnreferencedVerts(Vec<glm::ivec3>& triVerts);
7194
void InitializeOriginal();
@@ -137,13 +160,15 @@ struct Manifold::Impl {
137160
void SplitPinchedVerts();
138161

139162
// smoothing.cu
163+
glm::vec3 GetNormal(int halfedge, int normalIdx) const;
140164
std::vector<Smoothness> UpdateSharpenedEdges(
141165
const std::vector<Smoothness>&) const;
142166
Vec<bool> FlatFaces() const;
143167
Vec<int> VertFlatFace(const Vec<bool>&) const;
144168
std::vector<Smoothness> SharpenEdges(float minSharpAngle,
145169
float minSmoothness) const;
146170
void SetNormals(int normalIdx, float minSharpAngle);
171+
void CreateTangents(int normalIdx);
147172
void CreateTangents(std::vector<Smoothness>);
148173
Vec<Barycentric> Subdivide(std::function<int(glm::vec3)>);
149174
void Refine(std::function<int(glm::vec3)>);

src/manifold/src/manifold.cpp

+22-3
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,8 @@ Manifold Manifold::CalculateCurvature(int gaussianIdx, int meanIdx) const {
661661
*
662662
* @param normalIdx The property channel in which to store the X
663663
* values of the normals. The X, Y, and Z channels will be sequential. The
664-
* property set will be automatically expanded to include up through normalIdx
665-
* + 2.
664+
* property set will be automatically expanded such that NumProp will be at
665+
* least normalIdx + 3.
666666
*
667667
* @param minSharpAngle Any edges with angles greater than this value will
668668
* remain sharp, getting different normal vector properties on each side of the
@@ -679,7 +679,26 @@ Manifold Manifold::CalculateNormals(int normalIdx, float minSharpAngle) const {
679679
/**
680680
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
681681
* geometry will remain unchanged until Refine or RefineToLength is called to
682-
* interpolate the surface.
682+
* interpolate the surface. This version uses the supplied vertex normal
683+
* properties to define the tangent vectors.
684+
*
685+
* @param normalIdx The first property channel of the normals. NumProp must be
686+
* at least normalIdx + 3. Any vertex where multiple normals exist and don't
687+
* agree will result in a sharp edge.
688+
*/
689+
Manifold Manifold::SmoothByNormals(int normalIdx) const {
690+
auto pImpl = std::make_shared<Impl>(*GetCsgLeafNode().GetImpl());
691+
if (!IsEmpty()) {
692+
pImpl->CreateTangents(normalIdx);
693+
}
694+
return Manifold(std::make_shared<CsgLeafNode>(pImpl));
695+
}
696+
697+
/**
698+
* Smooths out the Manifold by filling in the halfedgeTangent vectors. The
699+
* geometry will remain unchanged until Refine or RefineToLength is called to
700+
* interpolate the surface. This version uses the geometry of the triangles and
701+
* pseudo-normals to define the tangent vectors.
683702
*
684703
* @param minSharpAngle degrees, default 60. Any edges with angles greater than
685704
* this value will remain sharp. The rest will be smoothed to G1 continuity,

0 commit comments

Comments
 (0)