sharpAgainstSmooth function
Two cylinders side by side, the left one with its wall marked sharp and the right one left smooth.
The one fixture whose whole point is a flag. Both halves have the same vertices, the same faces and the same volume; what differs is where the shading breaks. Sixteen sides puts each facet 22.5° from the next — inside the thirty degrees a smoothing threshold allows — so the angle alone would round both of them off, and only the flag makes one read as sixteen flat panels. Marking the rims instead would have shown nothing: a right angle between a cap and a wall breaks at any threshold anybody would set.
Implementation
EditMesh sharpAgainstSmooth() {
final mesh = const ParametricCylinder(
radiusTop: 0.5,
radiusBottom: 0.5,
height: 1.1,
segments: 16,
).toEditMesh();
final original = _allFaces(mesh);
mesh.beginStep();
final copy = duplicateSelection(mesh, original);
translateSelection(mesh, copy.selection, by: Vector3(0.75, 0, 0));
// The original goes the other way, so the pair straddles the origin and the
// camera frames both.
translateSelection(mesh, original, by: Vector3(-0.75, 0, 0));
for (final face in original.ids) {
mesh.forEachHalfEdge(face, (int half) {
final from = mesh.positionOf(mesh.originOf(half));
final to = mesh.positionOf(mesh.originOf(mesh.nextOf(half)));
// The uprights of the wall, which is where the two halves part company.
if ((from.y - to.y).abs() > 0.5) {
mesh.setEdgeFlag(half, EdgeFlags.sharp, on: true);
}
});
}
for (final face in copy.selection.ids) {
mesh.forEachHalfEdge(face, (int half) {
mesh.setEdgeFlag(half, EdgeFlags.sharp, on: false);
});
}
mesh
..endStep()
..clearJournal();
return mesh;
}