(filters)= # Filters This reference contains all 370 filters found in the descriptor registry when it was generated. Each filter can be called as a method on a `MeshSet` object, for example `ms.apply_filter("remove_duplicate_vertices", ...)`, or using the dynamically-bound snake_case name: `ms.remove_duplicate_vertices(...)`. A combined bibliography for cited algorithms is available as {download}`BibTeX `. (filter-add-noise-to-vertex-color)= ## Add Noise to Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Add random noise bits independently to RGB channels. ```{py:function} ms.add_noise_to_vertex_color(**params) :module: _meshlab Adds to the color the requested amount of bits of noise. Bits of noise are added independently for each RGB channel. **Parameters:** - **noiseBits** (*int*, default: `1`) — Bits of noise added to each RGB channel. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the added noise exactly reproducible. ``` --- (filter-adjust-vertex-color-brightness-contrast-gamma)= ## Adjust Vertex Color Brightness/Contrast/Gamma **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Adjust vertex-color brightness, contrast, and gamma. ```{py:function} ms.adjust_vertex_color_brightness_contrast_gamma(**params) :module: _meshlab Change the color the vertices of the mesh adjusting brightness, contrast and gamma. **Parameters:** - **brightness** (*double*, default: `0.0`) — Sets the amount of brightness that will be added/subtracted to the colors. - **contrast** (*double*, default: `0.0`) — Sets the amount of contrast of the mesh. - **gamma** (*double*, default: `1.0`) — Sets the values of the exponent gamma. ``` --- (filter-adjust-vertex-color-levels)= ## Adjust Vertex Color Levels **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Remap an input color interval into an output interval. ```{py:function} ms.adjust_vertex_color_levels(**params) :module: _meshlab The filter allows adjustment of color levels. It is a custom way to map an interval of color into another one. The user can set the input minimum and maximum levels, gamma and the output minimum and maximum levels (many tools call them respectively input black point, white point, gray point, output black point and white point). **Parameters:** - **gamma** (*double*, default: `1.0`) — Gamma correction factor. - **in_min** (*double*, default: `0.0`) — Minimum input level. - **in_max** (*double*, default: `255.0`) — Maximum input level. - **out_min** (*double*, default: `0.0`) — Minimum output level. - **out_max** (*double*, default: `255.0`) — Maximum output level. - **rCh** (*bool*, default: `True`) — Apply to red channel. - **gCh** (*bool*, default: `True`) — Apply to green channel. - **bCh** (*bool*, default: `True`) — Apply to blue channel. ``` --- (filter-adjust-vertex-color-white-balance)= ## Adjust Vertex Color White Balance **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Apply white balance so a chosen color becomes white. ```{py:function} ms.adjust_vertex_color_white_balance(**params) :module: _meshlab The filter provides a standard white balance transformation. It is done correcting the RGB channels with a factor such that, the brighter color in the mesh, that is supposed to be white, becomes really white. **Parameters:** - **color** (*color*, default: `#ffffff`) — The color that is supposed to be white. ``` --- (filter-colorize-edges-by-scalar)= ## Colorize Edges by Scalar **Categories:** `Attribute/Color`, `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Map the per-edge scalar of a polyline into per-edge colors. ```{py:function} ms.colorize_edges_by_scalar(**params) :module: _meshlab Color the **real edges of a polyline layer** according to their scalar, the way *Colorize Vertices by Scalar* does for vertices. Write the scalar first with *Compute Edge Scalar by Expression*. By default the full range of values present is mapped onto the color map; tick *Use Custom Range* to pin the ends instead, which is what makes two polylines directly comparable. Unlike the vertex and face versions there is no percentile crop, because VCGLib provides no per-edge quality histogram. Set the edge color source to *Per-Edge* in the render panel to see the result. **Parameters:** - **useCustomRange** (*bool*, default: `False`) — Map the range below instead of the smallest and largest values actually present. - **minVal** (*double*, default: `0.0`) — The value mapped to the lower end of the scale. - **maxVal** (*double*, default: `1.0`) — The value mapped to the upper end of the scale. - **zeroSym** (*bool*, default: `False`) — If true the min/max range is enlarged to be symmetric around zero. - **colorMap** (*enum*, default: `rgb`) — The color map to use. RGB is the VCGLib default, other colormaps are sampled from Matplotlib. ``` --- (filter-colorize-faces-by-scalar)= ## Colorize Faces by Scalar **Categories:** `Attribute/Color`, `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Map face quality into face colors. ```{py:function} ms.colorize_faces_by_scalar(**params) :module: _meshlab Color faces depending on their quality field (manually equalized). **Parameters:** - **minVal** (*double*, default: `@qualityFMin`) — The value mapped to the lower end of the scale. - **maxVal** (*double*, default: `@qualityFMax`) — The value mapped to the upper end of the scale. - **perc** (*double*, default: `0.0`) — If not zero this value is used for percentile cropping of the quality values. - **zeroSym** (*bool*, default: `False`) — If true the min/max range is enlarged to be symmetric around zero. - **colorMap** (*enum*, default: `rgb`) — The color map to use. RGB is the VCGLib default, other colormaps are sampled from Matplotlib. ``` --- (filter-colorize-vertices-by-disk-distance)= ## Colorize Vertices by Disk Distance **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.sampling Color a mesh according to the distance from projected point-cloud disks. ```{py:function} ms.colorize_vertices_by_disk_distance(**params) :module: _meshlab Given a Mesh M and a Pointset P, The filter project each vertex of P over M and color M according to the Euclidean distance from these projected points. Projection and coloring are done on a per vertex basis. **Parameters:** - **ColoredMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh whose vertices will be colored. - **VertexMesh** (*mesh*, default: `@otherMeshIndex`) — The point cloud whose vertices are used as disk centers. - **Radius** (*absperc*, default: `@bboxDiagTenth`) — Disk radius around each point-cloud seed. - **SampleRadius** (*bool*, default: `False`) — Use the per-vertex quality of the seed cloud as the disk radius. - **ApproximateGeodetic** (*bool*, default: `False`) — Weight the Euclidean distance by the normal difference between the two points. ``` --- (filter-colorize-vertices-by-perlin-noise)= ## Colorize Vertices by Perlin Noise **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Color the mesh with a Perlin-based color field. ```{py:function} ms.colorize_vertices_by_perlin_noise(**params) :module: _meshlab Paints the mesh using PerlinColor function. The color assigned to vertices depends on their position in the space; it means that near vertices will be painted with similar colors. **Parameters:** - **color1** (*color*, default: `#000000`) — Sets the first color to mix with Perlin Noise function. - **color2** (*color*, default: `#ffffff`) — Sets the second color to mix with Perlin Noise function. - **freq** (*double*, default: `10.0`) — Frequency of the Perlin Noise function, expressed as multiples of mesh bbox. - **offset** (*point3f*, default: `[0.0, 0.0, 0.0]`) — XYZ frequency offset of the noise function. ``` --- (filter-colorize-vertices-by-scalar)= ## Colorize Vertices by Scalar **Categories:** `Attribute/Color`, `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Map vertex quality into vertex colors. ```{py:function} ms.colorize_vertices_by_scalar(**params) :module: _meshlab Color vertices depending on their quality field. The filter uses the same colormap sampling and range normalization used by MeshLab quality visualization, so it can bake the current quality display into vertex colors. **Parameters:** - **minVal** (*double*, default: `@qualityVMin`) — The value mapped to the lower end of the scale. - **maxVal** (*double*, default: `@qualityVMax`) — The value mapped to the upper end of the scale. - **perc** (*double*, default: `0.0`) — If not zero this value is used for percentile cropping of the quality values. - **zeroSym** (*bool*, default: `False`) — If true the min/max range is enlarged to be symmetric around zero. - **colorMap** (*enum*, default: `rainbow`) — The color map to use. Built-in MeshLab maps match the quality visualization panel; RGB and RdPu preserve legacy VCGLib behavior. - **invert** (*bool*, default: `False`) — Invert the selected MeshLab colormap before sampling, matching the quality visualization panel. Legacy RGB/RdPu maps ignore this option. - **colorMapId** (*string*, default: ``) — Optional exact MeshLab colormap id. Leave empty for the selected Color Map enum. This is mainly used internally when baking the current view and also supports external colormaps loaded by MeshLab. ``` --- (filter-colorize-vertices-by-voronoi-regions)= ## Colorize Vertices by Voronoi Regions **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.sampling Color a mesh according to projected seed points from another layer. ```{py:function} ms.colorize_vertices_by_voronoi_regions(**params) :module: _meshlab Given a Mesh M and a Pointset P, The filter project each vertex of P over M and color M according to the geodesic distance from these projected points. Projection and coloring are done on a per vertex basis. **Parameters:** - **ColoredMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh whose surface will be colored. - **VertexMesh** (*mesh*, default: `@otherMeshIndex`) — The point cloud whose vertices are used as Voronoi seeds. - **backward** (*bool*, default: `False`) — Color according to the distance from the Voronoi frontier instead of from the seed. ``` --- (filter-compute-edge-color-by-expression)= ## Compute Edge Color by Expression **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.expression Computes per-edge RGBA colors from expressions. ```{py:function} ms.compute_edge_color_by_expression(**params) :module: _meshlab Color function using muparser lib to generate a new RGBA color for every edge of a **polyline layer**. Each edge takes one flat color, which is what distinguishes this from interpolating the endpoint vertex colors — pick *Per-Edge* as the edge color source in the render panel to see it. Endpoint values use the same names as the first two corners of a face: `x0,y0,z0`/`x1,y1,z1`, `nx0`..`nz1`, `r0,g0,b0,a0`/`r1`..`a1`, `q0,q1`, `vi0,vi1`, `vsel0,vsel1`. The edge itself gives `er,eg,eb,ea` (current color), `eq` (scalar), `ei` (index) and `esel`, plus the derived `elen` (length), `emx,emy,emz` (midpoint) and `edx,edy,edz` (unit direction; zero for a degenerate edge). Bounding-box values `xmin`..`bbdiag` are available as everywhere else. **Parameters:** - **r** (*string*, default: `255`) — Expression for red output in range [0, 255]. - **g** (*string*, default: `0`) — Expression for green output in range [0, 255]. - **b** (*string*, default: `255`) — Expression for blue output in range [0, 255]. - **a** (*string*, default: `255`) — Expression for alpha output in range [0, 255]. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-face-color-by-expression)= ## Compute Face Color by Expression **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.expression Computes per-face RGBA colors from expressions. ```{py:function} ms.compute_face_color_by_expression(**params) :module: _meshlab Color function using muparser lib to generate new RGBA color for every face
Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.
**Parameters:** - **r** (*string*, default: `255`) — Expression for red output in range [0, 255]. - **g** (*string*, default: `0`) — Expression for green output in range [0, 255]. - **b** (*string*, default: `255`) — Expression for blue output in range [0, 255]. - **a** (*string*, default: `255`) — Expression for alpha output in range [0, 255]. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-vertex-color-by-expression)= ## Compute Vertex Color by Expression **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.expression Computes per-vertex RGBA colors from expressions. ```{py:function} ms.compute_vertex_color_by_expression(**params) :module: _meshlab Color function using muparser lib to generate new RGBA color for every vertex
Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.
**Parameters:** - **x** (*string*, default: `255`) — Expression for X output. - **y** (*string*, default: `255`) — Expression for Y output. - **z** (*string*, default: `0`) — Expression for Z output. - **a** (*string*, default: `255`) — Expression for alpha output in range [0, 255]. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-desaturate-vertex-color)= ## Desaturate Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Convert vertex colors to grayscale using a chosen method. ```{py:function} ms.desaturate_vertex_color(**params) :module: _meshlab The filter desaturates the colors of the mesh. This provides a simple way to convert a mesh in gray tones. The user can choose the desaturation method to apply; they are based on Lightness, Luminosity and Average. **Parameters:** - **method** (*enum*, default: `lightness`) — Lightness is computed as (Max(r,g,b)+Min(r,g,b))/2; Luminosity as 0.212*r + 0.715*g + 0.072*b; Average as (r+g+b)/3. ``` --- (filter-equalize-vertex-color)= ## Equalize Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Equalize the vertex-color histogram. ```{py:function} ms.equalize_vertex_color(**params) :module: _meshlab The filter equalizes the colors histogram. It is a kind of automatic regulation of contrast; the colors histogram is expanded to fit all the range of colors. **Parameters:** - **rCh** (*bool*, default: `True`) — Select the red channel. - **gCh** (*bool*, default: `True`) — Select the green channel. - **bCh** (*bool*, default: `True`) — Select the blue channel. If no channel is selected the filter works on Lightness. ``` --- (filter-invert-vertex-color)= ## Invert Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Invert vertex colors. ```{py:function} ms.invert_vertex_color(**params) :module: _meshlab Inverts the colors of the vertices of the mesh. This filter has no parameters. ``` --- (filter-set-mesh-color)= ## Set Mesh Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Set a solid per-mesh color used by the plain rendering material. ```{py:function} ms.set_mesh_color(**params) :module: _meshlab Set a solid per-mesh color that overrides the plain fill material's color for this mesh. The color is stored in the mesh data and survives undo/redo. **Parameters:** - **color** (*color*, default: `#808080ff`) — The solid color to assign to this mesh. ``` --- (filter-set-random-component-color)= ## Set Random Component Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Assign a random color to each connected component. ```{py:function} ms.set_random_component_color(**params) :module: _meshlab Colorize each connected component randomly. This filter has no parameters. ``` --- (filter-set-random-face-color)= ## Set Random Face Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Assign random colors to faces or faux-connected polygons. ```{py:function} ms.set_random_face_color(**params) :module: _meshlab Colorize Faces randomly. If internal edges are present they are used. Useful for quads. This filter has no parameters. ``` --- (filter-set-random-layer-color)= ## Set Random Layer Color **Categories:** `Attribute/Color`, `Document/Layer` **Plugin:** meshlab2.filter.colorproc Scatter a distinct color across the visible layers, one each. ```{py:function} ms.set_random_layer_color(**params) :module: _meshlab Gives every visible layer its own **mesh color**, picked by *scattering* over the available hues so that layers close together in the list are as far apart in color as their number allows — the same scatter used to tell connected components apart. The layers are also switched to draw in that per-mesh color, so the result is visible without changing the color source by hand. Colors differ on every run unless a **Random seed** is given. The usual reason to want this is to tell layers apart at a glance after a split, an import of many files, or an alignment. **Parameters:** - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the color assignment exactly reproducible. ``` --- (filter-set-vertex-color)= ## Set Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Fill vertex colors with a chosen color. ```{py:function} ms.set_vertex_color(**params) :module: _meshlab Fills the color of the vertices of the mesh with a color chosen by the user. **Parameters:** - **color1** (*color*, default: `#000000`) — Sets the color to apply to vertices. ``` --- (filter-sharpen-vertex-color-by-unsharp-mask)= ## Sharpen Vertex Color by Unsharp Mask **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.unsharp Enhance per-vertex color variation with an unsharp mask. ```{py:function} ms.sharpen_vertex_color_by_unsharp_mask(**params) :module: _meshlab Sharpens the **per-vertex color**, pulling out variation that is hard to see in a low-contrast or noisy color field. Unsharp masking exaggerates local variation by adding back the difference between the signal and a smoothed copy of it: $$s' = s + \lambda\,(s - \mathrm{smooth}(s)).$$ **Weight** is $\lambda$; larger values sharpen harder and amplify noise along with the features. **Smoothing steps** sets how blurred the subtracted copy is, which fixes the scale of the detail being enhanced. **References:** - Paolo Cignoni, Roberto Scopigno, Marco Tarini. **A simple normal enhancement technique for interactive non-photorealistic renderings**. *Computers & Graphics* (2005). [DOI](https://doi.org/10.1016/j.cag.2004.11.012) [Web](https://www.sciencedirect.com/science/article/pii/S0097849304001980) **Parameters:** - **weight** (*double*, default: `0.3`) — Unsharp weight applied to the high-frequency color component. - **weightOrig** (*double*, default: `1.0`) — Weight of the original color signal. - **iterations** (*int*, default: `5`) — Number of Laplacian smoothing iterations used to build the low-pass color signal. ``` --- (filter-smooth-face-color)= ## Smooth Face Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Laplacian smooth face colors. ```{py:function} ms.smooth_face_color(**params) :module: _meshlab Laplacian Smooth Face Color **Parameters:** - **iteration** (*int*, default: `1`) — The number of iterations of the smoothing algorithm. ``` --- (filter-smooth-vertex-color)= ## Smooth Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Laplacian smooth vertex colors. ```{py:function} ms.smooth_vertex_color(**params) :module: _meshlab Laplacian Smooth Vertex Color **Parameters:** - **iteration** (*int*, default: `1`) — The number of iterations of the smoothing algorithm. ``` --- (filter-threshold-vertex-color)= ## Threshold Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Apply two colors according to a lightness threshold. ```{py:function} ms.threshold_vertex_color(**params) :module: _meshlab Colors the vertices of the mesh using two colors according to a lightness threshold (on the original color). **Parameters:** - **color1** (*color*, default: `#000000`) — Sets the color to apply below the threshold. - **color2** (*color*, default: `#ffffff`) — Sets the color to apply above the threshold. - **threshold** (*double*, default: `128.0`) — Vertices with color above the lightness threshold become Color 2, the others Color 1. ``` --- (filter-tint-vertex-color)= ## Tint Vertex Color **Categories:** `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Blend a chosen color into the existing vertex colors. ```{py:function} ms.tint_vertex_color(**params) :module: _meshlab Allows the application of a color to the mesh. In spite of the Fill operation, the color is blended with the mesh according to a given intensity. **Parameters:** - **hue** (*double*, default: `0.0`) — Changes the hue of the mesh. - **saturation** (*double*, default: `100.0`) — Changes the saturation of the mesh. - **luminance** (*double*, default: `50.0`) — Changes the luminance of the mesh. - **intensity** (*double*, default: `50.0`) — Sets the blending factor used in adding the new color to the existing one. ``` --- (filter-compute-curvature-apss)= ## Compute Curvature (APSS) **Categories:** `Attribute/Curvature` **Plugin:** meshlab2.filter.mls Compute APSS curvature estimates and store them in vertex quality. ```{py:function} ms.compute_curvature_apss(**params) :module: _meshlab Computes curvature at each vertex of a mesh or point set and stores it in the vertex scalar field. No color is baked; the view switches to scalar visualization when the filter finishes. This is the **algebraic point set surfaces** (APSS) variant: the local approximation fitted at each point is an algebraic sphere rather than a plane, which keeps curved regions from flattening out. It needs points carrying oriented normals. **References:** - Gaël Guennebaud, Markus Gross. **Algebraic point set surfaces**. *ACM Transactions on Graphics (SIGGRAPH 2007)* (2007). [DOI](https://doi.org/10.1145/1276377.1276406) - Gaël Guennebaud, Marcel Germann, Markus Gross. **Dynamic Sampling and Rendering of Algebraic Point Set Surfaces**. *Computer Graphics Forum (Eurographics 2008)* (2008). [DOI](https://doi.org/10.1111/j.1467-8659.2008.01163.x) **Parameters:** - **CurvatureType** (*enum*, default: `mean`) — The type of the curvature to plot.
ApproxMean uses the radius of the fitted sphere as an approximation of the mean curvature. - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SphericalParameter** (*double*, default: `1.0`) — Control the curvature of the fitted spheres: 0 is equivalent to a pure plane fit, 1 to a pure spherical fit, values between 0 and 1 give intermediate results, while other real values might give interesting results, but take care with extreme settings. - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-compute-curvature-discrete)= ## Compute Curvature (Discrete) **Categories:** `Attribute/Curvature` **Plugin:** meshlab2.filter.colorproc Compute discrete curvature and store it in vertex quality. ```{py:function} ms.compute_curvature_discrete(**params) :module: _meshlab Compute discrete curvature and store it in vertex quality. The filter does not bake colors; after it runs MeshLab switches the view to vertex-quality color visualization.
Computed as described in:
'Discrete Differential-Geometry Operators for Triangulated 2-Manifolds'
M. Meyer, M. Desbrun, P. Schroder, A. H. Barr **Parameters:** - **CurvatureType** (*enum*, default: `mean`) — Choose the curvature value that you want transferred onto the scalar Quality. ``` --- (filter-compute-curvature-rimls)= ## Compute Curvature (RIMLS) **Categories:** `Attribute/Curvature` **Plugin:** meshlab2.filter.mls Compute RIMLS curvature estimates and store them in vertex quality. ```{py:function} ms.compute_curvature_rimls(**params) :module: _meshlab Computes curvature at each vertex of a mesh or point set and stores it in the vertex scalar field. No color is baked; the view switches to scalar visualization when the filter finishes. This is the **robust implicit MLS** (RIMLS) variant: it extends implicit MLS with non-linear kernel regression, so sharp edges survive instead of being rounded away with the noise. It needs points carrying oriented normals. **References:** - A. Cengiz Öztireli, Gaël Guennebaud, Markus Gross. **Feature Preserving Point Set Surfaces based on Non-Linear Kernel Regression**. *Computer Graphics Forum (Eurographics 2009)* (2009). [DOI](https://doi.org/10.1111/j.1467-8659.2009.01388.x) **Parameters:** - **CurvatureType** (*enum*, default: `mean`) — The type of the curvature to plot. - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SigmaN** (*double*, default: `0.75`) — Width of the filter used by the normal refitting weight. This weight function is a Gaussian on the distance between two unit vectors: the current gradient and the input normal. Typical values range between 0.5 (sharp) and 2 (smooth). - **MaxRefittingIters** (*int*, default: `3`) — Max number of fitting iterations. (0 or 1 is equivalent to the standard IMLS). - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-compute-curvature-trueform)= ## Compute Curvature (TrueForm) **Categories:** `Attribute/Curvature` **Plugin:** meshlab2.filter.trueform Estimate principal curvatures by local fitting and store one measure in vertex scalar. ```{py:function} ms.compute_curvature_trueform(**params) :module: _meshlab Fits a local surface around each vertex over its k-ring neighbourhood and derives the two principal curvatures, then stores the chosen measure in **vertex scalar**. **Measure** selects what is written: | Measure | Meaning | |---|---| | Mean | (k1 + k2) / 2 | | Gaussian | k1 * k2 — positive on domes and bowls, negative on saddles | | Minimum / Maximum | the individual principal curvatures | | Shape index | scale-free descriptor of local shape, from cup through saddle to cap | **Ring** is the neighbourhood radius in rings of adjacent vertices. Larger values smooth the estimate and cost more; it is the knob to turn when noise dominates the result. The shape index is worth knowing about: unlike the curvature values it is **independent of scale**, so it describes the *kind* of shape at a point rather than how strongly curved it is, which makes it comparable across models of different sizes. Competing implementation: see also *Compute Curvature (Discrete)*, *(APSS)* and *(RIMLS)*. **Parameters:** - **measure** (*enum*, default: `mean`) — Which curvature measure to store in vertex scalar. - **ring** (*int*, default: `2`) — Neighbourhood radius in vertex rings. Larger is smoother and slower. ``` --- (filter-compute-gaussian-curvature-libigl)= ## Compute Gaussian Curvature (libigl) **Categories:** `Attribute/Curvature`, `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Compute the integrated Gaussian curvature at each vertex with libigl. ```{py:function} ms.compute_gaussian_curvature_libigl(**params) :module: _meshlab Computes libigl's discrete **angle deficit** at every face-referenced vertex and stores it in **vertex scalar**: $$K_i = 2\pi - \sum_{f \ni} \theta_{if}.$$ This is integrated Gaussian curvature, not curvature divided by a vertex area. On a closed manifold mesh its sum is governed by Gauss-Bonnet. At boundary vertices the expression is not an intrinsic Gaussian-curvature estimate; the reported value still uses $2\pi$, so interpret boundary values with care. Faux-edge polygon groups are processed through their stored triangle representation. No colors are baked into the mesh; MeshLab switches to vertex-scalar visualization after completion. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Mark Meyer, Mathieu Desbrun, Peter Schröder, Alan H. Barr. **Discrete Differential-Geometry Operators for Triangulated 2-Manifolds**. *Visualization and Mathematics III* (2003). [DOI](https://doi.org/10.1007/978-3-662-05105-4_2) This filter has no parameters. ``` --- (filter-compute-principal-curvature-directions-libigl)= ## Compute Principal Curvature Directions (libigl) **Categories:** `Attribute/Curvature`, `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Estimate principal curvature values and directions with libigl's multi-scale fitting method. ```{py:function} ms.compute_principal_curvature_directions_libigl(**params) :module: _meshlab Estimates the two principal curvatures and their tangent directions using libigl's multi-scale local fitting implementation. The maximal and minimal values are stored in the mesh curvature component as $k_1$ and $k_2$, with their corresponding directions. **Quality Mapping** also stores one derived value in **vertex scalar** for immediate visualization. **Neighborhood Radius** is measured in vertex rings when **Use K-ring Neighborhood** is enabled. Otherwise libigl interprets it relative to average edge length. Larger neighborhoods suppress noise but also smooth small features. Vertices for which libigl cannot form a valid fit are reported and assigned zero curvature and zero directions. Faux-edge polygon groups are processed through their stored triangle representation. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Daniele Panozzo, Enrico Puppo, Luigi Rocca. **Efficient Multi-scale Curvature and Crease Estimation**. *Proceedings of the 4th International Conference on Computer Graphics, Computer Vision and Mathematics (GraVisMa 2010)* (2010). **Parameters:** - **neighborhood_radius** (*int*, default: `5`) — Neighborhood size passed to libigl. With K-ring mode it is the number of adjacent vertex rings; otherwise it is relative to average edge length. - **use_k_ring** (*bool*, default: `True`) — Use a topological K-ring neighborhood. Disable it to use libigl's metric ball neighborhood. - **quality_mapping** (*enum*, default: `mean`) — Choose the curvature value also stored in vertex scalar and shown after completion. ``` --- (filter-compute-principal-curvature-directions-vcglib)= ## Compute Principal Curvature Directions (vcglib) **Categories:** `Attribute/Curvature` **Plugin:** meshlab2.filter.meshing Compute principal curvature directions. ```{py:function} ms.compute_principal_curvature_directions_vcglib(**params) :module: _meshlab Compute the principal directions of curvature with different algorithms. The selected curvature scalar is stored in vertex quality; the filter does not bake colors, and MeshLab switches the view to vertex-quality color visualization after it runs. **Parameters:** - **Method** (*enum*, default: `quadric_fitting`) — Choose method. - **CurvColorMethod** (*enum*, default: `mean`) — Choose the curvature value stored in vertex quality and shown through automatic quality visualization. - **Scale** (*absperc*, default: `@bboxDiagTenth`) — Scale for scale-dependent methods. - **Autoclean** (*bool*, default: `True`) — Remove unreferenced vertices before computing. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the PCA method's point sampling exactly reproducible. ``` --- (filter-define-custom-face-point-attribute)= ## Define Custom Face Point Attribute **Categories:** `Attribute/Custom` **Plugin:** meshlab2.filter.expression Defines and fills a custom per-face point attribute. ```{py:function} ms.define_custom_face_point_attribute(**params) :module: _meshlab Add a new Per-Face custom point attribute to current mesh and fill it with the defined functions.
Attribute names must contain only letters, numbers and underscores.
The name specified for the attribute can be used in other filter functions.
**Parameters:** - **name** (*string*, default: `CustomAttrName`) — Name of the new custom attribute. - **x_expr** (*string*, default: `x0`) — Expression for X component. - **y_expr** (*string*, default: `y0`) — Expression for Y component. - **z_expr** (*string*, default: `z0`) — Expression for Z component. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-define-custom-face-scalar-attribute)= ## Define Custom Face Scalar Attribute **Categories:** `Attribute/Custom` **Plugin:** meshlab2.filter.expression Defines and fills a custom per-face scalar attribute. ```{py:function} ms.define_custom_face_scalar_attribute(**params) :module: _meshlab Add a new Per-Face custom scalar attribute to current mesh and fill it with the defined function.
Attribute names must contain only letters, numbers and underscores.
The name specified for the attribute can be used in other filter functions.
**Parameters:** - **name** (*string*, default: `CustomAttrName`) — Name of the new custom attribute. - **expr** (*string*, default: `fi`) — Expression used to compute the scalar attribute. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-define-custom-vertex-point-attribute)= ## Define Custom Vertex Point Attribute **Categories:** `Attribute/Custom` **Plugin:** meshlab2.filter.expression Defines and fills a custom per-vertex point attribute. ```{py:function} ms.define_custom_vertex_point_attribute(**params) :module: _meshlab Add a new Per-Vertex custom point attribute to current mesh and fill it with the defined functions.
Attribute names must contain only letters, numbers and underscores.
The name specified for the attribute can be used in other filter functions.
**Parameters:** - **name** (*string*, default: `CustomAttrName`) — Name of the new custom attribute. - **x_expr** (*string*, default: `x`) — Expression for X component. - **y_expr** (*string*, default: `y`) — Expression for Y component. - **z_expr** (*string*, default: `z`) — Expression for Z component. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-define-custom-vertex-scalar-attribute)= ## Define Custom Vertex Scalar Attribute **Categories:** `Attribute/Custom` **Plugin:** meshlab2.filter.expression Defines and fills a custom per-vertex scalar attribute. ```{py:function} ms.define_custom_vertex_scalar_attribute(**params) :module: _meshlab Add a new Per-Vertex custom scalar attribute to current mesh and fill it with the defined function.
Attribute names must contain only letters, numbers and underscores.
The name specified for the attribute can be used in other filter functions.
**Parameters:** - **name** (*string*, default: `CustomAttrName`) — Name of the new custom attribute. - **expr** (*string*, default: `x`) — Expression used to compute the scalar attribute. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-face-normals)= ## Compute Face Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Recompute face normals from geometry. ```{py:function} ms.compute_face_normals(**params) :module: _meshlab Recompute face normals as the normal of the plane of the face.
See How to find surface normal of a triangle This filter has no parameters. ``` --- (filter-compute-face-normals-by-expression)= ## Compute Face Normals by Expression **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.expression Computes new per-face normals from expressions. ```{py:function} ms.compute_face_normals_by_expression(**params) :module: _meshlab Normal function using muparser to generate new Normal for every face
**Parameters:** - **x** (*string*, default: `-fnx`) — Expression for X output. - **y** (*string*, default: `-fny`) — Expression for Y output. - **z** (*string*, default: `-fnz`) — Expression for Z output. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-normals-trueform)= ## Compute Normals (TrueForm) **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.trueform Recompute per-vertex or per-face normals from the geometry. ```{py:function} ms.compute_normals_trueform(**params) :module: _meshlab Recomputes normals from the current geometry, either one per face or one per vertex (area-weighted from the incident faces). Normals are computed in world space and mapped back through the layer matrix, so a layer carrying a non-uniform scale gets correct normals rather than merely rotated ones. Competing implementation: *Compute Vertex Normals* and *Compute Face Normals* do the same with vcglib. This one is parallelised. **Parameters:** - **target** (*enum*, default: `vertex`) — Whether to write per-vertex or per-face normals. ``` --- (filter-compute-point-cloud-normals)= ## Compute Point Cloud Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.meshing Estimate normals for point clouds. ```{py:function} ms.compute_point_cloud_normals(**params) :module: _meshlab Compute the normals of the vertices of a mesh without exploiting the triangle connectivity, useful for dataset with no faces **Parameters:** - **K** (*int*, default: `10`) — Number of neighbors used to estimate normals. - **smoothIter** (*int*, default: `0`) — Number of smoothing iterations. - **flipFlag** (*bool*, default: `False`) — Use viewpoint to orient normals consistently. - **viewPos** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Viewpoint position for normal orientation. ``` --- (filter-compute-polygon-face-normals)= ## Compute Polygon Face Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Recompute polygon-shading normals for faux-edge polygon meshes. ```{py:function} ms.compute_polygon_face_normals(**params) :module: _meshlab Recompute face normals as the average of the normals of the triangles that builds a polygon. Useful for showing uniformly shaded quad or polygonal meshes represented using faux edges. This filter has no parameters. ``` --- (filter-compute-vertex-normals)= ## Compute Vertex Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Recompute vertex normals using one of several weighting schemes. ```{py:function} ms.compute_vertex_normals(**params) :module: _meshlab Recompute vertex normals according to four different schemes:
1) Simple (no weights) average of normals of the incident faces
2) Area weighted average of normals of the incident faces
3) Angle weighted sum of normals of the incident faces according to the article [1]. Probably this is the best all-purpose choice. It could slightly bias the result for degenerate, fat triangles.
4) Weighted sum of normals of the incident faces, as defined by article [2]. The weight for each wedge is the cross product of the two edges over the product of the square of the two edge lengths.According to the original article it is perfect only for spherical surface, but it should perform well also in practice.
[1]: Computing Vertex Normals from Polygonal Facet by G Thurmer and CA Wuthrich, JGT volume3, num 1. 1998
doi:10.1080/10867651.1998.10487487
[2]: Weights for Computing Vertex Normals from Facet Normals by Nelson Max, JGT vol4, num 2. 1999
doi:10.1080/10867651.1999.10487501 **Parameters:** - **weightMode** (*enum*, default: `simple_average`) — Choose how incident face normals contribute to each vertex normal. ``` --- (filter-compute-vertex-normals-by-expression)= ## Compute Vertex Normals by Expression **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.expression Computes new per-vertex normals from expressions. ```{py:function} ms.compute_vertex_normals_by_expression(**params) :module: _meshlab Normal function using muparser to generate new Normal for every vertex
**Parameters:** - **x** (*string*, default: `-nx`) — Expression for X output. - **y** (*string*, default: `-ny`) — Expression for Y output. - **z** (*string*, default: `-nz`) — Expression for Z output. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-normalize-face-normals)= ## Normalize Face Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Normalize face normals to unit length. ```{py:function} ms.normalize_face_normals(**params) :module: _meshlab Normalize Face Normal Lengths to unit vectors. This filter has no parameters. ``` --- (filter-normalize-vertex-normals)= ## Normalize Vertex Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Normalize vertex normals to unit length. ```{py:function} ms.normalize_vertex_normals(**params) :module: _meshlab Normalize Vertex Normal Lengths to unit vectors. This filter has no parameters. ``` --- (filter-orient-face-normals-by-ray-casting)= ## Orient Face Normals by Ray Casting **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.embree Reorients wrongly oriented faces using Embree ray casting. ```{py:function} ms.orient_face_normals_by_ray_casting(**params) :module: _meshlab Reorient face normals by geometry.Given the input mesh, this filter uses raytracing to determine if any faces are pointing inward and corrects their orientation. The number of rays is defined by the user; the higher the number, the higher the precision, but at the cost of computation time.This filter requires two values: For further details, see the reference paper: Kenshi Takayama, Alec Jacobson, Ladislav Kavan, Olga Sorkine-Hornung.
A Simple Method for Correcting Facet Orientations in Polygon Meshes Based on Ray Casting. Journal of Computer Graphics Techniques 3(4), 2014. This filter uses the Embree3 library by Intel. **Parameters:** - **rays** (*int*, default: `64`) — Number of rays shot from each face barycenter. - **parity_sampling** (*bool*, default: `False`) — Uses parity sampling instead of visibility sampling. ``` --- (filter-orient-point-cloud-normals)= ## Orient Point Cloud Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.cgal Make an unoriented normal field consistently point outward, using a minimum spanning tree. ```{py:function} ms.orient_point_cloud_normals(**params) :module: _meshlab Orients the vertex normals of a point cloud so that neighbouring normals agree in sign, by propagating orientation along a **minimum spanning tree of the Riemannian graph** (Hoppe et al.). This is the missing step between normal *estimation* and surface *reconstruction*. Filters such as *Compute Point Cloud Normals* fit a local surface and give each normal an arbitrary sign; Poisson-family and kinetic reconstruction all need normals that consistently point outward, and produce unusable results otherwise. **Neighbors** sets how many nearest neighbours are linked in the Riemannian graph. Larger values bridge gaps in sparse data but can propagate orientation across thin structures that should stay separate. A cloud in several disconnected pieces cannot be oriented as a whole: the normals of every component after the first are reported as unoriented and left untouched. Enable **Remove Unoriented Vertices** to delete them instead. Implemented with CGAL's Point Set Processing. Reference: Hugues Hoppe, Tony DeRose, Tom Duchamp, John McDonald, Werner Stuetzle, **Surface Reconstruction from Unorganized Points**, SIGGRAPH 1992. **Parameters:** - **neighbors** (*int*, default: `18`) — Number of nearest neighbours linked in the Riemannian graph. Larger values bridge sparse regions but risk propagating orientation across thin structures. - **removeUnoriented** (*bool*, default: `False`) — Delete the vertices whose normals could not be oriented instead of leaving them untouched. They are usually disconnected components. ``` --- (filter-orient-vertex-normals-by-cameras)= ## Orient Vertex Normals by Cameras **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.camera Reorient vertex normals to point toward the cameras that see them best. ```{py:function} ms.orient_vertex_normals_by_cameras(**params) :module: _meshlab Reorient vertex normals using visible rasters. For each vertex, the best camera is chosen among all visible rasters and the normal is oriented to face toward that camera. If the per-vertex attribute 'correspondences' exists (from Bundler .out imports), the original Bundler camera indices are used instead. This filter has no parameters. ``` --- (filter-sharpen-face-normals-by-unsharp-mask)= ## Sharpen Face Normals by Unsharp Mask **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Enhance face normal variation using an unsharp mask. ```{py:function} ms.sharpen_face_normals_by_unsharp_mask(**params) :module: _meshlab Sharpens the **per-face normals**, so that shading brings out variations in orientation that a flat rendering hides. The geometry is untouched -- only the normals change -- which makes it a rendering aid rather than a modelling operation. Unsharp masking exaggerates local variation by adding back the difference between the signal and a smoothed copy of it: $$s' = s + \lambda\,(s - \mathrm{smooth}(s)).$$ **Weight** is $\lambda$; larger values sharpen harder and amplify noise along with the features. **Smoothing steps** sets how blurred the subtracted copy is, which fixes the scale of the detail being enhanced. **References:** - Paolo Cignoni, Roberto Scopigno, Marco Tarini. **A simple normal enhancement technique for interactive non-photorealistic renderings**. *Computers & Graphics* (2005). [DOI](https://doi.org/10.1016/j.cag.2004.11.012) [Web](https://www.sciencedirect.com/science/article/pii/S0097849304001980) **Parameters:** - **recalc** (*bool*, default: `False`) — Recompute face normals from geometry before applying the unsharp mask. - **weight** (*double*, default: `0.3`) — Unsharp weight applied to the high-frequency component. - **weightOrig** (*double*, default: `1.0`) — Weight of the original normal signal. - **iterations** (*int*, default: `5`) — Number of Laplacian smoothing iterations used to build the low-pass component. ``` --- (filter-smooth-face-normals)= ## Smooth Face Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.unsharp Laplacian smoothing of face normals. ```{py:function} ms.smooth_face_normals(**params) :module: _meshlab Laplacian smooth of the face normals, without touching the position of the vertices. This filter has no parameters. ``` --- (filter-smooth-point-cloud-normals)= ## Smooth Point Cloud Normals **Categories:** `Attribute/Normal` **Plugin:** meshlab2.filter.meshing Smooth point-cloud normals. ```{py:function} ms.smooth_point_cloud_normals(**params) :module: _meshlab Smooth the normals of the vertices of a mesh without exploiting the triangle connectivity, useful for dataset with no faces **Parameters:** - **K** (*int*, default: `10`) — Number of neighbors used to smooth normals. - **useDist** (*bool*, default: `False`) — Weight neighbor normals according to distance. ``` --- (filter-clamp-vertex-scalar)= ## Clamp Vertex Scalar **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Clamp vertex quality to a chosen range or percentile crop. ```{py:function} ms.clamp_vertex_scalar(**params) :module: _meshlab Clamp vertex quality values to a given range according to specific values or to percentiles **Parameters:** - **minVal** (*double*, default: `@qualityVMin`) — Lower clamp bound. - **maxVal** (*double*, default: `@qualityVMax`) — Upper clamp bound. - **perc** (*double*, default: `0.0`) — If not zero this value is used for percentile cropping of the quality values. - **zeroSym** (*bool*, default: `False`) — If true the min/max range is enlarged to be symmetric around zero. ``` --- (filter-clamp-vertex-scalar-gradient)= ## Clamp Vertex Scalar Gradient **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Limit the spatial gradient of vertex quality. ```{py:function} ms.clamp_vertex_scalar_gradient(**params) :module: _meshlab Saturate vertex quality, so that for each vertex the gradient of the quality is lower than the given threshold value (in absolute value) The saturation is done in a conservative way (quality is always decreased and never increased) **Parameters:** - **gradientThr** (*double*, default: `1.0`) — The maximum value admitted for the quality gradient (in absolute value). - **updateColor** (*bool*, default: `False`) — Also write a per-vertex color ramp after saturating quality. Disabled by default because MeshLab automatically switches to vertex-quality visualization. ``` --- (filter-compute-edge-scalar-by-expression)= ## Compute Edge Scalar by Expression **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.expression Computes a per-edge scalar from an expression. ```{py:function} ms.compute_edge_scalar_by_expression(**params) :module: _meshlab Scalar function using muparser lib to write one value per edge of a **polyline layer**. Feed the result to *Colorize Edges by Scalar*, or tick *Map into Color* here to do both in one step. Edge scalars survive a PLY round trip as a `quality` property on the edge element; tick *Edge Scalar* in the save dialog to keep them. Endpoint values use the same names as the first two corners of a face: `x0,y0,z0`/`x1,y1,z1`, `nx0`..`nz1`, `r0,g0,b0,a0`/`r1`..`a1`, `q0,q1`, `vi0,vi1`, `vsel0,vsel1`. The edge itself gives `er,eg,eb,ea` (current color), `eq` (scalar), `ei` (index) and `esel`, plus the derived `elen` (length), `emx,emy,emz` (midpoint) and `edx,edy,edz` (unit direction; zero for a degenerate edge). Bounding-box values `xmin`..`bbdiag` are available as everywhere else. **Parameters:** - **q** (*string*, default: `elen`) — Expression evaluated per edge; its value becomes the edge scalar. - **normalize** (*bool*, default: `False`) — Rescale the computed values into [0, 1] once every edge has been evaluated. - **map** (*bool*, default: `False`) — Also map the resulting scalar into per-edge color, using the full value range. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-exact-geodesic-distance-from-selection-libigl)= ## Compute Exact Geodesic Distance from Selection (libigl) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Compute exact surface distance from selected vertices with libigl. ```{py:function} ms.compute_exact_geodesic_distance_from_selection_libigl(**params) :module: _meshlab Computes the exact polyhedral geodesic distance from the nearest selected, face-referenced vertex to every face-referenced vertex and stores it in **vertex scalar**. Distances follow the piecewise-linear triangle surface, not only mesh edges. Faux edges therefore remain ordinary edges of the stored surface triangulation. This implementation is substantially more expensive than graph or heat-method approximations and is intended when exact distances are required. At least one face-referenced vertex must be selected. No colors are baked into the mesh; MeshLab switches to vertex-scalar visualization after completion. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Joseph S. B. Mitchell, David M. Mount, Christos H. Papadimitriou. **The Discrete Geodesic Problem**. *SIAM Journal on Computing* (1987). [DOI](https://doi.org/10.1137/0216045) This filter has no parameters. ``` --- (filter-compute-face-ambient-occlusion)= ## Compute Face Ambient Occlusion **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.embree Computes cosine-weighted ambient visibility on a surface mesh. ```{py:function} ms.compute_face_ambient_occlusion(**params) :module: _meshlab Computes self-occlusion on a surface mesh by tracing rays with Intel Embree. Rays start at each face barycenter and only directions in the outward hemisphere contribute, weighted by the cosine of their angle to the face normal. The resulting ambient-visibility scalar is stored in face quality and interpolated to vertex quality; a larger value means that more ambient light reaches the surface. The average unoccluded direction is also stored in the per-face custom attribute `BentNormal`. By default directions cover the sphere uniformly. **Directional Bias** replaces a fraction of them with directions inside the cone defined by **Lighting Direction** and **Cone Half-Angle**: `0` is fully uniform ambient illumination and `1` uses only the cone. More rays improve angular sampling at greater cost. The filter does not bake colors; MeshLab switches to face-quality visualization after completion. **Parameters:** - **rays** (*int*, default: `64`) — Number of lighting directions tested at each face barycenter. - **directional_bias** (*double*, default: `0.0`) — Fraction of ray directions sampled inside the lighting cone: 0 is uniform ambient light, 1 uses only the cone. - **cone_direction** (*point3f*, default: `[0.0, 1.0, 0.0]`) — Axis of the directionally biased lighting cone. - **cone_half_angle** (*double*, default: `30.0`) — Half-angle in degrees of the directionally biased lighting cone. ``` --- (filter-compute-face-quality-trueform)= ## Compute Face Quality (TrueForm) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.trueform Measure the shape of every face and store one measure in face scalar. ```{py:function} ms.compute_face_quality_trueform(**params) :module: _meshlab Measures the shape of each face and stores the chosen number in **face scalar**, where the scalar histogram and the quality colour maps can read it. **Measure** selects what is written: | Measure | Meaning | |---|---| | Triangle quality | 1 for an equilateral triangle, approaching 0 for a sliver | | Minimum angle | the smallest corner angle, in degrees | | Maximum angle | the largest corner angle, in degrees | | Aspect ratio | the longest side over the shortest; 1 for equilateral, large for a needle | All four are computed in a single pass, so the parameter only chooses which one is kept. Two things are worth knowing. **Triangle quality is a triangle's measure**: a face that is not a triangle has none and reads **-1**, which is outside the range of every real value and so is easy to select or filter out. The angles and the aspect ratio hold at any arity. And a corner angle is **unsigned and never exceeds 180 degrees**, so a reflex corner of a non-convex face reads its explement rather than the turn you might expect. This is the measure to drive a remesh from: sliver triangles are what break normals, curvature estimation and simplification, and colouring by quality shows immediately whether they are scattered or concentrated in one region. **Parameters:** - **measure** (*enum*, default: `quality`) — Which face measure to store in face scalar. ``` --- (filter-compute-face-scalar-by-expression)= ## Compute Face Scalar by Expression **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.expression Computes per-face scalar quality from an expression. ```{py:function} ms.compute_face_scalar_by_expression(**params) :module: _meshlab Quality function using muparser to generate new Quality for every face
Insert three function each one for quality of the three vertex of a face
**Parameters:** - **q** (*string*, default: `x0+y0+z0`) — Expression for quality output. - **normalize** (*bool*, default: `False`) — Normalize computed quality into range [0, 1]. - **map** (*bool*, default: `False`) — Also write a per-face color ramp. Disabled by default because MeshLab automatically switches to face-quality visualization after the quality is computed. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-face-scalar-from-geometry)= ## Compute Face Scalar from Geometry **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Compute face quality from triangle shape, area, or polygonal planarity. ```{py:function} ms.compute_face_scalar_from_geometry(**params) :module: _meshlab Computes a geometric measure for every face and stores the result in **face quality**. No colors are baked into the mesh; after completion MeshLab switches the view to face-quality visualization. The triangle-shape measures are scale independent and approach zero for degenerate triangles: - **Area / squared maximum side**: $2A/L_{\max}^2$, where $A$ is triangle area and $L_{\max}$ is its longest side. Its range is $[0,\sqrt{3}/2]$; an equilateral triangle reaches $\sqrt{3}/2$. - **Normalized radius ratio**: $2r/R$, where $r$ and $R$ are the inradius and circumradius. Its range is $[0,1]$; an equilateral triangle reaches $1$. - **Mean ratio**: $4\sqrt{3}A/(a^2+b^2+c^2)$. Its range is $[0,1]$; an equilateral triangle reaches $1$. - **Area**: the triangle area in the mesh's squared coordinate units. This measure is not scale independent. The planarity measures apply only to polygonal meshes represented by faux-edge triangle groups. MeshLab fits a support plane to each polygon and assigns the same result to all its component triangles: - **Polygonal planarity (maximum)**: maximum vertex distance from the fitted plane. - **Polygonal planarity (relative)**: mean vertex-to-plane distance divided by the polygon's half-perimeter. **Parameters:** - **metric** (*enum*, default: `area_max_side`) — Choose the geometric measure stored in face quality. ``` --- (filter-compute-face-scalar-from-raster-coverage)= ## Compute Face Scalar from Raster Coverage **Categories:** `Attribute/Scalar`, `Transfer/From Rasters` **Plugin:** meshlab2.filter.img_patch_param Compute a quality value representing the number of images into which each face of the active mesh is visible. ```{py:function} ms.compute_face_scalar_from_raster_coverage(**params) :module: _meshlab Compute a quality value representing the number of images into which each face of the active mesh is visible. For each active raster, a software depth buffer is built and each face is tested for visibility. A face is considered visible if at least one of its three vertices is visible. The quality value counts how many rasters each face is visible in. Optionally normalizes to [0,1]. **Parameters:** - **normalizeQuality** (*bool*, default: `False`) — Rescale quality values to the range [0,1]. - **depthEpsilon** (*double*, default: `0.5`) — Tolerance for depth test when checking vertex visibility. Increase for noisy registrations. ``` --- (filter-compute-generalized-winding-number-libigl)= ## Compute Generalized Winding Number (libigl) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Evaluate another layer's generalized winding-number field at every current-layer vertex. ```{py:function} ms.compute_generalized_winding_number_libigl(**params) :module: _meshlab Evaluates the oriented **Surface Mesh** winding-number field at every vertex of the current mesh or point cloud and stores it in **vertex scalar**. Layer transforms are applied before evaluation. For a consistently oriented closed surface, values are approximately $1$ inside and $0$ outside; reversing its orientation reverses the sign. On open, self-intersecting, or non-manifold triangle soups the field remains continuous and useful, but the value $0.5$ is only a conventional classification threshold. **Fast Approximation** builds libigl's second-order hierarchy and is the practical default for large inputs. **Exact** directly accumulates triangle solid angles and can be prohibitively expensive because its work grows with both surface triangles and query vertices. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Alec Jacobson, Ladislav Kavan, Olga Sorkine-Hornung. **Robust Inside-Outside Segmentation using Generalized Winding Numbers**. *ACM Transactions on Graphics* (2013). [DOI](https://doi.org/10.1145/2461912.2461916) - Gavin Barill, Neil G. Dickson, Ryan Schmidt, David I. W. Levin, Alec Jacobson. **Fast Winding Numbers for Soups and Clouds**. *ACM Transactions on Graphics* (2018). [DOI](https://doi.org/10.1145/3197517.3201337) [Web](https://www.dgp.toronto.edu/projects/fast-winding-numbers/) **Parameters:** - **surface_mesh** (*mesh*, default: `@otherMeshIndex`) — Oriented triangle surface whose winding-number field is evaluated. - **method** (*enum*, default: `fast`) — Use the hierarchical approximation for speed or direct solid-angle accumulation for exact values. ``` --- (filter-compute-geodesic-distance-from-border)= ## Compute Geodesic Distance from Border **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.geodesic Compute geodesic distance from mesh borders into vertex quality. ```{py:function} ms.compute_geodesic_distance_from_border(**params) :module: _meshlab Store in the vertex quality field the geodesic distance from borders. The filter does not bake colors; after it runs MeshLab switches the view to vertex-quality color visualization. This filter has no parameters. ``` --- (filter-compute-geodesic-distance-from-point)= ## Compute Geodesic Distance from Point **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.geodesic Compute geodesic distance from a given point into vertex quality. ```{py:function} ms.compute_geodesic_distance_from_point(**params) :module: _meshlab Store in the vertex quality field the geodesic distance from a given point on the mesh surface. The filter does not bake colors; after it runs MeshLab switches the view to vertex-quality color visualization. **Parameters:** - **startPoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — The point from which geodesic distance is measured. The closest surface vertex is used as seed. - **maxDistance** (*absperc*, default: `@bboxDiag`) — Cut-off distance. Vertices beyond this threshold are assigned distance 0. Set to 0 to compute everywhere. ``` --- (filter-compute-geodesic-distance-from-selection-vcglib)= ## Compute Geodesic Distance from Selection (vcglib) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.geodesic Compute geodesic distance from selected vertices into vertex quality. ```{py:function} ms.compute_geodesic_distance_from_selection_vcglib(**params) :module: _meshlab Store in the vertex quality field the geodesic distance from the selected points on the mesh surface. The filter does not bake colors; after it runs MeshLab switches the view to vertex-quality color visualization. **Parameters:** - **maxDistance** (*absperc*, default: `@bboxDiag`) — Cut-off distance. Vertices beyond this threshold are assigned distance 0. Set to 0 to compute everywhere. ``` --- (filter-compute-harmonic-scalar-field)= ## Compute Harmonic Scalar Field **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.unsharp Compute a harmonic scalar field over the mesh. ```{py:function} ms.compute_harmonic_scalar_field(**params) :module: _meshlab Generates a scalar harmonic field over the mesh. Input scalar values must be assigned to two vertices as Dirichlet boundary conditions. Applying the filter, a discrete Laplace operator generates the harmonic field values for all the mesh vertices, which are stored in the quality per vertex attribute of the mesh.
For more details see:Dynamic Harmonic Fields for Surface Processing by Kai Xua, Hao Zhang, Daniel Cohen-Or, Yueshan Xionga. Computers & Graphics, 2009
doi:10.1016/j.cag.2009.03.022 **Parameters:** - **point1** (*point3f*, default: `[0.0, 0.0, 0.0]`) — A vertex on the mesh representing one harmonic field boundary condition. - **point2** (*point3f*, default: `[1.0, 1.0, 1.0]`) — A vertex on the mesh representing the other harmonic field boundary condition. - **value1** (*double*, default: `0.0`) — Harmonic field value assigned to the first constrained vertex. - **value2** (*double*, default: `1.0`) — Harmonic field value assigned to the second constrained vertex. - **colorize** (*bool*, default: `False`) — Also write a per-vertex color ramp after computing the harmonic field. Disabled by default because MeshLab automatically switches to vertex-quality visualization. ``` --- (filter-compute-heat-geodesic-distance-from-selection-libigl)= ## Compute Heat Geodesic Distance from Selection (libigl) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Approximate surface distance from selected vertices with libigl's heat method. ```{py:function} ms.compute_heat_geodesic_distance_from_selection_libigl(**params) :module: _meshlab Approximates geodesic distance from the nearest selected, face-referenced vertex with the heat method and stores it in **vertex scalar**. The method diffuses heat for a short time, normalizes its gradient, and solves a Poisson equation. It is generally much faster than the exact method for large source-to-all queries. The timestep is $t = m h^2$, where $h$ is average edge length and **Time Step Multiplier** is $m$. Smaller values preserve finer detail but may be less stable. **Intrinsic Delaunay Operators** uses libigl's intrinsic Delaunay cotangent, mass, and gradient operators, reducing sensitivity to poor input triangulations without changing connectivity. At least one face-referenced vertex must be selected. Faux-edge polygon groups are processed through their stored triangle representation. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Keenan Crane, Clarisse Weischedel, Max Wardetzky. **Geodesics in Heat: A New Approach to Computing Distance Based on Heat Flow**. *ACM Transactions on Graphics* (2013). [DOI](https://doi.org/10.1145/2516971.2516977) [Web](https://www.cs.cmu.edu/~kmcrane/Projects/HeatMethod/paperCACM.pdf) **Parameters:** - **time_step_multiplier** (*double*, default: `1.0`) — Multiplier m in t = m h², where h is average edge length. Smaller values are more local but can be less stable. - **use_intrinsic_delaunay** (*bool*, default: `False`) — Build the heat-method operators from libigl's intrinsic Delaunay triangulation. This often improves robustness on poorly shaped triangles. ``` --- (filter-compute-heat-geodesic-distance-from-selection-vcglib)= ## Compute Heat Geodesic Distance from Selection (vcglib) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.geodesic Approximate geodesic distance via the heat method into vertex quality. ```{py:function} ms.compute_heat_geodesic_distance_from_selection_vcglib(**params) :module: _meshlab Store in the vertex quality field the approximated geodesic distance, computed via the heat method (Crane et al.), from the selected points on the mesh surface. The filter does not bake colors; after it runs MeshLab switches the view to vertex-quality color visualization. As this implementation does not use intrinsic triangulation it is very sensitive to triangulation. First run takes longer because factorization has to be built. **Parameters:** - **m** (*double*, default: `1.0`) — Multiplier applied to the squared average edge length to compute the backward-Euler timestep. Larger values give smoother but less accurate results. ``` --- (filter-compute-obscurance)= ## Compute Obscurance **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.embree Computes volumetric obscurance and stores it in quality. ```{py:function} ms.compute_obscurance(**params) :module: _meshlab Compute ambient Obscurance.
Ambient obscurance is a computer graphics technique used to simulate the effect of global ambient light in a 3D scene, making the mesh appear more realistic.
This filter requires two values:The resulting values for the obscurance are saved into face quality. The filter does not bake colors; after it runs MeshLab switches the view to face-quality color visualization.
For further details see the reference paper: Iones Krupkin Sbert Zhukov Fast, Realistic Lighting for Video Games IEEECG&A 2003
This filter uses Embree3 library by INTEL. **Parameters:** - **rays** (*int*, default: `64`) — Number of rays shot from each face barycenter. - **tau** (*double*, default: `0.1`) — Spatial decay factor used in obscurance accumulation. ``` --- (filter-compute-point-cloud-ambient-occlusion)= ## Compute Point Cloud Ambient Occlusion **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.embree Computes point-cloud visibility against a surface occluder. ```{py:function} ms.compute_point_cloud_ambient_occlusion(**params) :module: _meshlab Traces rays from every point of the current point-cloud layer against a separate **Occluder Mesh**, using Intel Embree. The result is stored in vertex quality; a larger value means that the point is more exposed. Layer transforms are respected, and the average direction of escaping rays is stored in the per-vertex custom attribute `BentNormal`. **Normal Source** selects the meaning of the measurement:By default directions cover the sphere uniformly. **Directional Bias** replaces a fraction of them with directions inside the cone defined by **Lighting Direction** and **Cone Half-Angle**: `0` is fully uniform and `1` uses only the cone. More rays improve angular sampling at greater cost. The filter does not bake colors; MeshLab switches to vertex-quality visualization after completion. **Parameters:** - **occluder_mesh** (*mesh*, default: `@otherMeshIndex`) — Surface mesh tested by rays from the current point cloud. - **normal_source** (*enum*, default: `closest_occluder_surface`) — Selects an existing point normal, the closest occluder triangle normal, or orientation-independent spherical visibility. - **rays** (*int*, default: `64`) — Number of visibility directions tested at each point. - **directional_bias** (*double*, default: `0.0`) — Fraction of ray directions sampled inside the lighting cone: 0 is uniform ambient light, 1 uses only the cone. - **cone_direction** (*point3f*, default: `[0.0, 1.0, 0.0]`) — Axis of the directionally biased lighting cone. - **cone_half_angle** (*double*, default: `30.0`) — Half-angle in degrees of the directionally biased lighting cone. ``` --- (filter-compute-shape-diameter-function)= ## Compute Shape Diameter Function **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.embree Computes SDF and stores it in quality. ```{py:function} ms.compute_shape_diameter_function(**params) :module: _meshlab Compute Shape-Diameter Function
The SDF defines the distance between a point in 3D space and the nearest point on the object's surface.This filter can be used to find out the thickness of the mesh
Given a face, a set of rays are shot inward, and an average of the distance to hit a face is saved in the face quality. The filter does not bake colors; after it runs MeshLab switches the view to face-quality color visualization.This filter requires two values:
For further details see the reference paper: Shapira Shamir Cohen-Or, Consistent Mesh Partitioning and Skeletonisation using the shaper diameter function, Visual Comput. J. (2008)
This filter uses Embree3 library by INTEL. **Parameters:** - **rays** (*int*, default: `64`) — Number of rays shot from each face barycenter. - **cone_amplitude** (*double*, default: `90.0`) — Cone opening angle in degrees used for SDF ray directions. ``` --- (filter-compute-signed-distance-to-mesh-trueform)= ## Compute Signed Distance to Mesh (TrueForm) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.trueform Store each vertex's signed distance to another layer's surface in vertex scalar. ```{py:function} ms.compute_signed_distance_to_mesh_trueform(**params) :module: _meshlab Writes, for every vertex, its distance to the nearest point of the reference layer's surface — **negative inside, positive outside**. The sign is what makes this a field rather than a proximity readout. It can be contoured with *Create Polyline from Scalar Isocontour (TrueForm)* (the zero contour is the intersection curve), thresholded to select a shell of given thickness, or used to measure how far a simplified or reconstructed model departs from its original and in which direction. Both layers are taken in world space. The reference must be a **closed surface** for the sign to mean anything; on an open sheet the inside is undefined and the sign follows the surface orientation instead. Enable **Unsigned** for absolute distance, which is what you want when only proximity matters. Compare with *Measure Hausdorff Distance*, which reports a single worst-case number, and *Measure Chamfer Distance (TrueForm)*, which reports a mean. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer whose vertices are measured. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The closed surface distances are measured to. - **unsigned** (*bool*, default: `False`) — Store absolute distance, discarding inside/outside. ``` --- (filter-compute-uv-distortion)= ## Compute UV Distortion **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Measure angular, area, edge-length, or directional stretch distortion in a UV mapping. ```{py:function} ms.compute_uv_distortion(**params) :module: _meshlab Compares every triangle in 3D with its mapping in UV space and stores the resulting dimensionless distortion in **face quality**. No colors are baked into the mesh; after completion MeshLab switches the view to face-quality visualization. Both per-wedge and per-vertex texture coordinates are supported, and texture image files are not required. - **Angle distortion**: the mean relative angular error over the three corners, $$D_{\mathrm{angle}}=\frac{1}{3}\sum_{i=1}^{3}\frac{|\theta_i^{UV}-\theta_i^{3D}|}{\theta_i^{3D}}.$$ A value of $0$ means that the mapping preserves all triangle angles; larger values indicate increasing conformal distortion. Uniform scaling and rigid transformations of the UV triangle do not affect this measure. - **Area distortion**: first computes one global area scale $s_A=\sum A_{3D}/\sum A_{UV}$, then evaluates each face as $$D_{\mathrm{area}}=\frac{|s_A A_{UV}-A_{3D}|}{A_{3D}}.$$ A value of $0$ means that the face has the globally expected texel density; larger values identify local expansion or compression relative to the mesh-wide average. - **Edge-length distortion**: uses the global length scale $s_L=\sum l_{3D}/\sum l_{UV}$ and averages the relative error of the three edges, $$D_{\mathrm{edge}}=\frac{1}{3}\sum_{i=1}^{3}\frac{|s_L l_i^{UV}-l_i^{3D}|}{l_i^{3D}}.$$ The ideal value is $0$. Unlike angle distortion, this measure responds to local changes in scale as well as triangle shape. - **L2 stretch**: measures the root-mean-square directional stretch of the locally linear map from texture space to the surface, $$L_2=\sqrt{\frac{a+c}{2}},\qquad a=\frac{\|S_s\|^2}{s_A},\quad c=\frac{\|S_t\|^2}{s_A}.$$ The ideal value is $1$. It summarizes average sampling distortion within the triangle. - **L-infinity stretch**: measures the largest directional stretch, $$L_\infty=\sqrt{\frac{a+c+\sqrt{(a-c)^2+4b^2}}{2}},\qquad b=\frac{S_s\cdot S_t}{s_A}.$$ The ideal value is $1$. It highlights the worst local undersampling direction and is therefore more conservative than L2 stretch. The global normalization makes every metric invariant to uniform resizing of the complete UV map. UV area is oriented, matching VCGLib's distortion implementation. A zero total oriented UV area makes area normalization undefined; stretch additionally requires that total to be positive. For L2 and L-infinity stretch, folded or degenerate individual UV triangles produce non-finite quality values, which are excluded from the displayed finite quality range. **Parameters:** - **metric** (*enum*, default: `angle`) — Choose the UV distortion measure stored in face quality. ``` --- (filter-compute-vertex-scalar-by-expression)= ## Compute Vertex Scalar by Expression **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.expression Computes per-vertex scalar quality from an expression. ```{py:function} ms.compute_vertex_scalar_by_expression(**params) :module: _meshlab Quality function using muparser to generate new Quality for every vertex
**Parameters:** - **q** (*string*, default: `vi`) — Expression for quality output. - **normalize** (*bool*, default: `False`) — Normalize computed quality into range [0, 1]. - **map** (*bool*, default: `False`) — Also write a per-vertex color ramp. Disabled by default because MeshLab automatically switches to vertex-quality visualization after the quality is computed. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-compute-vertex-scalar-from-camera)= ## Compute Vertex Scalar from Camera **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.camera Compute vertex quality using the camera definition, according to viewing angle or distance. ```{py:function} ms.compute_vertex_scalar_from_camera(**params) :module: _meshlab Compute vertex quality using the camera definition, according to viewing angle or distance. Uses the current raster camera if available. **Parameters:** - **depth** (*bool*, default: `True`) — Use depth from camera as a factor (quality proportional to distance). - **facing** (*bool*, default: `False`) — Use cosine of viewing angle as a factor. - **clip** (*bool*, default: `False`) — Clip quality values to zero for vertices outside the camera viewport. - **normalize** (*bool*, default: `False`) — If checked normalize all quality values in range [0..1]. - **map** (*bool*, default: `False`) — If checked map quality generated values into per-vertex color. ``` --- (filter-compute-vertex-scalar-from-raster-coverage)= ## Compute Vertex Scalar from Raster Coverage **Categories:** `Attribute/Scalar`, `Transfer/From Rasters` **Plugin:** meshlab2.filter.img_patch_param Compute a quality value representing the number of images into which each vertex of the active mesh is visible. ```{py:function} ms.compute_vertex_scalar_from_raster_coverage(**params) :module: _meshlab Compute a quality value representing the number of images into which each vertex of the active mesh is visible. For each active raster, a software depth buffer is built and each vertex is tested for visibility (inside the image bounds, front-facing, and passing the depth test). The quality value counts how many rasters each vertex is visible in. Optionally normalizes to [0,1]. **Parameters:** - **normalizeQuality** (*bool*, default: `False`) — Rescale quality values to the range [0,1]. - **depthEpsilon** (*double*, default: `0.5`) — Tolerance for depth test when checking vertex visibility. Increase for noisy registrations. ``` --- (filter-sharpen-vertex-scalar-by-unsharp-mask)= ## Sharpen Vertex Scalar by Unsharp Mask **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.unsharp Enhance per-vertex quality variations with an unsharp mask. ```{py:function} ms.sharpen_vertex_scalar_by_unsharp_mask(**params) :module: _meshlab Sharpens the **per-vertex scalar field**, so that gentle gradients in the values become steeper and easier to read once the field is mapped to color. Unsharp masking exaggerates local variation by adding back the difference between the signal and a smoothed copy of it: $$s' = s + \lambda\,(s - \mathrm{smooth}(s)).$$ **Weight** is $\lambda$; larger values sharpen harder and amplify noise along with the features. **Smoothing steps** sets how blurred the subtracted copy is, which fixes the scale of the detail being enhanced. **References:** - Paolo Cignoni, Roberto Scopigno, Marco Tarini. **A simple normal enhancement technique for interactive non-photorealistic renderings**. *Computers & Graphics* (2005). [DOI](https://doi.org/10.1016/j.cag.2004.11.012) [Web](https://www.sciencedirect.com/science/article/pii/S0097849304001980) **Parameters:** - **weight** (*double*, default: `0.3`) — Unsharp weight applied to the high-frequency quality component. - **weightOrig** (*double*, default: `1.0`) — Weight of the original quality signal. - **iterations** (*int*, default: `5`) — Number of Laplacian smoothing iterations used to build the low-pass quality signal. ``` --- (filter-smooth-vertex-scalar)= ## Smooth Vertex Scalar **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.unsharp Laplacian smoothing of vertex quality values. ```{py:function} ms.smooth_vertex_scalar(**params) :module: _meshlab Laplacian smooth of the quality per vertex values. This filter has no parameters. ``` --- (filter-smooth-vertex-scalar-by-hessian-energy-libigl)= ## Smooth Vertex Scalar by Hessian Energy (libigl) **Categories:** `Attribute/Scalar` **Plugin:** meshlab2.filter.igl Smooth vertex scalar values with Hessian energy and natural boundary conditions. ```{py:function} ms.smooth_vertex_scalar_by_hessian_energy_libigl(**params) :module: _meshlab Smooths the current **vertex scalar** field by minimizing $$\alpha\,u^T H u + (1-\alpha)(u-f)^T M(u-f),$$ where $f$ is the input scalar field, $H$ is libigl's mixed finite-element Hessian-energy matrix, and $M$ is the Voronoi mass matrix. Unlike a squared-Laplacian construction, Hessian energy supplies natural high-order boundary conditions, so the geometric shape of an open boundary does not impose the usual low-order boundary bias. **Smoothing Weight** is $\alpha$: zero preserves the input and values near one favor an affine field. Its effect depends on mesh scale because the two energy terms have different physical dimensions. The filter changes scalar values only, not geometry or colors. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Oded Stein, Eitan Grinspun, Max Wardetzky, Alec Jacobson. **Natural Boundary Conditions for Smoothing in Geometry Processing**. *ACM Transactions on Graphics* (2018). [DOI](https://doi.org/10.1145/3186564) [Web](https://arxiv.org/abs/1707.04348) **Parameters:** - **smoothing_weight** (*double*, default: `0.01`) — Tradeoff alpha between Hessian smoothness and fidelity to the input scalar values. ``` --- (filter-create-annulus)= ## Create Annulus **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a flat annulus (holed disk). ```{py:function} ms.create_annulus(**params) :module: _meshlab Create an Annulus e.g. a flat region bounded by two concentric circles, or a holed disk. **Parameters:** - **inner_radius** (*double*, default: `0.5`) — Inner radius of the annulus. - **outer_radius** (*double*, default: `1.0`) — Outer radius of the annulus. - **sides** (*int*, default: `32`) — Number of sides of the polygonal approximation. ``` --- (filter-create-circle)= ## Create Circle **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a circle, or any regular polygon, as a closed polyline. ```{py:function} ms.create_circle(**params) :module: _meshlab Creates a new layer holding a **circle** as a closed **polyline**: a ring of vertices joined by edges, with no faces. Polylines are the edge-based curves MeshLab uses for sections, contours and outlines — this makes one from nothing, to measure against, to sweep along, or to project onto a surface. **Sides** is how many segments approximate the curve, which also makes this a general regular-polygon generator: 3 draws a triangle, 5 a pentagon, 6 a hexagon, and a couple of hundred a circle no viewport will show as faceted. **Normal** turns the circle to face any direction. It is always centred on the origin and lies in the plane at right angles to that direction. For a *filled* flat ring with faces rather than a curve, use **Create Annulus**. **Parameters:** - **radius** (*double*, default: `1.0`) — Distance from the centre to each vertex. - **sides** (*int*, default: `64`) — Number of segments the circle is approximated by. Small values give a regular polygon: 3 a triangle, 6 a hexagon. - **axis** (*point3f*, default: `[0.0, 0.0, 1.0]`) — Direction the polyline faces. It lies in the plane through the origin at right angles to this. Need not be normalized. ``` --- (filter-create-cone)= ## Create Cone **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a Cone or truncated cone. ```{py:function} ms.create_cone(**params) :module: _meshlab Create a Cone **Parameters:** - **r0** (*double*, default: `1.0`) — Radius of the bottom circle. - **r1** (*double*, default: `2.0`) — Radius of the top circle. - **h** (*double*, default: `3.0`) — Height of the cone. - **subdiv** (*int*, default: `36`) — Number of sides of the polygonal approximation. ``` --- (filter-create-cylinder)= ## Create Cylinder **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a cylinder of the given radius and height around an arbitrary axis. ```{py:function} ms.create_cylinder(**params) :module: _meshlab Creates a cylinder centred on the origin, like **Create Cone** with equal radii but with a choice of axis and a tessellation that can be refined along its length. *Sides* sets the angular tessellation; *Stacks* cuts the side wall into rings along the axis. One stack is enough for a cylinder that will only be rendered — add more when something downstream needs to deform or resample the side wall, since a single quad strip has no interior vertices to move. *Axis* need not be normalized; only its direction is used, and the cylinder is always centred on the origin, spanning half the height either side. **Parameters:** - **radius** (*double*, default: `1.0`) — Radius of the cylinder. - **height** (*double*, default: `3.0`) — Length of the cylinder along its axis. - **sides** (*int*, default: `36`) — Number of sides of the polygonal approximation. - **stacks** (*int*, default: `1`) — Number of segments along the axis. One leaves the side wall as a single band of quads; raise it when the mesh will be deformed or resampled. - **capped** (*bool*, default: `True`) — Add a flat cap at each end. Without them the result is an open tube. - **axis** (*point3f*, default: `[0.0, 1.0, 0.0]`) — Direction of the cylinder's axis. Need not be normalized, and its sign makes no difference: the cylinder is centred on the origin. ``` --- (filter-create-dodecahedron)= ## Create Dodecahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a Dodecahedron. ```{py:function} ms.create_dodecahedron(**params) :module: _meshlab Create a Dodecahedron This filter has no parameters. ``` --- (filter-create-grid)= ## Create Grid **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.expression Creates a regular grid of quads: a plane, subdivided, in any orientation. ```{py:function} ms.create_grid(**params) :module: _meshlab Creates a new layer holding a regular grid of quads: a **plane** cut into `Vertices U` × `Vertices V` samples, which is the usual starting point for a ground plane, a cutting plane, a backdrop, or a height field to displace. The two in-plane directions are called **U** and **V** rather than X and Y, because the grid no longer has to lie in the XY plane: **Normal** turns it to face any direction, and U and V are then whatever two perpendicular directions come with it. **Fit to Layer** sizes and places the grid from an existing layer instead of from the size boxes: the grid is made as wide as that layer's bounding-box diagonal, square, and centred on the box centre, so it always cuts clean through the object whichever way it is turned. The layer's own transformation is taken into account. Leave it on *None* to use the sizes below. Without a fit layer, **Center on Origin** decides whether the grid straddles the origin or starts there and runs out along +U and +V. **Parameters:** - **numVertU** (*int*, default: `10`) — Number of vertices along the first in-plane direction. - **numVertV** (*int*, default: `10`) — Number of vertices along the second in-plane direction. - **sizeU** (*double*, default: `0.3`) — Total extent of the grid along U. Ignored when a fit layer is chosen. - **sizeV** (*double*, default: `0.3`) — Total extent of the grid along V. Ignored when a fit layer is chosen. - **axis** (*point3f*, default: `[0.0, 0.0, 1.0]`) — Direction the grid faces. U and V are two perpendicular directions in the plane at right angles to it. Need not be normalized. - **fitLayer** (*mesh*, default: `-1`) — Size the grid as that layer's bounding-box diagonal and centre it on the box centre, taking the layer's transformation into account. None uses the sizes above. - **center** (*bool*, default: `False`) — Straddle the origin instead of starting there and running out along +U and +V. Ignored when a fit layer is chosen, which centres the grid on that layer instead. ``` --- (filter-create-handle-and-tunnel-loops)= ## Create Handle and Tunnel Loops **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Create two polyline layers with short handle loops and tunnel loops of a surface of nonzero genus. ```{py:function} ms.create_handle_and_tunnel_loops(**params) :module: _meshlab A closed surface of genus $g$ bounds an inside and an outside. A **handle loop** bounds a disk inside but not outside: it circles a handle, like a meridian going around the tube of a torus. A **tunnel loop** bounds a disk outside but not inside: it circles a tunnel, like the inner equator going around the hole of a torus. The filter finds $g$ short handle loops and $g$ short tunnel loops, closed paths along mesh edges, and puts each family in a new polyline layer. They are what to cut to remove a spurious handle, or to fill to close a spurious tunnel, as when repairing the topology of a scanned or reconstructed surface. Each edge carries the number of its loop as its scalar, so *Colorize Edges by Scalar* tells the loops apart; the log reports the genus and the length of every loop. The loops come from the Reeb graph of a random height function, classified as handles or tunnels and then shortened. Shortening is a heuristic: the loops are short, not the shortest. It dominates the running time, which grows with the size and genus of the mesh, from seconds to minutes; zero tightening rounds keeps the loops as found, which is fast but gives long loops, and may split one basis element into several loops. The surface must be connected, orientable and edge-manifold. Small holes are allowed and are closed internally; large ones make the classification depend on how they would be closed. A surface of genus zero has no such loops, and the filter says so instead of creating empty layers. **References:** - Tamal K. Dey, Fengtao Fan, Yusu Wang. **An efficient computation of handle and tunnel loops via Reeb graphs**. *ACM Transactions on Graphics* (2013). [DOI](https://doi.org/10.1145/2461912.2462017) - Valerio Pascucci, Giorgio Scorzelli, Peer-Timo Bremer, Ajith Mascarenhas. **Robust on-line computation of Reeb graphs: simplicity and speed**. *ACM Transactions on Graphics* (2007). [DOI](https://doi.org/10.1145/1276377.1276449) **Parameters:** - **tighteningRounds** (*int*, default: `100`) — Maximum number of rounds spent shortening the loops. Zero keeps the loops found on the Reeb graph, which is fast but gives long loops. - **patience** (*int*, default: `10`) — Stop shortening after this many consecutive rounds without a shorter set of loops. - **randomSeed** (*int*, default: `0`) — Seeds the random height direction and the projection directions. Zero draws a fresh seed on every run, so repeated applications may find different loops; any other value makes the run exactly reproducible. ``` --- (filter-create-hexahedron)= ## Create Hexahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Create a box: a cube, or a hexahedron with a side length you choose. ```{py:function} ms.create_hexahedron(**params) :module: _meshlab Creates a new layer holding an axis-aligned **hexahedron** centred on the origin — a **box**, and with equal sides a **cube**. **Side Length** sets the length of every edge, so the result is always a cube; scale it afterwards for a box with unequal sides. The six faces are quads, kept as pairs of triangles with the diagonal marked faux, so the box displays as six faces rather than twelve. **Parameters:** - **size** (*double*, default: `1.0`) — Length of each side of the box. ``` --- (filter-create-icosahedron)= ## Create Icosahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates an Icosahedron. ```{py:function} ms.create_icosahedron(**params) :module: _meshlab Create an Icosahedron This filter has no parameters. ``` --- (filter-create-isosurface-from-expression)= ## Create Isosurface from Expression **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.expression Extracts an isosurface from an implicit scalar field. ```{py:function} ms.create_isosurface_from_expression(**params) :module: _meshlab Generate a new mesh that corresponds to the 0 valued isosurface defined by the scalar field generated by the given expression **Parameters:** - **voxelSize** (*double*, default: `0.05`) — Sampling step used for volumetric evaluation. - **minX** (*double*, default: `-1.0`) — Sampling range parameter. - **minY** (*double*, default: `-1.0`) — Sampling range parameter. - **minZ** (*double*, default: `-1.0`) — Sampling range parameter. - **maxX** (*double*, default: `1.0`) — Sampling range parameter. - **maxY** (*double*, default: `1.0`) — Sampling range parameter. - **maxZ** (*double*, default: `1.0`) — Sampling range parameter. - **expr** (*string*, default: `x*x+y*y+z*z-0.5`) — Scalar field expression f(x,y,z). The 0-isovalue is extracted. - **closeBoundary** (*bool*, default: `False`) — If enabled, where the surface runs into the boundary of the sampling range it is closed there with flat caps lying exactly on the faces of the range, so the result is a closed solid: the part of the region where the function is negative that lies inside the range. The caps follow the sampling grid, one or two triangles per boundary cell. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-create-isosurface-from-perlin-noise)= ## Create Isosurface from Perlin Noise **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.basic Creates an isosurface perturbed by 3D Perlin noise. ```{py:function} ms.create_isosurface_from_perlin_noise(**params) :module: _meshlab Generates a scalar field over a cubic grid and extracts an isosurface using marching cubes. **Parameters:** - **resolution** (*int*, default: `64`) — Resolution of the side of the cubic grid used for volume creation. - **closeBoundary** (*bool*, default: `False`) — If enabled, where the surface runs into the boundary of the grid it is closed there with flat caps, so the result is a closed solid instead of a tube left open at its ends and wherever the noise pushes it out of the grid. The caps follow the grid, one or two triangles per boundary cell. ``` --- (filter-create-mesh-bounding-box)= ## Create Mesh Bounding Box **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.cgal Turn the current layer's bounding box into a mesh of its own. ```{py:function} ms.create_mesh_bounding_box(**params) :module: _meshlab Creates a new layer holding the bounding box of the current layer as an actual eight-vertex, twelve-triangle box, rather than as an annotation drawn over the viewport. Useful whenever the box has to be *operated on* — measured, exported, intersected, used as a crop volume or as a stand-in for the object in a larger scene. **Alignment** chooses between the three boxes worth having: - **Axis aligned** is the box the viewport draws: the smallest box whose sides are parallel to the layer's own axes. It is exact, instant, and depends on how the object happens to be oriented. - **Oriented** is the smallest box in *any* orientation, found by searching the space of rotations. For an object lying at an angle it is dramatically tighter than the axis-aligned one; for an object already aligned to its axes the two coincide. The search is an approximation, not a proven optimum, and it costs time on large inputs — it runs on the convex hull, so cost follows the hull rather than the vertex count. - **Oriented, turning the layer** finds the same box and then turns the object instead of the box: the rotation is written into the layer's transformation, so the layer comes to rest on the axes and the box is created axis-aligned alongside it. The vertices are not touched — only the matrix — which is how you straighten an object that was digitised or exported at an arbitrary angle. The new layer inherits the source layer's matrix, so the box sits on the object wherever the object has been moved to. To box the whole scene rather than one layer, use **Create Scene Bounding Box**. The oriented box is computed with CGAL's Optimal Bounding Box package. Reference: Konstantinos Katrioplas, Mael Rouxel-Labbé, **Optimal Bounding Box**, CGAL User and Reference Manual, CGAL Editorial Board. **Parameters:** - **alignment** (*enum*, default: `axis_aligned`) — Axis aligned is the box the viewport draws, parallel to the layer's own axes. Oriented searches for the smallest box in any orientation, which is much tighter for an object lying at an angle but costs time to find. ``` --- (filter-create-octahedron)= ## Create Octahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates an Octahedron. ```{py:function} ms.create_octahedron(**params) :module: _meshlab Create an Octahedron This filter has no parameters. ``` --- (filter-create-plane-from-selection)= ## Create Plane from Selection **Categories:** `Creation/Primitives`, `Measurement/Geometric` **Plugin:** meshlab2.filter.create Creates a quad on the plane fitting the current selection. ```{py:function} ms.create_plane_from_selection(**params) :module: _meshlab Fits a plane to the selected vertices (or vertices of selected faces) of the current mesh and creates a new planar quad mesh aligned to that plane. **Parameters:** - **extent** (*double*, default: `1.0`) — Size of the plane relative to the selection bounding box on the plane. 1.0 = same size, 1.1 = 10% larger. - **subdiv** (*int*, default: `3`) — Number of subdivisions along each side of the plane. ``` --- (filter-create-points-on-sphere)= ## Create Points on a Sphere **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a point cloud distributed on a unit sphere. ```{py:function} ms.create_points_on_sphere(**params) :module: _meshlab Create a spherical point cloud, it can be random or regularly distributed. **Parameters:** - **point_num** (*int*, default: `100`) — Approximate number of points to generate. - **technique** (*enum*, default: `fibonacci`) — Strategy used to distribute points on the sphere. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the Monte Carlo point set exactly reproducible. ``` --- (filter-create-points-on-spherical-cap)= ## Create Points on a Spherical Cap **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates an area-uniform point cloud on a unit-sphere cap. ```{py:function} ms.create_points_on_spherical_cap(**params) :module: _meshlab Creates points on the surface of a unit-sphere cap centred on **Cap Direction** and bounded by **Cap Half-Angle** $\alpha$. Every generated point also receives its outward radial normal. Both techniques are uniform with respect to spherical surface area: equivalently, $\cos\theta$ is distributed uniformly in $[\cos\alpha,1]$, rather than $\theta$ being distributed uniformly. **Monte Carlo** generates independent random samples and can be reproduced with a non-zero seed. **Fibonacci** is deterministic and uses VCGLib's direct equal-area spherical-cap construction, producing the exact requested count without first generating and discarding points from a complete sphere. A half-angle of $180^\circ$ covers the complete sphere. **Parameters:** - **point_num** (*int*, default: `100`) — Exact number of points to generate. - **direction** (*point3f*, default: `[0.0, 1.0, 0.0]`) — Direction from the sphere centre to the centre of the cap. - **half_angle** (*double*, default: `30.0`) — Polar angle in degrees from the cap axis to its boundary; 90 is a hemisphere and 180 covers the complete sphere. - **technique** (*enum*, default: `fibonacci`) — Random Monte Carlo sampling or deterministic Fibonacci sampling. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run; any other value makes Monte Carlo sampling exactly reproducible. ``` --- (filter-create-polyline-from-boundary-rims-trueform)= ## Create Polyline from Boundary Rims (TrueForm) **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.trueform Extract each boundary curve of an open mesh as its own polyline layer. ```{py:function} ms.create_polyline_from_boundary_rims_trueform(**params) :module: _meshlab Walks the layer's boundary edges into **rims** and creates one polyline layer per rim, tagged with its number and whether it closes. A rim ends where the boundary stops passing straight through, so a boundary that pinches — one vertex the boundary reaches more than twice — comes back as its separate pieces rather than as one figure eight. Every layer this produces is therefore a **simple curve**, which is what makes it usable: measurable as a length, sweepable by *Create Tube from Polyline (TrueForm)*, or usable to drive a hole fill. A closed rim's polyline runs back to its first vertex; an open one has two loose ends. On a consistently wound mesh each rim runs the way its faces wind their boundary, so the direction is meaningful rather than arbitrary. A closed surface has no boundary and so no rims, and the filter says so rather than creating an empty layer. *Measure Mesh Health (TrueForm)* reports the rim count without creating anything. This filter has no parameters. ``` --- (filter-create-polyline-from-cut-graph)= ## Create Polyline from Cut Graph **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Create a polyline along mesh edges that, once cut, opens the mesh into a topological disk. ```{py:function} ms.create_polyline_from_cut_graph(**params) :module: _meshlab Compute a cut graph: a set of mesh edges such that cutting the surface along them leaves a single topological disk. A closed surface of genus $g$ needs a graph with $2g$ independent cycles, so a sphere is opened by a short cut and a torus by two loops around the tube and the hole. The graph becomes a new polyline layer lying exactly on mesh edges; *Embed Polyline in Surface* then selects those edges (after an optional *Smooth Polyline on Surface*), and *Cut Along Selected Edges* opens the mesh. It is the first step towards a parametrization that needs disk topology. The graph is found by visiting the faces in a random order and keeping only the edges where different fronts of the visit meet, so different seeds give different, equally valid cuts. The mesh must be connected and manifold, without duplicate vertices; one that is already a disk needs no cut, and the filter says so. **Parameters:** - **randomSeed** (*int*, default: `0`) — Seeds the starting face and the order of the visit. Zero draws a fresh seed on every run, so repeated applications give different cuts; any other value makes the cut exactly reproducible. ``` --- (filter-create-polyline-from-mesh-intersection-trueform)= ## Create Polyline from Mesh Intersection (TrueForm) **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.trueform Extract the curve where two layers cross, as a polyline layer. ```{py:function} ms.create_polyline_from_mesh_intersection_trueform(**params) :module: _meshlab Extracts the exact curve along which two layers intersect, as a new polyline layer. Both are taken in world space, so their layer matrices are applied first. The curve is computed with the same exact arrangement the booleans use, so it is the true intersection rather than a sampled approximation, and it is usable as a construction line — a seam to cut along, a profile to sweep, or a measurement. Layers that do not touch produce nothing. **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — The first layer. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — The second layer. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-create-polyline-from-planar-section)= ## Create Polyline from Planar Section **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Compute planar section polyline. ```{py:function} ms.create_polyline_from_planar_section(**params) :module: _meshlab Compute the polyline representing a planar section (a slice) of a mesh; if the resulting polyline is closed the result is filled and also a triangular mesh representing the section is saved **Parameters:** - **planeAxis** (*enum*, default: `x`) — Slicing plane normal axis. - **customAxis** (*point3f*, default: `[0.0, 1.0, 0.0]`) — Custom slicing plane normal direction. - **planeOffset** (*double*, default: `0.0`) — Offset from reference point. - **relativeTo** (*enum*, default: `origin`) — Reference frame for plane offset. - **createSectionSurface** (*bool*, default: `False`) — Create triangulated sections from closed contours, including holes and disconnected regions. - **splitSurfaceWithSection** (*bool*, default: `False`) — Create under/over split layers (requires manifold mesh). ``` --- (filter-create-polyline-from-scalar-isocontour-trueform)= ## Create Polyline from Scalar Isocontour (TrueForm) **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.trueform Extract contour lines of the per-vertex scalar field as polylines on the surface. ```{py:function} ms.create_polyline_from_scalar_isocontour_trueform(**params) :module: _meshlab Extracts level sets of the **per-vertex scalar field** as polylines lying exactly on the surface. This turns every scalar MeshLab can compute into something with extractable contours: geodesic distance from a point or a border, curvature, ambient occlusion, shape diameter, raster coverage, or anything written by *Compute Vertex Scalar by Expression*. Contours of a geodesic distance are isodistance rings; of a height field, topographic contour lines. **Contours** sets how many levels are extracted. They are spaced evenly and placed strictly *inside* the range, never at its extremes, where a contour is either empty or the whole boundary. By default the range is the field's own minimum and maximum. Enable **Use Custom Range** to contour a chosen band instead — useful when a few outliers would otherwise compress every contour into a corner of the model. A constant field has no contours, and the filter says so rather than returning an empty layer. All the levels land in one layer, so every edge carries **the value of the contour it belongs to** as its scalar. Run *Colorize Edges by Scalar* on the result to tell the levels apart; without that they draw in one flat colour. The scalars survive a PLY round trip, so the layer can be saved and re-colored later. **Parameters:** - **contourCount** (*int*, default: `10`) — How many evenly spaced contour levels to extract. - **useCustomRange** (*bool*, default: `False`) — Contour a chosen value band instead of the field's full min-max range. - **minValue** (*double*, default: `@qualityVMin`) — Lower end of the contoured range. Ignored unless Use Custom Range is on. - **maxValue** (*double*, default: `@qualityVMax`) — Upper end of the contoured range. Ignored unless Use Custom Range is on. ``` --- (filter-create-polyline-from-selected-edges)= ## Create Polyline from Selected Edges **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Create edge mesh from selected edges. ```{py:function} ms.create_polyline_from_selected_edges(**params) :module: _meshlab Create a new Layer with an edge mesh composed only by the selected edges of the current mesh This filter has no parameters. ``` --- (filter-create-polyline-from-selection-perimeter)= ## Create Polyline from Selection Perimeter **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Create polyline from selection perimeter. ```{py:function} ms.create_polyline_from_selection_perimeter(**params) :module: _meshlab Create a new Layer with an edge mesh (polyline) tracing the perimeter of the **selected faces**: every edge of a selected face whose adjacent face is not selected. Selecting all the faces of the mesh therefore converts its boundary edges into a polyline.
To build a polyline from an *edge* selection instead, use *Build a Polyline from Selected Edges*. This filter has no parameters. ``` --- (filter-create-polyline-from-self-intersections-trueform)= ## Create Polyline from Self-Intersections (TrueForm) **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.trueform Extract the curve where a mesh passes through itself, as a polyline layer. ```{py:function} ms.create_polyline_from_self_intersections_trueform(**params) :module: _meshlab Extracts the exact curve along which the layer intersects **itself**, as a new polyline layer. *Select Self Intersecting Faces* marks the faces involved; this gives the intersection itself, which is what you need to see where the problem is rather than merely that it exists — and, being exact geometry rather than a selection, it can be measured, exported, or swept into a tube. A clean mesh produces nothing, and the filter says so. This filter has no parameters. ``` --- (filter-create-reeb-graph-from-vertex-scalar)= ## Create Reeb Graph from Vertex Scalar **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.meshing Create a polyline layer with the Reeb graph of the vertex scalar field. ```{py:function} ms.create_reeb_graph_from_vertex_scalar(**params) :module: _meshlab The Reeb graph of a scalar field on a surface collapses every connected component of every level set to a point. Its nodes are the critical points of the field (minima, maxima, and the saddles where a contour splits or two contours merge) and its arcs are the families of contours swept between them. It is a compact description of the shape along the field, used for shape matching, skeletons and topology repair. The graph becomes a new polyline layer: a vertex per node, placed at its mesh vertex and carrying the field value there as its scalar, and an edge per arc. Whatever the field, the graph of a closed orientable surface of genus $g$ has exactly $g$ independent cycles, and the log reports how many it found. With boundaries that count no longer equals the genus. The field is the current vertex scalar, which must be finite everywhere; ties are broken consistently, so it need not be free of flat regions. To use a height function, compute it first with *Compute Vertex Scalar by Expression* (for instance `y`). The surface must be edge-manifold. **References:** - Valerio Pascucci, Giorgio Scorzelli, Peer-Timo Bremer, Ajith Mascarenhas. **Robust on-line computation of Reeb graphs: simplicity and speed**. *ACM Transactions on Graphics* (2007). [DOI](https://doi.org/10.1145/1276377.1276449) This filter has no parameters. ``` --- (filter-create-scene-bounding-box)= ## Create Scene Bounding Box **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.cgal Turn the bounding box of every visible layer into a mesh of its own. ```{py:function} ms.create_scene_bounding_box(**params) :module: _meshlab Creates a new layer holding the bounding box of the **whole scene**: one box around every *visible* layer, measured in world space so each layer's own transformation is taken into account. Hidden layers are ignored, which is how you box a subset — hide what should not count and run it again. The box is created in world space with an identity transformation, so it stays put whatever the layers it was measured from do afterwards. **Alignment** chooses between the two boxes worth having: - **Axis aligned** is the smallest box whose sides are parallel to the world axes — the extent the viewport frames to. - **Oriented** is the smallest box in *any* orientation. For a scene laid out at an angle it is much tighter; for one already square to the axes the two coincide. The search is an approximation, not a proven optimum, and it costs time on large scenes — it runs on the convex hull, so cost follows the hull rather than the total vertex count. There is deliberately no *turning the scene* option: straightening is a per-layer operation, and **Create Mesh Bounding Box** offers it for the current layer. The oriented box is computed with CGAL's Optimal Bounding Box package. Reference: Konstantinos Katrioplas, Mael Rouxel-Labbé, **Optimal Bounding Box**, CGAL User and Reference Manual, CGAL Editorial Board. **Parameters:** - **alignment** (*enum*, default: `axis_aligned`) — Axis aligned is the smallest box parallel to the world axes. Oriented searches for the smallest box in any orientation, which is much tighter for a scene laid out at an angle but costs time to find. ``` --- (filter-create-solid-wireframe)= ## Create Solid Wireframe **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.voronoi Convert the current mesh into a solid shell made of cylinders, spheres, and face prisms. ```{py:function} ms.create_solid_wireframe(**params) :module: _meshlab Create a new solid wireframe layer by replacing edges with cylinders, vertices with spheres or short cylinders, and faces with prisms. **Parameters:** - **edgeCylFlag** (*bool*, default: `True`) — Replace edges with cylinders. - **edgeCylRadius** (*absperc*, default: `@bboxDiag01`) — Radius of each edge cylinder. - **vertCylFlag** (*bool*, default: `False`) — Replace vertices with short normal-aligned cylinders. - **vertCylRadius** (*absperc*, default: `@bboxDiag01`) — Radius of each vertex cylinder. - **vertSphFlag** (*bool*, default: `True`) — Replace vertices with spheres. - **vertSphRadius** (*absperc*, default: `@bboxDiag01`) — Radius of each vertex sphere. - **faceExtFlag** (*bool*, default: `True`) — Replace faces with extruded prisms. - **faceExtHeight** (*absperc*, default: `@bboxDiag0005`) — Height of each face prism. - **faceExtInset** (*absperc*, default: `@bboxDiag0005`) — Inset amount used to shrink each face prism toward its center. - **edgeFauxFlag** (*bool*, default: `True`) — Preserved for MeshLab compatibility. The current VCG shell builder consumes the unique real edge set. - **cylinderSideNum** (*int*, default: `16`) — Number of sides used for edge and vertex cylinders. ``` --- (filter-create-sphere)= ## Create Sphere **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a Sphere by recursive subdivision of an Icosahedron. ```{py:function} ms.create_sphere(**params) :module: _meshlab Create a Sphere, whose topology is obtained as regular subdivision of an icosahedron. **Parameters:** - **radius** (*double*, default: `1.0`) — Radius of the sphere. - **subdiv** (*int*, default: `3`) — Number of recursive subdivisions. 0=icosahedron, 3=1280 faces, max=8. ``` --- (filter-create-sphere-cap)= ## Create Sphere Cap **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a triangulated unit-radius spherical cap from a refined hexagonal disk. ```{py:function} ms.create_sphere_cap(**params) :module: _meshlab Creates a unit-radius spherical cap above the XY plane, with its circular boundary in the plane and its axis along +Z. The cap starts as a six-triangle disk; each subdivision splits every triangle into four, redistributes the interior vertices by Laplacian smoothing, and then lifts all vertices onto the sphere. This construction gives a regular, compact triangulation for shallow caps, but it is not a general-purpose spherical mesher. Triangle distortion grows toward the boundary for wide caps, becoming severe as the cap approaches a hemisphere. **Cap Half-Angle** is the polar angle from the +Z axis out to the cap boundary, so it is half the cap's full angular diameter: 30° spans a 60° cap, and a hemisphere would be 90°. The filter stops at 89.5° because this disk-based parameterization degenerates at the hemisphere limit. For a well-shaped hemisphere or a wider spherical patch, start from a complete sphere and extract the required region instead. **Parameters:** - **half_angle** (*double*, default: `30.0`) — Polar angle in degrees from the cap axis to its boundary, i.e. half the full angular diameter. A hemisphere would be 90°, where this construction degenerates. - **subdiv** (*int*, default: `3`) — Number of recursive refinements of the initial six triangles. Level n creates 6 × 4^n faces. ``` --- (filter-create-square)= ## Create Square **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a square as a closed polyline. ```{py:function} ms.create_square(**params) :module: _meshlab Creates a new layer holding a **square** as a closed **polyline**: four vertices, four edges, no faces. Polylines are the edge-based curves MeshLab uses for sections, contours and outlines — this makes one from nothing, as a frame, a footprint, or a path to measure against. **Side Length** is the length of each of the four edges; the square is centred on the origin, so it reaches half of that either side along each of its in-plane directions. **Normal** turns the square to face any direction. Its sides stay square to the two in-plane axes rather than its corners, which is the difference between this and asking **Create Circle** for four sides. For a *filled* square with faces rather than a curve, use **Create Grid**, or scale a **Create Hexahedron** flat. **Parameters:** - **size** (*double*, default: `1.0`) — Length of each of the four edges. - **axis** (*point3f*, default: `[0.0, 0.0, 1.0]`) — Direction the polyline faces. It lies in the plane through the origin at right angles to this. Need not be normalized. ``` --- (filter-create-symmetric-dodecahedron)= ## Create Symmetric Dodecahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a symmetrically triangulated Dodecahedron. ```{py:function} ms.create_symmetric_dodecahedron(**params) :module: _meshlab Create a Dodecahedron, but triangulated with an additional vertex in the middle of each face to preserve symmetry. This filter has no parameters. ``` --- (filter-create-tetrahedron)= ## Create Tetrahedron **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a Tetrahedron. ```{py:function} ms.create_tetrahedron(**params) :module: _meshlab Create a Tetrahedron This filter has no parameters. ``` --- (filter-create-torus)= ## Create Torus **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.create Creates a Torus. ```{py:function} ms.create_torus(**params) :module: _meshlab Create a Torus **Parameters:** - **h_radius** (*double*, default: `3.0`) — Radius of the whole horizontal ring of the torus. - **v_radius** (*double*, default: `1.0`) — Radius of the vertical cross-section of the ring. - **h_subdiv** (*int*, default: `24`) — Subdivision steps around the ring. - **v_subdiv** (*int*, default: `12`) — Subdivision steps of the cross-section circle. ``` --- (filter-create-tube-from-polyline-trueform)= ## Create Tube from Polyline (TrueForm) **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.trueform Sweep a circular profile along a polyline to make a solid tube. ```{py:function} ms.create_tube_from_polyline_trueform(**params) :module: _meshlab Sweeps a circular profile along each path of a polyline layer, producing a solid tube. The *Create Polyline* filters produce edge meshes, which render as hairlines and cannot be shaded, exported to a solid format, or printed. This turns one into geometry — so a measured cross-section, an intersection seam, or a set of isocontours becomes something you can look at properly or fabricate. **Radius** is the tube radius and **Sides** the number of segments around it; 8 is smooth enough for most uses, more for close-ups. Edges are chained into paths first. A vertex where three or more edges meet cannot be swept unambiguously, so the polyline is **split** there rather than branched, and the count of such junctions is reported. **Parameters:** - **radius** (*absperc*, default: `@bboxDiag001`) — Radius of the swept profile. - **segments** (*int*, default: `8`) — Number of segments around the tube. Higher is smoother and heavier. ``` --- (filter-create-voronoi-scaffolding)= ## Create Voronoi Scaffolding **Categories:** `Creation/Primitives` **Plugin:** meshlab2.filter.voronoi Build a scaffold mesh from a volumetric Voronoi sampling of a watertight mesh. ```{py:function} ms.create_voronoi_scaffolding(**params) :module: _meshlab Build a volumetric Voronoi sampling of the current mesh, relax the internal seeds, and extract a scaffold mesh from the implicit Voronoi structure. **Parameters:** - **sampleSurfRadius** (*absperc*, default: `@bboxDiag01`) — Surface Poisson radius used as an acceleration structure for signed-distance queries. - **sampleVolNum** (*int*, default: `100000`) — Number of volumetric samples used to choose and relax Voronoi seeds. - **voxelRes** (*int*, default: `50`) — Number of voxels along the longest side of the implicit extraction grid. - **isoThr** (*double*, default: `1.0`) — Width of the generated scaffold element expressed in voxel units. - **smoothStep** (*int*, default: `3`) — Number of Laplacian smoothing iterations applied to the scaffold mesh. - **relaxStep** (*int*, default: `5`) — Number of volumetric Lloyd relaxation steps for the Voronoi seeds. - **surfFlag** (*bool*, default: `True`) — Extract the scaffold as a structure joined to the original surface envelope. - **elemType** (*enum*, default: `edge`) — Voronoi feature type to extract. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the scaffolding exactly reproducible. ``` --- (filter-create-convex-hull)= ## Create Convex Hull **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.create Create the convex hull of the current mesh or point cloud. ```{py:function} ms.create_convex_hull(**params) :module: _meshlab Creates a new layer holding the **convex hull** of the current layer: the boundary of the smallest convex set containing all of its vertices. Only the vertex positions are used, so this works on a point cloud just as well as on a mesh; faces, if any, are ignored. Every hull vertex is one of the input points, and interior points are discarded — which is why the result is a new layer rather than a modification of the current one. At least 4 vertices are required, and they must not all be coincident, collinear, or coplanar. Implemented with VCGLib's Quickhull. Reference: C. Bradford Barber, David P. Dobkin, Hannu Huhdanpaa, **The Quickhull Algorithm for Convex Hulls**, ACM Transactions on Mathematical Software 22(4), 1996. This filter has no parameters. ``` --- (filter-reconstruct-surface-by-advancing-front)= ## Reconstruct Surface by Advancing Front **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Reconstruct a surface from an unoriented point cloud by growing a triangulation outward. ```{py:function} ms.reconstruct_surface_by_advancing_front(**params) :module: _meshlab Grows a triangulation outward from a seed facet, repeatedly choosing the most plausible candidate triangle on the advancing boundary. It is an **interpolating** reconstruction: every output vertex is one of the input points, and no normals are required. **Radius Ratio Bound** rejects candidate triangles whose circumradius is more than this multiple of the shortest edge, which is what stops the front from bridging across gaps. Raise it on sparse or uneven sampling; lower it to keep holes open rather than filling them with sliver triangles. **Beta** is half the angle of the wedge in which only the triangle radius decides plausibility. This is CGAL's counterpart to the *Reconstruct Surface by Ball Pivoting* filters: both grow a surface outward and interpolate the input points, but they are different algorithms and are worth comparing on the same cloud. CGAL has no ball-pivoting implementation of its own. Implemented with CGAL's Advancing Front Surface Reconstruction. Reference: David Cohen-Steiner, Frank Da, **A greedy Delaunay-based surface reconstruction algorithm**, The Visual Computer 20(1), 2004. **Parameters:** - **radiusRatioBound** (*double*, default: `5.0`) — Reject a candidate triangle whose circumradius exceeds this multiple of its shortest edge. Larger values close more holes; smaller values leave sparse regions open. - **beta** (*double*, default: `30.0`) — Half the angle of the wedge in which only the triangle radius counts towards plausibility. CGAL's default is 0.52 rad, about 30 degrees. ``` --- (filter-reconstruct-surface-by-alpha-shape)= ## Reconstruct Surface by Alpha Shape **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Build the alpha complex or alpha shape of the current mesh or point cloud. ```{py:function} ms.reconstruct_surface_by_alpha_shape(**params) :module: _meshlab Builds the **alpha shape** of the current layer's vertices: the subcomplex of their Delaunay triangulation kept by a ball of radius `Alpha` that can reach it without enclosing any point. Small `Alpha` values give a sparse, pitted result; as `Alpha` grows the shape fills in and converges to the convex hull. Only vertex positions are used, so a raw point cloud with no faces and no normals works — it is an *interpolating* reconstruction, meaning every output vertex is one of the input points. **Output** selects what is written: - *Alpha Shape* — the boundary of the alpha complex (CGAL `REGULAR` facets). This is the surface. - *Alpha Complex* — also keeps the `SINGULAR` facets, the lower-dimensional sheets that the boundary drops. Useful for seeing what the complex contains, not for a clean surface. Each face carries its **circumradius in face scalar**, so the scalar histogram shows the alpha distribution and helps pick a better value. Facet orientation comes from the Delaunay triangulation and is not made globally coherent; run *Orient Faces Consistently* if you need it. Implemented with CGAL's 3D Alpha Shapes. Reference: Herbert Edelsbrunner, Ernst P. Mucke, **Three-Dimensional Alpha Shapes**, ACM Transactions on Graphics 13(1), 1994. **Parameters:** - **alpha** (*absperc*, default: `@bboxDiag002`) — Radius of the probing ball, as a percentage of the bounding box diagonal. Small values carve the shape away; large values converge to the convex hull. - **output** (*enum*, default: `shape`) — Alpha Shape writes the boundary surface. Alpha Complex additionally writes the singular facets held by the complex. ``` --- (filter-reconstruct-surface-by-alpha-wrapping)= ## Reconstruct Surface by Alpha Wrapping **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Generate a watertight alpha wrapping of the current mesh or point cloud using CGAL. ```{py:function} ms.reconstruct_surface_by_alpha_wrapping(**params) :module: _meshlab Compute an alpha wrapping with an offset around the current mesh and add the result as a new mesh layer. Alpha wrapping is useful for producing robust watertight approximations of defective, self-intersecting, open, or highly detailed input geometry. Smaller `Alpha` values follow the input more tightly but increase output complexity and computation time. `Offset` controls the clearance added around the input surface and must be strictly positive. Faces are optional, but they are **used**, not merely a container for the vertices: - A layer **with faces** is wrapped as a *triangle soup*. Triangle interiors are part of the input, so a large flat face is solid to the rolling ball, and CGAL subdivides oversized faces so that the spatial structure resolves at the `Alpha` scale. - A layer with **only vertices** is wrapped as a *point set*, which makes this a point-cloud reconstruction method. Unlike Poisson-family reconstruction it needs no vertex normals, because the positive offset is what defines the envelope. The two paths therefore give **different results on the same geometry**. Where a triangle spans a wide gap, the point-set path sees only its three corners and the ball can roll into the space between them, denting or holing the wrap. Wrap a point cloud only when the sampling is dense relative to `Alpha` and `Offset`; if the layer has faces, keep them. The result is an *approximating* reconstruction: the offset is strictly positive, so the output surface never passes through the input points. The filter uses CGAL's 3D Alpha Wrapping implementation. Reference: Cédric Portaneri, Mael Rouxel-Labbé, Michael Hemmer, David Cohen-Steiner, Pierre Alliez, **Alpha Wrapping with an Offset**, 2022. Original MeshLab plugin contribution: Lex van der Sluijs, PTC. **Parameters:** - **Alpha** (*absperc*, default: `@bboxDiag002`) — Radius of the rolling ball used by CGAL alpha wrapping. Smaller values produce a tighter and more detailed wrap, but increase computation time and output mesh size. MeshLab default: 2% of the bounding-box diagonal. - **Offset** (*absperc*, default: `@bboxDiag001`) — Positive offset added around the input surface. Larger values make a looser, more conservative envelope; very small values can make the computation heavier. MeshLab default: 0.1% of the bounding-box diagonal. ``` --- (filter-reconstruct-surface-by-ball-pivoting-gruber)= ## Reconstruct Surface by Ball Pivoting (Gruber) **Categories:** `Creation/Reconstruction` Reconstruct a surface from oriented points using a direct implementation of the original Ball Pivoting paper. ```{py:function} ms.reconstruct_surface_by_ball_pivoting_gruber(**params) :module: _meshlab Rolls a ball of the given radius over the point cloud: starting from a seed triangle the ball pivots around each boundary edge until it lands on another point, which makes the next triangle, and so on until the front runs out. Every vertex of the result is one of the input points -- nothing is invented, nothing is moved. This is Bernhard Gruber's implementation, a direct and deliberately unelaborated reading of the 1999 paper. MeshLab also ships **Reconstruct Surface by Ball Pivoting (vcglib)**, and the two behave very differently on the same cloud, which is why both are here: | | this filter | (vcglib) | | --- | --- | --- | | seeds | one, and the front grows from it alone | re-seeds, so every disconnected piece is covered | | radius | you give it | you give it, or 0 to guess from the bounding box | | clustering | none -- every input point stands | merges points closer than a clustering radius | | creases | none -- the ball rolls over any fold | stops at a crease angle you set | The single seed is the difference you will notice first. On a cloud in several pieces this one reconstructs whichever piece its seed landed in and leaves the rest bare; that is the published algorithm, and the filter says so in its report when it happens. Against that, nothing is clustered away, so on a cloud you have already sampled evenly it gives you back exactly the points you put in. Works best on uniformly sampled clouds. If the sampling is uneven, run **Sample Surface by Poisson Disk** first. The points must carry normals, and they must be oriented consistently -- the ball needs to know which side the surface is on. Reference: Bernardini F., Mittleman J., Rushmeier H., Silva C., Taubin G., **The ball-pivoting algorithm for surface reconstruction**, IEEE TVCG 1999. **Parameters:** - **ballRadius** (*absperc*, default: `0.0`) — Radius of the ball rolled over the points. Gaps wider than the ball are left open, and pits narrower than it are bridged over. There is no autoguess here, unlike the vcglib implementation: pick something close to the spacing of the cloud, and raise it until the holes close. - **deleteInitialFaces** (*bool*, default: `True`) — Throw away any faces the layer already has and rebuild from the points alone. This implementation always starts from its own seed triangle and cannot grow a front from existing faces, so leaving this off simply keeps the old faces alongside the new ones. ``` --- (filter-reconstruct-surface-by-ball-pivoting-vcglib)= ## Reconstruct Surface by Ball Pivoting (vcglib) **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.clean Reconstruct a surface from oriented points using Ball Pivoting. ```{py:function} ms.reconstruct_surface_by_ball_pivoting_vcglib(**params) :module: _meshlab Given a point cloud with normals it reconstructs a surface using the Ball Pivoting Algorithm.Starting with a seed triangle, the BPA algorithm pivots a ball of the given radius around the already formed edges until it touches another point, forming another triangle. The process continues until all reachable edges have been tried. This surface reconstruction algorithm uses the existing points without creating new ones. Works better with uniformly sampled point clouds. If needed first perform a poisson disk subsampling of the point cloud.
Bernardini F., Mittleman J., Rushmeier H., Silva C., Taubin G.
The ball-pivoting algorithm for surface reconstruction.
IEEE TVCG 1999 **Parameters:** - **ball_radius** (*absperc*, default: `0.0`) — The radius of the ball pivoting (rolling) over the set of points. Gaps that are larger than the ball radius will not be filled; similarly small pits smaller than the ball radius will be filled. Use `0` for autoguess. - **clustering_percent** (*double*, default: `20.0`) — To avoid creation of too small triangles, if a vertex is found too close to a previous one, it is clustered/merged with it. - **crease_threshold_deg** (*double*, default: `90.0`) — If we encounter a crease angle that is too large we should stop the ball rolling. - **delete_initial_faces** (*bool*, default: `False`) — If true all the initial faces of the mesh are deleted and the whole surface is rebuilt from scratch. Otherwise current faces are used as a starting point. ``` --- (filter-reconstruct-surface-by-kinetic-partition)= ## Reconstruct Surface by Kinetic Partition **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Reconstruct a piecewise-planar surface from oriented points by kinetic space partition and min-cut. ```{py:function} ms.reconstruct_surface_by_kinetic_partition(**params) :module: _meshlab A piecewise-planar reconstruction pipeline, run end to end by this one filter: 1. **Shape detection** finds planar regions in the point cloud. 2. **Regularization** aligns those planes where they are nearly parallel, coplanar or orthogonal. 3. **Kinetic space partition** propagates the planes until they collide, cutting the bounding box into convex volumes. 4. **Min-cut** labels each volume inside or outside; the surface is the boundary between the two labels. Because the output is built from detected planes rather than fitted to the samples, it is planar **by construction** — which suits buildings, rooms and other man-made shapes far better than a smooth reconstruction, and is quite unsuitable for organic ones. **Requires oriented normals.** Run *Compute Point Cloud Normals* and then *Orient Point Cloud Normals* first if the layer has none. **Maximum Distance** is the most important setting: it is how far a point may sit from a plane and still belong to it, so it must be set to the scale of the noise in the data. **Lambda** trades faithfulness against simplicity — higher values give fewer, larger facets. The reconstruction emits convex polygons, which this filter fan-triangulates because MeshLab stores triangle meshes. Implemented with CGAL's Kinetic Surface Reconstruction. Reference: Sven Oesau, Florent Lafarge, **Kinetic Shape Reconstruction**, ACM Transactions on Graphics 39(5), 2020. **Parameters:** - **maximumDistance** (*absperc*, default: `@bboxDiag01`) — How far a point may lie from a plane and still be assigned to it. Set this to the noise scale of the data; it is the setting that most affects the result. - **maximumAngle** (*double*, default: `15.0`) — Largest angle between a point's normal and its plane's normal for the point to be assigned to that plane. - **lambda** (*double*, default: `0.5`) — Trades data faithfulness against model complexity, in [0, 1). Higher values give a simpler surface with fewer facets. - **minimumRegionSize** (*int*, default: `50`) — Smallest number of points a detected planar region must contain to be kept. - **kNeighbors** (*int*, default: `12`) — Number of nearest neighbours used when growing planar regions. - **intersections** (*int*, default: `1`) — How many times propagating planes may intersect before the partition stops. Higher values give a finer partition and cost considerably more. ``` --- (filter-reconstruct-surface-by-marching-cubes-apss)= ## Reconstruct Surface by Marching Cubes (APSS) **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.mls Extract an APSS iso-surface as a new mesh with marching cubes. ```{py:function} ms.reconstruct_surface_by_marching_cubes_apss(**params) :module: _meshlab Extracts the iso-surface of an MLS surface as a mesh, using marching cubes. The coarse extraction is followed by an accurate projection onto the MLS surface and a zero-removal pass. This is the **algebraic point set surfaces** (APSS) variant: the local approximation fitted at each point is an algebraic sphere rather than a plane, which keeps curved regions from flattening out. It needs points carrying oriented normals. **References:** - Gaël Guennebaud, Markus Gross. **Algebraic point set surfaces**. *ACM Transactions on Graphics (SIGGRAPH 2007)* (2007). [DOI](https://doi.org/10.1145/1276377.1276406) - Gaël Guennebaud, Marcel Germann, Markus Gross. **Dynamic Sampling and Rendering of Algebraic Point Set Surfaces**. *Computer Graphics Forum (Eurographics 2008)* (2008). [DOI](https://doi.org/10.1111/j.1467-8659.2008.01163.x) **Parameters:** - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SphericalParameter** (*double*, default: `1.0`) — Control the curvature of the fitted spheres: 0 is equivalent to a pure plane fit, 1 to a pure spherical fit, values between 0 and 1 give intermediate results, while other real values might give interesting results, but take care with extreme settings. - **AccurateNormal** (*bool*, default: `True`) — If checked, use the accurate MLS gradient instead of the local approximation to compute the normals. - **Resolution** (*int*, default: `200`) — The resolution of the grid on which we run the marching cubes. This marching cubes is memory friendly, so you can safely set large values up to 1000 or even more. - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-reconstruct-surface-by-marching-cubes-rimls)= ## Reconstruct Surface by Marching Cubes (RIMLS) **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.mls Extract a Robust Implicit MLS iso-surface as a new mesh with marching cubes. ```{py:function} ms.reconstruct_surface_by_marching_cubes_rimls(**params) :module: _meshlab Extracts the iso-surface of an MLS surface as a mesh, using marching cubes. The coarse extraction is followed by an accurate projection onto the MLS surface and a zero-removal pass. This is the **robust implicit MLS** (RIMLS) variant: it extends implicit MLS with non-linear kernel regression, so sharp edges survive instead of being rounded away with the noise. It needs points carrying oriented normals. **References:** - A. Cengiz Öztireli, Gaël Guennebaud, Markus Gross. **Feature Preserving Point Set Surfaces based on Non-Linear Kernel Regression**. *Computer Graphics Forum (Eurographics 2009)* (2009). [DOI](https://doi.org/10.1111/j.1467-8659.2009.01388.x) **Parameters:** - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SigmaN** (*double*, default: `0.75`) — Width of the filter used by the normal refitting weight. This weight function is a Gaussian on the distance between two unit vectors: the current gradient and the input normal. Typical values range between 0.5 (sharp) and 2 (smooth). - **MaxRefittingIters** (*int*, default: `3`) — Max number of fitting iterations. (0 or 1 is equivalent to the standard IMLS). - **Resolution** (*int*, default: `200`) — The resolution of the grid on which we run the marching cubes. This marching cubes is memory friendly, so you can safely set large values up to 1000 or even more. - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-reconstruct-surface-by-poisson-cgal)= ## Reconstruct Surface by Poisson (CGAL) **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Reconstruct a watertight surface from oriented points with CGAL's Poisson solver. ```{py:function} ms.reconstruct_surface_by_poisson_cgal(**params) :module: _meshlab Solves the Poisson equation for an implicit function whose gradient best matches the input normal field, then extracts its zero level set. It differs from *Reconstruct Surface by Screened Poisson* in how that level set is **meshed**: CGAL uses Delaunay refinement rather than marching cubes, so the output is manifold with well-shaped triangles and a size driven by the sampling, at the cost of being slower. The two are worth comparing on the same cloud — that is why both are here. **Requires oriented normals.** If the layer has none, run *Compute Point Cloud Normals* and then *Orient Point Cloud Normals* first. Triangle size and quality are controlled relative to the estimated average point spacing: - **Minimum Angle** — the lower bound on triangle angles, in degrees. - **Maximum Radius** — largest triangle circumradius, as a multiple of the spacing. - **Approximation Error** — how far the mesh may deviate from the level set, as a multiple of the spacing. Implemented with CGAL's Poisson Surface Reconstruction. Reference: Michael Kazhdan, Matthew Bolitho, Hugues Hoppe, **Poisson Surface Reconstruction**, Symposium on Geometry Processing 2006. **Parameters:** - **smAngle** (*double*, default: `20.0`) — Lower bound on the angles of the output triangles. Lower values are easier to satisfy; CGAL's default is 20. - **smRadius** (*double*, default: `30.0`) — Largest triangle circumradius, as a multiple of the estimated average point spacing. Smaller values give a denser mesh. - **smDistance** (*double*, default: `0.375`) — How far the mesh may deviate from the implicit surface, as a multiple of the average point spacing. Smaller values follow the data more closely and cost more. - **perturb** (*bool*, default: `False`) — Displace every input point by about a millionth of the bounding-box diagonal before reconstructing. Far below any modelling tolerance, and invisible in the result, but it breaks the exact symmetries that can stop CGAL's surface mesher terminating -- an analytically generated sphere or cylinder, where every point lies exactly on the same surface, is the case that needs it. Leave it off for scanned or otherwise noisy data, which is never degenerate in this way. The displacement is deterministic, so a run stays reproducible. - **spacingNeighbors** (*int*, default: `6`) — Number of neighbours used to estimate the average point spacing that the three settings above are relative to. ``` --- (filter-reconstruct-surface-by-scale-space)= ## Reconstruct Surface by Scale Space **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Reconstruct a surface by smoothing the point set to a coarser scale, then meshing it. ```{py:function} ms.reconstruct_surface_by_scale_space(**params) :module: _meshlab Smooths the current layer's points for a number of iterations — moving them to a coarser *scale* at which a surface is easier to extract — and then triangulates the smoothed points. Only vertex positions are used, so a raw point cloud with no faces and no normals works. **Iterations** controls how far the point set is smoothed: more iterations tolerate more noise but lose detail. **Neighbors** and **Samples** configure the weighted-PCA smoother. **Mesher** selects how the smoothed points are triangulated: - *Alpha Shape* — uses **Alpha** as the probing radius, and can be asked to separate shells or to force a manifold result. - *Advancing Front* — grows a triangulation outward and needs no radius. Unlike the other interpolating reconstructions here, the output vertices are the **smoothed** positions, not the original points: this filter moves the geometry before meshing it. Keep the input layer if you need the originals. Implemented with CGAL's 3D Scale-Space Surface Reconstruction. Reference: Thijs van Lankveld, Marc van Kreveld, Remco Veltkamp, **Watertight Scenes from Urban LiDAR and Planar Surfaces**, Computer Graphics Forum 32(5), 2013. **Parameters:** - **iterations** (*int*, default: `4`) — How many times the point set is smoothed before meshing. Zero meshes the points as they are; more iterations tolerate more noise but lose detail. - **mesher** (*enum*, default: `alpha_shape`) — How the smoothed points are triangulated. Alpha Shape uses the Alpha radius below; Advancing Front needs no radius. - **alpha** (*absperc*, default: `@bboxDiag002`) — Probing ball radius for the Alpha Shape mesher, as a percentage of the bounding box diagonal. Ignored by the Advancing Front mesher. - **neighbors** (*int*, default: `12`) — Number of nearest neighbours used by the weighted-PCA smoother at each point. - **samples** (*int*, default: `300`) — Number of points sampled to estimate the smoothing neighbourhood radius. - **forceManifold** (*bool*, default: `True`) — Ask the Alpha Shape mesher for a manifold result, dropping the facets that would violate it. - **separateShells** (*bool*, default: `False`) — Keep separate shells of the Alpha Shape mesher's output apart instead of merging them. ``` --- (filter-reconstruct-surface-by-screened-poisson)= ## Reconstruct Surface by Screened Poisson **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.screened_poisson Creates a watertight surface from an oriented point set. ```{py:function} ms.reconstruct_surface_by_screened_poisson(**params) :module: _meshlab Reconstructs a watertight surface from an oriented point set using the screened Poisson formulation. The implementation uses the original PoissonRecon code by Michael Kazhdan and Matthew Bolitho. **References:** - Michael Kazhdan, Hugues Hoppe. **Screened Poisson Surface Reconstruction**. *ACM Transactions on Graphics* (2013). [DOI](https://doi.org/10.1145/2487228.2487237) [Web](https://hhoppe.com/screenedpoisson.pdf) **Parameters:** - **visibleLayer** (*bool*, default: `False`) — Enabling this flag means that all the visible layers will be used for providing the points. - **preserveColor** (*bool*, default: `True`) — If enabled and input meshes have vertex colors, colors are propagated to the reconstructed surface. - **depth** (*int*, default: `8`) — This integer is the maximum depth of the tree that will be used for surface reconstruction. Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than 2^d x 2^d x 2^d. The default value for this parameter is 8. - **fullDepth** (*int*, default: `5`) — This integer specifies the depth beyond which the octree will be adapted. At coarser depths, the octree will be complete, containing all 2^d x 2^d x 2^d nodes. The default value for this parameter is 5. - **cgDepth** (*int*, default: `0`) — This integer is the depth up to which a conjugate-gradients solver will be used to solve the linear system. Beyond this depth, Gauss-Seidel relaxation will be used. The default value for this parameter is 0. - **scale** (*double*, default: `1.1`) — This floating point value specifies the ratio between the diameter of the cube used for reconstruction and the diameter of the samples' bounding cube. The default value is 1.1. - **samplesPerNode** (*double*, default: `1.5`) — This floating point value specifies the minimum number of sample points that should fall within an octree node as the octree construction is adapted to sampling density. For noise-free samples, small values in the range [1.0 - 5.0] can be used. For noisy samples, larger values in the range [15.0 - 20.0] may be needed to provide a smoother, noise-reduced reconstruction. The default value is 1.5. - **pointWeight** (*double*, default: `4.0`) — This floating point value specifies the importance that interpolation of the point samples is given in the formulation of the screened Poisson equation. The results of the original unscreened Poisson reconstruction can be obtained by setting this value to 0. The default value for this parameter is 4. - **iters** (*int*, default: `8`) — This integer value specifies the number of Gauss-Seidel relaxations to be performed at each level of the hierarchy. The default value for this parameter is 8. - **confidence** (*bool*, default: `False`) — Enabling this flag tells the reconstructor to use the quality as confidence information. This is done by scaling the unit normals with the quality values. When the flag is not enabled, all normals are normalized to have unit length prior to reconstruction. - **preClean** (*bool*, default: `False`) — Enabling this flag forces a cleaning pre-pass on the data, removing all unreferenced vertices or vertices with null normals. - **threads** (*int*, default: `@hardwareThreads`) — Maximum number of threads that the reconstruction algorithm can use. ``` --- (filter-reconstruct-surface-by-smooth-signed-distance)= ## Reconstruct Surface by Smooth Signed Distance **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.screened_poisson Creates a watertight surface using smooth signed distance reconstruction. ```{py:function} ms.reconstruct_surface_by_smooth_signed_distance(**params) :module: _meshlab This filter reconstructs a surface from an oriented point set using the SSD reconstruction formulation provided by the `PoissonRecon` code base. Compared to Screened Poisson, the SSD formulation exposes separate weights for zero-crossing, gradient, and bi-Laplacian terms, making it useful when you want more direct control over smoothness and interpolation. **Parameters:** - **visibleLayer** (*bool*, default: `False`) — Enabling this flag means that all the visible layers will be used for providing the points. - **preserveColor** (*bool*, default: `True`) — If enabled and input meshes have vertex colors, colors are propagated to the reconstructed surface. - **depth** (*int*, default: `8`) — This integer is the maximum depth of the tree that will be used for surface reconstruction. Running at depth d corresponds to solving on a voxel grid whose resolution is no larger than 2^d x 2^d x 2^d. The default value for this parameter is 8. - **fullDepth** (*int*, default: `5`) — The depth at which the sample values (color, normal) are directly interpolated into the octree rather than pulled up from coarser depths. Set to a larger value if you want more detailed correct interpolation, at the price of a higher per-sample memory consumption. - **baseDepth** (*int*, default: `0`) — This integer specifies the depth of the coarsest multigrid solve level. Larger values make the coarse solve finer and more expensive. - **scale** (*double*, default: `1.1`) — This floating point value specifies the ratio between the diameter of the cube used for reconstruction and the diameter of the samples' bounding cube. The default value is 1.1. - **samplesPerNode** (*double*, default: `1.5`) — This floating point value specifies the minimum number of sample points that should fall within a node as the tree construction is adapted to sampling density. The default value is 1.5. - **valueWeight** (*double*, default: `1.0`) — This floating point value specifies the weight associated with the zero-crossing term of the SSD energy. Larger values make the reconstruction interpolate the input points more strongly. - **gradientWeight** (*double*, default: `1.0`) — This floating point value specifies the weight associated with the gradient fitting term of the SSD energy. The value must be strictly positive. - **biLapWeight** (*double*, default: `1.0`) — This floating point value specifies the weight associated with the bi-Laplacian smoothing term of the SSD energy. Larger values produce smoother surfaces. The value must be strictly positive. - **iters** (*int*, default: `8`) — This integer value specifies the number of Gauss-Seidel relaxations to be performed at each level of the hierarchy. The default value is 8. - **exactInterpolation** (*bool*, default: `False`) — If enabled, the exact interpolation formulation is used when building the SSD system. - **nonLinearFit** (*bool*, default: `False`) — If enabled, the extracted iso-surface uses the non-linear fit. If disabled, the linear fit is used. - **nonManifold** (*bool*, default: `False`) — If enabled, the extractor does not force the output mesh to be manifold. - **cgAccuracy** (*double*, default: `0.001`) — This floating point value specifies the accuracy used by the conjugate gradients solver. Smaller values make the linear solve more accurate and more expensive. - **dataScale** (*double*, default: `32.0`) — This floating point value specifies the pull factor used by the hierarchical SSD formulation. The default value is 32. - **confidence** (*bool*, default: `False`) — Enabling this flag tells the reconstructor to use the quality as confidence information. This is done by scaling the unit normals with the quality values. When the flag is not enabled, all normals are normalized to have unit length prior to reconstruction. - **preClean** (*bool*, default: `False`) — Enabling this flag forces a cleaning pre-pass on the data, removing all unreferenced vertices or vertices with null normals. - **threads** (*int*, default: `@hardwareThreads`) — Maximum number of threads that the reconstruction algorithm can use. ``` --- (filter-reconstruct-surface-by-volumetric-merging)= ## Reconstruct Surface by Volumetric Merging **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.plymc A volumetric surface reconstruction algorithm that creates a mesh from all visible layers. ```{py:function} ms.reconstruct_surface_by_volumetric_merging(**params) :module: _meshlab Surface reconstruction algorithm using volumetric distance fields and Marching Cubes. All visible meshes/point clouds are used to build the volumetric field. Supports sub-volume splitting for very high resolution reconstructions, geodesic weighting for smooth blending of overlapping range maps, hole filling via volume dilation, and optional vertex splatting. **Parameters:** - **voxSize** (*double*, default: `0.01`) — The side length of each voxel. A percentage of the bounding box diagonal. - **subdiv** (*int*, default: `1`) — The level of recursive splitting (1 = no split, 3 = 3×3×3 subdivision producing 27 sub-meshes). - **geodesic** (*double*, default: `2.0`) — Weight each range map by geodesic distance from borders for smooth blending of overlaps. - **smoothNum** (*int*, default: `1`) — Number of volume Laplacian smoothing steps to clean out noisy borders. - **wideNum** (*int*, default: `3`) — How many voxels the field is expanded. Larger values fill more holes. - **mergeColor** (*bool*, default: `False`) — Splat vertices into the grid instead of rasterizing faces. Requires at least one sample per voxel. - **simplification** (*bool*, default: `False`) — Automatically simplify the mesh after reconstruction. - **normalSmooth** (*int*, default: `3`) — Face normal Laplacian iterations before voxelization. Helps with noisy borders. ``` --- (filter-reconstruct-surface-by-voronoi-filtering)= ## Reconstruct Surface by Voronoi Filtering **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.cgal Reconstruct a surface from an unoriented point cloud with the Amenta-Bern crust. ```{py:function} ms.reconstruct_surface_by_voronoi_filtering(**params) :module: _meshlab Reconstructs a surface from the current layer's vertices using **Voronoi filtering**, the crust algorithm of Amenta and Bern. It needs **no vertex normals**, which is what distinguishes it from the Poisson-family filters. How it works, in two Delaunay passes: 1. Triangulate the samples. For each sample the two *poles* are found — the Voronoi vertices of its cell farthest from it, one on each side. Poles approximate the medial axis, so they lie far from the surface. 2. Triangulate samples and poles together. A Delaunay triangle whose three corners are all samples cannot span the medial axis, so those triangles are the reconstructed surface. This is an *interpolating* reconstruction: every output vertex is one of the input points, and no new positions are invented. **Limitations**, inherent to the algorithm rather than this implementation: it assumes a **closed, well-sampled, noise-free** surface. Points lying on the convex hull have unbounded Voronoi cells and therefore no finite outer pole, so open boundaries stay ragged; noisy input scatters the poles and thins the crust. For scanned or noisy data prefer *Reconstruct Surface by Screened Poisson*. **Threshold** discards Voronoi vertices farther from their sample than that multiple of the bounding box diagonal, keeping near-degenerate cells from throwing a pole off to infinity. Built on CGAL's 3D Delaunay triangulation. Reference: Nina Amenta, Marshall Bern, **Surface Reconstruction by Voronoi Filtering**, Discrete & Computational Geometry 22(4), 1999. **Parameters:** - **threshold** (*double*, default: `10.0`) — Discard Voronoi vertices farther from their sample than this multiple of the bounding box diagonal. Guards against near-degenerate cells sending a pole to infinity. ``` --- (filter-trim-surface-by-scalar-isovalue)= ## Trim Surface by Scalar Isovalue **Categories:** `Creation/Reconstruction` **Plugin:** meshlab2.filter.screened_poisson Trims a reconstructed mesh using the scalar values stored on the vertices. ```{py:function} ms.trim_surface_by_scalar_isovalue(**params) :module: _meshlab This filter trims a reconstructed surface by cutting the mesh along an isovalue defined over the vertices. It is especially useful after Poisson-based reconstruction when the vertex quality stores the reconstruction density, allowing low-confidence regions to be removed. **Parameters:** - **trim** (*double*, default: `0.0`) — This floating point value specifies the trimming value. Faces whose scalar field is below this threshold are trimmed away; crossing faces are split along the threshold. - **islandAreaRatio** (*double*, default: `0.001`) — This floating point value specifies the relative area threshold used to detect small disconnected islands. Smaller components may be merged or removed according to the selected options. - **removeIslands** (*bool*, default: `False`) — If enabled, disconnected components whose area is below the island area ratio are removed instead of being preserved. - **polygonMesh** (*bool*, default: `False`) — The original tool can preserve polygonal output. MeshLab stores triangle meshes, so the result is always triangulated even when this option is enabled. ``` --- (filter-sample-mesh-elements)= ## Sample Mesh Elements **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Create a point set by subsampling mesh vertices, edges, or faces. ```{py:function} ms.sample_mesh_elements(**params) :module: _meshlab Create a new layer holding one sample per mesh element. **Number of samples** elements are drawn uniformly at random -- every element of the chosen kind is equally likely -- and one point is emitted for each: a **Vertex** contributes its own position, an **Edge** its midpoint, a **Face** its barycenter. Asking for at least as many samples as there are elements simply returns them all. Edge sampling ignores *faux* edges, the diagonals that triangulate a polygonal face, since those are not edges of the polygonal mesh and the wireframe does not draw them. Note that midpoints and barycenters lie slightly inside a curved surface, which is inherent to taking a single sample per element. To place several samples along each edge instead, in proportion to its length, use *Sample Surface by Stratified Triangles* with the **Sample Edges** strategy. **Parameters:** - **Sampling** (*enum*, default: `vertex`) — Choose which mesh elements are sampled. - **SampleNum** (*int*, default: `1000`) — How many elements to draw. Reaching or exceeding the element count returns every element. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the chosen subset of elements exactly reproducible. It has no effect when the requested number reaches the element count, since then every element is taken. ``` --- (filter-sample-offset-surface-recursively)= ## Sample Offset Surface Recursively **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Generate offset surface samples by recursively subdividing the bounding box. ```{py:function} ms.sample_offset_surface_recursively(**params) :module: _meshlab The bounding box is recursively partitioned in a octree style, center of bbox are considered, when the center is nearer to the surface than a given threshold it is projected on it. It works also for building offsetted samples. **Parameters:** - **CellSize** (*absperc*, default: `@bboxDiag01`) — Subdivision threshold. Smaller values generate denser samples. - **Offset** (*absperc*, default: `0.0`) — Offset distance applied to the projected samples. ``` --- (filter-sample-surface-by-monte-carlo)= ## Sample Surface by Monte Carlo **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Create a random point cloud from the current surface. ```{py:function} ms.sample_surface_by_monte_carlo(**params) :module: _meshlab Create a new layer populated with a point sampling of the current mesh; samples are generated in a randomly uniform way, or with a distribution biased by the per-vertex quality values of the mesh. **Parameters:** - **SampleNum** (*int*, default: `1000`) — Desired number of generated samples. - **Weighted** (*bool*, default: `False`) — Use per-vertex quality to bias the sampling density. - **PerFaceNormal** (*bool*, default: `False`) — Store the face normal on each sample instead of interpolated vertex normals. - **RadiusVariance** (*double*, default: `1.0`) — When quality-weighted sampling is used, the sampling radius may vary between r/var and r*var. - **ExactNum** (*bool*, default: `True`) — If enabled, try to generate exactly the requested number of samples. - **EdgeSampling** (*bool*, default: `False`) — Restrict sampling to mesh edges. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the sample positions exactly reproducible. ``` --- (filter-sample-surface-by-poisson-disk)= ## Sample Surface by Poisson Disk **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Generate well-spaced samples over a surface or point cloud. ```{py:function} ms.sample_surface_by_poisson_disk(**params) :module: _meshlab Create a new layer populated with a point sampling of the current mesh;samples are generated according to a Poisson-disk distribution, using the algorithm described in:
'Efficient and Flexible Sampling with Blue Noise Properties of Triangular Meshes'
Massimiliano Corsini, Paolo Cignoni, Roberto Scopigno
IEEE TVCG 2012 **Parameters:** - **SampleNum** (*int*, default: `1000`) — Desired number of samples. Ignored if an explicit radius is provided. - **Radius** (*absperc*, default: `0.0`) — If non-zero, overrides the sample number and uses this radius directly. - **MontecarloRate** (*int*, default: `20`) — Oversampling factor used to generate the initial Montecarlo candidates. - **SaveMontecarlo** (*bool*, default: `False`) — Also create a layer containing the raw Montecarlo candidates. - **ApproximateGeodesicDistance** (*bool*, default: `False`) — Use a normal-aware approximate geodesic distance during Poisson pruning. - **Subsample** (*bool*, default: `False`) — Use the original vertices as the candidate set instead of generating Montecarlo samples. - **RefineFlag** (*bool*, default: `False`) — Use an existing sample layer as pre-generated seeds that are refined further. - **RefineMesh** (*mesh*, default: `@currentMeshIndex`) — Layer used as the initial sample set when Refine Existing Samples is enabled. - **BestSampleFlag** (*bool*, default: `True`) — Use a heuristic to improve the maximality of the chosen sample set. - **BestSamplePool** (*int*, default: `10`) — Number of candidate attempts used when the best-sample heuristic is enabled. - **ExactNumFlag** (*bool*, default: `False`) — Search for a radius that matches the requested number of samples within the given tolerance. - **ExactNumTolerance** (*double*, default: `0.005`) — Tolerance used by precise sample count search, expressed as a fraction of the requested sample count. - **RadiusVariance** (*double*, default: `1.0`) — Allow the Poisson disk radius to vary between r and r*var using vertex quality as a density bias. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the generated sample set exactly reproducible. ``` --- (filter-sample-surface-by-stratified-triangles)= ## Sample Surface by Stratified Triangles **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Generate structured samples over the triangle mesh. ```{py:function} ms.sample_surface_by_stratified_triangles(**params) :module: _meshlab Create a new layer populated with a point sampling of the current mesh; to generate multiple samples inside a triangle each triangle is subdivided according to various stratified strategies. Distribution is often biased by triangle shape. **Parameters:** - **SampleNum** (*int*, default: `5000`) — Desired number of generated samples. - **Sampling** (*enum*, default: `similar_triangle`) — Choose the structured sampling strategy. - **Random** (*bool*, default: `False`) — For each virtual cell, choose a random sample instead of the midpoint. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the sample positions inside each face exactly reproducible. ``` --- (filter-sample-surface-by-voronoi-relaxation)= ## Sample Surface by Voronoi Relaxation **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.voronoi Sample a surface and relax the samples with a geodesic Voronoi/Lloyd process. ```{py:function} ms.sample_surface_by_voronoi_relaxation(**params) :module: _meshlab Compute a point sampling over the current mesh and perform Lloyd relaxation on the surface. The selected vertices of the current mesh become the final seeds, and two additional layers are produced: a Voronoi region mesh and a polyline representation of the Voronoi boundaries. **Parameters:** - **iterNum** (*int*, default: `10`) — Number of Lloyd relaxation iterations. - **sampleNum** (*int*, default: `10`) — Target number of surface samples. - **radiusVariance** (*double*, default: `1.0`) — For quality-weighted distance, the metric varies between 1/x and x according to per-vertex quality. - **colorStrategy** (*enum*, default: `seed_distance`) — How the current mesh should be colored during Voronoi relaxation. - **distanceType** (*enum*, default: `euclidean`) — Metric used by the Voronoi relaxation. - **preprocessFlag** (*bool*, default: `False`) — Refine the current mesh before relaxation so the supporting triangulation is dense enough for the requested sample count. - **refineFactor** (*int*, default: `10`) — Controls how much the mesh is refined during preprocessing. Larger values create a denser supporting triangulation. - **perturbProbability** (*double*, default: `0.0`) — Probability that each seed is slightly perturbed during restricted relaxation. - **perturbAmount** (*double*, default: `0.001`) — Perturbation amplitude as a fraction of the bounding-box diagonal. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the seed placement and relaxation exactly reproducible. - **relaxType** (*enum*, default: `squared_distance`) — How a new seed is chosen inside each Voronoi region. ``` --- (filter-sample-texels)= ## Sample Texels **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Create one point sample per covered texel in texture space. ```{py:function} ms.sample_texels(**params) :module: _meshlab Create a new layer with a point sampling of the current mesh, a sample for each texel of the mesh is generated **Parameters:** - **TextureW** (*int*, default: `512`) — Sampling resolution in texels. If 0 and Recover Color is enabled, use the current texture width. - **TextureH** (*int*, default: `512`) — Sampling resolution in texels. If 0 and Recover Color is enabled, use the current texture height. - **TextureSpace** (*bool*, default: `False`) — Place output points in UV space instead of the original mesh space. - **RecoverColor** (*bool*, default: `True`) — Sample the current texture image and store its colors on the generated points. - **sourceTexture** (*textureref*, default: `0`) — When Recover Color is enabled, choose which associated texture to sample. Automatic uses each face's per-wedge texture slot assignment. ``` --- (filter-sample-vertices-by-clustering)= ## Sample Vertices by Clustering **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.sampling Cluster the point set into grid cells and keep one representative per cell. ```{py:function} ms.sample_vertices_by_clustering(**params) :module: _meshlab Create a new layer populated with a subsampling of the vertices of the current mesh; the subsampling is driven by a simple one-per-gridded cell strategy. **Parameters:** - **Threshold** (*absperc*, default: `@bboxDiag01`) — Size of the clustering grid cell. Smaller cells preserve more detail. - **Sampling** (*enum*, default: `closest_to_center`) — Choose how each cell representative is computed. ``` --- (filter-sample-volume)= ## Sample Volume **Categories:** `Creation/Sampling` **Plugin:** meshlab2.filter.voronoi Generate diagnostic Monte Carlo and surface samples inside a watertight mesh. ```{py:function} ms.sample_volume(**params) :module: _meshlab Compute a volumetric Monte Carlo sampling of a watertight mesh and add diagnostic sample layers. This follows the original MeshLab filter behavior: the Poisson-filtered volume point set is not emitted yet by the upstream implementation. **Parameters:** - **sampleSurfRadius** (*absperc*, default: `@bboxDiag01`) — Surface Poisson radius used as an acceleration structure for signed-distance queries. - **sampleVolNum** (*int*, default: `200000`) — Number of volumetric Monte Carlo samples to scatter inside the mesh. - **poissonFiltering** (*bool*, default: `True`) — Preserve the original MeshLab option. The current upstream implementation does not emit the filtered volume layer. - **poissonRadius** (*absperc*, default: `@bboxDiag01`) — Radius used by the internal Poisson pruning stage. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the generated sample set exactly reproducible. ``` --- (filter-export-cameras-from-visible-rasters)= ## Export Cameras from Visible Rasters **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.layer Export the cameras of the visible raster layers to a file. ```{py:function} ms.export_cameras_from_visible_rasters(**params) :module: _meshlab Exports the cameras of all visible raster layers as MeshLab-compatible VCGCamera XML entries. **Parameters:** - **camera_file** (*file_save*, default: ``) — Destination XML file for the active raster cameras. ``` --- (filter-import-cameras-to-visible-rasters)= ## Import Cameras to Visible Rasters **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.layer Import cameras from a file into the visible raster layers. ```{py:function} ms.import_cameras_to_visible_rasters(**params) :module: _meshlab Imports MeshLab-compatible VCGCamera XML entries and assigns them, in file order, to visible raster layers. **Parameters:** - **camera_file** (*file_open*, default: ``) — XML file containing VCGCamera entries for the active raster layers. ``` --- (filter-rotate-cameras)= ## Rotate Cameras **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Rotate the camera, or all the cameras of the project. ```{py:function} ms.rotate_cameras(**params) :module: _meshlab Rotate the camera, or all the cameras of the project. The selected raster is the reference if viewpoint rotation is selected. **Parameters:** - **camera** (*enum*, default: `raster`) — Choose the camera to rotate. - **rotAxis** (*enum*, default: `x`) — Axis of rotation. - **rotCenter** (*enum*, default: `origin`) — Center of rotation. - **angle** (*double*, default: `0.0`) — Angle of rotation in degrees. - **customAxis** (*point3f*, default: `[1.0, 0.0, 0.0]`) — Rotation axis used only if 'custom axis' option is chosen. - **customCenter** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Rotation center used only if 'custom point' option is chosen. - **toallRaster** (*bool*, default: `False`) — Apply the same rotation to all active raster layers. Used only if 'Raster Camera' is selected. - **toall** (*bool*, default: `False`) — Apply the same rotation to all visible raster and mesh layers. ``` --- (filter-scale-cameras)= ## Scale Cameras **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Scale the camera, or all the cameras of the project. ```{py:function} ms.scale_cameras(**params) :module: _meshlab **Parameters:** - **camera** (*enum*, default: `raster`) — Choose the camera to scale. - **scaleCenter** (*enum*, default: `origin`) — Center of scaling. - **customCenter** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Scaling center used only if 'custom point' option is chosen. - **scale** (*double*, default: `1.0`) — The scale factor to apply to the camera. - **toallRaster** (*bool*, default: `False`) — Apply the same scaling to all active raster layers. - **toall** (*bool*, default: `False`) — Apply the same scaling to all visible raster and mesh layers. ``` --- (filter-set-camera-from-direction)= ## Set Camera from Direction **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Position the camera looking toward a target from an explicit direction. ```{py:function} ms.set_camera_from_direction(**params) :module: _meshlab Compute a camera that looks toward a target (mesh bounding box center or current raster) from an explicit world-space direction. The camera is positioned so that the target fills the viewport. The resulting camera state JSON is written to the log and applied to the current raster if one is active. **Parameters:** - **direction** (*point3f*, default: `[0.0, 0.0, -1.0]`) — World-space direction from camera to target. - **target** (*enum*, default: `mesh_bbox`) — What the camera should look at. - **marginFactor** (*double*, default: `1.0`) — Viewport margin multiplier. 1.0 = tight fit, 2.0 = zoom out. - **fovYDeg** (*double*, default: `45.0`) — Vertical field of view in degrees. ``` --- (filter-set-camera-to-view-selection)= ## Set Camera to View Selection **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Position the camera to frame the current selection, looking along the average selected normal direction. ```{py:function} ms.set_camera_to_view_selection(**params) :module: _meshlab Compute a camera that frames the current selection in the viewport. The camera is positioned so that the selected faces/vertices fill the viewport, looking along the average face/vertex normal direction of the selection. The resulting camera state JSON is written to the log and applied to the current raster if one is active. **Parameters:** - **marginFactor** (*double*, default: `1.0`) — Viewport margin multiplier. 1.0 = tight fit, 1.5 = some padding. - **fovYDeg** (*double*, default: `45.0`) — Vertical field of view in degrees. - **useFaceNormals** (*bool*, default: `True`) — Average face normals to determine the view direction. If no faces are selected, falls back to vertex normals. ``` --- (filter-set-mesh-camera)= ## Set Mesh Camera **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Set the camera parameters for the current mesh. ```{py:function} ms.set_mesh_camera(**params) :module: _meshlab Set camera parameters for the current mesh. The camera is stored and used by other filters such as 'Vertex Quality from Camera'. **Parameters:** - **viewpoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Camera position in world space. - **direction** (*point3f*, default: `[0.0, 0.0, -1.0]`) — Camera viewing direction. - **focalMm** (*double*, default: `50.0`) — Camera focal length in millimeters. - **cameraType** (*enum*, default: `perspective`) — Type of camera projection. ``` --- (filter-set-raster-camera)= ## Set Raster Camera **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Set the camera parameters for the current raster. ```{py:function} ms.set_raster_camera(**params) :module: _meshlab Set camera parameters for the current raster. The viewport is automatically recalculated from the raster image dimensions. **Parameters:** - **viewpoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Camera position in world space. - **direction** (*point3f*, default: `[0.0, 0.0, -1.0]`) — Camera viewing direction. - **focalMm** (*double*, default: `50.0`) — Camera focal length in millimeters. - **sensorWidthMm** (*double*, default: `36.0`) — Camera sensor width in millimeters. ``` --- (filter-transform-camera-extrinsics)= ## Transform Camera Extrinsics **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Apply a similarity transformation to the camera extrinsics. ```{py:function} ms.transform_camera_extrinsics(**params) :module: _meshlab Apply a similarity transformation to the camera extrinsics, or all the cameras of the project. **Parameters:** - **camera** (*enum*, default: `raster`) — Choose the camera to transform. - **behaviour** (*enum*, default: `apply`) — How the transformation matrix is interpreted. - **rotationDeg** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Rotation angles around X, Y, Z axes in degrees. - **translation** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Translation vector. - **uniformScale** (*double*, default: `1.0`) — Uniform scale factor. - **toallRaster** (*bool*, default: `False`) — Apply the same transformation to all active raster layers. - **toall** (*bool*, default: `False`) — Apply the same transformation to all visible raster and mesh layers. ``` --- (filter-translate-cameras)= ## Translate Cameras **Categories:** `Document/Camera` **Plugin:** meshlab2.filter.camera Translate the camera, or all the cameras of the project. ```{py:function} ms.translate_cameras(**params) :module: _meshlab **Parameters:** - **camera** (*enum*, default: `raster`) — Choose the camera to translate. - **tx** (*double*, default: `0.0`) — Absolute translation amount along the X axis. - **ty** (*double*, default: `0.0`) — Absolute translation amount along the Y axis. - **tz** (*double*, default: `0.0`) — Absolute translation amount along the Z axis. - **centerFlag** (*bool*, default: `False`) — If selected, the camera viewpoint is translated to the origin. - **toallRaster** (*bool*, default: `False`) — Apply the same translation to all active raster layers. - **toall** (*bool*, default: `False`) — Apply the same translation to all visible raster and mesh layers. ``` --- (filter-duplicate-current-layer)= ## Duplicate Current Layer **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Create a new layer containing the same model as the current one. ```{py:function} ms.duplicate_current_layer(**params) :module: _meshlab This filter has no parameters. ``` --- (filter-extract-selected-faces)= ## Extract Selected Faces **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Extract the selected faces into a new mesh layer, moving or copying them. ```{py:function} ms.extract_selected_faces(**params) :module: _meshlab Selected faces are moved (or duplicated) in a new layer. Warning! per-vertex and per-face user defined attributes will not be transferred. **Parameters:** - **DeleteOriginal** (*bool*, default: `True`) — Deletes the original selected faces, thus splitting the mesh among layers. If false, the selected faces are duplicated in the new layer. ``` --- (filter-extract-selected-vertices)= ## Extract Selected Vertices **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Extract the selected vertices into a new mesh layer, moving or copying them. ```{py:function} ms.extract_selected_vertices(**params) :module: _meshlab Selected vertices are moved (or duplicated) in a new layer. Warning! per-vertex user defined attributes will not be transferred. **Parameters:** - **DeleteOriginal** (*bool*, default: `True`) — Deletes the original selected vertices, thus splitting the mesh among layers. If false, the selected vertices are duplicated in the new layer. ``` --- (filter-merge-visible-layers)= ## Merge Visible Layers **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Merge all layers, or only the visible ones, into a single new mesh. Also known as flattening. ```{py:function} ms.merge_visible_layers(**params) :module: _meshlab Merge all layers, or only the visible ones, into a single new mesh. Also known as flattening.
Transformations are preserved. Existing layers can be optionally deleted. **Parameters:** - **MergeVisible** (*bool*, default: `True`) — If true, flatten only visible layers, otherwise all layers are used. - **DeleteLayer** (*bool*, default: `True`) — Delete all the layers used as source in flattening. If all layers are visible only a single layer will remain after the invocation of this filter. - **MergeVertices** (*bool*, default: `True`) — Merge the vertices that are duplicated among different layers. Very useful when the layers are spliced portions of a single big mesh. - **AlsoUnreferenced** (*bool*, default: `True`) — Do not discard unreferenced vertices from source layers. Necessary for point-cloud layers. ``` --- (filter-remove-current-mesh-layer)= ## Remove Current Mesh Layer **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Remove the current mesh layer. ```{py:function} ms.remove_current_mesh_layer(**params) :module: _meshlab The current mesh layer is deleted. This filter has no parameters. ``` --- (filter-remove-current-raster)= ## Remove Current Raster **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Remove the current raster layer. ```{py:function} ms.remove_current_raster(**params) :module: _meshlab The current raster layer is deleted. This filter has no parameters. ``` --- (filter-remove-hidden-mesh-layers)= ## Remove Hidden Mesh Layers **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Remove every mesh layer that is currently hidden. ```{py:function} ms.remove_hidden_mesh_layers(**params) :module: _meshlab All the non visible mesh layers are deleted. This filter has no parameters. ``` --- (filter-remove-hidden-rasters)= ## Remove Hidden Rasters **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Remove every raster layer that is currently hidden. ```{py:function} ms.remove_hidden_rasters(**params) :module: _meshlab All non-active raster layers are deleted. As in MeshLab, active rasters are the visible raster layers. This filter has no parameters. ``` --- (filter-rename-current-mesh-layer)= ## Rename Current Mesh Layer **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Explicitly change the label shown for the current mesh. ```{py:function} ms.rename_current_mesh_layer(**params) :module: _meshlab Explicitly change the label shown for a given mesh. **Parameters:** - **newName** (*string*, default: ``) — New label for the mesh. ``` --- (filter-rename-current-raster)= ## Rename Current Raster **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Explicitly change the label shown for the current raster. ```{py:function} ms.rename_current_raster(**params) :module: _meshlab **Parameters:** - **newName** (*string*, default: ``) — New label for the raster. ``` --- (filter-split-into-connected-components)= ## Split into Connected Components **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.layer Split the current layer into one layer per connected component. ```{py:function} ms.split_into_connected_components(**params) :module: _meshlab Split current layer into many layers, one for each connected component. **Parameters:** - **delete_source_mesh** (*bool*, default: `False`) — Deletes the source mesh after all the connected component meshes are generated. ``` --- (filter-split-into-connected-components-trueform)= ## Split into Connected Components (TrueForm) **Categories:** `Document/Layer` **Plugin:** meshlab2.filter.trueform Split a layer into one layer per connected surface, computed in parallel. ```{py:function} ms.split_into_connected_components_trueform(**params) :module: _meshlab Splits the layer into one new layer per connected surface, exactly as *Split into Connected Components* does — this is the same operation through TrueForm, which labels the faces in parallel and emits the components in one pass. On a million-face mesh that is the difference worth having; on a small one the two are indistinguishable. **Connectivity** chooses what counts as joining two faces, and all three standards are one call each. | Setting | Two faces are joined when | |---|---| | Manifold edges | a chain of shared edges links them, counting only edges that exactly two faces use | | Any shared edge | a chain of shared edges links them, however many faces use each | | Any shared vertex | a chain of shared vertices links them | The default separates at seams: a **boundary** edge joins nothing, and neither does an edge three or more faces meet along, so sheets passing through a shared seam come back as separate layers. *Any shared edge* walks through such a seam and reproduces what *Split into Connected Components* does there; *any shared vertex* additionally joins pieces that only touch at a single point. On a manifold mesh all three agree. Weld first with *Remove Duplicate Vertices (TrueForm)* if a layer arrived as a triangle soup: unwelded faces share nothing at all, and every one of them is its own component under any setting. The source layer is kept, and the layer matrix is baked into the results. Reads TrueForm's `make_manifold_edge_connected_component_labels`, `make_edge_connected_component_labels` or `make_vertex_connected_component_labels`, then `split_into_components`. **Parameters:** - **connectivity** (*enum*, default: `manifold`) — What counts as joining two faces. Manifold edges keep sheets that meet at a seam apart; any shared edge walks through the seam; any shared vertex also joins pieces that only touch at a point. ``` --- (filter-render-from-render-state-json)= ## Render from Render-State JSON **Categories:** `Document/Render` **Plugin:** meshlab2.filter.layer Run a deterministic offscreen render from a serialized render-state JSON payload. ```{py:function} ms.render_from_render_state_json(**params) :module: _meshlab Applies a render-state JSON payload to the active view, renders an offscreen snapshot, and optionally saves it as PNG and/or adds it as a raster layer. Useful for reproducible filter-driven rendering workflows. **Parameters:** - **camera_state** (*camerastate*, default: ``) — Camera-state JSON payload (kind = MeshLab.CameraState). Source can be Text, File, or Current View. - **render_state** (*renderstate*, default: ``) — Render-state JSON payload (kind = MeshLab.RenderState). Source can be Text, File, or Current View. - **output_width** (*int*, default: `0`) — Output width in pixels. Use 0 to keep the current active view width. - **output_height** (*int*, default: `0`) — Output height in pixels. Use 0 to keep the current active view height. - **save_png_path** (*file_save*, default: ``) — Optional output PNG path. If empty, no PNG file is written. - **add_as_raster** (*bool*, default: `True`) — If true, adds the rendered snapshot as a new raster layer in the document. - **raster_name** (*string*, default: `Programmatic Render`) — Name used when adding the snapshot as a raster layer. ``` --- (filter-align-by-bounding-box-trueform)= ## Align by Bounding Box (TrueForm) **Categories:** `Geometry/Alignment` **Plugin:** meshlab2.filter.trueform Coarsely align one layer to another by matching their oriented bounding boxes. ```{py:function} ms.align_by_bounding_box_trueform(**params) :module: _meshlab Aligns the source layer to the reference by fitting their **oriented bounding boxes**. It needs no initial guess and no correspondences, and it is fast, which makes it the natural first step before ICP — *Align by ICP* can run it for you. An oriented bounding box is only defined up to 180-degree flips about its axes, so the fit is ambiguous in principle. TrueForm resolves this by testing the candidate orientations against a spatial index of the reference and keeping the best. The result is written to the source layer's **matrix**; vertex coordinates are not touched. Implemented with TrueForm's `fit_obb_alignment`. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer that is moved. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The layer that stays put. ``` --- (filter-align-by-icp-trueform)= ## Align by ICP (TrueForm) **Categories:** `Geometry/Alignment` **Plugin:** meshlab2.filter.trueform Align one layer to another with iterative closest point, point-to-point or point-to-plane. ```{py:function} ms.align_by_icp_trueform(**params) :module: _meshlab Refines the alignment of the source layer onto the reference by **iterative closest point**. **Metric** chooses the error being minimised: - *Point to point* — the classic formulation. Robust, but converges slowly across flat regions where many correspondences are nearly equivalent. - *Point to plane* — measures each correspondence along the reference's surface normal, so the source can slide freely along a surface. It converges in far fewer iterations on smooth geometry, and is the better default when the reference has reliable normals. ICP only refines **locally**: from a poor starting position it converges confidently to the wrong answer rather than failing. **Coarse Initialization** therefore runs *Align by Bounding Box (TrueForm)* first, which is usually enough to land in the right basin. **Samples** subsamples the source each iteration, which is what keeps large clouds tractable; 0 uses every point. **Outlier Proportion** discards that fraction of the worst correspondences each iteration, which matters when the two layers only partly overlap. The reported **Chamfer residual** is the mean one-way distance after alignment — useful for comparing runs. The result is written to the source layer's **matrix**; vertex coordinates are not touched. Implemented with TrueForm's `fit_icp_alignment`. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer that is moved. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The layer that stays put. - **metric** (*enum*, default: `point_to_plane`) — Point to plane converges faster on smooth surfaces; point to point is safer when the reference normals are unreliable. - **coarseInit** (*bool*, default: `True`) — Run a bounding-box alignment first. Leave on unless the layers are already roughly registered. - **maxIterations** (*int*, default: `50`) — Upper bound on ICP iterations. - **samples** (*int*, default: `1000`) — Source points sampled per iteration. 0 uses all of them, which is slower but deterministic. - **minImprovement** (*double*, default: `0.001`) — Stop once the error improves by less than this fraction between iterations. - **outlierProportion** (*double*, default: `0.0`) — Fraction of the worst correspondences rejected each iteration. Raise it when the two layers only partly overlap. ``` --- (filter-align-by-icp-vcglib)= ## Align by ICP (vcglib) **Categories:** `Geometry/Alignment` **Plugin:** meshlab2.filter.icp Compute an ICP transform that aligns one mesh layer to another. ```{py:function} ms.align_by_icp_vcglib(**params) :module: _meshlab Perform Iterative Closest Point alignment between a fixed reference layer and a moving source layer. The source layer transform is updated; vertex coordinates are not baked. Existing layer transforms are used as the initial pose, so the alignment follows what is visible in the 3D view. **References:** - Paul J. Besl, Neil D. McKay. **A Method for Registration of 3-D Shapes**. *IEEE Transactions on Pattern Analysis and Machine Intelligence* (1992). [DOI](https://doi.org/10.1109/34.121791) **Parameters:** - **ReferenceMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh kept fixed during ICP. - **SourceMesh** (*mesh*, default: `@otherMeshIndex`) — The mesh whose transform will be updated to match the reference. - **SampleNum** (*int*, default: `2000`) — Number of source samples used at each ICP iteration. - **MinDistAbs** (*double*, default: `10.0`) — Initial maximum correspondence distance. Only source samples nearer than this value are used. - **TrgDistAbs** (*double*, default: `0.005`) — ICP stops when the median sample distance goes below this value. - **MaxIterNum** (*int*, default: `75`) — Maximum number of ICP iterations. - **SampleMode** (*bool*, default: `True`) — Distribute samples uniformly with respect to normal directions instead of spatial random sampling. - **ReduceFactorPerc** (*double*, default: `0.8`) — Percentile used to reduce the maximum correspondence distance at each iteration. - **PassHiFilter** (*double*, default: `0.75`) — Discard samples farther than this percentile of the current correspondence distances. - **MatchMode** (*bool*, default: `True`) — If enabled, ICP solves only rotations and translations. If disabled, similarity matching may include scale. - **UseVertexOnly** (*bool*, default: `False`) — Use closest vertices instead of closest points on faces. This is automatically used for point clouds. - **MaxAngleDeg** (*double*, default: `45.0`) — Maximum angle, in degrees, between source and reference normals for accepted correspondences. - **MinPointNum** (*int*, default: `30`) — Minimum number of accepted point pairs required for an ICP iteration to be valid. - **SaveLastIteration** (*bool*, default: `False`) — Create two diagnostic point layers containing the last accepted source samples and their reference correspondences. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the sub-sampling of the moving mesh exactly reproducible. ``` --- (filter-align-meshes-globally)= ## Align Meshes Globally **Categories:** `Geometry/Alignment` **Plugin:** meshlab2.filter.icp Globally align overlapping mesh layers using pairwise ICP arcs. ```{py:function} ms.align_meshes_globally(**params) :module: _meshlab Build an overlap graph among the selected document layers, run ICP on sufficiently overlapping layer pairs, then solve a global alignment. The chosen base mesh remains fixed and the other layer transforms are updated without baking coordinates. **References:** - Kari Pulli. **Multiview Registration for Large Data Sets**. *Proceedings of the 2nd International Conference on 3-D Digital Imaging and Modeling (3DIM)* (1999). [Web](https://graphics.stanford.edu/papers/pulli-3dim99/3dim99.pdf) **Parameters:** - **BaseMesh** (*mesh*, default: `@currentMeshIndex`) — The layer that remains fixed while the other aligned layers are moved. - **OnlyVisibleMeshes** (*bool*, default: `False`) — If enabled, align only visible layers. The base mesh must be visible. - **OGSize** (*int*, default: `50000`) — Resolution budget used to detect overlapping mesh pairs. - **arcThreshold** (*double*, default: `0.3`) — Only mesh pairs with normalized overlap above this threshold become ICP arcs. - **recalcThreshold** (*double*, default: `0.1`) — Fraction of existing high-error arcs to recompute during iterative global alignment. This port computes arcs once, so the value is retained for MeshLab parameter compatibility. - **SampleNum** (*int*, default: `2000`) — Number of source samples used for each pairwise ICP arc. - **MinDistAbs** (*double*, default: `10.0`) — Initial maximum correspondence distance. - **TrgDistAbs** (*double*, default: `0.005`) — ICP stop distance for each pairwise arc. - **MaxIterNum** (*int*, default: `75`) — Maximum number of ICP iterations for each pairwise arc. - **SampleMode** (*bool*, default: `True`) — Distribute samples uniformly with respect to normal directions. - **ReduceFactorPerc** (*double*, default: `0.8`) — Percentile used to reduce correspondence distance. - **PassHiFilter** (*double*, default: `0.75`) — Discard samples farther than this percentile. - **MatchMode** (*bool*, default: `True`) — If enabled, pairwise and global alignment use rigid transforms. - **UseVertexOnly** (*bool*, default: `False`) — Use closest vertices instead of closest points on faces. - **MaxAngleDeg** (*double*, default: `45.0`) — Maximum accepted normal angle in degrees. - **MinPointNum** (*int*, default: `30`) — Minimum number of matched point pairs required for a valid pairwise ICP arc. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the sub-sampling of each aligned pair exactly reproducible. ``` --- (filter-align-to-corresponding-points-trueform)= ## Align to Corresponding Points (TrueForm) **Categories:** `Geometry/Alignment` **Plugin:** meshlab2.filter.trueform Align two layers whose vertices already correspond one to one, optionally solving for scale. ```{py:function} ms.align_to_corresponding_points_trueform(**params) :module: _meshlab Computes the transformation that best maps the source layer's vertices onto the reference's, assuming the two are already in **one-to-one correspondence**: same number of live vertices, in matching order. This is the Procrustes (Kabsch) fit. Use it when the correspondence is known by construction — two states of the same mesh, a mesh and its deformed copy, or point sets you have paired yourself. When the correspondence is unknown, use *Align by ICP* instead, which searches for it. **Allow Uniform Scale** is the reason to reach for this filter over ICP: with correspondences given, scale can be solved for as well as rotation and translation, which no ICP variant here does. Leave it off for a rigid fit. The result is written to the source layer's **matrix**; vertex coordinates are not touched. Implemented with TrueForm's `fit_rigid_alignment` and `fit_similarity_alignment`. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer that is moved. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The layer that stays put. - **allowScale** (*bool*, default: `False`) — Also solve for a single scale factor. Only possible because the correspondences are given rather than searched for. ``` --- (filter-compute-vertex-coordinates-by-expression)= ## Compute Vertex Coordinates by Expression **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.expression Computes new per-vertex coordinates from expressions. ```{py:function} ms.compute_vertex_coordinates_by_expression(**params) :module: _meshlab Geometric function using muparser lib to generate new Coord
You can change x,y,z for every vertex according to the function specified.
**Parameters:** - **x** (*string*, default: `x`) — Expression for X output. - **y** (*string*, default: `y`) — Expression for Y output. - **z** (*string*, default: `sin(x+y)`) — Expression for Z output. - **a** (*string*, default: `1`) — Expression for alpha channel (ignored for geometry). - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-displace-vertices-by-fractal-brownian-motion)= ## Displace Vertices by Fractal Brownian Motion **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Displace vertices along their normals using fractal Brownian motion. ```{py:function} ms.displace_vertices_by_fractal_brownian_motion(**params) :module: _meshlab Evaluates fractal Brownian motion (fBM) in normalized object space and displaces each vertex along a smoothed normal. The noise is the weighted sum $$N(\mathbf{x})=\sum_{i=0}^{n-1} L^{-Hi}\,P(L^i\mathbf{x}),$$ where $P$ is VCGLib's three-dimensional Perlin noise, $n$ is the octave count, $L$ is lacunarity, and $H$ is the fractal increment. Lower $H$ retains more high-frequency detail. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **References:** - David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley. **Texturing and Modeling: A Procedural Approach** (2002). **Parameters:** - **maxHeight** (*absperc*, default: `@bboxDiag01`) — Maximum positive displacement, relative to the mesh bounding-box diagonal. - **scale** (*absperc*, default: `@bboxDiag`) — Spatial size of the base noise features; smaller values produce finer detail. - **octaves** (*int*, default: `10`) — Number of Perlin-noise frequency bands. - **lacunarity** (*double*, default: `2.0`) — Frequency multiplier between consecutive octaves. - **fractalIncrement** (*double*, default: `1.2`) — Exponent controlling the spectral weight of higher frequencies. - **seed** (*double*, default: `1.0`) — Translation of the noise domain; changing it produces another morphology. - **normalSmoothingSteps** (*int*, default: `5`) — Laplacian smoothing iterations applied to normals before displacement. ``` --- (filter-displace-vertices-by-heterogeneous-multifractal-noise)= ## Displace Vertices by Heterogeneous Multifractal Noise **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Displace vertices using elevation-dependent heterogeneous multifractal noise. ```{py:function} ms.displace_vertices_by_heterogeneous_multifractal_noise(**params) :module: _meshlab Evaluates a heterogeneous multifractal whose successive increments are modulated by the accumulated signal. This makes high-frequency detail depend on the local elevation already produced by lower octaves, yielding spatially varying roughness rather than a stationary noise field. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **References:** - David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley. **Texturing and Modeling: A Procedural Approach** (2002). **Parameters:** - **maxHeight** (*absperc*, default: `@bboxDiag01`) — Maximum positive displacement, relative to the mesh bounding-box diagonal. - **scale** (*absperc*, default: `@bboxDiag`) — Spatial size of the base noise features; smaller values produce finer detail. - **octaves** (*int*, default: `8`) — Number of Perlin-noise frequency bands. - **lacunarity** (*double*, default: `3.0`) — Frequency multiplier between consecutive octaves. - **fractalIncrement** (*double*, default: `0.9`) — Exponent controlling the spectral weight of higher frequencies. - **offset** (*double*, default: `0.4`) — Bias controlling the strength of multifractal modulation. - **seed** (*double*, default: `1.0`) — Translation of the noise domain; changing it produces another morphology. - **normalSmoothingSteps** (*int*, default: `5`) — Laplacian smoothing iterations applied to normals before displacement. ``` --- (filter-displace-vertices-by-hybrid-multifractal-noise)= ## Displace Vertices by Hybrid Multifractal Noise **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Displace vertices using signal-weighted hybrid multifractal noise. ```{py:function} ms.displace_vertices_by_hybrid_multifractal_noise(**params) :module: _meshlab Evaluates hybrid multifractal noise, where each octave controls how strongly the following octave contributes. The feedback is clamped to avoid unbounded amplification, producing terrain-like regions with locally varying roughness. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **References:** - David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley. **Texturing and Modeling: A Procedural Approach** (2002). **Parameters:** - **maxHeight** (*absperc*, default: `@bboxDiag01`) — Maximum positive displacement, relative to the mesh bounding-box diagonal. - **scale** (*absperc*, default: `@bboxDiag`) — Spatial size of the base noise features; smaller values produce finer detail. - **octaves** (*int*, default: `8`) — Number of Perlin-noise frequency bands. - **lacunarity** (*double*, default: `4.0`) — Frequency multiplier between consecutive octaves. - **fractalIncrement** (*double*, default: `0.1`) — Exponent controlling the spectral weight of higher frequencies. - **offset** (*double*, default: `0.3`) — Bias controlling the initial signal and octave feedback. - **seed** (*double*, default: `1.0`) — Translation of the noise domain; changing it produces another morphology. - **normalSmoothingSteps** (*int*, default: `5`) — Laplacian smoothing iterations applied to normals before displacement. ``` --- (filter-displace-vertices-by-ridged-multifractal-noise)= ## Displace Vertices by Ridged Multifractal Noise **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Displace vertices using ridged multifractal noise. ```{py:function} ms.displace_vertices_by_ridged_multifractal_noise(**params) :module: _meshlab Evaluates ridged multifractal noise by folding each Perlin signal around zero, subtracting it from the offset, and squaring it. Feedback controlled by the gain sharpens coherent ridges while suppressing detail away from them. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **References:** - David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley. **Texturing and Modeling: A Procedural Approach** (2002). **Parameters:** - **maxHeight** (*absperc*, default: `@bboxDiag01`) — Maximum positive displacement, relative to the mesh bounding-box diagonal. - **scale** (*absperc*, default: `@bboxDiag`) — Spatial size of the base noise features; smaller values produce finer detail. - **octaves** (*int*, default: `8`) — Number of Perlin-noise frequency bands. - **lacunarity** (*double*, default: `4.0`) — Frequency multiplier between consecutive octaves. - **fractalIncrement** (*double*, default: `0.5`) — Exponent controlling the spectral weight of higher frequencies. - **offset** (*double*, default: `0.9`) — Sets the ridge level before squaring the folded signal. - **gain** (*double*, default: `2.0`) — Controls feedback strength and ridge sharpness. - **seed** (*double*, default: `2.0`) — Translation of the noise domain; changing it produces another morphology. - **normalSmoothingSteps** (*int*, default: `5`) — Laplacian smoothing iterations applied to normals before displacement. ``` --- (filter-displace-vertices-by-standard-multifractal-noise)= ## Displace Vertices by Standard Multifractal Noise **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Displace vertices using multiplicative standard multifractal noise. ```{py:function} ms.displace_vertices_by_standard_multifractal_noise(**params) :module: _meshlab Evaluates standard multifractal noise in normalized object space and displaces vertices along smoothed normals. Unlike additive fBM, its octave contributions are multiplied: $$N(\mathbf{x})=\prod_{i=0}^{n-1}\left(O+L^{-Hi}P(L^i\mathbf{x})\right).$$ The offset $O$ controls multifractality and the fractal increment $H$ controls the contribution of high frequencies. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **References:** - David S. Ebert, F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, Steven Worley. **Texturing and Modeling: A Procedural Approach** (2002). **Parameters:** - **maxHeight** (*absperc*, default: `@bboxDiag01`) — Maximum positive displacement, relative to the mesh bounding-box diagonal. - **scale** (*absperc*, default: `@bboxDiag`) — Spatial size of the base noise features; smaller values produce finer detail. - **octaves** (*int*, default: `8`) — Number of Perlin-noise frequency bands. - **lacunarity** (*double*, default: `2.0`) — Frequency multiplier between consecutive octaves. - **fractalIncrement** (*double*, default: `0.9`) — Exponent controlling the spectral weight of higher frequencies. - **offset** (*double*, default: `0.9`) — Bias added to every octave before multiplication. - **seed** (*double*, default: `1.0`) — Translation of the noise domain; changing it produces another morphology. - **normalSmoothingSteps** (*int*, default: `5`) — Laplacian smoothing iterations applied to normals before displacement. ``` --- (filter-displace-vertices-randomly)= ## Displace Vertices Randomly **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.vertex_displacement Move every vertex by an independently generated random vector. ```{py:function} ms.displace_vertices_randomly(**params) :module: _meshlab Adds an independent uniformly distributed displacement to each coordinate of every vertex. With maximum displacement $d$, each coordinate offset lies in $[-d,d]$. Set a nonzero random seed to obtain repeatable results. **Upstream:** [MeshLab Fractal Filter](https://github.com/cnr-isti-vclab/meshlab/tree/main/src/meshlabplugins/filter_fractal) **License:** GPL-2.0-or-later **Parameters:** - **maxDisplacement** (*absperc*, default: `@bboxDiag01`) — Maximum absolute displacement applied independently to each coordinate. - **recomputeNormals** (*bool*, default: `True`) — Recompute face and vertex normals after displacement. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the displacement exactly reproducible. ``` --- (filter-displace-vertices-toward-target-mesh)= ## Displace Vertices toward Target Mesh **Categories:** `Geometry/Deformation` **Plugin:** meshlab2.filter.unsharp Linearly morph the current mesh toward another mesh. ```{py:function} ms.displace_vertices_toward_target_mesh(**params) :module: _meshlab Morphs the current mesh toward a target mesh that has the same number of vertices in the same order. Each source vertex moves along the straight line to its counterpart: $$p_i^{\mathrm{result}}=(1-\lambda)\,p_i^{\mathrm{source}}+\lambda\,p_i^{\mathrm{target}}.$$ **Weight** is $\lambda$: 0 leaves the mesh alone, 1 lands exactly on the target, and values in between interpolate. Values outside $[0,1]$ extrapolate past either end. **Parameters:** - **TargetMesh** (*mesh*, default: `@otherMeshIndex`) — Mesh that acts as the morph target. - **PercentMorph** (*double*, default: `0.0`) — 0 keeps the current mesh, 100 reaches the target mesh, values outside [0,100] extrapolate. ``` --- (filter-project-vertices-onto-line-of-sight)= ## Project Vertices onto the Line of Sight **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Snap vertices back onto the sight line through their stored position. ```{py:function} ms.project_vertices_onto_line_of_sight(**params) :module: _meshlab Projects every vertex back onto the line joining **Viewpoint** to the position stored for it in a per-vertex custom point attribute, keeping only the part of its displacement that lies along that line and discarding the part across it. Writing $o$ for the stored position, $p$ for the current one and $d$ for the unit vector from the viewpoint to $o$: $$p_{\mathrm{new}} = o + d\,\big((p-o)\cdot d\big).$$ Run it after a smoothing filter to confine that filter's effect to depth. Time-of-flight scanners resolve *x,y* well but carry much larger depth error, so smoothing is worth trusting along the line of sight and worth undoing across it. Store the original coordinates first, in the custom attribute named here. Note that this is a projection, not a blend: there is no mixing factor, and every vertex moves. **Parameters:** - **attr_name** (*string*, default: ``) — Name of the per-vertex custom point attribute containing the original geometry. - **viewPoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Position of the viewpoint whose sight lines the vertices are projected onto. ``` --- (filter-project-vertices-onto-mls-surface-apss)= ## Project Vertices onto MLS Surface (APSS) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.mls Project a mesh or point set onto an Algebraic Point Set Surface. ```{py:function} ms.project_vertices_onto_mls_surface_apss(**params) :module: _meshlab Projects a mesh, or a bare point set, onto the MLS surface defined by itself or by another point set. This is the **algebraic point set surfaces** (APSS) variant: the local approximation fitted at each point is an algebraic sphere rather than a plane, which keeps curved regions from flattening out. It needs points carrying oriented normals. **References:** - Gaël Guennebaud, Markus Gross. **Algebraic point set surfaces**. *ACM Transactions on Graphics (SIGGRAPH 2007)* (2007). [DOI](https://doi.org/10.1145/1276377.1276406) - Gaël Guennebaud, Marcel Germann, Markus Gross. **Dynamic Sampling and Rendering of Algebraic Point Set Surfaces**. *Computer Graphics Forum (Eurographics 2008)* (2008). [DOI](https://doi.org/10.1111/j.1467-8659.2008.01163.x) **Parameters:** - **ControlMesh** (*mesh*, default: `@currentMeshIndex`) — The point set (or mesh) which defines the MLS surface. - **ProxyMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh that will be projected/resampled onto the MLS surface. - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SphericalParameter** (*double*, default: `1.0`) — Control the curvature of the fitted spheres: 0 is equivalent to a pure plane fit, 1 to a pure spherical fit, values between 0 and 1 give intermediate results, while other real values might give interesting results, but take care with extreme settings. - **AccurateNormal** (*bool*, default: `True`) — If checked, use the accurate MLS gradient instead of the local approximation to compute the normals. - **MaxSubdivisions** (*int*, default: `0`) — Max number of subdivisions. - **ThAngleInDegree** (*double*, default: `2.0`) — Threshold angle between two faces controlling the refinement. - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-project-vertices-onto-mls-surface-rimls)= ## Project Vertices onto MLS Surface (RIMLS) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.mls Project a mesh or point set onto a Robust Implicit MLS surface. ```{py:function} ms.project_vertices_onto_mls_surface_rimls(**params) :module: _meshlab Projects a mesh, or a bare point set, onto the MLS surface defined by itself or by another point set. This is the **robust implicit MLS** (RIMLS) variant: it extends implicit MLS with non-linear kernel regression, so sharp edges survive instead of being rounded away with the noise. It needs points carrying oriented normals. **References:** - A. Cengiz Öztireli, Gaël Guennebaud, Markus Gross. **Feature Preserving Point Set Surfaces based on Non-Linear Kernel Regression**. *Computer Graphics Forum (Eurographics 2009)* (2009). [DOI](https://doi.org/10.1111/j.1467-8659.2009.01388.x) **Parameters:** - **ControlMesh** (*mesh*, default: `@currentMeshIndex`) — The point set (or mesh) which defines the MLS surface. - **ProxyMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh that will be projected/resampled onto the MLS surface. - **FilterScale** (*double*, default: `2.0`) — Scale of the spatial low pass filter. It is relative to the radius (local point spacing) of the vertices. - **SigmaN** (*double*, default: `0.75`) — Width of the filter used by the normal refitting weight. This weight function is a Gaussian on the distance between two unit vectors: the current gradient and the input normal. Typical values range between 0.5 (sharp) and 2 (smooth). - **MaxRefittingIters** (*int*, default: `3`) — Max number of fitting iterations. (0 or 1 is equivalent to the standard IMLS). - **MaxSubdivisions** (*int*, default: `0`) — Max number of subdivisions. - **ThAngleInDegree** (*double*, default: `2.0`) — Threshold angle between two faces controlling the refinement. - **ProjectionAccuracy** (*double*, default: `0.0001`) — Threshold value used to stop the projections. This value is scaled by the mean point spacing to get the actual threshold. - **MaxProjectionIters** (*int*, default: `15`) — Max number of iterations for the projection. ``` --- (filter-sharpen-vertices-by-unsharp-mask)= ## Sharpen Vertices by Unsharp Mask **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Enhance geometric ridges and valleys with an unsharp mask. ```{py:function} ms.sharpen_vertices_by_unsharp_mask(**params) :module: _meshlab Sharpens the **vertex positions**, deepening ridges and valleys in the surface itself. Unlike the normal variant this really moves geometry, so the effect survives export. Unsharp masking exaggerates local variation by adding back the difference between the signal and a smoothed copy of it: $$s' = s + \lambda\,(s - \mathrm{smooth}(s)).$$ **Weight** is $\lambda$; larger values sharpen harder and amplify noise along with the features. **Smoothing steps** sets how blurred the subtracted copy is, which fixes the scale of the detail being enhanced. **References:** - Paolo Cignoni, Roberto Scopigno, Marco Tarini. **A simple normal enhancement technique for interactive non-photorealistic renderings**. *Computers & Graphics* (2005). [DOI](https://doi.org/10.1016/j.cag.2004.11.012) [Web](https://www.sciencedirect.com/science/article/pii/S0097849304001980) **Parameters:** - **weight** (*double*, default: `0.3`) — Unsharp weight applied to the high-frequency geometric component. - **weightOrig** (*double*, default: `1.0`) — Weight of the original geometry signal. - **iterations** (*int*, default: `5`) — Number of Laplacian smoothing iterations used to build the low-pass geometry. ``` --- (filter-smooth-polyline-on-surface)= ## Smooth Polyline on Surface **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.meshing Smooth the current polyline while keeping it on a surface layer, so each strand tends to a geodesic. ```{py:function} ms.smooth_polyline_on_surface(**params) :module: _meshlab Smooth a polyline lying on a surface without letting it leave the surface: at every iteration each free vertex moves towards the average of its neighbours and is then pulled back onto the surface. The polyline is resampled as it goes, adding vertices where it strays from the surface and removing them where it is flat, and the last iteration projects it exactly. The curve is read as **control points** joined by **strands**. Control points are only projected; each strand between them shortens towards a geodesic of the surface, staying in its own homotopy class: a helix around a cylinder with fixed ends stays a helix. By default the control points are the ends of the polyline and its junctions; *Selected vertices* uses the vertex selection of the polyline. Afterwards the control points are the selected vertices of the polyline. The surface layer is not changed. The polyline must lie close to it; it can then be embedded with *Embed Polyline in Surface*. **Parameters:** - **surface** (*mesh*, default: `@otherMeshIndex`) — The surface layer the polyline lies on. It is left unchanged. - **iterations** (*int*, default: `10`) — Number of smoothing iterations. - **smoothWeight** (*double*, default: `0.5`) — How far each iteration moves a vertex towards the average of its neighbours, from 0 (not at all) to 1 (all the way). - **projectWeight** (*double*, default: `0.5`) — How far each iteration pulls a vertex back onto the surface, from 0 to 1. The last iteration always projects fully. - **controlPoints** (*enum*, default: `ends_and_nodes`) — Which polyline vertices stay fixed (only projected). ``` --- (filter-smooth-vertices-along-one-direction)= ## Smooth Vertices along One Direction **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Smooth vertices only along a given depth direction. ```{py:function} ms.smooth_vertices_along_one_direction(**params) :module: _meshlab A laplacian smooth that is constrained to move vertices only in one given direction (usually the viewer direction). **Parameters:** - **stepSmoothNum** (*int*, default: `3`) — Number of smoothing iterations. - **viewPoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Position of the viewpoint that defines the allowed displacement direction. - **delta** (*double*, default: `1.0`) — How much smoothing is applied: 0 means no smoothing, 1 means full smoothing. ``` --- (filter-smooth-vertices-by-hc-laplacian)= ## Smooth Vertices by HC Laplacian **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Improved Laplacian smoothing with better shape preservation. ```{py:function} ms.smooth_vertices_by_hc_laplacian(**params) :module: _meshlab HC Laplacian smoothing: an extended Laplacian smoothing that pushes each vertex back toward its original position after every averaging step, which removes most of the shrinkage plain Laplacian smoothing causes. **References:** - J. Vollmer, R. Mencl, H. Müller. **Improved Laplacian Smoothing of Noisy Surface Meshes**. *Computer Graphics Forum* (1999). [DOI](https://doi.org/10.1111/1467-8659.00334) [Web](https://onlinelibrary.wiley.com/doi/abs/10.1111/1467-8659.00334) This filter has no parameters. ``` --- (filter-smooth-vertices-by-laplacian-trueform)= ## Smooth Vertices by Laplacian (TrueForm) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.trueform Move each vertex towards the average of its neighbours. ```{py:function} ms.smooth_vertices_by_laplacian_trueform(**params) :module: _meshlab Moves each vertex towards the average position of its linked neighbours, repeatedly. **Lambda** is how far towards that average each step travels: 1.0 goes all the way, smaller values creep. **Iterations** is how many steps. Laplacian smoothing **shrinks**: every step pulls the surface towards its own average, so a closed shape loses volume and sharp features round off. That is the price of its simplicity, and the reason for its Taubin sibling, which alternates a shrinking step with an expanding one to compensate. Enable **Selected Only** to restrict movement to the current vertex selection. Competing implementation: MeshLab already has vcglib smoothing under *Geometry/Smoothing*. TrueForm's is parallelised through oneTBB, which shows on large meshes. Results should agree closely; where they differ the difference is in the boundary handling. **Parameters:** - **iterations** (*int*, default: `10`) — How many smoothing steps to take. - **lambda** (*double*, default: `0.5`) — How far each step moves towards the neighbour average, 0 to 1. ``` --- (filter-smooth-vertices-by-laplacian-vcglib)= ## Smooth Vertices by Laplacian (vcglib) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Average vertex positions with their neighbors. ```{py:function} ms.smooth_vertices_by_laplacian_vcglib(**params) :module: _meshlab Laplacian smoothing: each vertex moves toward the average position of its neighbours. The simplest and fastest of the smoothing filters, and the one that shrinks the mesh most -- repeated passes pull the surface inward. Use Taubin or HC Laplacian where that matters. **Parameters:** - **stepSmoothNum** (*int*, default: `3`) — Number of smoothing iterations. - **Boundary** (*bool*, default: `True`) — Smooth boundary edges only by themselves instead of shrinking them into the surface. - **cotangentWeight** (*bool*, default: `True`) — Use cotangent weights instead of umbrella weights for the position average. ``` --- (filter-smooth-vertices-by-scale-dependent-laplacian)= ## Smooth Vertices by Scale-Dependent Laplacian **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Fujiwara-style scale-dependent Laplacian smoothing. ```{py:function} ms.smooth_vertices_by_scale_dependent_laplacian(**params) :module: _meshlab Scale-dependent Laplacian smoothing, using the Fujiwara extended umbrella operator. Weighting each neighbour by the inverse of its edge length makes the smoothing step independent of how unevenly the mesh is tessellated, so dense and sparse regions are faired at the same rate rather than the dense ones collapsing first. **References:** - Mathieu Desbrun, Mark Meyer, Peter Schröder, Alan H. Barr. **Implicit fairing of irregular meshes using diffusion and curvature flow**. *Proceedings of the 26th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH '99)* (1999). [DOI](https://doi.org/10.1145/311535.311576) **Parameters:** - **stepSmoothNum** (*int*, default: `3`) — Number of smoothing iterations. - **delta** (*absperc*, default: `@bboxDiag001`) — Maximum displacement scale used by the Fujiwara operator. ``` --- (filter-smooth-vertices-by-surface-preserving-laplacian-vcglib)= ## Smooth Vertices by Surface-Preserving Laplacian (vcglib) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.trioptimize Laplacian smooth while limiting normal deviation from the original surface. ```{py:function} ms.smooth_vertices_by_surface_preserving_laplacian_vcglib(**params) :module: _meshlab Laplacian smooth with limited surface modification: each vertex moves toward the average position of neighboring vertices only when the new position still almost lies on the original surface. **Parameters:** - **AngleDeg** (*double*, default: `0.5`) — Maximum mean normal angle displacement allowed from old to new faces. - **iterations** (*int*, default: `1`) — Number of smoothing iterations. ``` --- (filter-smooth-vertices-by-taubin-trueform)= ## Smooth Vertices by Taubin (TrueForm) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.trueform Smooth without the shrinkage that Laplacian smoothing causes. ```{py:function} ms.smooth_vertices_by_taubin_trueform(**params) :module: _meshlab Alternates a Laplacian shrinking step with a slightly larger expanding one, so noise is removed while the overall volume is preserved. This is the smoothing to reach for by default; plain Laplacian is the one to reach for when you *want* the shape to contract. **Lambda** is the shrinking step and **Kpb** sets the expanding one — larger Kpb pushes back harder against shrinkage. The defaults are the values from Taubin's paper and are a reasonable starting point. Enable **Selected Only** to restrict movement to the current vertex selection. Competing implementation: MeshLab already has vcglib smoothing under *Geometry/Smoothing*. TrueForm's is parallelised through oneTBB, which shows on large meshes. Results should agree closely; where they differ the difference is in the boundary handling. **References:** - Gabriel Taubin. **A signal processing approach to fair surface design**. *Proceedings of the 22nd Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH '95)* (1995). [DOI](https://doi.org/10.1145/218380.218473) **Parameters:** - **iterations** (*int*, default: `10`) — How many smoothing steps to take. - **lambda** (*double*, default: `0.5`) — The shrinking step size, 0 to 1. - **kpb** (*double*, default: `0.1`) — Controls the compensating expansion. Larger values resist shrinkage more. ``` --- (filter-smooth-vertices-by-taubin-vcglib)= ## Smooth Vertices by Taubin (vcglib) **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Lambda-mu smoothing with reduced shrinkage. ```{py:function} ms.smooth_vertices_by_taubin_vcglib(**params) :module: _meshlab The $\lambda$-$\mu$ Taubin smoothing. Each iteration combines two low-pass filtering steps -- a positive $\lambda$ pass followed by a negative $\mu$ pass -- so that noise is attenuated without the volume loss of repeated Laplacian smoothing. **References:** - Gabriel Taubin. **A signal processing approach to fair surface design**. *Proceedings of the 22nd Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH '95)* (1995). [DOI](https://doi.org/10.1145/218380.218473) **Parameters:** - **lambda** (*double*, default: `0.5`) — Lambda parameter of Taubin smoothing. - **mu** (*double*, default: `-0.53`) — Mu parameter of Taubin smoothing. - **stepSmoothNum** (*int*, default: `10`) — Number of Taubin smoothing iterations. ``` --- (filter-smooth-vertices-by-two-step-normal-fitting)= ## Smooth Vertices by Two-Step Normal Fitting **Categories:** `Geometry/Smoothing` **Plugin:** meshlab2.filter.unsharp Feature-preserving smoothing through normal smoothing and vertex fitting. ```{py:function} ms.smooth_vertices_by_two_step_normal_fitting(**params) :module: _meshlab A feature-preserving fairing filter that runs in two stages: 1. **Normal smoothing** -- face normals that already point in similar directions are averaged together, while normals that differ sharply are left alone, so creases survive. 2. **Vertex repositioning** -- vertices are then moved to fit the smoothed normals. Smoothing the normals first and the positions second is what separates this from plain Laplacian smoothing: noise is removed without rounding off the edges that carry the shape. **References:** - Alexander Belyaev, Yutaka Ohtake. **A comparison of mesh smoothing methods**. *Israel-Korea Bi-National Conference on Geometric Modeling and Computer Graphics* (2003). [Web](https://www.researchgate.net/publication/47861030_A_comparison_of_mesh_smoothing_methods) **Parameters:** - **stepSmoothNum** (*int*, default: `3`) — Number of full algorithm iterations. - **normalThr** (*double*, default: `60.0`) — Features forming angles larger than this threshold are preserved. - **stepNormalNum** (*int*, default: `20`) — Number of normal smoothing iterations per step. - **stepFitNum** (*int*, default: `20`) — Number of vertex fitting iterations per step. ``` --- (filter-freeze-matrix)= ## Freeze Matrix **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Bake the layer matrix into the vertex coordinates. ```{py:function} ms.freeze_matrix(**params) :module: _meshlab Freeze the current transformation matrix into the coordinates of the vertices of the mesh (and set this matrix to the identity). In other words it applies in a definetive way the current matrix to the vertex coordinates. This filter has no parameters. ``` --- (filter-invert-matrix)= ## Invert Matrix **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Invert current transformation matrix. ```{py:function} ms.invert_matrix(**params) :module: _meshlab Invert the current transformation matrix. The current transformation is reversed, becoming its opposite. This filter has no parameters. ``` --- (filter-mirror-or-swap-axes)= ## Mirror or Swap Axes **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Flip or swap axes. ```{py:function} ms.mirror_or_swap_axes(**params) :module: _meshlab Generate a matrix transformation that flips each one of the axis or swaps a couple of axis. The listed transformations are applied in that order. This kind of transformation cannot be applied to set of Raster! **Parameters:** - **flipX** (*bool*, default: `False`) — Mirror along YZ plane. - **flipY** (*bool*, default: `False`) — Mirror along XZ plane. - **flipZ** (*bool*, default: `False`) — Mirror along XY plane. - **swapXY** (*bool*, default: `False`) — Swap X and Y. - **swapXZ** (*bool*, default: `False`) — Swap X and Z. - **swapYZ** (*bool*, default: `False`) — Swap Y and Z. ``` --- (filter-normalize-reference-frame)= ## Normalize Reference Frame **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Bring the mesh into a canonical position, orientation and scale. ```{py:function} ms.normalize_reference_frame(**params) :module: _meshlab Places the mesh in a canonical reference frame, so that two copies of the same shape end up superimposed however they were positioned, oriented or scaled beforehand. Each of the three controls can be left at **Unchanged**, so a partial canonicalization is fine. The three are independent by construction. A centre $C$ is derived from **Position**, the rotation and the scale are both taken about that centre, and the result is composed in a fixed order: $$M = T_{\mathrm{target}}\cdot S\cdot R\cdot T_{-C}.$$ When **Position** is *Unchanged*, $C$ is still used as the pivot and the object is put back where it started, so changing **Scale** or **Rotation** never moves it. **Position** picks the point that lands on the origin. *Bounding Box Center* is cheap but follows the extremes, so a single stray vertex moves it. *Vertex Average* is biased by tessellation density. *Shell Barycenter* weights by triangle area and is the robust choice for a surface. *Mesh Barycenter* is the centre of mass of the enclosed solid and needs a watertight mesh. **Rotation** is *Unchanged* by default, since turning a mesh is rarely what someone normalizing it expects. The other two choices align the principal axes with X, Y and Z, most spread first. *On Vertices* is biased wherever the tessellation is dense; *Area Weighted* integrates over the surface and is usually what you want. Principal axes are only defined up to sign, so the axis directions are fixed by the sign of the third moment along each one, and the third axis is set to the cross product of the first two. Without that step the same shape canonicalizes to any of four different frames depending on how it happened to be oriented on input. **Minimum Axis Separation** guards the ill-conditioned cases. A sphere has three equal eigenvalues and a cylinder two, so their principal axes are arbitrary; when the relative gap between consecutive eigenvalues falls below this value the rotation is skipped and the reason is logged. Zero always rotates. **Scale** is always uniform, and is measured *after* rotation, in the canonical frame. Note that applying this to several layers at once gives each layer its own frame, which will pull apart layers that were registered to each other. **Parameters:** - **position** (*enum*, default: `bbox_center`) — Which point of the mesh is moved onto the origin. - **rotation** (*enum*, default: `unchanged`) — Align the principal axes to X, Y and Z, widest spread first. - **scale** (*enum*, default: `unit_longest_side`) — Uniform scale, measured after rotation. - **minAxisSeparation** (*double*, default: `0.0`) — Skip the rotation when consecutive principal eigenvalues are closer than this relative gap, as they are for a sphere or a cylinder. Zero always rotates. ``` --- (filter-rotate)= ## Rotate **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Rotate mesh. ```{py:function} ms.rotate(**params) :module: _meshlab Generate a matrix transformation that rotates the mesh. The mesh can be rotated around one of the axis or a given axis and w.r.t. to the origin or the baricenter, or a given point. **Parameters:** - **rotAxis** (*enum*, default: `x`) — Choose rotation axis. - **rotCenter** (*enum*, default: `origin`) — Choose center of rotation. - **angle** (*double*, default: `0.0`) — Angle in degrees. - **customAxis** (*point3f*, default: `[0.0, 0.0, 1.0]`) — Custom rotation axis direction. - **customCenter** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Custom rotation center point. - **snapFlag** (*bool*, default: `False`) — Snap angle according to snap value. - **snapAngle** (*double*, default: `30.0`) — Snap step in degrees. ``` --- (filter-rotate-to-fitted-plane)= ## Rotate to Fitted Plane **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Rotate selection to fit a reference plane. ```{py:function} ms.rotate_to_fitted_plane(**params) :module: _meshlab Generate a matrix transformation that rotates the mesh so that the selection fits one of the main planes XY YZ ZX. May also translate such that the selection centroid rest on the origin. It reports on the log the average error of the fitting (in mesh units). **Parameters:** - **targetPlane** (*enum*, default: `xy`) — Target plane. - **rotAxis** (*enum*, default: `any`) — Rotation axis constraint. - **ToOrigin** (*bool*, default: `True`) — Translate so selection centroid rests on origin. ``` --- (filter-scale)= ## Scale **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Scale mesh. ```{py:function} ms.scale(**params) :module: _meshlab Generate a matrix transformation that scale the mesh. The mesh can be also automatically scaled to a unit side box. **Parameters:** - **axisX** (*double*, default: `1.0`) — Scale X. - **axisY** (*double*, default: `1.0`) — Scale Y. - **axisZ** (*double*, default: `1.0`) — Scale Z. - **uniformFlag** (*bool*, default: `True`) — Use same scale for all axes (axisX value). - **scaleCenter** (*enum*, default: `origin`) — Scaling center. - **customCenter** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Custom scaling center point. ``` --- (filter-set-matrix-from-translation-rotation-scale)= ## Set Matrix from Translation/Rotation/Scale **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Build transformation from T/R/S parameters. ```{py:function} ms.set_matrix_from_translation_rotation_scale(**params) :module: _meshlab Set the current transformation matrix starting from parameters: [XYZ] translation, [XYZ] Euler angles rotation and [XYZ] scaling. **Parameters:** - **translationX** (*double*, default: `0.0`) — Translation X. - **translationY** (*double*, default: `0.0`) — Translation Y. - **translationZ** (*double*, default: `0.0`) — Translation Z. - **rotationX** (*double*, default: `0.0`) — Euler rotation X (deg). - **rotationY** (*double*, default: `0.0`) — Euler rotation Y (deg). - **rotationZ** (*double*, default: `0.0`) — Euler rotation Z (deg). - **scaleX** (*double*, default: `1.0`) — Scale X. - **scaleY** (*double*, default: `1.0`) — Scale Y. - **scaleZ** (*double*, default: `1.0`) — Scale Z. - **compose** (*bool*, default: `False`) — Compose with current matrix. ``` --- (filter-set-matrix-from-values-or-layer)= ## Set Matrix from Values or Layer **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Set transformation matrix values. ```{py:function} ms.set_matrix_from_values_or_layer(**params) :module: _meshlab Set the current transformation matrix by filling it, or copying from another layer. **Parameters:** - **m00** (*double*, default: `1.0`) — Matrix coefficient. - **m01** (*double*, default: `0.0`) — Matrix coefficient. - **m02** (*double*, default: `0.0`) — Matrix coefficient. - **m03** (*double*, default: `0.0`) — Matrix coefficient. - **m10** (*double*, default: `0.0`) — Matrix coefficient. - **m11** (*double*, default: `1.0`) — Matrix coefficient. - **m12** (*double*, default: `0.0`) — Matrix coefficient. - **m13** (*double*, default: `0.0`) — Matrix coefficient. - **m20** (*double*, default: `0.0`) — Matrix coefficient. - **m21** (*double*, default: `0.0`) — Matrix coefficient. - **m22** (*double*, default: `1.0`) — Matrix coefficient. - **m23** (*double*, default: `0.0`) — Matrix coefficient. - **m30** (*double*, default: `0.0`) — Matrix coefficient. - **m31** (*double*, default: `0.0`) — Matrix coefficient. - **m32** (*double*, default: `0.0`) — Matrix coefficient. - **m33** (*double*, default: `1.0`) — Matrix coefficient. - **compose** (*bool*, default: `False`) — Compose with current matrix. ``` --- (filter-set-matrix-to-identity)= ## Set Matrix to Identity **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Reset transform matrix to identity. ```{py:function} ms.set_matrix_to_identity(**params) :module: _meshlab Set the current transformation matrix to the Identity. This filter has no parameters. ``` --- (filter-translate)= ## Translate **Categories:** `Geometry/Transform` **Plugin:** meshlab2.filter.meshing Translate mesh. ```{py:function} ms.translate(**params) :module: _meshlab Generate a matrix transformation that translate the mesh. The mesh can be translated around one of the axis or a given axis and w.r.t. to the origin or the baricenter, or a given point. **Parameters:** - **traslMethod** (*enum*, default: `xyz`) — Translation strategy. - **axis** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Custom translation vector. - **newOrigin** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Custom new origin point. ``` --- (filter-compute-distance-from-reference-mesh)= ## Compute Distance from Reference Mesh **Categories:** `Measurement/Geometric`, `Attribute/Scalar` **Plugin:** meshlab2.filter.sampling Compute per-vertex distance from another mesh or point cloud. ```{py:function} ms.compute_distance_from_reference_mesh(**params) :module: _meshlab Compute the signed/unsigned (per vertex) distance between a mesh/pointcloud and a reference mesh/pointcloud. Distance is stored in vertex quality; after the filter runs MeshLab switches the measured mesh to vertex-quality color visualization without baking colors. **Parameters:** - **MeasureMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh that will receive the computed distances in vertex quality. - **RefMesh** (*mesh*, default: `@otherMeshIndex`) — The mesh or point cloud used as the reference. - **SignedDist** (*bool*, default: `True`) — If enabled, compute a signed distance instead of the absolute value. - **MaxDist** (*absperc*, default: `@bboxDiag`) — Search is interrupted when nothing is found within this range. ``` --- (filter-measure-chamfer-distance-trueform)= ## Measure Chamfer Distance (TrueForm) **Categories:** `Measurement/Geometric` **Plugin:** meshlab2.filter.trueform Report the mean nearest-point distance between two layers. ```{py:function} ms.measure_chamfer_distance_trueform(**params) :module: _meshlab Reports the **mean** distance from each vertex of one layer to the nearest vertex of the other. Where the *Measure Hausdorff Distance* reports the single worst correspondence — and so is dominated by one stray vertex — the chamfer distance averages over all of them. That makes it the more useful number for scoring an overall fit: comparing simplification settings, judging whether a registration improved, or tracking a reconstruction against ground truth. Use Hausdorff when the worst case is what matters, and this when the typical case is. The measure is **not symmetric**: the mean distance from A to B differs from B to A, and a subset of a surface can sit very close to it while the surface as a whole sits far from the subset. **Symmetric** measures both directions and also reports the larger, which is the honest single number. **Outlier Proportion** discards that fraction of the worst correspondences before averaging, for partial overlaps. This measures vertex to vertex, so it is sensitive to how densely each layer is sampled. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer being measured. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The layer measured against. - **symmetric** (*bool*, default: `True`) — Measure both directions and report the larger. - **outlierProportion** (*double*, default: `0.0`) — Fraction of the worst correspondences discarded before averaging. ``` --- (filter-measure-geometric-properties)= ## Measure Geometric Properties **Categories:** `Measurement/Geometric` **Plugin:** meshlab2.filter.measure Compute a set of geometric measures of a mesh or point cloud. ```{py:function} ms.measure_geometric_properties(**params) :module: _meshlab Compute a set of geometric measures of a mesh/pointcloud. Bounding box extents and diagonal, principal axis, thin shell barycenter (mesh only), vertex barycenter and quality-weighted barycenter (pointcloud only), surface area (mesh only), volume (closed mesh) and inertia tensor matrix (closed mesh). This filter has no parameters. ``` --- (filter-measure-hausdorff-distance)= ## Measure Hausdorff Distance **Categories:** `Measurement/Geometric`, `Attribute/Scalar` **Plugin:** meshlab2.filter.sampling Compute directional Hausdorff distance statistics between two meshes. ```{py:function} ms.measure_hausdorff_distance(**params) :module: _meshlab Compute the Measure Hausdorff Distance between two layers, sampling one of the two and finding for each sample the closest point over the other mesh. If sample layers are saved, distances are stored in vertex quality and MeshLab switches those layers to vertex-quality color visualization without baking colors. **Parameters:** - **SampledMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh whose surface is sampled. - **TargetMesh** (*mesh*, default: `@otherMeshIndex`) — The reference mesh searched for closest points. - **SaveSample** (*bool*, default: `False`) — Create two new layers with the used sample points and closest points. - **SampleVert** (*bool*, default: `True`) — Sample vertices of the sampled mesh. - **SampleEdge** (*bool*, default: `False`) — Sample edges of the sampled mesh. - **SampleFauxEdge** (*bool*, default: `False`) — Include faux edges when edge sampling is enabled. - **SampleFace** (*bool*, default: `False`) — Sample faces of the sampled mesh by Montecarlo sampling. - **SampleNum** (*int*, default: `1000`) — Desired number of samples for each enabled sampling strategy. - **MaxDist** (*absperc*, default: `@bboxDiagHalf`) — Discard sample points whose closest point is farther than this threshold. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the measured sample set exactly reproducible. ``` --- (filter-measure-layer-overlap)= ## Measure Layer Overlap **Categories:** `Measurement/Geometric` **Plugin:** meshlab2.filter.icp Report which mesh layers overlap in an occupancy grid. ```{py:function} ms.measure_layer_overlap(**params) :module: _meshlab Voxelize all mesh layers into an occupancy grid and report the pairs that occupy common cells. This is an information filter and does not modify the document. **Parameters:** - **OGSize** (*int*, default: `50000`) — Resolution budget used by the occupancy grid. ``` --- (filter-measure-selection-area-and-perimeter)= ## Measure Selection Area and Perimeter **Categories:** `Measurement/Geometric` **Plugin:** meshlab2.filter.measure Compute area and perimeter of the face selection. ```{py:function} ms.measure_selection_area_and_perimeter(**params) :module: _meshlab Compute area and perimeter of the FACE selection. This filter has no parameters. ``` --- (filter-estimate-radius-from-density)= ## Estimate Radius from Density **Categories:** `Measurement/Statistics` **Plugin:** meshlab2.filter.mls Estimate local point spacing for each vertex. ```{py:function} ms.estimate_radius_from_density(**params) :module: _meshlab Estimate the local point spacing (aka radius) around each vertex using a basic estimate of the local density. **Parameters:** - **NbNeighbors** (*int*, default: `16`) — Number of neighbors used to estimate the local density. Larger values lead to smoother variations. ``` --- (filter-measure-face-scalar-histogram)= ## Measure Face Scalar Histogram **Categories:** `Measurement/Statistics` **Plugin:** meshlab2.filter.measure Compute a histogram of per-face quality values. ```{py:function} ms.measure_face_scalar_histogram(**params) :module: _meshlab Compute an histogram of the values of the per-face quality. **Parameters:** - **HistMin** (*double*, default: `@qualityFMin`) — Lower bound of the histogram range. - **HistMax** (*double*, default: `@qualityFMax`) — Upper bound of the histogram range. - **areaWeighted** (*bool*, default: `False`) — If false, each bin reports the number of faces in the range. If true, each bin reports the approximate area in that range. - **binNum** (*int*, default: `20`) — The number of bins of the histogram. ``` --- (filter-measure-face-scalar-statistics)= ## Measure Face Scalar Statistics **Categories:** `Measurement/Statistics` **Plugin:** meshlab2.filter.measure Compute aggregate statistics over per-face quality. ```{py:function} ms.measure_face_scalar_statistics(**params) :module: _meshlab Compute some aggregate statistics over the per face quality, like Min, Max, Average, StdDev and Variance. This filter has no parameters. ``` --- (filter-measure-vertex-scalar-histogram)= ## Measure Vertex Scalar Histogram **Categories:** `Measurement/Statistics` **Plugin:** meshlab2.filter.measure Compute a histogram of per-vertex quality values. ```{py:function} ms.measure_vertex_scalar_histogram(**params) :module: _meshlab Compute an histogram of the values of the per-vertex quality. It can be useful to evaluate the distribution of the quality value over the surface. It can be discrete (e.g. based on vertex count or area weighted). **Parameters:** - **HistMin** (*double*, default: `@qualityVMin`) — Lower bound of the histogram range. - **HistMax** (*double*, default: `@qualityVMax`) — Upper bound of the histogram range. - **areaWeighted** (*bool*, default: `False`) — If false, each bin reports the number of vertices in the range. If true, each bin reports the approximate mesh area associated with those values. - **binNum** (*int*, default: `20`) — The number of bins of the histogram. ``` --- (filter-measure-vertex-scalar-statistics)= ## Measure Vertex Scalar Statistics **Categories:** `Measurement/Statistics` **Plugin:** meshlab2.filter.measure Compute aggregate statistics over per-vertex quality. ```{py:function} ms.measure_vertex_scalar_statistics(**params) :module: _meshlab Compute some aggregate statistics over the per vertex quality, like Min, Max, Average, StdDev and Variance. This filter has no parameters. ``` --- (filter-measure-abstract-domain)= ## Measure Abstract Domain **Categories:** `Measurement/Topological`, `Parametrization/UV Creation` **Plugin:** meshlab2.filter.isoparam Report the structure, quality and validity of the abstract domain attached to a layer. ```{py:function} ms.measure_abstract_domain(**params) :module: _meshlab Report everything known about the abstract domain a previous run of *Parametrize by Abstract Domain* left on this layer. Nothing is modified. The domain is otherwise hard to inspect: it lives in layer data, the layer panel shows only three numbers, and each filter that consumes it exposes just the part it needs. This reports: - **Structure.** The number of sub-domains -- the unit-sided equilateral triangles the domain is made of -- with the domain's vertex, edge and face counts, its Euler characteristic and genus, and whether it is closed and 2-manifold. - **Vertex valences.** A histogram, and the count of irregular vertices. Valence six is regular; the *Star* and *Hexagon* chart shapes of *Create Atlased Mesh* merge around regular vertices by default, so this predicts how much they can merge. - **Chart counts.** How many charts each chart shape of *Create Atlased Mesh* would produce, which saves running it to find out. - **How the mesh sits in the domain.** Parametrized vertex and face counts, layer faces per sub-domain, the spread of vertices across sub-domains, and how many faces straddle more than one sub-domain. - **Quality.** The stretch efficiency and area distortion the parametrizator reported when it stopped. A stretch of 1.0 is isometric. - **Structural checks.** The invariants the technique requires: at least four sub-domains, a closed domain, no sub-domain left uncovered, and every vertex naming a sub-domain that exists and sitting inside its triangle. A domain that fails one of these is not usable, and the symptom is otherwise just a later filter misbehaving. Every figure is also returned as a named output value, so a script can assert on it. **References:** - Nico Pietroni, Marco Tarini, Paolo Cignoni. **Almost Isometric Mesh Parameterization through Abstract Domains**. *IEEE Transactions on Visualization and Computer Graphics* (2010). [DOI](https://doi.org/10.1109/TVCG.2009.96) This filter has no parameters. ``` --- (filter-measure-mesh-health-trueform)= ## Measure Mesh Health (TrueForm) **Categories:** `Measurement/Topological` **Plugin:** meshlab2.filter.trueform Report a layer's manifoldness, closure, self-intersections, Euler characteristic, boundary rims and non-manifold counts. ```{py:function} ms.measure_mesh_health_trueform(**params) :module: _meshlab Reports every structural fact TrueForm can state about one layer, in one place: | Line | Meaning | |---|---| | Manifold | whether the faces around every vertex form one fan, which also says no edge carries more than two | | Closed | whether the surface has no boundary edge, and so encloses a volume | | Self-intersecting | whether the surface passes through itself anywhere | | Euler characteristic | V - E + F, each undirected edge counted once; 2 for a sphere, 0 for a torus | | Boundary rims | how many separate boundary curves there are, and how many of them close | | Non-manifold edges | edges carried by three or more faces | | Non-manifold vertices | vertices whose faces are not one fan | Each fact has its own filter elsewhere, but a mesh that misbehaves for no visible reason is usually diagnosed by reading several of them together: **closed but not manifold** points at a seam three sheets share, **manifold but not closed** at holes, and **self-intersecting** at geometry that has no well-defined inside no matter how clean its topology looks. The answers are computed off one shared connectivity structure rather than one per question. Only the self-intersection test needs a spatial index, and it stops at the first contact it finds, so a mesh that does intersect itself is answered without the rest of it being examined. Nothing is modified; this filter only reports. This filter has no parameters. ``` --- (filter-measure-mesh-summary)= ## Measure Mesh Summary **Categories:** `Measurement/Topological` **Plugin:** meshlab2.filter.basic Prints a compact summary for the current mesh. ```{py:function} ms.measure_mesh_summary(**params) :module: _meshlab Outputs vertex/edge/face counts and bounding-box metrics for the current mesh. **Parameters:** - **precision** (*int*, default: `3`) — Number of decimals used when formatting bounding-box metrics. ``` --- (filter-measure-topological-properties)= ## Measure Topological Properties **Categories:** `Measurement/Topological` **Plugin:** meshlab2.filter.measure Compute a set of topological measures over a mesh. ```{py:function} ms.measure_topological_properties(**params) :module: _meshlab This filter has no parameters. ``` --- (filter-measure-topological-properties-for-quad-mesh)= ## Measure Topological Properties for Quad Mesh **Categories:** `Measurement/Topological` **Plugin:** meshlab2.filter.measure Compute a set of topological measures over a quad mesh. ```{py:function} ms.measure_topological_properties_for_quad_mesh(**params) :module: _meshlab This filter has no parameters. ``` --- (filter-mesh-csg-expression-trueform)= ## Mesh CSG Expression (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Evaluate a boolean expression over any number of layers in one exact pass. ```{py:function} ms.mesh_csg_expression_trueform(**params) :module: _meshlab Evaluates an arbitrary constructive-solid-geometry expression over the document's layers, in a **single arrangement** rather than a chain of pairwise booleans. That matters for more than convenience: chaining booleans re-meshes and re-intersects at every step, accumulating error and cost, while one arrangement resolves all the surfaces together and classifies each region once. **Operands are layer numbers**, as shown in the layer panel. Operators, loosest-binding first: | Operator | Meaning | |---|---| | `\\|` | union | | `-` | difference | | `&` | intersection | | `~` | complement | `|` and `-` share the lowest precedence and associate to the left; `&` binds tighter; `~` binds tightest. Parentheses group. Examples: - `0 | 1 | 2` — the union of three layers - `(0 | 1) - 2` — two layers joined, then a third drilled out of them - `0 & ~1` — the part of layer 0 outside layer 1, i.e. the difference A layer may appear more than once; it becomes a single operand. Every referenced layer is taken in world space. **Sheets.** A layer listed in *Sheets* enters the expression as an **open oriented surface** rather than a solid: it cuts the other operands without enclosing any volume of its own, and its operand bit means *behind the surface*, on the far side of its normals. Anything can be a sheet — a plane, a curved terrain, a trimmed patch — and it need not be closed or even reach past the solid it divides. For a cube as layer 0 and a surface through it as layer 1, `0 - 1` is the piece in front of the surface and `0 & 1` the piece behind it, each capped along the cut and watertight. Leave *Sheets* empty and every operand is a solid, which is what a closed mesh should be. **Parameters:** - **expression** (*string*, default: `0 | 1`) — A boolean expression over layer numbers, e.g. (0 | 1) - 2. Operators: | union, - difference, & intersection, ~ complement. - **sheets** (*string*, default: ``) — Layer numbers to treat as open cutting surfaces rather than solids, e.g. 1 2. Each must also appear in the expression. Leave empty to treat every operand as a solid. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-mesh-difference-geogram)= ## Mesh Difference (geogram) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.geogram Create the exact difference of two mesh layers using geogram. ```{py:function} ms.mesh_difference_geogram(**params) :module: _meshlab Computes the exact boolean difference of two mesh layers, first minus second, and creates the result as a new layer, using geogram's exact predicates. Both operands should be closed, consistently oriented surfaces without self-intersections; *Repair Self-Intersections (geogram)* can prepare an input that is not. The optional attribute transfers recover the correspondence geometrically: every face of the result lies on one of the two operand surfaces, so the nearest operand face to a result face is the face it came from. Vertices created along the intersection curve match no operand vertex, so per-vertex values are interpolated across the source face rather than copied from a nearest vertex. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **simplifyCoplanarFacets** (*bool*, default: `True`) — Merge facets that end up coplanar in the result. Turning this off keeps every triangle the intersection produced, which is larger but preserves the original tessellation more closely. - **transferFaceColor** (*bool*, default: `False`) — Copy the face color of the originating operand face onto each result face. - **transferFaceScalar** (*bool*, default: `False`) — Copy the face scalar value of the originating operand face onto each result face. - **transferVertexColor** (*bool*, default: `False`) — Interpolate vertex color from the originating operand face onto each result vertex. - **transferVertexScalar** (*bool*, default: `False`) — Interpolate the vertex scalar value from the originating operand face onto each result vertex. ``` --- (filter-mesh-difference-libigl)= ## Mesh Difference (libigl) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.igl Create the exact difference of two mesh layers using libigl and CGAL. ```{py:function} ms.mesh_difference_libigl(**params) :module: _meshlab Executes an exact boolean difference between two mesh layers and creates the result as a new layer. The computation uses libigl's CGAL-backed mesh boolean implementation. The result is `First Mesh - Second Mesh`. Both operands should be watertight and consistently oriented. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) **Parameters:** - **first_mesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **second_mesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **transfer_face_color** (*bool*, default: `False`) — Copy the birth face color to the result faces when available. - **transfer_face_quality** (*bool*, default: `False`) — Copy the birth face quality to the result faces when available. - **transfer_vert_color** (*bool*, default: `False`) — Copy birth vertex colors where possible and average neighboring source colors for newly created vertices. - **transfer_vert_quality** (*bool*, default: `False`) — Copy birth vertex qualities where possible and average neighboring source qualities for newly created vertices. ``` --- (filter-mesh-difference-trueform)= ## Mesh Difference (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Exact boolean difference of two layers. ```{py:function} ms.mesh_difference_trueform(**params) :module: _meshlab The first solid with the second removed from it. Order matters: swap the two layers to get the opposite difference. TrueForm evaluates booleans with **exact predicates**, so coplanar faces and near-degenerate intersections are decided consistently rather than by a tolerance. Both layers are taken in **world space**, so their layer matrices are applied first, and the result is added as a new layer with an identity matrix. The libigl implementation of the same operation is also available and worth comparing on difficult input. **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — The first operand. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — The second operand. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-mesh-intersection-geogram)= ## Mesh Intersection (geogram) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.geogram Create the exact intersection of two mesh layers using geogram. ```{py:function} ms.mesh_intersection_geogram(**params) :module: _meshlab Computes the exact boolean intersection of two mesh layers and creates the result as a new layer, using geogram's exact predicates. Both operands should be closed, consistently oriented surfaces without self-intersections; *Repair Self-Intersections (geogram)* can prepare an input that is not. The optional attribute transfers recover the correspondence geometrically: every face of the result lies on one of the two operand surfaces, so the nearest operand face to a result face is the face it came from. Vertices created along the intersection curve match no operand vertex, so per-vertex values are interpolated across the source face rather than copied from a nearest vertex. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **simplifyCoplanarFacets** (*bool*, default: `True`) — Merge facets that end up coplanar in the result. Turning this off keeps every triangle the intersection produced, which is larger but preserves the original tessellation more closely. - **transferFaceColor** (*bool*, default: `False`) — Copy the face color of the originating operand face onto each result face. - **transferFaceScalar** (*bool*, default: `False`) — Copy the face scalar value of the originating operand face onto each result face. - **transferVertexColor** (*bool*, default: `False`) — Interpolate vertex color from the originating operand face onto each result vertex. - **transferVertexScalar** (*bool*, default: `False`) — Interpolate the vertex scalar value from the originating operand face onto each result vertex. ``` --- (filter-mesh-intersection-libigl)= ## Mesh Intersection (libigl) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.igl Create the exact intersection of two mesh layers using libigl and CGAL. ```{py:function} ms.mesh_intersection_libigl(**params) :module: _meshlab Executes an exact boolean intersection between two mesh layers and creates the result as a new layer. The computation uses libigl's CGAL-backed mesh boolean implementation. Both operands should be watertight and consistently oriented. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) **Parameters:** - **first_mesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **second_mesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **transfer_face_color** (*bool*, default: `False`) — Copy the birth face color to the result faces when available. - **transfer_face_quality** (*bool*, default: `False`) — Copy the birth face quality to the result faces when available. - **transfer_vert_color** (*bool*, default: `False`) — Copy birth vertex colors where possible and average neighboring source colors for newly created vertices. - **transfer_vert_quality** (*bool*, default: `False`) — Copy birth vertex qualities where possible and average neighboring source qualities for newly created vertices. ``` --- (filter-mesh-intersection-trueform)= ## Mesh Intersection (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Exact boolean intersection of two layers. ```{py:function} ms.mesh_intersection_trueform(**params) :module: _meshlab The intersection of two closed solids: only what lies inside both. TrueForm evaluates booleans with **exact predicates**, so coplanar faces and near-degenerate intersections are decided consistently rather than by a tolerance. Both layers are taken in **world space**, so their layer matrices are applied first, and the result is added as a new layer with an identity matrix. The libigl implementation of the same operation is also available and worth comparing on difficult input. **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — The first operand. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — The second operand. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-mesh-symmetric-difference-geogram)= ## Mesh Symmetric Difference (geogram) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.geogram Create the exact symmetric difference of two mesh layers using geogram. ```{py:function} ms.mesh_symmetric_difference_geogram(**params) :module: _meshlab Computes the exact boolean symmetric difference (XOR) of two mesh layers and creates the result as a new layer. geogram's boolean evaluator provides union, intersection and the two differences, but not the symmetric difference, so this filter composes it as $(A \setminus B) \cup (B \setminus A)$. That is **three** boolean evaluations rather than one, so expect it to take roughly three times as long as *Mesh Difference (geogram)* on the same operands. Both operands should be closed, consistently oriented surfaces without self-intersections; *Repair Self-Intersections (geogram)* can prepare an input that is not. The optional attribute transfers recover the correspondence geometrically: every face of the result lies on one of the two operand surfaces, so the nearest operand face to a result face is the face it came from. Vertices created along the intersection curve match no operand vertex, so per-vertex values are interpolated across the source face rather than copied from a nearest vertex. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **simplifyCoplanarFacets** (*bool*, default: `True`) — Merge facets that end up coplanar in the result. Turning this off keeps every triangle the intersection produced, which is larger but preserves the original tessellation more closely. - **transferFaceColor** (*bool*, default: `False`) — Copy the face color of the originating operand face onto each result face. - **transferFaceScalar** (*bool*, default: `False`) — Copy the face scalar value of the originating operand face onto each result face. - **transferVertexColor** (*bool*, default: `False`) — Interpolate vertex color from the originating operand face onto each result vertex. - **transferVertexScalar** (*bool*, default: `False`) — Interpolate the vertex scalar value from the originating operand face onto each result vertex. ``` --- (filter-mesh-symmetric-difference-libigl)= ## Mesh Symmetric Difference (libigl) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.igl Create the exact symmetric difference of two mesh layers using libigl and CGAL. ```{py:function} ms.mesh_symmetric_difference_libigl(**params) :module: _meshlab Executes an exact boolean symmetric difference between two mesh layers and creates the result as a new layer. The computation uses libigl's CGAL-backed mesh boolean implementation. Both operands should be watertight and consistently oriented. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) **Parameters:** - **first_mesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **second_mesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **transfer_face_color** (*bool*, default: `False`) — Copy the birth face color to the result faces when available. - **transfer_face_quality** (*bool*, default: `False`) — Copy the birth face quality to the result faces when available. - **transfer_vert_color** (*bool*, default: `False`) — Copy birth vertex colors where possible and average neighboring source colors for newly created vertices. - **transfer_vert_quality** (*bool*, default: `False`) — Copy birth vertex qualities where possible and average neighboring source qualities for newly created vertices. ``` --- (filter-mesh-symmetric-difference-trueform)= ## Mesh Symmetric Difference (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Exact boolean symmetric difference of two layers. ```{py:function} ms.mesh_symmetric_difference_trueform(**params) :module: _meshlab Everything inside exactly one of the two solids, and nothing inside both. TrueForm's boolean primitive offers union, intersection and difference but not this one, so it is evaluated through the CSG evaluator as `(A - B) | (B - A)`. The result is the same; only the route differs. TrueForm evaluates booleans with **exact predicates**, so coplanar faces and near-degenerate intersections are decided consistently rather than by a tolerance. Both layers are taken in **world space**, so their layer matrices are applied first, and the result is added as a new layer with an identity matrix. The libigl implementation of the same operation is also available and worth comparing on difficult input. **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — The first operand. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — The second operand. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-mesh-union-geogram)= ## Mesh Union (geogram) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.geogram Create the exact union of two mesh layers using geogram. ```{py:function} ms.mesh_union_geogram(**params) :module: _meshlab Computes the exact boolean union of two mesh layers and creates the result as a new layer, using geogram's exact predicates. Both operands should be closed, consistently oriented surfaces without self-intersections; *Repair Self-Intersections (geogram)* can prepare an input that is not. The optional attribute transfers recover the correspondence geometrically: every face of the result lies on one of the two operand surfaces, so the nearest operand face to a result face is the face it came from. Vertices created along the intersection curve match no operand vertex, so per-vertex values are interpolated across the source face rather than copied from a nearest vertex. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **simplifyCoplanarFacets** (*bool*, default: `True`) — Merge facets that end up coplanar in the result. Turning this off keeps every triangle the intersection produced, which is larger but preserves the original tessellation more closely. - **transferFaceColor** (*bool*, default: `False`) — Copy the face color of the originating operand face onto each result face. - **transferFaceScalar** (*bool*, default: `False`) — Copy the face scalar value of the originating operand face onto each result face. - **transferVertexColor** (*bool*, default: `False`) — Interpolate vertex color from the originating operand face onto each result vertex. - **transferVertexScalar** (*bool*, default: `False`) — Interpolate the vertex scalar value from the originating operand face onto each result vertex. ``` --- (filter-mesh-union-libigl)= ## Mesh Union (libigl) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.igl Create the exact union of two mesh layers using libigl and CGAL. ```{py:function} ms.mesh_union_libigl(**params) :module: _meshlab Executes an exact boolean union between two mesh layers and creates the result as a new layer. The computation uses libigl's CGAL-backed mesh boolean implementation. Both operands should be watertight and consistently oriented. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) **Parameters:** - **first_mesh** (*mesh*, default: `@currentMeshIndex`) — First operand of the boolean operation. - **second_mesh** (*mesh*, default: `@otherMeshIndex`) — Second operand of the boolean operation. - **transfer_face_color** (*bool*, default: `False`) — Copy the birth face color to the result faces when available. - **transfer_face_quality** (*bool*, default: `False`) — Copy the birth face quality to the result faces when available. - **transfer_vert_color** (*bool*, default: `False`) — Copy birth vertex colors where possible and average neighboring source colors for newly created vertices. - **transfer_vert_quality** (*bool*, default: `False`) — Copy birth vertex qualities where possible and average neighboring source qualities for newly created vertices. ``` --- (filter-mesh-union-trueform)= ## Mesh Union (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Exact boolean union of two layers. ```{py:function} ms.mesh_union_trueform(**params) :module: _meshlab The union of two closed solids: everything inside either one. TrueForm evaluates booleans with **exact predicates**, so coplanar faces and near-degenerate intersections are decided consistently rather than by a tolerance. Both layers are taken in **world space**, so their layer matrices are applied first, and the result is added as a new layer with an identity matrix. The libigl implementation of the same operation is also available and worth comparing on difficult input. **Parameters:** - **firstMesh** (*mesh*, default: `@currentMeshIndex`) — The first operand. - **secondMesh** (*mesh*, default: `@otherMeshIndex`) — The second operand. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-split-into-solid-domains-trueform)= ## Split into Solid Domains (TrueForm) **Categories:** `Meshing/Boolean` **Plugin:** meshlab2.filter.trueform Split the volume the layers enclose into one watertight layer per region. ```{py:function} ms.split_into_solid_domains_trueform(**params) :module: _meshlab Builds one arrangement of the listed layers and emits **every region of space they enclose** as its own watertight layer. Two overlapping solids give three: what only the first encloses, what only the second encloses, and what both do. A self-intersecting layer decomposes on its own, into the regions its surface actually bounds. This has no equivalent anywhere else in MeshLab. A boolean answers one question about one region and merges everything else away; *Split into Connected Components* separates surfaces that are already apart. Neither can hand you the pieces a set of overlapping solids cuts space into, which is what a bill of materials, a contact analysis or a volumetric mesh generator needs. **Layers** are layer numbers as shown in the layer panel, separated by spaces or commas; a single number is a valid answer. **Sheets** names those of them that are open cutting surfaces rather than solids, exactly as in *Mesh CSG Expression* — a solid crossed by a sheet decomposes into the pieces on either side of it. Each output layer is closed and named for the domain it carries. The unbounded outside is not one of them, and the layer matrices are baked in, so every layer is world-space geometry. Reads TrueForm's `make_csg_domains`. **Parameters:** - **layers** (*string*, default: `0 1`) — The layer numbers to decompose, e.g. 0 1 2. A single layer decomposes into the regions its own surface encloses. - **sheets** (*string*, default: ``) — Which of those layers are open cutting surfaces rather than solids, e.g. 1. Leave empty to treat every layer as a solid. - **resolveSelfIntersections** (*bool*, default: `False`) — Also resolve each operand's own self-intersections — TrueForm's 'within' request. Leave off for clean solids; turn it on when an operand crosses itself, at some extra cost. Without it a self-intersecting operand is not classified correctly. ``` --- (filter-remove-all-faces)= ## Remove All Faces **Categories:** `Meshing/Deletion` **Plugin:** meshlab2.filter.select Delete all faces, turning mesh into point cloud. ```{py:function} ms.remove_all_faces(**params) :module: _meshlab Delete ALL faces, turning the mesh into a pointcloud. This filter has no parameters. ``` --- (filter-remove-selected-faces)= ## Remove Selected Faces **Categories:** `Meshing/Deletion` **Plugin:** meshlab2.filter.select Delete selected faces; unreferenced vertices are not deleted. ```{py:function} ms.remove_selected_faces(**params) :module: _meshlab Delete the current set of selected faces, vertices that remains unreferenced are not deleted. This filter has no parameters. ``` --- (filter-remove-selected-faces-and-vertices)= ## Remove Selected Faces and Vertices **Categories:** `Meshing/Deletion` **Plugin:** meshlab2.filter.select Delete selected faces and enclosed selected vertices. ```{py:function} ms.remove_selected_faces_and_vertices(**params) :module: _meshlab Delete the current set of selected faces and all the vertices surrounded by that faces. This filter has no parameters. ``` --- (filter-remove-selected-vertices)= ## Remove Selected Vertices **Categories:** `Meshing/Deletion` **Plugin:** meshlab2.filter.select Delete selected vertices; incident faces are deleted too. ```{py:function} ms.remove_selected_vertices(**params) :module: _meshlab Delete the current set of selected vertices; faces that share one of the deleted vertices are deleted too. This filter has no parameters. ``` --- (filter-convert-to-pure-triangles)= ## Convert to Pure Triangles **Categories:** `Meshing/Quad` **Plugin:** meshlab2.filter.meshing Split any polygonal face into triangles. ```{py:function} ms.convert_to_pure_triangles(**params) :module: _meshlab Convert into a tri-mesh by splitting any polygonal face. This filter has no parameters. ``` --- (filter-convert-to-quad-dominant-mesh)= ## Convert to Quad-Dominant Mesh **Categories:** `Meshing/Quad` **Plugin:** meshlab2.filter.meshing Convert tri mesh to quad-dominant mesh. ```{py:function} ms.convert_to_quad_dominant_mesh(**params) :module: _meshlab Convert a tri-mesh into a quad-dominant mesh by pairing suitable triangles. **Parameters:** - **level** (*enum*, default: `fewest`) — Greedy strategy. ``` --- (filter-convert-to-quads-by-4-8-subdivision)= ## Convert to Quads by 4-8 Subdivision **Categories:** `Meshing/Quad` **Plugin:** meshlab2.filter.meshing Convert tri mesh into quad mesh by 4-8 subdivision. ```{py:function} ms.convert_to_quads_by_4_8_subdivision(**params) :module: _meshlab Convert a tri mesh into a quad mesh by applying a 4-8 subdivision scheme.It introduces less overhead than the plain Catmull-Clark Subdivision Surfaces, and applying two step of this procedure generates the same connectivity of the Catmull-Clark subdivision approach.(it adds only a single vertex for each triangle instead of four).
See:
4-8 Subdivision
Luiz Velho, Denis Zorin
CAGD, volume 18, Issue 5, Pages 397-427. This filter has no parameters. ``` --- (filter-convert-to-quads-by-triangle-pairing)= ## Convert to Quads by Triangle Pairing **Categories:** `Meshing/Quad` **Plugin:** meshlab2.filter.meshing Pair triangles into quads. ```{py:function} ms.convert_to_quads_by_triangle_pairing(**params) :module: _meshlab Converts a triangle mesh into a quad mesh by merging pairs of adjacent triangles. Pairs are chosen by **quad quality** -- how close to a square the merged pair would be -- so the diagonals that were introduced when a quad mesh was triangulated are the ones removed again. Triangles that no good partner leaves over are then resolved by edge flipping, which can reach a pure quad mesh at the cost of some quality; if any remain unpaired the result is quad dominant and the filter says so. An odd triangle count cannot become pure quads, so one triangle is split first to make the count even. This filter has no parameters. ``` --- (filter-cut-along-crease-edges)= ## Cut Along Crease Edges **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.unsharp Split the mesh along sharp edges. ```{py:function} ms.cut_along_crease_edges(**params) :module: _meshlab Cut the mesh along crease edges, duplicating the vertices as necessary. Crease (or sharp) edges are defined according to the variation of normal of the adjacent faces. **Parameters:** - **angleDeg** (*double*, default: `90.0`) — If the angle between adjacent face normals is larger than this threshold, the edge is treated as a crease and the mesh is cut along it. ``` --- (filter-cut-along-scalar-isocontour-trueform)= ## Cut Along Scalar Isocontour (TrueForm) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.trueform Split the surface along contours of the vertex scalar field. ```{py:function} ms.cut_along_scalar_isocontour_trueform(**params) :module: _meshlab Cuts the surface along evenly spaced contours of the **per-vertex scalar field**, so the band between each pair of successive contour values becomes its own set of faces, with real edges along the boundaries. Where *Create Polyline from Scalar Isocontour (TrueForm)* draws the contour lines, this one cuts the mesh at them: the bands are geometry, so they can be coloured separately, split into layers, exported, or measured. Contour a height field and you get terraces; contour a geodesic distance and you get rings you can separate. Every band is kept, so the result is the whole surface cut up rather than a filtered part of it. Compute a scalar first — a constant field has nothing to cut along, and the filter says so. **Parameters:** - **contourCount** (*int*, default: `5`) — How many evenly spaced contours to cut at. N contours give N+1 bands. ``` --- (filter-cut-along-selected-edges)= ## Cut Along Selected Edges **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.meshing Open the mesh along the selected edges, duplicating the vertices on them. ```{py:function} ms.cut_along_selected_edges(**params) :module: _meshlab Cut the surface along every selected edge: the vertices on the cut are duplicated so that each selected edge becomes a border edge on both sides. Faces and positions are unchanged; only the connectivity is, so a closed cut line separates the mesh into pieces and an open one leaves a slit. A vertex where a cut ends inside the surface is not duplicated. The edges can come from any filter that selects them, such as *Select Crease Edges* (which with this filter gives the same result as *Cut Along Crease Edges*), or from an embedded polyline. The mesh must be manifold. This filter has no parameters. ``` --- (filter-embed-polyline-in-surface)= ## Embed Polyline in Surface **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.meshing Retriangulate the current mesh so that a polyline layer runs along its edges, and select those edges. ```{py:function} ms.embed_polyline_in_surface(**params) :module: _meshlab Project a polyline layer onto the current surface and make it part of the tessellation: the faces it crosses are split so that every polyline segment becomes a mesh edge, and those edges are selected. Follow it with *Cut Along Selected Edges* to open the surface along the curve, or with *Create Polyline from Selected Edges* to get the curve back exactly on the mesh. The polyline layer itself is not changed. The curve is read as **control points** joined by **strands**. Control points are only projected; between them each strand is traced across the mesh face by face, crossing every edge at its exact intersection point, and only those crossing points are kept, so the strand runs straight inside each face. By default the control points are the ends of the polyline and its junctions; *All vertices* keeps every input vertex, *Selected vertices* uses the vertex selection of the polyline layer. Curves may cross and touch: the mesh gets a vertex at every crossing, and coinciding curves share their vertices and edges. New vertices take the color, scalar, normal and texture coordinate of the surface where they lie, and split faces keep their attributes, so the mesh looks unchanged. The surface must be manifold and free of zero-area faces, and the polyline must lie close to it. **References:** - S. W. Sloan. **A fast algorithm for generating constrained Delaunay triangulations**. *Computers & Structures* (1993). [DOI](https://doi.org/10.1016/0045-7949(93)90239-A) **Parameters:** - **polyline** (*mesh*, default: `@otherMeshIndex`) — The polyline layer to embed. It is projected onto the current mesh, and left unchanged. - **controlPoints** (*enum*, default: `ends_and_nodes`) — Which polyline vertices are kept exactly (only projected). Between them the curve follows the surface and keeps only its crossings with mesh edges. ``` --- (filter-flip-edges-by-curvature)= ## Flip Edges by Curvature **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.trioptimize Optimize local triangulation by reducing discrete curvature. ```{py:function} ms.flip_edges_by_curvature(**params) :module: _meshlab Mesh optimization by edge flipping to improve local mesh curvature. The method evaluates edge flips with discrete curvature metrics and applies flips that reduce the local curvature measure. **Parameters:** - **pthreshold** (*double*, default: `1.0`) — Only face pairs with a dihedral angle larger than this threshold are considered for curvature optimization. - **curvtype** (*enum*, default: `mean`) — Metric used to evaluate curvature reduction before and after a flip. ``` --- (filter-flip-edges-by-planarity)= ## Flip Edges by Planarity **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.trioptimize Optimize local triangle quality by flipping nearly coplanar edges. ```{py:function} ms.flip_edges_by_planarity(**params) :module: _meshlab Mesh optimization by edge flipping, improving local triangle quality for face pairs whose dihedral angle is below the planar threshold. A small surface-preserving Laplacian relaxation can be run after the flip pass. **Parameters:** - **pthreshold** (*double*, default: `1.0`) — Only adjacent faces whose dihedral angle is below this threshold are considered for planar optimization. - **planartype** (*enum*, default: `area_max_side`) — Metric used to rank planar edge flips. - **iterations** (*int*, default: `1`) — Number of surface-preserving planar Laplacian smoothing iterations performed after the flip pass. ``` --- (filter-remesh-by-abstract-domain)= ## Remesh by Abstract Domain **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.isoparam Remesh a layer uniformly by sampling each region of its abstract domain on a regular grid. ```{py:function} ms.remesh_by_abstract_domain(**params) :module: _meshlab Builds a new layer by resampling the surface through the abstract domain. One square patch of *N* x *N* samples is taken over each **half-diamond** of the domain -- the region belonging to one domain edge -- on a grid of lines parallel to its sides, and the patches are stitched together into a single mesh. The result is close to uniform, and regular almost everywhere. Every interior sample of a patch ends up with exactly six neighbours, four along the grid and two along the one patch diagonal that is used, and because the domain's triangles are equilateral by construction those six come out at nearly equal distances on the surface. Irregular vertices survive only where the domain itself is irregular, at its cone singularities. The output size is the number of domain edges -- half again the number of domain faces -- times the square of the sampling rate, less the samples merged where patches meet. The filter reports which interpolation domain each sample was placed through: a single domain triangle where the sample and its neighbourhood fit inside one, a half-diamond where they straddle a domain edge, a half-star where they turn around a domain vertex. All three cover the whole domain, so a sample always has at least one to use. Requires an abstract domain on the layer: run **Parametrize by Abstract Domain** first. **References:** - Nico Pietroni, Marco Tarini, Paolo Cignoni. **Almost Isometric Mesh Parameterization through Abstract Domains**. *IEEE Transactions on Visualization and Computer Graphics* (2010). [DOI](https://doi.org/10.1109/TVCG.2009.96) **Parameters:** - **samplingRate** (*int*, default: `10`) — Side of the square patch sampled over each region of the domain. This is a resolution, not a target face count: the output grows with its square, and with the number of domain edges. A 200-face domain at rate 10 is about 30,000 samples. ``` --- (filter-remesh-by-centroidal-voronoi-tessellation-geogram)= ## Remesh by Centroidal Voronoi Tessellation (geogram) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.geogram Rebuild the surface from a centroidal Voronoi tessellation, isotropically or aligned to curvature. ```{py:function} ms.remesh_by_centroidal_voronoi_tessellation_geogram(**params) :module: _meshlab Rebuilds the current mesh by distributing the requested number of vertices over the surface with Lloyd relaxation followed by Newton optimization, then extracting the restricted Voronoi diagram as the new tessellation. In **anisotropic** mode the optimization runs in a six-dimensional space where the extra three coordinates are the surface normal scaled by the anisotropy strength, so elements stretch along flat directions and concentrate across curved ones. No other remesher in MeshLab offers this; the isotropic mode competes with *Remesh Isotropically (vcglib)* and *(TrueForm)*. The vertex count is a target, not a guarantee: geogram may add vertices to resolve problematic configurations. Because the surface is rebuilt from scratch there is no correspondence with the original tessellation, so **per-vertex and per-face attributes are not preserved** — transfer them back afterwards with a filter from the Transfer family. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **targetVertexCount** (*int*, default: `10000`) — How many vertices the result should have. geogram may exceed it to resolve problematic configurations. - **anisotropic** (*bool*, default: `False`) — Align elements with the surface's curvature instead of keeping them as equilateral as possible. - **anisotropy** (*double*, default: `0.04`) — How strongly elements follow curvature, as a fraction of the bounding box diagonal. Larger values stretch them more. Ignored unless Anisotropic is set. - **adjustToSource** (*bool*, default: `True`) — After remeshing, nudge the vertices so the new faces approximate the original surface more closely. - **adjustMaxEdgeDistance** (*double*, default: `0.5`) — How far to search for the nearest original vertex, relative to the local average edge length. Ignored unless Adjust to Source Surface is set. - **lloydIterations** (*int*, default: `5`) — Lloyd relaxation passes, which spread the vertices out evenly before the Newton phase refines them. - **newtonIterations** (*int*, default: `30`) — Newton optimization passes. More gives a better-conditioned tessellation at a higher cost. - **newtonHessianSamples** (*int*, default: `7`) — How many evaluations the Newton solver uses to approximate the Hessian. ``` --- (filter-remesh-by-edge-flipping-trueform)= ## Remesh by Edge Flipping (TrueForm) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.trueform Improve triangle shape by flipping edges and relaxing vertices, without changing the vertex count. ```{py:function} ms.remesh_by_edge_flipping_trueform(**params) :module: _meshlab Alternates rounds of **edge flipping** and **tangential relaxation** to improve triangle quality. Connectivity and vertex positions both change, but no vertex is added or removed — so this refines a tessellation you want to keep the size of, where *Remesh Isotropically* would rebuild it. The two steps depend on each other, which is why they interleave: a flip creates room for a vertex to move somewhere useful, and a moved vertex makes a different flip worthwhile. **Objective** decides which flips are taken: | Objective | Effect | |---|---| | Valence | evens out how many edges meet at each vertex, giving a regular-looking mesh | | Minimum angle | maximises the smallest angle, attacking slivers directly | Use *Valence* for a tidy mesh, *Minimum angle* when thin triangles are causing numerical trouble. **Relaxation** moves each vertex along the surface towards its neighbours' centroid; **Lambda** is how far. Set **Max Deviation** above zero to bound how far the surface may drift from its starting shape — worth doing when the geometry matters more than the triangles. **Check Normals** rejects any flip or move that would fold a triangle over. Leave it on unless you know the mesh is well behaved. Competing implementations: *Flip Edges by Curvature* and *Flip Edges by Planarity* do the flipping half with vcglib, driven by different objectives; the vcglib *Smooth* filters do the relaxation half. This does both together. **Parameters:** - **objective** (*enum*, default: `valence`) — What the edge flips optimise for. - **iterations** (*int*, default: `3`) — How many flip-then-relax rounds to run. - **relaxationIterations** (*int*, default: `3`) — Relaxation passes inside each round. Zero flips without moving anything. - **lambda** (*double*, default: `0.5`) — How far relaxation moves a vertex towards its neighbours, 0 to 1. - **maxDeviation** (*absperc*, default: `0.0`) — Largest distance the surface may drift from its starting shape. Zero leaves relaxation unbounded. - **checkNormals** (*bool*, default: `True`) — Reject flips and moves that would fold a triangle over. ``` --- (filter-remesh-isotropically-trueform)= ## Remesh Isotropically (TrueForm) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.trueform Rebuild the tessellation with triangles of a uniform target edge length. ```{py:function} ms.remesh_isotropically_trueform(**params) :module: _meshlab Rebuilds the tessellation so triangles approach a uniform size and shape, by splitting long edges, collapsing short ones, flipping to improve valence and relaxing vertices along the surface. **Target Edge Length** is the size aimed for. **Iterations** is how many split/collapse/flip/relax rounds run; **Relaxation Iterations** the tangential smoothing passes inside each round. **Feature Angle** protects sharp edges: any dihedral angle above it is treated as a crease and preserved rather than smoothed away. It is off by default (negative), which is right for organic surfaces and wrong for anything with intended hard edges. Competing implementation: *Remesh Isotropically* does the same with vcglib. TrueForm's is parallelised and has the explicit feature and boundary contracts above. **Parameters:** - **targetLength** (*absperc*, default: `@bboxDiag01`) — The edge length the remesher aims for. - **iterations** (*int*, default: `3`) — How many remeshing rounds to run. - **relaxationIterations** (*int*, default: `3`) — Tangential smoothing passes within each round. - **preserveBoundary** (*bool*, default: `True`) — Hold boundary edges fixed. Turn off only if the border is allowed to move. - **featureAngle** (*double*, default: `-1.0`) — Dihedral angle above which an edge counts as a sharp feature and is protected. Negative disables feature detection. ``` --- (filter-remesh-isotropically-vcglib)= ## Remesh Isotropically (vcglib) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.meshing Explicit isotropic remeshing by local operations. ```{py:function} ms.remesh_isotropically_vcglib(**params) :module: _meshlab Perform a explicit remeshing of a triangular mesh, by repeatedly applying edge flip, collapse, relax and refine operations to regularize size and aspect ration of the triangular meshing. Loosely inspired to:
Hugues Hoppe, Tony DeRose, Tom Duchamp, John McDonald, and Werner Stuetzle.
Mesh optimization
(SIGGRAPH '93). ACM, New York, NY, USA, 19–26. DOI **Parameters:** - **Iterations** (*int*, default: `10`) — Number of remeshing iterations. - **Adaptive** (*bool*, default: `False`) — Toggle adaptive isotropic remeshing. - **TargetLen** (*absperc*, default: `@bboxDiag01`) — Target length for remeshed edges. - **FeatureDeg** (*double*, default: `30.0`) — Minimum angle to treat an edge as feature. - **CheckSurfDist** (*bool*, default: `False`) — Each operation must satisfy max surface distance. - **MaxSurfDist** (*absperc*, default: `@bboxDiag01`) — Maximum allowed local surface deviation. - **ReferenceMesh** (*mesh*, default: `@currentMeshIndex`) — Mesh used for surface-distance checks and reprojection. The current mesh preserves the original behavior; choosing another layer checks/remeshes against that layer, respecting both mesh transforms. - **SplitFlag** (*bool*, default: `True`) — Include refine step. - **CollapseFlag** (*bool*, default: `True`) — Include collapse step. - **SwapFlag** (*bool*, default: `True`) — Include edge-swap step. - **SmoothFlag** (*bool*, default: `True`) — Include smoothing step. - **ReprojectFlag** (*bool*, default: `True`) — Include projection step. ``` --- (filter-remesh-to-quads-instant-meshes)= ## Remesh to Quads (Instant Meshes) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.instant_meshes Generate an isotropic, field-aligned quad or quad-dominant mesh with Instant Meshes. ```{py:function} ms.remesh_to_quads_instant_meshes(**params) :module: _meshlab Runs the original **Instant Field-Aligned Meshes** pipeline by Jakob et al. The method builds a multiresolution hierarchy, optimizes a four-fold rotational orientation field and a compatible position field, then extracts a new surface whose edges follow those fields. It is a local, parallel method designed to scale linearly with input size. The result is created as a new geometry-only layer. MeshLab stores each generated quad as two triangles connected by a VCGLib faux edge, preserving polygonal rendering and saving. Vertex attributes, selections, materials and textures are not transferred. **Pure quads** subdivides irregular extracted faces to obtain only quads; **quad dominant** retains exceptional triangles. The target edge length is approximate because extraction is driven by the optimized fields. **Upstream:** [Instant Meshes](https://github.com/wjakob/instant-meshes) **License:** BSD-3-Clause **References:** - Wenzel Jakob, Marco Tarini, Daniele Panozzo, Olga Sorkine-Hornung. **Instant Field-Aligned Meshes**. *ACM Transactions on Graphics* (2015). [DOI](https://doi.org/10.1145/2816795.2818078) [Web](https://igl.ethz.ch/projects/instant-meshes/) **Parameters:** - **targetEdgeLength** (*absperc*, default: `@bboxDiag01`) — Approximate world-space edge length of the generated mesh. - **outputTopology** (*enum*, default: `pure_quads`) — Pure quads subdivides exceptional faces; quad dominant permits triangles around irregular regions. - **detectCreases** (*bool*, default: `False`) — Split normals at sufficiently sharp input edges so the generated field follows them. - **creaseAngle** (*double*, default: `30.0`) — Dihedral-angle threshold used when sharp-crease detection is enabled. - **alignBoundaries** (*bool*, default: `False`) — Constrain the orientation and position fields to open mesh boundaries. - **optimizationSpace** (*enum*, default: `extrinsic`) — Extrinsic optimization uses embedded 3D directions; intrinsic optimization transports directions over the surface. - **smoothingIterations** (*int*, default: `2`) — Post-extraction smoothing iterations with projection back to the input surface. Zero disables smoothing and BVH construction. - **deterministic** (*bool*, default: `False`) — Prefer reproducible graph construction and ordering at some performance cost. - **threads** (*int*, default: `0`) — Maximum oneTBB parallelism. Zero uses the runtime default. ``` --- (filter-remesh-to-quads-quadwild-bimdf)= ## Remesh to Quads (QuadWild-BiMDF) **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.quadwild Generate a feature-aligned pure-quad mesh with QuadWild and its open-source Bi-MDF quantizer. ```{py:function} ms.remesh_to_quads_quadwild_bimdf(**params) :module: _meshlab Runs the original **QuadWild** feature-line-driven remeshing pipeline, using the open-source **Bi-MDF** solver from the cgg-bern fork instead of the commercial Gurobi solver. The method computes a feature-aligned cross field, traces a coarse patch layout that may contain T-junctions and non-quadrilateral patches, and quantizes and tessellates that layout into a conforming pure-quad mesh. MeshLab invokes the two unmodified upstream helper executables in an isolated temporary directory. Their crashes and process-level exits therefore cannot terminate MeshLab. The result is imported through VCGLib: each quad becomes two triangles joined by a faux edge, preserving polygonal rendering and saving. Geometry is created in a new layer with the input layer transform; input attributes, selections, textures and materials are not transferred. **Feature-aware** detects creases above 35 degrees and is intended for mechanical or CAD-like surfaces. **Organic** disables automatic sharp-feature detection. **Output scale** is QuadWild's dimensionless `scaleFact`: larger values generate larger, fewer quads. This is an expensive global algorithm and can take substantial time on complex meshes. **Upstream:** [QuadWild-BiMDF](https://github.com/cgg-bern/quadwild-bimdf) **License:** GPL-3.0-or-later **References:** - Nico Pietroni, Stefano Nuvoli, Thomas Alderighi, Paolo Cignoni, Marco Tarini. **Reliable Feature-Line Driven Quad-Remeshing**. *ACM Transactions on Graphics* (2021). [DOI](https://doi.org/10.1145/3450626.3459941) [Web](https://www.quadmesh.cloud/) - Martin Heistermann, Jethro Warnett, David Bommes. **Min-Deviation-Flow in Bi-directed Graphs for T-Mesh Quantization**. *ACM Transactions on Graphics* (2023). [DOI](https://doi.org/10.1145/3592437) [Web](https://www.algohex.eu/publications/bimdf-quantization) **Parameters:** - **surfacePreset** (*enum*, default: `feature_aware`) — Feature-aware detects sharp creases; Organic treats the surface as smooth. - **outputScale** (*double*, default: `1.0`) — Dimensionless QuadWild scale factor. Larger values produce larger and fewer quads. - **alignSingularities** (*bool*, default: `True`) — Encourage irregular vertices to align across the patch layout. - **smoothOutput** (*bool*, default: `True`) — Import QuadWild's surface-projected smoothed result instead of the unsmoothed quadrangulation. ``` --- (filter-remesh-uniformly-by-volumetric-resampling)= ## Remesh Uniformly by Volumetric Resampling **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.sampling Build an offset mesh from a signed distance field sampled on a regular grid. ```{py:function} ms.remesh_uniformly_by_volumetric_resampling(**params) :module: _meshlab Create a new mesh that is a resampled version of the current one.
The resampling is done by building a uniform volumetric representation where each voxel contains the signed distance from the original surface. The resampled surface is reconstructed using the marching cube algorithm over this volume. **Parameters:** - **CellSize** (*absperc*, default: `@bboxDiag01`) — Sampling cell size. Smaller cells give more precise results at higher cost. - **Offset** (*absperc*, default: `0.0`) — Offset of the extracted surface relative to the original mesh. - **mergeCloseVert** (*bool*, default: `False`) — Merge nearly coincident vertices in the generated mesh. - **discretize** (*bool*, default: `False`) — Use fixed edge midpoints instead of linear interpolation for a stair-step appearance. - **multisample** (*bool*, default: `False`) — Compute the distance field more accurately by multisampling the volume. - **absDist** (*bool*, default: `False`) — Use an unsigned distance field to create an inner and outer shell around the input mesh. ``` --- (filter-trim-surface-by-plane)= ## Trim Surface by Plane **Categories:** `Meshing/Remeshing` **Plugin:** meshlab2.filter.meshing Cuts the mesh with an oriented plane and keeps one side. ```{py:function} ms.trim_surface_by_plane(**params) :module: _meshlab Trims the current layer along an oriented plane, discarding everything behind it. Faces crossing the plane are split along it, so the cut is a clean boundary rather than a jagged edge along the nearest face borders. The per-vertex scalar, colour and texture coordinates are preserved, and interpolated onto the vertices created along the cut. Unless the cut is closed the result is a surface with a new boundary, not a solid. **Parameters:** - **planeNormal** (*point3f*, default: `[1.0, 0.0, 0.0]`) — Direction the cutting plane faces. Everything behind the plane is discarded. It need not be unit length. - **relativeTo** (*enum*, default: `center`) — Point the offset is measured from. - **planeOffset** (*double*, default: `0.0`) — Distance from the reference point to the plane, measured along the plane normal. - **flip** (*bool*, default: `False`) — If enabled, the side that would have been discarded is kept instead. The same as negating the plane normal, kept as a control because reversing a cut is a thing you do often. - **snapTolerance** (*double*, default: `0.0`) — How close to an existing vertex, as a fraction of the edge, the cut may fall before that vertex is moved onto the plane instead of the edge being split. Zero, the default, splits every crossing edge exactly; a vertex lying on the plane to within rounding is put on it regardless. Raising it leaves fewer thin triangles along the cut, but moves vertices by up to that fraction of an edge, which on long edges, such as the cap of an earlier cut, is enough to see. - **closeCut** (*bool*, default: `False`) — If enabled, the boundary opened by the plane is filled with new faces, so a closed mesh stays closed. All the loops on the plane are filled together with an even-odd rule, so a cut that leaves concentric outlines is capped as a ring rather than as overlapping discs. Only those loops are filled; holes the mesh already had are left alone. Parts of the layer that pass through each other are closed one by one. An outline that crosses or touches itself, as the section of a self-intersecting scan can, is still closed, though a few of its new faces may fold over others where it crosses. The log says how many edges of the cut, if any, could not be closed. ``` --- (filter-simplify-by-decimation-trueform)= ## Simplify by Decimation (TrueForm) **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.trueform Reduce the triangle count to a target fraction of the original. ```{py:function} ms.simplify_by_decimation_trueform(**params) :module: _meshlab Collapses edges until the face count reaches the requested **fraction of the original**, choosing collapses by geometric error so detail is given up where it costs least. A proportion rather than an absolute count, so the filter behaves the same on any input and can be applied repeatedly: 0.5 halves the mesh each time. Use *Simplify by Error Bound (TrueForm)* when fidelity matters more than the resulting size. Competing implementation: see also the quadric edge collapse filters under *Meshing/Simplification*. **Parameters:** - **targetProportion** (*double*, default: `0.5`) — Fraction of the original face count to keep. 0.5 halves the mesh. - **preserveBoundary** (*bool*, default: `True`) — Hold boundary edges fixed. Turn off only if the border is allowed to move. - **featureAngle** (*double*, default: `-1.0`) — Dihedral angle above which an edge counts as a sharp feature and is protected. Negative disables feature detection. ``` --- (filter-simplify-by-error-bound-trueform)= ## Simplify by Error Bound (TrueForm) **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.trueform Reduce triangle count as far as a geometric error bound allows. ```{py:function} ms.simplify_by_error_bound_trueform(**params) :module: _meshlab Collapses edges for as long as the surface stays within an **error bound**, rather than towards a face count. That is the useful difference from the other simplifiers here: you state the fidelity you will accept and get however few triangles that permits, instead of stating a triangle count and discovering the error afterwards. **Error Bound** is a distance. Type it directly in model units when you know the tolerance you have to hold -- a measurement accuracy, a printing tolerance -- or switch the field to a percentage of the bounding-box diagonal when you want the same value to mean the same thing across models of different scales. The default is 0.1% of the diagonal, which is conservative. Use *Simplify by Decimation (TrueForm)* when you need a specific face count instead. **Parameters:** - **errorBound** (*absperc*, default: `@bboxDiag001`) — Largest geometric deviation allowed. Enter it directly in model units, or as a percentage of the bounding-box diagonal. - **iterations** (*int*, default: `1`) — How many simplification passes to run. - **preserveBoundary** (*bool*, default: `True`) — Hold boundary edges fixed. Turn off only if the border is allowed to move. - **featureAngle** (*double*, default: `-1.0`) — Dihedral angle above which an edge counts as a sharp feature and is protected. Negative disables feature detection. ``` --- (filter-simplify-by-quadric-edge-collapse-qslim)= ## Simplify by Quadric Edge Collapse (QSlim) **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.qslim Simplify a triangle mesh with Garland's original QSlim implementation. ```{py:function} ms.simplify_by_quadric_edge_collapse_qslim(**params) :module: _meshlab Runs the original `MxEdgeQSlim` edge-contraction implementation from Michael Garland's MixKit, preserved through the pinned [QSlim 2.1 repository](https://github.com/alecjacobson/qslim). This is a separate implementation from MeshLab's VCGLib quadric decimator, allowing results and historical behavior to be compared directly. QSlim's placement and weighting policies, boundary constraint weight, compactness threshold, and meshing penalty are exposed using their original meanings. The result is created as a new geometry-only layer and preserves the input layer transform. Vertex and face attributes, materials, textures, selections, and polygonal edge markings are not transferred. The original core has no cancellation or fine-grained progress API, so only phase-level progress is available. **Upstream:** [QSlim 2.1 (original MixKit implementation)](https://github.com/alecjacobson/qslim) **License:** LGPL-2.0-or-later with MixKit static-linking exception **References:** - Michael Garland, Paul S. Heckbert. **Surface Simplification Using Quadric Error Metrics**. *Proceedings of the 24th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH '97)* (1997). [DOI](https://doi.org/10.1145/258734.258849) [Web](https://github.com/alecjacobson/qslim) **Parameters:** - **TargetFaceNum** (*int*, default: `@faceCountHalf`) — Desired final number of faces. - **PlacementPolicy** (*enum*, default: `optimal`) — Original QSlim placement policy for the vertex produced by an edge contraction. - **WeightingPolicy** (*enum*, default: `area`) — Original QSlim policy used to weight face quadrics. - **BoundaryWeight** (*double*, default: `1000.0`) — Weight of the original QSlim boundary-preserving constraint. Zero disables it. - **CompactnessRatio** (*double*, default: `0.0`) — Minimum local triangle compactness accepted by QSlim. Zero disables this penalty. - **MeshingPenalty** (*double*, default: `1.0`) — Scale applied to QSlim's local validity, compactness, inversion, and degree penalties. ``` --- (filter-simplify-by-quadric-edge-collapse-vcglib)= ## Simplify by Quadric Edge Collapse (vcglib) **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.meshing Simplify using quadric-based edge-collapse. ```{py:function} ms.simplify_by_quadric_edge_collapse_vcglib(**params) :module: _meshlab Simplifies a mesh with VCGLib's quadric edge-collapse implementation, a variant of the Garland–Heckbert algorithm with additional weighting schemes for poorly shaped faces and planar or degenerate regions. This filter uses VCGLib and remains distinct from the separately available **Original QSlim Quadric Edge Collapse** filter, which compiles Garland's original `MxEdgeQSlim` implementation. **References:** - Michael Garland, Paul S. Heckbert. **Surface Simplification Using Quadric Error Metrics**. *Proceedings of the 24th Annual Conference on Computer Graphics and Interactive Techniques (SIGGRAPH '97)* (1997). [DOI](https://doi.org/10.1145/258734.258849) [Web](https://github.com/alecjacobson/qslim) **Parameters:** - **TargetFaceNum** (*int*, default: `@selOrFaceCountHalf`) — Desired final number of faces. - **TargetPerc** (*double*, default: `0.0`) — Desired final size as percentage of initial size. - **QualityThr** (*double*, default: `0.3`) — Quality threshold for penalizing bad shaped faces. - **PreserveBoundary** (*bool*, default: `False`) — Try to preserve mesh boundaries. - **BoundaryWeight** (*double*, default: `1.0`) — Boundary importance during simplification. - **PreserveNormal** (*bool*, default: `False`) — Try to avoid face flipping effects. - **PreserveTopology** (*bool*, default: `False`) — Avoid collapses causing topology changes. - **OptimalPlacement** (*bool*, default: `True`) — Place collapsed vertices minimizing quadric error. - **PlanarQuadric** (*bool*, default: `False`) — Additional constraints preserving planar areas. - **PlanarWeight** (*double*, default: `0.001`) — Weight for preserving planar regions. - **QualityWeight** (*bool*, default: `False`) — Use per-vertex quality as weighting factor. - **AutoClean** (*bool*, default: `True`) — Run cleaning after simplification. ``` --- (filter-simplify-by-quadric-edge-collapse-with-texture-vcglib)= ## Simplify by Quadric Edge Collapse with Texture (vcglib) **Categories:** `Meshing/Simplification`, `Texture` **Plugin:** meshlab2.filter.meshing Simplify textured meshes preserving UVs. ```{py:function} ms.simplify_by_quadric_edge_collapse_with_texture_vcglib(**params) :module: _meshlab Simplifies a textured mesh with VCGLib's attribute-aware quadric edge-collapse implementation while preserving its UV parameterization. This follows the Garland–Heckbert extension of quadric error metrics to material attributes. **References:** - Michael Garland, Paul S. Heckbert. **Simplifying Surfaces with Color and Texture using Quadric Error Metrics**. *Proceedings of IEEE Visualization '98* (1998). [DOI](https://doi.org/10.1109/VISUAL.1998.745312) [Web](https://mgarland.org/papers/quadric2.pdf) **Parameters:** - **TargetFaceNum** (*int*, default: `@selOrFaceCountHalf`) — Desired final number of faces. - **TargetPerc** (*double*, default: `0.0`) — Desired final size as percentage of initial size. - **QualityThr** (*double*, default: `0.3`) — Quality threshold for penalizing bad shaped faces. - **Extratcoordw** (*double*, default: `1.0`) — Additional weight for extra texture coordinates. - **PreserveBoundary** (*bool*, default: `False`) — Try to preserve mesh boundaries. - **BoundaryWeight** (*double*, default: `1.0`) — Boundary importance during simplification. - **OptimalPlacement** (*bool*, default: `True`) — Place collapsed vertices minimizing quadric error. - **PreserveNormal** (*bool*, default: `False`) — Try to avoid face flipping effects. - **PlanarQuadric** (*bool*, default: `False`) — Additional constraints preserving planar areas. ``` --- (filter-simplify-by-vertex-clustering)= ## Simplify by Vertex Clustering **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.meshing Simplify mesh by clustering vertices on a grid. ```{py:function} ms.simplify_by_vertex_clustering(**params) :module: _meshlab Simplify the mesh by clustering vertices; by using a uniform grid over the mesh, the algorithm merges all the vertices in a grid cell into a single vertex. By design this approach removes all small triangles, but also create a number of non-manifold situation.
See:

Jarek Rossignac, and Paul Borrel.
Multi-resolution 3D approximations for rendering complex scenes.
Modeling in computer graphics: methods and applications. Springer, 1993 **Parameters:** - **Threshold** (*absperc*, default: `@bboxDiag01`) — Cell size of clustering grid. ``` --- (filter-simplify-marching-cubes-mesh-by-edge-collapse)= ## Simplify Marching-Cubes Mesh by Edge Collapse **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.plymc Simplify only meshes generated by Marching Cubes, preserving the grid structure. ```{py:function} ms.simplify_marching_cubes_mesh_by_edge_collapse(**params) :module: _meshlab A simplification/cleaning algorithm that works only on meshes generated by Marching Cubes. It detects the grid spacing automatically and collapses redundant edges while preserving the bounding box. **Parameters:** - **cellError** (*double*, default: `0.25`) — Collapse error in MC cell units. 0.25 = 1/4 of a cell side (original default). 1.0 = 1 full cell side (more aggressive). 0.0 = auto (same as 0.25). - **preserveBB** (*bool*, default: `False`) — If true, vertices on the bounding box are not collapsed. - **flipThreshold** (*double*, default: `10.0`) — T-vertex removal aggressiveness. Higher = more removal. Default 10. A vertex within 1/threshold of the edge length is considered a T-vertex. ``` --- (filter-simplify-point-cloud)= ## Simplify Point Cloud **Categories:** `Meshing/Simplification` **Plugin:** meshlab2.filter.sampling Simplify a point cloud with Poisson-disk pruning. ```{py:function} ms.simplify_point_cloud(**params) :module: _meshlab Create a new layer populated with a simplified version of the current point cloud. The simplification is performed by subsampling the original point cloud using a Poisson Disk strategy using the algorithm described in:
'Efficient and Flexible Sampling with Blue Noise Properties of Triangular Meshes'
Massimiliano Corsini, Paolo Cignoni, Roberto Scopigno
IEEE TVCG 2012 **Parameters:** - **SampleNum** (*int*, default: `1000`) — Desired number of samples. Ignored if an explicit radius is provided. - **Radius** (*absperc*, default: `0.0`) — If non-zero, overrides the sample number and uses this radius directly. - **BestSampleFlag** (*bool*, default: `True`) — Use a heuristic to improve the maximality of the chosen sample set. - **BestSamplePool** (*int*, default: `10`) — Number of candidate attempts used when the best-sample heuristic is enabled. - **ExactNumFlag** (*bool*, default: `False`) — Search for a radius that matches the requested number of samples within the given tolerance. - **ExactNumTolerance** (*double*, default: `0.005`) — Tolerance used by precise sample count search, expressed as a fraction of the requested sample count. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the surviving subset of points exactly reproducible. ``` --- (filter-refine-by-user-expression)= ## Refine by User Expression **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.expression Refines edges selected by an expression and places split points by expressions. ```{py:function} ms.refine_by_user_expression(**params) :module: _meshlab Refine current mesh with user defined parameters.
Specify a Boolean Function needed to select which edges will be cut for refinement purpose.
Each edge is identified with first and second vertex.
Arguments accepted are first and second vertex attributes:
**Parameters:** - **condSelect** (*string*, default: `(q0 >= 0 && q1 >= 0)`) — Boolean expression used to decide whether an edge is refined. - **x** (*string*, default: `(x0+x1)/2`) — Expression for X output. - **y** (*string*, default: `(y0+y1)/2`) — Expression for Y output. - **z** (*string*, default: `(z0+z1)/2`) — Expression for Z output. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-subdivide-by-butterfly)= ## Subdivide by Butterfly **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply Butterfly subdivision. ```{py:function} ms.subdivide_by_butterfly(**params) :module: _meshlab Apply Butterfly Subdivision Surface algorithm. It is an interpolated refinement method, defined on arbitrary triangular meshes. The scheme is known to be C1 but not C2 on regular meshes
**Parameters:** - **Iterations** (*int*, default: `3`) — Number of times the model is subdivided. - **Threshold** (*absperc*, default: `@bboxDiag01`) — All edges longer than this threshold are refined. ``` --- (filter-subdivide-by-catmull-clark)= ## Subdivide by Catmull-Clark **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply Catmull-Clark subdivision. ```{py:function} ms.subdivide_by_catmull_clark(**params) :module: _meshlab Apply a number of iteration of the classical Catmull-Clark Subdivision Surfaces. If the mesh is triangle based (no faux edges) it generates a quad mesh, otherwise it honores it the faux-edge bits **Parameters:** - **Iterations** (*int*, default: `2`) — Number of times model is subdivided. ``` --- (filter-subdivide-by-doo-sabin)= ## Subdivide by Doo-Sabin **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply Doo-Sabin subdivision. ```{py:function} ms.subdivide_by_doo_sabin(**params) :module: _meshlab Apply the DooSabin Subdivision Surfaces. It is a Dual approximating refinement scheme that creates a new face for each vertex, edge and face. On a pure quad mesh it will add non quad face for each extraordinarhy vertex in the mesh (e.g. in a cube it will add a triangular face for each corner. On the other hand after a refinement step all the vertices will have degree 4. **Parameters:** - **Iterations** (*int*, default: `2`) — Number of times model is subdivided. ``` --- (filter-subdivide-by-loop)= ## Subdivide by Loop **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply Loop subdivision. ```{py:function} ms.subdivide_by_loop(**params) :module: _meshlab Apply Loop's Subdivision Surface algorithm. It is an approximant refinement method and it works for every triangle and has rules for extraordinary vertices.
**Parameters:** - **LoopWeight** (*enum*, default: `loop`) — Change the weights used. Allows one to optimize some behaviors over others. - **Iterations** (*int*, default: `3`) — Number of times the model is subdivided. - **Threshold** (*absperc*, default: `@bboxDiag01`) — All edges longer than this threshold are refined. Zero means uniform refinement. ``` --- (filter-subdivide-by-ls3-loop)= ## Subdivide by LS3 Loop **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply LS3 Loop subdivision. ```{py:function} ms.subdivide_by_ls3_loop(**params) :module: _meshlab Apply LS3 Subdivision Surface algorithm using Loop's weights. This refinement method take normals into account.
See:Boye', S. Guennebaud, G. & Schlick, C.
Least squares subdivision surfaces
Computer Graphics Forum, 2010.

Alternatives weighting schemes are based on the paper: Barthe, L. & Kobbelt, L.
Subdivision scheme tuning around extraordinary vertices
Computer Aided Geometric Design, 2004, 21, 561-583.
The current implementation of these schemes don't handle vertices of valence > 12 **Parameters:** - **LoopWeight** (*enum*, default: `loop`) — Change the weights used. - **Iterations** (*int*, default: `3`) — Number of times the model is subdivided. - **Threshold** (*absperc*, default: `@bboxDiag01`) — All edges longer than this threshold are refined. ``` --- (filter-subdivide-by-midpoint)= ## Subdivide by Midpoint **Categories:** `Meshing/Subdivision` **Plugin:** meshlab2.filter.meshing Apply midpoint subdivision. ```{py:function} ms.subdivide_by_midpoint(**params) :module: _meshlab Apply a plain subdivision scheme where every edge is split on its midpoint. Useful to uniformly refine a mesh substituting each triangle with four smaller triangles. **Parameters:** - **Iterations** (*int*, default: `3`) — Number of times the model is subdivided. - **Threshold** (*absperc*, default: `@bboxDiag01`) — All edges longer than this threshold are refined. ``` --- (filter-pack-uv-charts-geogram)= ## Pack UV Charts (geogram) **Categories:** `Parametrization/Atlas Packing` **Plugin:** meshlab2.filter.geogram Lay the existing UV charts out again in a single atlas, using geogram's packers. ```{py:function} ms.pack_uv_charts_geogram(**params) :module: _meshlab Rearranges the charts of an existing parametrization in the unit square, leaving the flattening of each chart untouched. The mesh must already carry per-wedge texture coordinates. The Tetris packer is the one described in the original LSCM paper and is not available from any other MeshLab filter. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **packer** (*enum*, default: `tetris`) — Which packing algorithm to apply. ``` --- (filter-pack-uv-charts-vcglib)= ## Pack UV Charts (vcglib) **Categories:** `Parametrization/Atlas Packing`, `Texture` **Plugin:** meshlab2.filter.texture_defragmentation Lay the existing UV charts out again in a single atlas, using a choice of vcglib packing algorithms. ```{py:function} ms.pack_uv_charts_vcglib(**params) :module: _meshlab Repacks the atlas without changing the charts themselves: no merging, no reparametrization, just a new layout for the islands the mesh already has. Four packers are offered, and they trade quality against time very differently: - **Rasterized, scaled to fit** rasterizes each chart outline and searches for the largest scale at which everything fits. The tightest packing, and the slowest. - **Rasterized, best effort** keeps the charts at their current scale and places as many as it can in the atlas you asked for. - **Axis-aligned rectangles** packs each chart's bounding box. Fast and loose. - **Object-oriented rectangles** packs each chart's minimum-area oriented box, rotating the chart to match. Usually tighter than axis-aligned for nothing like the cost of rasterizing. The *Try chart permutations* option is worth knowing about. The rasterized packers can retry the layout with reshuffled chart orders, which costs five packing passes per similarly sized chart -- on an atlas whose islands are all much of a muchness that is five passes per chart, and it dominates the run. It is off here by default. **Parameters:** - **algorithm** (*enum*, default: `rasterized_scaled`) — Which vcglib packer lays the charts out. - **textureSize** (*int*, default: `1024`) — Side of the square atlas the charts are packed into. - **gutterWidth** (*int*, default: `4`) — Padding kept around each chart, so bilinear filtering cannot bleed between neighbours. - **rotationNum** (*int*, default: `4`) — How many orientations each chart is tried at, rounded to the nearest multiple of four -- the packer derives four slots from every base rasterization, so only multiples of four are usable. Rasterized packers only. - **permutations** (*bool*, default: `False`) — Retry the layout with reshuffled chart orders. Costs five packing passes per similarly sized chart, so on a uniform atlas it is five per chart and it dominates the run. Rasterized packers only. - **resampleTextures** (*bool*, default: `True`) — Render the new atlas by resampling the original texture images. Turn it off to treat this as a parametrization-only filter: the layer comes back with the reorganized UV layout and no texture images, which is what you want when the texture is going to be baked again afterwards. The source images are still required either way -- the algorithm measures islands and distortion in texel space, so it needs their resolution before it can start. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the atlas packing exactly reproducible. ``` --- (filter-defragment-texture-atlas)= ## Defragment Texture Atlas **Categories:** `Parametrization/Defragmentation`, `Texture` **Plugin:** meshlab2.filter.texture_defragmentation Reduce texture atlas fragmentation by merging compatible charts and resampling the texture map. ```{py:function} ms.defragment_texture_atlas(**params) :module: _meshlab Reduces texture fragmentation by merging compatible atlas charts, repacking the resulting charts, and resampling the associated texture images onto the optimized atlas. This MeshLab port vendors the upstream TextureDefrag reference implementation from `https://github.com/maggio-a/texture-defrag` and adapts it to MeshLab's mesh-owned texture model. The filter creates a new mesh layer named `texdefrag_` rather than overwriting the input mesh, preserving the original atlas for comparison. Turn off *Resample textures* to treat this as a parametrization operation instead: the layer comes back with the reorganized UV layout and no texture images, and in that mode it accepts a layer that has a parametrization but no texture yet. Implementation note: the original reference code used OpenGL to rasterize the new texture atlas. MeshLab isolates that step behind the original `RenderTexture` boundary; this first integration uses an internal image renderer so the algorithm can run from the filter framework without requiring an OpenGL context. The renderer boundary is intentionally narrow so a QRhi backend can replace it cleanly. **References:** - Andrea Maggiordomo, Paolo Cignoni, Marco Tarini. **Texture Defragmentation for Photo-Reconstructed 3D Models**. *Computer Graphics Forum* (2021). [DOI](https://doi.org/10.1111/cgf.142615) [Web](https://diglib.eg.org/items/b3e092cd-5a96-4575-975d-af22795e870b) **Parameters:** - **matchingThreshold** (*double*, default: `2.0`) — Threshold on the seam alignment error. Higher values allow more seams to be considered compatible, which can reduce fragmentation, but may increase runtime and risk more distortion. MeshLab default: `2.0`. - **boundaryTolerance** (*double*, default: `0.2`) — Cutoff on the minimum fractional seam length relative to the chart perimeter. Seams with lower fractional length are not merged, helping keep chart borders compact. MeshLab default: `0.2`. - **distortionTolerance** (*double*, default: `0.5`) — Local UV optimization distortion tolerance when merging a seam. If local ARAP energy exceeds this value, the merge is reverted. Smaller values preserve the original parameterization more strictly; larger values can merge more charts. MeshLab default: `0.5`. - **globalDistortionTolerance** (*double*, default: `0.025`) — Global atlas ARAP distortion tolerance when accepting a seam merge. If the global atlas energy exceeds this value, the merge is reverted. This is usually kept much smaller than the local tolerance. MeshLab default: `0.025`. - **uvReductionLimit** (*double*, default: `0.0`) — Target UV boundary length reduction, expressed as a percentage of the input UV boundary length. The algorithm stops once this reduction has been reached, or when no further seams can be merged. `0` means no target reduction stop condition. MeshLab default: `0`. - **offsetFactor** (*double*, default: `5.0`) — Coefficient controlling the extension of the local UV optimization area. Larger values can make defragmentation more effective by giving the optimizer more room, but increase geometric optimization cost and runtime. MeshLab default: `5.0`. - **timelimit** (*double*, default: `0.0`) — Time limit for the defragmentation process. `0` means unlimited. This is useful for very large atlases where chart merging can be expensive. MeshLab default: `0`. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the atlas packing exactly reproducible. - **resampleTextures** (*bool*, default: `True`) — Render the new atlas by resampling the original texture images. Turn it off to treat this as a parametrization-only filter: the layer comes back with the reorganized UV layout and no texture images, which is what you want when the texture is going to be baked again afterwards. The source images are still required either way -- the algorithm measures islands and distortion in texel space, so it needs their resolution before it can start. ``` --- (filter-merge-texture-islands)= ## Merge Texture Islands **Categories:** `Parametrization/Defragmentation`, `Texture` **Plugin:** meshlab2.filter.texture_defragmentation Merge texture islands -- the small ones, or the ones you select -- into neighbors sharing a seam, then repack and resample the atlas. ```{py:function} ms.merge_texture_islands(**params) :module: _meshlab Dissolves texture islands into a neighbour they share a seam with, so the pair becomes one island with one fewer seam between them. Which islands go is up to *Islands to merge*: either every island under a size threshold, which is the automatic sweep, or the ones you picked by hand. In the second mode any island holding at least one selected face is a candidate -- select a single face to name an island -- and it is merged into an adjacent island, which is how you fold a chart into a particular neighbour rather than whichever the size sweep would have chosen. An island with no selected neighbour has nowhere to go and is left alone. The procedure tries to avoid distortion and overlap introduced by the removal of islands. It shares the defragmentation pipeline: UVs are scaled into pixel space before anything else runs, the surviving charts are repacked, and the new atlas is resampled from the originals, so the layer comes back with new texture images and not just moved UVs. Turn off *Resample textures* to treat it as a parametrization operation instead. The layer then comes back with the merged, repacked UV layout and no texture images -- and in that mode a layer that has a parametrization but no texture yet is a valid input. **References:** - Andrea Maggiordomo, Paolo Cignoni, Marco Tarini. **Texture Defragmentation for Photo-Reconstructed 3D Models**. *Computer Graphics Forum* (2021). [DOI](https://doi.org/10.1111/cgf.142615) [Web](https://diglib.eg.org/items/b3e092cd-5a96-4575-975d-af22795e870b) **Parameters:** - **islandSource** (*enum*, default: `by_size`) — Which islands get dissolved into their neighbours. *Below a size threshold* is the automatic sweep, governed by the size multiplier. *The selected ones* takes them from the face selection instead: any island holding at least one selected face is a candidate, so one face is enough to name an island, and the size multiplier is ignored. - **maxMultiplier** (*double*, default: `1.0`) — Islands whose UV boundary length is smaller than this factor times the median island boundary length are candidates for removal. A value of 1.0 targets all below-median islands; 0.2 targets only the absolute tiniest fragments; values above 1.0 also capture larger-than-median islands. Set to 0 to attempt removal of all islands. Ignored when *Islands to merge* is set to the selected ones. - **distortionMode** (*enum*, default: `STRICT`) — Specifies how aggressively the algorithm removes islands: **STRICT**: operations that introduce significant geometric distortion are immediately rejected. Prioritizes visual fidelity over compactness. **LOOSE**: distortion introduced by the removal of islands is ignored. Still, operations that introduce overlaps are rejected. Prioritizes layout compactness over quality. **UNSAFE**: ignores any distortion and intersection introduced by a merge operation. This mode leads to the most compact and fast result. Note that topologically incompatible merges are still skipped, as they cannot be parameterized. - **targetTexCount** (*int*, default: `0`) — Specifies the maximum number of output textures that can be generated by the filter. If set to zero the parameter is ignored and the algorithm employs the default packing strategy. - **timelimit** (*double*, default: `0.0`) — Time limit for the chart merging stage. `0` means unlimited. Note that it does not bound the atlas packing that follows, which on a heavily fragmented layout can be the slower half. - **quickRun** (*bool*, default: `False`) — Speeds up the running time of the filter by never attempting again any rejected merge operation.
Although fast, it could lead to worst results. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the atlas packing exactly reproducible. - **resampleTextures** (*bool*, default: `True`) — Render the new atlas by resampling the original texture images. Turn it off to treat this as a parametrization-only filter: the layer comes back with the reorganized UV layout and no texture images, which is what you want when the texture is going to be baked again afterwards. The source images are still required either way -- the algorithm measures islands and distortion in texel space, so it needs their resolution before it can start. ``` --- (filter-compute-chart-segmentation-geogram)= ## Compute Chart Segmentation (geogram) **Categories:** `Parametrization/Segmentation`, `Attribute/Scalar` **Plugin:** meshlab2.filter.geogram Partition the mesh into charts and store each face's chart index in the face scalar field. ```{py:function} ms.compute_chart_segmentation_geogram(**params) :module: _meshlab Segments the current mesh into a requested number of charts and stores the chart index of each face in the per-face scalar field, so the partition can be shown with the scalar colormap and used by later filters. No texture coordinates are created. The two VSA segmenters implement Variational Shape Approximation: the $L^2$ metric groups faces by position and the $L^{2,1}$ metric by normal, which makes the latter follow anisotropic features more closely. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **segmenter** (*enum*, default: `vsaL2`) — Which segmentation algorithm to use. The spectral options need geogram's ARPACK eigensolver. - **segmentCount** (*int*, default: `8`) — How many charts to aim for. The segmenter may return a different number. ``` --- (filter-convert-per-vertex-uv-to-per-wedge-uv)= ## Convert Per-Vertex UV to Per-Wedge UV **Categories:** `Parametrization/UV Conversion` **Plugin:** meshlab2.filter.texture Convert per-vertex texture coordinates into per-wedge texture coordinates. ```{py:function} ms.convert_per_vertex_uv_to_per_wedge_uv(**params) :module: _meshlab Converts per Vertex Texture Coordinates to per Wedge Texture Coordinates. It does not merge superfluous vertices... This filter has no parameters. ``` --- (filter-convert-per-wedge-uv-to-per-vertex-uv)= ## Convert Per-Wedge UV to Per-Vertex UV **Categories:** `Parametrization/UV Conversion` **Plugin:** meshlab2.filter.texture Convert per-wedge texture coordinates into per-vertex texture coordinates, splitting vertices when needed. ```{py:function} ms.convert_per_wedge_uv_to_per_vertex_uv(**params) :module: _meshlab Converts per Wedge Texture Coordinates to per Vertex Texture Coordinates splitting vertices with not coherent Wedge coordinates. This filter has no parameters. ``` --- (filter-create-atlased-mesh-from-abstract-domain)= ## Create Atlased Mesh from Abstract Domain **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.isoparam Build a new layer carrying a per-wedge atlas parametrization, with a choice of how the abstract domain is cut into charts. ```{py:function} ms.create_atlased_mesh_from_abstract_domain(**params) :module: _meshlab Turns the abstract domain into an ordinary texture atlas. The domain is a set of unit-sided equilateral triangles, and it can be cut into charts in several ways -- three of them are partitions given in the paper this is built on (Pietroni et al. 2010, section 4.2) -- after which one of the vcglib packers lays the charts out in a single UV square. The result is a new layer with per-wedge UVs, all sharing texture index 0, usable by anything that consumes a normal parametrization. *Chart shape* decides both the cut and the unfolding: - **Square** takes one chart per *half-diamond* -- the region belonging to a domain edge -- and flattens it onto a square, which is what the paper's own geometry-image construction does. It packs best, but that map is explicitly not rigid, so it distorts. - **Rhombus** unfolds the same region as the 60 degree rhombus it actually is, so both halves come out as the equilateral triangles the paper says its samples form when the right patch diagonal is used. Near-isometric, at the cost of some atlas area. - **Hexagon** merges: a half-diamond is a rhombus whose obtuse corners sit on the two triangle barycentres it spans, so the three that meet across a domain triangle join at 120 degrees each and tile a regular hexagon. Every domain triangle is a candidate, but a half-diamond belongs to the triangles on both sides of its edge and can only go to one of them, so some charts come out a wedge short and a few regions stay single. - **Polygon** uses the paper's *half-star* partition instead: one chart per domain vertex, each the k-agon joining the barycentres of the k triangles around it. It is a partition and not a search, so every region lands in exactly one chart and nothing is left over -- the fewest charts of any option, and the lowest area distortion, because that unfolding is area-preserving by construction where the square and rhombus ones are not. - **Star** merges around domain vertices the other way, out of whole half-diamonds. They meet at their *acute* corners there, so six of them close the ring but leave a six-pointed chart whose points cost atlas area. On a 1.2k sphere with a 194-triangle domain: | shape | charts | atlas covered | area distortion | | --- | --- | --- | --- | | Square | 291 | 73% | 1.35 | | Rhombus | 291 | 65% | 1.35 | | Hexagon | 131 | 69% | 1.35 | | Polygon | 99 | 62% | 1.30 | | Star | 154 | 60% | 1.35 | | Star, irregular too | 94 | 54% | 1.33 | (*area distortion* is the 95th percentile of per-face texel density over its median; 1.0 would be perfectly area-preserving.) Every shape lays its charts out at one texel density, so no chart takes more of the atlas per unit of surface than another. There is no single winner: **Square** buys atlas area with distortion and seams, **Polygon** buys the fewest seams and the truest areas with atlas area, and **Hexagon** sits between them. Pick by whether the atlas is going to be baked once or authored against. Four packers are offered, and they trade quality against time very differently -- see **Pack UV Charts**, which drives the same ones -- but *Rasterized, scaled to fit* is what you want here unless the chart count makes it too slow. Requires an abstract domain on the layer: run **Parametrize by Abstract Domain** first. Based on Pietroni, Tarini and Cignoni, *Almost isometric mesh parameterization through abstract domains*, IEEE TVCG 2010; the square patches and the half-star partition are theirs, the merged hexagon and star charts are not. **References:** - Nico Pietroni, Marco Tarini, Paolo Cignoni. **Almost Isometric Mesh Parameterization through Abstract Domains**. *IEEE Transactions on Visualization and Computer Graphics* (2010). [DOI](https://doi.org/10.1109/TVCG.2009.96) **Parameters:** - **chartShape** (*enum*, default: `square`) — How the domain is cut into charts and each chart unfolded. Square and Rhombus give one chart per domain edge; Polygon gives one per domain vertex, the fewest charts and the truest areas; Hexagon merges three edge-charts per domain triangle and packs tightest of the merged options; Star merges around vertices instead and wastes atlas area on its points. - **mergeIrregularStars** (*bool*, default: `False`) — Star charts normally merge only around regular domain vertices, the ones with exactly six triangles. With this on, vertices with five or seven triangles are merged too. Far more diamonds get absorbed -- on a 1.2k sphere, 266 of 291 against 176 -- at the cost of some stretch, since those triangles have to open to 72 degrees or close to 51 to make the ring meet. Ignored unless the chart shape is Star. - **borderSize** (*double*, default: `0.1`) — How far a face may stray outside its diamond before it is split in two. Smaller values cut the mesh more finely and keep the charts tighter to the domain, which also lets more diamonds join a hexagonal chart. The gutter between packed charts is set separately. - **packingAlgorithm** (*enum*, default: `rasterized_scaled`) — Which vcglib packer lays the charts out in the atlas. - **textureSize** (*int*, default: `2048`) — Side of the square atlas the charts are packed into. The UVs come back normalized either way; this sets the resolution the packer works at, and so what the gutter is worth. A domain has many small charts, and the gutter is what costs atlas area: on a 1.2k sphere, 291 charts at 1024 with a 4-pixel gutter cover 56% of the atlas, and the same run at 2048 covers 67%. - **gutterWidth** (*int*, default: `2`) — Padding kept around each chart, so bilinear filtering cannot bleed between neighbours. - **rotationNum** (*int*, default: `4`) — How many orientations each chart is tried at, rounded to the nearest multiple of four -- the packer derives four slots from every base rasterization, so only multiples of four are usable. Rasterized packers only. - **permutations** (*bool*, default: `False`) — Retry the layout with reshuffled chart orders. Costs five packing passes per similarly sized chart, so on a uniform atlas it is five per chart and it dominates the run. Rasterized packers only. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the chart permutations exactly reproducible. ``` --- (filter-parametrize-by-abstract-domain)= ## Parametrize by Abstract Domain **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.isoparam Build an abstract domain of equilateral triangles and an almost isometric parametrization of the layer onto it. ```{py:function} ms.parametrize_by_abstract_domain(**params) :module: _meshlab Simplifies the layer down to a coarse **abstract domain** and parametrizes the original surface onto it, keeping the mapping as close to isometric as the surface allows. The domain is *abstract* in a strict sense: it is connectivity and adjacency only, with every one of its triangles taken to be equilateral and unit-sided. It has no 3D embedding, and for most surfaces none exists. That is what makes it a simple domain to work over -- all its regions are the same shape and size -- and it is also what the parametrization aims at: regions of equal area on the mesh, separated by paths of equal length, which is exactly the condition for the mapping to be isometric. It is built by decimation. Every triangle of the input starts as its own sub-domain; edge collapses and edge flips on the domain then reduce it, each one followed by a local reoptimization of the mapping and, at intervals, a global one over the whole mesh. A collapse costs the inverse of the two regions' areas plus the squared length of the path between them, so the smallest regions and the shortest paths go first, and what survives tends toward equally sized regions separated by equally long paths. The optimizer weights area preservation three times as heavily as conformality. The domain is attached to the layer as plugin data rather than written into the mesh, and the layer panel reports its size and distortion. It is dropped automatically if the layer's geometry changes, because a parametrization of moved vertices would be meaningless. What *is* written into the mesh is the mapping itself, as per-vertex UVs, and the domain regions, as scalars: each vertex gets the region its own position falls in, and each face gets the one its centre falls in. The per-face one is the better picture -- a region boundary is a path across the surface rather than a chain of mesh edges, so a face can straddle one, and deciding per face keeps the regions crisp where the per-vertex values dither along the seam. The filter asks the view to colour by it when it finishes, which is the quickest way to see what kind of domain you got. Any per-vertex or per-face scalar already on the layer is overwritten. The mesh must be a **single watertight two-manifold component**; the filter says which precondition failed when it is not. Counter-intuitively, a *smaller* abstract domain costs more, not less. The two size bounds are a search range, not a tolerance: decimation always runs all the way down to the smallest, scoring the domain at every step, and then back-tracks to the best size in the interval. Lowering the smallest therefore buys more work, not less. On a 40k-vertex sphere, 150-200 faces took about twice as long as 400-500. Based on Pietroni, Tarini and Cignoni, *Almost isometric mesh parameterization through abstract domains*, IEEE TVCG 2010. **References:** - Nico Pietroni, Marco Tarini, Paolo Cignoni. **Almost Isometric Mesh Parameterization through Abstract Domains**. *IEEE Transactions on Visualization and Computer Graphics* (2010). [DOI](https://doi.org/10.1109/TVCG.2009.96) **Parameters:** - **minDomainFaces** (*int*, default: `150`) — Fewest faces the abstract domain may have. Decimation runs down to this number whatever the criteria then choose, so this is what sets the cost of the run: lowering it means more collapses, not fewer. Domains of four to a few hundred faces are the usual range. - **maxDomainFaces** (*int*, default: `200`) — Most faces the abstract domain may have. Together with the smallest it bounds the interval the stopping criteria search over; a wide interval gives them more to choose from, at the cost of holding every intermediate domain in memory. - **stopCriteria** (*enum*, default: `correspondence`) — Which measure decides where in the size interval to stop. **Heuristic** is the rule the original technique proposes: distortion multiplied by the square root of the number of sub-domains, so a domain that needs more faces to reduce distortion is penalized for it. Use this when you have no particular size in mind and want the sweet-spot. **Correspondence** is that distortion on its own -- area and angle distortion combined, area weighted three to one. With no penalty on domain size it will lean toward the largest domain in the interval, since distortion falls as the domain grows. Use it when you have already chosen the size and just want the least distorted result in it. **Domain regularity** counts domain vertices that are not surrounded by six triangles. Those are the cone singularities, and they are the only places where the mapping between a domain region and its parametrization is not an isometry, so fewer of them makes everything downstream better behaved. **L2 stretch** is the standard stretch-efficiency measure, if you want to compare against results quoted in that metric. - **convergenceAccuracy** (*int*, default: `1`) — How hard the mapping is optimized. It raises the effort spent on each local reoptimization after a collapse or a flip, and both the iteration count and the tightness of the global optimization that runs between them. The global phase usually converges within ten passes at the default, so higher values buy less than they cost. - **doubleStep** (*bool*, default: `True`) — Decimate in two phases on large inputs: a cheap first pass down to 15,000 sub-domains, then the full optimized run from there. It only engages above 30,000 faces, and below that the setting does nothing. ``` --- (filter-parametrize-by-angle-based-flattening-geogram)= ## Parametrize by Angle-Based Flattening (geogram) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.geogram Compute an ABF++ angle-based UV parametrization using geogram. ```{py:function} ms.parametrize_by_angle_based_flattening_geogram(**params) :module: _meshlab Computes an ABF++ (Angle-Based Flattening) parametrization of the current mesh and stores the result as per-vertex texture coordinates. ABF++ solves for the flattened *angles* rather than the vertex positions, which generally yields noticeably lower angle distortion than LSCM on the same input, at a higher cost. The mesh must have a boundary. If the mesh already carries per-wedge texture coordinates they are synchronized from the new per-vertex ones. This is the reference implementation, by the authors of the original paper. The flattening follows the mesh's existing vertex connectivity: coincident but distinct vertices stay split and appear as a seam, so run *Remove Duplicate Vertices* first on a mesh loaded from a format that does not share them, such as STL. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) This filter has no parameters. ``` --- (filter-parametrize-by-as-rigid-as-possible-libigl)= ## Parametrize by As-Rigid-As-Possible (libigl) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.igl Optimize a harmonic UV map with libigl's ARAP local-global solver. ```{py:function} ms.parametrize_by_as_rigid_as_possible_libigl(**params) :module: _meshlab Computes an **as-rigid-as-possible (ARAP)** UV parametrization. A harmonic map with a circular boundary supplies the initial guess; libigl's local-global solver then reduces local metric distortion without fixing the boundary. The input must be a connected disk-like triangle surface with at least one interior vertex. **Iterations** limits the nonlinear optimization. More iterations generally improve convergence at additional cost. ARAP strongly favors locally rigid maps but does not guarantee a globally injective result; use SLIM when preventing flipped triangles is the primary goal. The result is stored as per-vertex texture coordinates and synchronized to existing per-wedge coordinates. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Olga Sorkine, Marc Alexa. **As-Rigid-As-Possible Surface Modeling**. *Geometry Processing* (2007). [DOI](https://doi.org/10.2312/SGP/SGP07/109-116) **Parameters:** - **iterations** (*int*, default: `50`) — Maximum number of ARAP local-global iterations. ``` --- (filter-parametrize-by-atlas-geogram)= ## Parametrize by Atlas (geogram) **Categories:** `Parametrization/UV Creation`, `Parametrization/Segmentation` **Plugin:** meshlab2.filter.geogram Segment the mesh into charts, flatten each one and pack them into a single atlas, using geogram. ```{py:function} ms.parametrize_by_atlas_geogram(**params) :module: _meshlab Runs geogram's complete atlas pipeline on the current mesh: the surface is cut into charts along sharp edges, each chart is flattened, any chart whose distortion is still too high is split further, and the charts are finally packed into the unit square. The result is stored as per-wedge texture coordinates. Unlike the single-chart flatteners, this works on a **closed** mesh, because the segmentation step creates the boundaries the flatteners need. If the mesh already carries a `chart` face attribute the pipeline uses it to seed the segmentation. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **hardAngleThreshold** (*double*, default: `45.0`) — Edges whose dihedral angle exceeds this value, in degrees, become chart boundaries. Lower values cut the surface into more, flatter charts. - **chartParametrizer** (*enum*, default: `abf`) — How each individual chart is flattened. - **chartPacker** (*enum*, default: `tetris`) — How the flattened charts are arranged in the unit square. ``` --- (filter-parametrize-by-atlas-xatlas)= ## Parametrize by Atlas (xatlas) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.xatlas Generate a charted and packed UV atlas for the current triangular mesh using xatlas. ```{py:function} ms.parametrize_by_atlas_xatlas(**params) :module: _meshlab Generates a new UV atlas for the current triangular mesh using **xatlas**, the lightweight atlas-generation library by Jonathan Young, an independent fork of **thekla_atlas**. The resulting UVs are written back to the current mesh as per-wedge texture coordinates and are suitable for baking and texture painting workflows. This first MeshLab integration currently targets **single-atlas output** on the current mesh. Practical tuning notes: - For **denser packing**, try enabling **Brute-force packing**, keep chart rotation enabled, and reduce **Padding** as far as your baking workflow tolerates. - For **less fragmented atlases** with fewer, larger charts, try increasing **Max cost**, lowering **Normal deviation weight** and **Normal seam weight**, and leaving **Max chart area** and **Max boundary length** at `0`. - These goals trade off against each other: fewer/larger charts usually mean more distortion, while tighter packing with less padding increases the risk of bleeding and mipmap artifacts. **Parameters:** - **padding** (*int*, default: `0`) — Number of texels of padding inserted around charts. Lower values give denser packing, but increase the risk of bleeding and mipmap artifacts. Higher values are safer for baking. Reasonable values are usually `0..8`; `1..4` is a common practical range. - **texelsPerUnit** (*double*, default: `0.0`) — Unit-to-texel scale. Leave `0` to let xatlas estimate a suitable value automatically. Higher values allocate more texture area to the mesh and can make it harder to stay within a single atlas. A practical range is highly model-dependent, but values around `1..256` are much more common than very large values. - **resolution** (*int*, default: `0`) — If `0`, xatlas chooses a single-atlas size automatically. If greater than `0`, xatlas tries to match this atlas resolution. Large requested resolutions, especially with high texels-per-unit or padding, can force xatlas to create multiple atlases. Common values are `512`, `1024`, `2048`, and `4096`. - **bruteForce** (*bool*, default: `False`) — Use the slower but higher-quality chart packing strategy. This is the main option to try when you want more aggressive packing and better atlas utilization. - **use_dummy_texture** (*bool*, default: `False`) — If enabled, also attach a generated dummy base-color texture to the mesh after the xatlas UVs are created, so the result is immediately visible in textured and UV views. - **dummy_img_size** (*int*, default: `1024`) — Size in pixels of the generated dummy texture. Common values are `512`, `1024`, and `2048`. - **dummy_check_size** (*int*, default: `32`) — Size of the check or grid cells in pixels. A practical range is usually `8..128` depending on texture resolution. - **dummy_type** (*enum*, default: `checkerboard`) — Choose between a checkerboard, a line grid, and a UV grid whose lines along U are red and along V blue, for the generated dummy texture. - **bilinear** (*bool*, default: `True`) — Leave space around charts for texels that would be sampled by bilinear filtering. Keep this enabled for safer baked textures; disabling it can improve packing density slightly but increases artifact risk. - **blockAlign** (*bool*, default: `False`) — Align charts to 4x4 blocks. This can improve packing speed and can help block-compressed textures, but it is usually a little less aggressive in raw packing efficiency. - **maxChartSize** (*int*, default: `0`) — Charts larger than this are scaled down. Leave `0` for no limit. A small limit can make the atlas more fragmented by preventing large islands from remaining large. Practical values are typically `256..4096` when you want to constrain very large charts. - **rotateChartsToAxis** (*bool*, default: `True`) — Rotate charts to the axis of their convex hull before packing. Usually helps packing and gives a cleaner starting orientation for islands. - **rotateCharts** (*bool*, default: `True`) — Allow chart rotation during packing to improve utilization. This usually helps create a denser atlas. - **normalDeviationWeight** (*double*, default: `2.0`) — Weight of angle deviation between a face and the average chart normal during chart growth. Higher values resist bending a chart across changing normals and usually increase fragmentation. Lower values can allow larger charts. A good working range is usually about `0.5..8`, with the default `2` being a balanced start. - **roundnessWeight** (*double*, default: `0.01`) — Weight that encourages compact, rounder charts. Higher values can promote smaller, tidier islands, sometimes at the cost of more fragmentation. Practical values are often in the `0..1` range; the default `0.01` is already fairly gentle. - **straightnessWeight** (*double*, default: `6.0`) — Weight that encourages straighter chart boundaries. This mostly affects boundary shape, but can also influence how readily charts split. A useful tuning range is commonly `0..20`, with the default `6` as a solid starting point. - **normalSeamWeight** (*double*, default: `4.0`) — Weight applied to chart boundaries crossing normal seams. Very high values preserve such seams strongly and usually create more fragmented atlases. Lower values allow more merging across those seams. A practical range is often `0..16`; values above that become increasingly aggressive about preserving seams. - **maxCost** (*double*, default: `2.0`) — Maximum growth cost for charts. Lower values generally produce more charts. Raising this is the first thing to try if you want fewer, larger islands and a less fragmented atlas. A good exploration range is usually `0.5..10`, with the default `2` as a balanced value. - **maxIterations** (*int*, default: `1`) — Number of chart seeding and growth iterations. Higher values may improve chart quality and coherence, though they also cost more time. Practical values are typically `1..10`; going much higher is uncommon unless you are explicitly experimenting. - **maxChartArea** (*double*, default: `0.0`) — Upper bound on chart area during growth. Leave `0` for no limit. Setting this to a small value forces more splitting and therefore a more fragmented atlas. This is scene-scale dependent; when used at all, it is usually tuned relative to mesh size rather than by absolute universal values. - **maxBoundaryLength** (*double*, default: `0.0`) — Upper bound on chart boundary length during growth. Leave `0` for no limit. Setting this to a small value tends to force more chart splitting. Like max chart area, this is model-scale dependent and is usually left at `0` unless you have a specific reason to constrain chart growth. - **fixWinding** (*bool*, default: `False`) — Enforce consistent texture-coordinate winding in the generated charts. This is mainly a robustness option rather than a packing or fragmentation control. ``` --- (filter-parametrize-by-cylindrical-projection)= ## Parametrize by Cylindrical Projection **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.meshing Unwrap geometry along cylindrical projection. ```{py:function} ms.parametrize_by_cylindrical_projection(**params) :module: _meshlab Unwrap the geometry of current mesh along a clylindrical equatorial projection. The cylindrical projection axis is centered on the origin and directed along the vertical Y axis. **Parameters:** - **startAngle** (*double*, default: `0.0`) — Starting angle of unrolling. - **endAngle** (*double*, default: `360.0`) — Ending angle of unrolling. - **radius** (*double*, default: `0.0`) — Reference cylinder radius. 0 = auto. ``` --- (filter-parametrize-by-flat-plane)= ## Parametrize by Flat Plane **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.texture Generate a trivial flat-plane parametrization. ```{py:function} ms.parametrize_by_flat_plane(**params) :module: _meshlab Builds a trivial flat-plane parametrization. **Parameters:** - **projectionPlane** (*enum*, default: `xy`) — Choose the projection plane. - **aspectRatio** (*bool*, default: `False`) — If checked the resulting parametrization will preserve the original apsect ratio of the model otherwise it will fill up the whole 0..1 uv space. - **sideGutter** (*double*, default: `0.0`) — Leave an empty space around the parametrization area of the specified size (in texture space); accepted range [0.0 - 0.5]. ``` --- (filter-parametrize-by-harmonic-map-libigl)= ## Parametrize by Harmonic Map (libigl) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.igl Compute a single-patch fixed-boundary harmonic UV parametrization using libigl. ```{py:function} ms.parametrize_by_harmonic_map_libigl(**params) :module: _meshlab Computes a single-patch fixed-boundary harmonic parametrization of the current mesh and stores the result as per-vertex texture coordinates. The mesh must have a boundary. If the mesh already has per-wedge texture coordinates, they are synchronized from the new per-vertex coordinates so the result is immediately visible in texture and UV views. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) **Parameters:** - **harm_function** (*int*, default: `1`) — Order of the harmonic function. `1` is harmonic, `2` is biharmonic, `3` is triharmonic, and so on. ``` --- (filter-parametrize-by-least-squares-conformal-maps-geogram)= ## Parametrize by Least Squares Conformal Maps (geogram) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.geogram Compute a Least Squares Conformal Maps UV parametrization using geogram. ```{py:function} ms.parametrize_by_least_squares_conformal_maps_geogram(**params) :module: _meshlab Computes a Least Squares Conformal Maps parametrization of the current mesh and stores the result as per-vertex texture coordinates. LSCM minimizes conformal (angle) distortion with two fixed points, so the mesh must have a boundary. If the mesh already carries per-wedge texture coordinates they are synchronized from the new per-vertex ones, so the result is immediately visible in the texture and UV views. This is the reference implementation, by the authors of the original paper. The flattening follows the mesh's existing vertex connectivity: coincident but distinct vertices stay split and appear as a seam, so run *Remove Duplicate Vertices* first on a mesh loaded from a format that does not share them, such as STL. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) This filter has no parameters. ``` --- (filter-parametrize-by-least-squares-conformal-maps-libigl)= ## Parametrize by Least Squares Conformal Maps (libigl) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.igl Compute a Least Squares Conformal Maps UV parametrization using libigl. ```{py:function} ms.parametrize_by_least_squares_conformal_maps_libigl(**params) :module: _meshlab Computes a Least Squares Conformal Maps parametrization of the current mesh and stores the result as per-vertex texture coordinates. The mesh must have a boundary. If the mesh already has per-wedge texture coordinates, they are synchronized from the new per-vertex coordinates so the result is immediately visible in texture and UV views. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) This filter has no parameters. ``` --- (filter-parametrize-by-slim-libigl)= ## Parametrize by SLIM (libigl) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.igl Optimize a flip-preventing UV map with libigl's SLIM solver. ```{py:function} ms.parametrize_by_slim_libigl(**params) :module: _meshlab Computes a UV parametrization with **Scalable Locally Injective Mappings (SLIM)**. The filter starts from a circular-boundary harmonic map and minimizes the selected distortion energy through SLIM's flip-preventing local-global iterations. If the cotangent harmonic initializer contains flips, a uniform-weight harmonic map is tried instead. The input must be a connected disk-like triangle surface with at least one interior vertex. **Symmetric Dirichlet** balances angle and area distortion and is the recommended default. **ARAP** emphasizes local rigidity; **Conformal** emphasizes angle preservation. SLIM preserves injectivity when supplied with an injective initial map, but cannot repair an initializer that remains folded. The result is stored as per-vertex texture coordinates and synchronized to existing per-wedge coordinates. **Upstream:** [libigl](https://github.com/libigl/libigl) **License:** MPL-2.0 **References:** - Alec Jacobson, Daniele Panozzo. **libigl: A Simple C++ Geometry Processing Library** (2017). [Web](https://libigl.github.io/) - Michael Rabinovich, Roi Poranne, Daniele Panozzo, Olga Sorkine-Hornung. **Scalable Locally Injective Mappings**. *ACM Transactions on Graphics* (2017). [DOI](https://doi.org/10.1145/3072959.2983621) **Parameters:** - **energy** (*enum*, default: `symmetric_dirichlet`) — Distortion energy minimized by SLIM. - **iterations** (*int*, default: `10`) — Number of SLIM optimization iterations. ``` --- (filter-parametrize-by-spectral-conformal-maps-geogram)= ## Parametrize by Spectral Conformal Maps (geogram) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.geogram Compute a Spectral Conformal Parameterization using geogram. ```{py:function} ms.parametrize_by_spectral_conformal_maps_geogram(**params) :module: _meshlab Computes a Spectral Conformal Parameterization of the current mesh and stores the result as per-vertex texture coordinates. Where plain LSCM pins two vertices and solves a least-squares system, the spectral formulation finds the smallest non-trivial eigenvector of the conformal energy instead, so the layout does not depend on which two points were pinned and is usually less distorted. The mesh must have a boundary. This method needs geogram's ARPACK eigensolver. It is present in a standard build; if it cannot be loaded the filter refuses rather than returning a degenerate layout. The flattening follows the mesh's existing vertex connectivity: coincident but distinct vertices stay split and appear as a seam, so run *Remove Duplicate Vertices* first on a mesh loaded from a format that does not share them, such as STL. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) This filter has no parameters. ``` --- (filter-parametrize-by-trivial-per-triangle-layout)= ## Parametrize by Trivial Per-Triangle Layout **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.texture Generate a triangle-by-triangle parametrization using either equal-size or space-optimizing layout. ```{py:function} ms.parametrize_by_trivial_per_triangle_layout(**params) :module: _meshlab Builds a trivial triangle-by-triangle parametrization.
Two methods are provided, the first maps all triangles into equal sized triangles, while the second one adapt the size of the triangles in texture space to their original size. **Parameters:** - **sidedim** (*int*, default: `0`) — Indicates how many triangles have to be put on each line (every quad contains two triangles) Leave 0 for automatic calculation. - **textdim** (*int*, default: `1024`) — Gives an indication on how big the texture is. - **border** (*int*, default: `2`) — Specifies how many pixels to be left between triangles in parametrization domain. - **method** (*enum*, default: `space_optimizing`) — Choose space optimizing to map smaller faces into smaller triangles in parametrizazion domain. ``` --- (filter-parametrize-by-voronoi-atlas-vcglib)= ## Parametrize by Voronoi Atlas (vcglib) **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.texture Build an atlased parametrization using a geodesic Voronoi partition of the surface. ```{py:function} ms.parametrize_by_voronoi_atlas_vcglib(**params) :module: _meshlab Build an atlased parametrization based on a geodesic voronoi partitioning of the surface and parametrizing each region using Harmonic Mapping. For the parametrization of the disk like voronoi regions the used method is:
Ulrich Pinkall, Konrad Polthier
Computing Discrete Minimal Surfaces and Their Conjugates
Experimental Mathematics, Vol 2 (1), 1993. **Parameters:** - **regionNum** (*int*, default: `10`) — An estimation of the number of regions that must be generated. Smaller regions could lead to parametrizations with smaller distortion. - **overlapFlag** (*bool*, default: `False`) — If checked the resulting parametrization will be composed by overlapping regions, e.g. the resulting mesh will have duplicated faces: each region will have a ring of ovelapping duplicate faces that will ensure that border regions will be parametrized in the atlas twice. This is quite useful for building mipmap robust atlases. - **randomSeed** (*int*, default: `0`) — Zero draws a fresh seed on every run, so repeated applications differ; any other value makes the atlas regions exactly reproducible. ``` --- (filter-parametrize-from-registered-rasters)= ## Parametrize from Registered Rasters **Categories:** `Parametrization/UV Creation`, `Transfer/From Rasters` **Plugin:** meshlab2.filter.img_patch_param The mesh is parameterized by creating some patches that correspond to projection of portions of surfaces onto the set of registered rasters. ```{py:function} ms.parametrize_from_registered_rasters(**params) :module: _meshlab The mesh is parameterized by creating patches that correspond to projections of surface portions onto the set of registered rasters. For each face, a reference raster is chosen based on visibility, viewing angle, and optional weights. Connected faces sharing the same reference raster form patches. UV coordinates are computed by projecting faces onto the reference raster's image plane. Patches are then packed into texture space using rectangle packing. Requires at least one visible raster with a valid camera and a 2-manifold mesh. **Parameters:** - **useDistanceWeight** (*bool*, default: `True`) — Includes a weight accounting for the distance to the camera during the computation of reference images. - **useImgBorderWeight** (*bool*, default: `True`) — Includes a weight accounting for the distance to the image border during the computation of reference images. - **useAlphaWeight** (*bool*, default: `False`) — If true, alpha channel of the image is used as additional weight. Makes it possible to mask-out parts of images that should not be projected on the mesh. - **cleanIsolatedTriangles** (*bool*, default: `True`) — Remove all patches composed of a single triangle by aggregating them to adjacent patches. - **stretchingAllowed** (*bool*, default: `False`) — If true, texture coordinates are stretched to cover the full [0,1] interval for both directions. - **textureGutter** (*int*, default: `4`) — Extra boundary to add to each patch before packing in texture space (in pixels). - **depthEpsilon** (*double*, default: `0.5`) — Tolerance for depth test when checking vertex visibility against the software depth buffer. Increasing this value merges similar-depth regions, reducing the number of patches. Use values of a few units for noisy or inaccurate camera registrations. - **maxPackingSize** (*int*, default: `0`) — Maximum dimension of the packing grid (in pixels). Set to 0 to auto-compute from the total patch area. Lower values speed up packing but may produce denser, lower-resolution layouts. ``` --- (filter-parametrize-from-registered-rasters-with-texture)= ## Parametrize from Registered Rasters with Texture **Categories:** `Parametrization/UV Creation`, `Texture`, `Transfer/From Rasters` **Plugin:** meshlab2.filter.img_patch_param The mesh is parameterized and textured by creating some patches that correspond to projection of portions of surfaces onto the set of registered rasters. ```{py:function} ms.parametrize_from_registered_rasters_with_texture(**params) :module: _meshlab The mesh is parameterized and textured by creating patches that correspond to projections of surface portions onto the set of registered rasters. After patch-based parameterization, a texture image is generated by painting each raster into the corresponding UV regions. Optionally, a color correction step ensures seamless transitions between adjacent patches. Requires at least one visible raster with a valid camera and a 2-manifold mesh. **Parameters:** - **textureSize** (*int*, default: `1024`) — Specifies the dimension of the generated texture. - **textureName** (*filesave*, default: `texture.png`) — Specifies the name of the file into which the texture image will be saved. - **colorCorrection** (*bool*, default: `True`) — If true, the final texture is corrected to ensure seamless transitions between adjacent patches. - **colorCorrectionFilterSize** (*int*, default: `1`) — Radius (in pixels) of the kernel used to compute the difference between corresponding texels in different rasters. Default of 1 generates a 3x3 kernel. Higher values increase robustness for strong misalignments. - **useDistanceWeight** (*bool*, default: `True`) — Includes a weight accounting for the distance to the camera during the computation of reference images. - **useImgBorderWeight** (*bool*, default: `True`) — Includes a weight accounting for the distance to the image border during the computation of reference images. - **useAlphaWeight** (*bool*, default: `False`) — If true, alpha channel of the image is used as additional weight. Makes it possible to mask-out parts of images that should not be projected on the mesh. - **cleanIsolatedTriangles** (*bool*, default: `True`) — Remove all patches composed of a single triangle by aggregating them to adjacent patches. - **stretchingAllowed** (*bool*, default: `False`) — If true, texture coordinates are stretched to cover the full [0,1] interval for both directions. - **textureGutter** (*int*, default: `4`) — Extra boundary to add to each patch before packing in texture space (in pixels). - **depthEpsilon** (*double*, default: `0.5`) — Tolerance for depth test when checking vertex visibility against the software depth buffer. Increasing this value merges similar-depth regions, reducing the number of patches. Use values of a few units for noisy or inaccurate camera registrations. - **maxPackingSize** (*int*, default: `0`) — Maximum dimension of the packing grid (in pixels). Set to 0 to auto-compute from the total patch area. Lower values speed up packing but may produce denser, lower-resolution layouts. ``` --- (filter-parametrize-per-vertex-by-expression)= ## Parametrize per Vertex by Expression **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.expression Computes per-vertex texture coordinates from expressions. ```{py:function} ms.parametrize_per_vertex_by_expression(**params) :module: _meshlab Texture function using muparser to generate new texture coords for every vertex
**Parameters:** - **u** (*string*, default: `x`) — Expression for U texture coordinate. - **v** (*string*, default: `y`) — Expression for V texture coordinate. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-parametrize-per-wedge-by-expression)= ## Parametrize per Wedge by Expression **Categories:** `Parametrization/UV Creation` **Plugin:** meshlab2.filter.expression Computes per-wedge texture coordinates from expressions. ```{py:function} ms.parametrize_per_wedge_by_expression(**params) :module: _meshlab Texture function using muparser to generate new per wedge tex coords for every face
Insert six functions each u v for each one of the three vertex of a face
**Parameters:** - **u0** (*string*, default: `x0`) — Expression for wedge texture coordinate. - **v0** (*string*, default: `y0`) — Expression for wedge texture coordinate. - **u1** (*string*, default: `x1`) — Expression for wedge texture coordinate. - **v1** (*string*, default: `y1`) — Expression for wedge texture coordinate. - **u2** (*string*, default: `x2`) — Expression for wedge texture coordinate. - **v2** (*string*, default: `y2`) — Expression for wedge texture coordinate. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-remove-isolated-components-by-diameter)= ## Remove Isolated Components by Diameter **Categories:** `Repair/Degenerate` **Plugin:** meshlab2.filter.clean Remove isolated connected components whose diameter is below a threshold. ```{py:function} ms.remove_isolated_components_by_diameter(**params) :module: _meshlab Remove isolated connected components whose diameter is smaller than the specified constant **Parameters:** - **min_component_diag** (*absperc*, default: `@bboxDiagTenth`) — Delete all connected components (floating pieces) with a diameter smaller than the specified one. - **remove_unref** (*bool*, default: `True`) — If true, the unreferenced vertices remaining after face deletion are removed. ``` --- (filter-remove-isolated-components-by-face-count)= ## Remove Isolated Components by Face Count **Categories:** `Repair/Degenerate` **Plugin:** meshlab2.filter.clean Remove isolated connected components composed of few triangles. ```{py:function} ms.remove_isolated_components_by_face_count(**params) :module: _meshlab Remove isolated connected components composed of a limited number of triangles **Parameters:** - **min_component_size** (*int*, default: `25`) — Delete all the connected components (floating pieces) composed by a number of triangles smaller than the specified one. - **remove_unref** (*bool*, default: `True`) — If true, the unreferenced vertices remaining after face deletion are removed. ``` --- (filter-remove-vertices-by-scalar)= ## Remove Vertices by Scalar **Categories:** `Repair/Degenerate` **Plugin:** meshlab2.filter.clean Remove all vertices whose scalar is lower than a threshold. ```{py:function} ms.remove_vertices_by_scalar(**params) :module: _meshlab Remove all the vertices whose scalar is smaller than the specified constant **Parameters:** - **max_quality_thr** (*double*, default: `@qualityVMax`) — Vertices with quality lower than this threshold are deleted. ``` --- (filter-remove-zero-area-faces)= ## Remove Zero-Area Faces **Categories:** `Repair/Degenerate` **Plugin:** meshlab2.filter.clean Remove null faces with zero area. ```{py:function} ms.remove_zero_area_faces(**params) :module: _meshlab Remove null faces (the one with area equal to zero) This filter has no parameters. ``` --- (filter-merge-close-vertices)= ## Merge Close Vertices **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.clean Merge vertices that are nearer than a threshold. ```{py:function} ms.merge_close_vertices(**params) :module: _meshlab Merge together all the vertices that are nearer than the specified threshold. Like a unify duplicated vertices but with some tolerance. **Parameters:** - **threshold** (*absperc*, default: `@bboxDiag0001`) — All vertices closer than this threshold are merged together. Use very small values; default is 1/10000 of bounding box diagonal. ``` --- (filter-merge-close-wedge-uvs)= ## Merge Close Wedge UVs **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.clean Merge per-wedge UVs that are very close. ```{py:function} ms.merge_close_wedge_uvs(**params) :module: _meshlab Merge together per-wedge UVs that are very close. Used to correct apparent texture seams that can arise from numerical approximations when saving in ascii formats. **Parameters:** - **merge_thr** (*double*, default: `0.0001`) — All per-wedge texture coords that are on the same vertex and are distant less than the threshold are merged together. Distance is in texture space. ``` --- (filter-remove-duplicate-faces)= ## Remove Duplicate Faces **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.clean Remove all duplicate faces. ```{py:function} ms.remove_duplicate_faces(**params) :module: _meshlab Remove all the duplicate faces. Two faces are considered equal if they are composed by the same set of vertices, regardless of the order of the vertices. This filter has no parameters. ``` --- (filter-remove-duplicate-vertices-trueform)= ## Remove Duplicate Vertices (TrueForm) **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.trueform Weld coincident vertices and drop the degeneracies that welding exposes. ```{py:function} ms.remove_duplicate_vertices_trueform(**params) :module: _meshlab Welds vertices at the same position into one and removes the degenerate faces that welding leaves behind. This is the first thing to run on a triangle soup — an STL, or anything exported face by face — because until the vertices are shared the mesh has no connectivity at all: no edges, no adjacency, and so no boundary, no components and no topology for any other filter to work with. **Tolerance** of zero welds only exactly coincident vertices, which is the safe choice. A positive tolerance also merges vertices within that distance, which closes cracks left by finite precision but will collapse genuinely small features if set too large. Note that MeshLab's own STL reader (*TrueForm OBJ/STL*) already welds on import, so this is mainly for geometry that arrived unwelded by another route. Competing implementation: *Remove Duplicate Vertices* and *Merge Close Vertices* do the same with vcglib. **Parameters:** - **tolerance** (*absperc*, default: `0.0`) — Weld vertices within this distance. Zero welds only exactly coincident ones. ``` --- (filter-remove-duplicate-vertices-vcglib)= ## Remove Duplicate Vertices (vcglib) **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.clean Merge vertices that have exactly the same coordinates. ```{py:function} ms.remove_duplicate_vertices_vcglib(**params) :module: _meshlab Check for every vertex on the mesh: if there are two vertices with same coordinates they are merged into a single one. This filter has no parameters. ``` --- (filter-remove-unreferenced-vertices)= ## Remove Unreferenced Vertices **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.clean Remove vertices that are not referenced by any face. ```{py:function} ms.remove_unreferenced_vertices(**params) :module: _meshlab Check for every vertex on the mesh: if it is NOT referenced by a face, removes it This filter has no parameters. ``` --- (filter-split-vertices-by-attribute-seam)= ## Split Vertices by Attribute Seam **Categories:** `Repair/Duplicates` **Plugin:** meshlab2.filter.meshing Split vertices to make attributes seam-independent. ```{py:function} ms.split_vertices_by_attribute_seam(**params) :module: _meshlab Make all selected vertex attributes connectivity-independent:
vertices are duplicated whenever two or more selected wedge or face attributes do not match.
This is particularly useful for GPU-friendly mesh layout, where a single index must be used to access all required vertex attributes. **Parameters:** - **NormalMode** (*enum*, default: `none`) — Choose normal source. - **ColorMode** (*enum*, default: `none`) — Choose color source. - **TexcoordMode** (*enum*, default: `none`) — Choose texcoord source. ``` --- (filter-close-holes)= ## Close Holes **Categories:** `Repair/Holes and Borders` **Plugin:** meshlab2.filter.meshing Close holes under a size threshold. ```{py:function} ms.close_holes(**params) :module: _meshlab Close holes whose boundary is composed by a number of edges smaller than a given threshold **Parameters:** - **MaxHoleSize** (*int*, default: `30`) — Hole size threshold in boundary-edge count. - **Selected** (*bool*, default: `False`) — Only holes with selected boundary faces are closed. - **NewFaceSelected** (*bool*, default: `True`) — Leave newly created faces selected. - **SelfIntersection** (*bool*, default: `True`) — Try to avoid creating self-intersecting faces. - **RefineHole** (*bool*, default: `False`) — Refine newly created hole triangles. - **RefineHoleEdgeLen** (*absperc*, default: `@bboxDiag003`) — Target edge length for hole refinement. ``` --- (filter-repair-mismatched-borders)= ## Repair Mismatched Borders **Categories:** `Repair/Holes and Borders` **Plugin:** meshlab2.filter.clean Try to snap together slightly mismatched adjacent borders. ```{py:function} ms.repair_mismatched_borders(**params) :module: _meshlab Try to snap together adjacent borders that are slightly mismatched.
This situation can happen on badly triangulated adjacent patches defined by high order surfaces.
For each border vertex the filter snap it onto the closest boundary edge only if it is closest of edge_length*threshold. When vertex is snapped the corresponding face is split and a new vertex is created. **Parameters:** - **edge_dist_ratio** (*double*, default: `0.01`) — Collapse edge when the edge / distance ratio is greater than this value. Larger values enforce that only vertices very close to the line are removed. - **unify_vertices** (*bool*, default: `True`) — If true, snapped vertices are welded together. ``` --- (filter-extract-outer-shell-trueform)= ## Extract Outer Shell (TrueForm) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.trueform Keep only the outermost surface of a layer, discarding internal shells. ```{py:function} ms.extract_outer_shell_trueform(**params) :module: _meshlab Resolves the layer's self-intersections and keeps only the **outermost** boundary, dropping every internal shell and any surface enclosed by another. This is the repair step for geometry assembled from overlapping parts — kitbashed models, scans merged from several pieces, or anything destined for 3D printing, where interior walls are invisible but still slow slicing and can confuse a slicer about what is solid. The input should be solid rather than an open sheet: an open surface has no inside, so there is no outer shell to extract. This filter has no parameters. ``` --- (filter-invert-face-orientation)= ## Invert Face Orientation **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.meshing Flip mesh face orientation. ```{py:function} ms.invert_face_orientation(**params) :module: _meshlab Invert faces orientation, flipping the normals of the mesh.
If requested, it tries to guess the right orientation; mainly it decide to flip all the faces if the minimum/maximum vertices have not outward point normals for a few directions.
Works well for single component watertight objects. **Parameters:** - **forceFlip** (*bool*, default: `True`) — Always flip normals; otherwise try to set normals outside. ``` --- (filter-orient-faces-consistently-trueform)= ## Orient Faces Consistently (TrueForm) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.trueform Make neighboring faces wind the same way. ```{py:function} ms.orient_faces_consistently_trueform(**params) :module: _meshlab Propagates a consistent winding across each connected component, so neighboring faces agree about which side is front. Meshes assembled from several sources, or exported by tools that do not care, commonly arrive with patches wound both ways — which makes backface culling, shading and every boolean unreliable. This makes the winding *consistent*; it does not decide which way is out. Use *Orient Faces Outward (TrueForm)* for that. Competing implementation: *Orient Faces Consistently (vcglib)* does the same with vcglib. **Implementation note.** A single pass of the underlying routine only partly repairs a badly mixed winding, so this filter repeats it until the winding stops improving and reports how many passes were needed. If edges remain inconsistent afterwards the surface is probably non-orientable — a Möbius-like configuration has no consistent winding to find. For diagnosis prefer the vcglib *Orient Faces Consistently (vcglib)*: it detects and reports a **non-orientable** surface, which this routine cannot distinguish from an incomplete repair. This filter has no parameters. ``` --- (filter-orient-faces-consistently-vcglib)= ## Orient Faces Consistently (vcglib) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.meshing Orient faces consistently. ```{py:function} ms.orient_faces_consistently_vcglib(**params) :module: _meshlab Re-orient in a consistent way all the faces of the mesh.
The filter visits a mesh face to face, reorienting any unvisited face so that it is coherent to the already visited faces. If the surface is orientable it will end with a consistent orientation of all the faces. If the surface is not orientable (e.g. it is non manifold or non orientable like a moebius This filter has no parameters. ``` --- (filter-orient-faces-outward-trueform)= ## Orient Faces Outward (TrueForm) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.trueform Make the winding consistent and pointing out of the solid. ```{py:function} ms.orient_faces_outward_trueform(**params) :module: _meshlab First makes the winding consistent, then checks the **signed volume** and flips the whole mesh if it came out negative — so normals point out of the solid rather than into it. That second step is what distinguishes this from *Orient Faces Consistently (TrueForm)*: a consistently wound mesh can still be inside out, and nothing local can tell, because every face agrees with its neighbours either way. Only the sign of the enclosed volume settles it. The input must therefore be **closed** for the answer to mean anything: an open sheet encloses no volume, so there is no outward. This filter has no parameters. ``` --- (filter-remove-isolated-folded-faces-by-edge-flip)= ## Remove Isolated Folded Faces by Edge Flip **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.clean Repair isolated folded triangles by changing the local triangulation. ```{py:function} ms.remove_isolated_folded_faces_by_edge_flip(**params) :module: _meshlab Repair an isolated folded triangle whose normal is nearly opposite to all three adjacent faces. The filter flips one supporting edge only when the opposite vertex projects strictly inside the adjacent triangle and the flip reduces the number of near-opposite normal relations in the affected neighborhood. No vertices or faces are removed. The input must be a consistently oriented, 2-manifold triangle mesh. Polygonal faux-edge meshes and meshes with per-wedge UVs are rejected because an edge flip cannot preserve their polygon boundaries or UV seams unambiguously. **Parameters:** - **normal_threshold_deg** (*double*, default: `175.0`) — Minimum angle, in degrees, between the candidate face normal and each adjacent face normal. Values near 180 detect only nearly reversed triangles. ``` --- (filter-remove-t-vertices)= ## Remove T-Vertices **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.clean Remove T-vertices using edge collapse or edge flip. ```{py:function} ms.remove_t_vertices(**params) :module: _meshlab Remove t-vertices from the mesh by edge collapse (collapsing the shortest of the incident edges) or edge flip (flipping the opposite edge on the degenerate face if the triangulation quality improves). **Parameters:** - **method** (*enum*, default: `edge_collapse`) — Selects whether to remove t-vertices by edge collapse or edge flip. - **threshold** (*double*, default: `40.0`) — Detects faces where the base/height ratio is lower than this value. - **repeat** (*bool*, default: `True`) — Iterates the algorithm until it reaches convergence. ``` --- (filter-repair-non-manifold-edges)= ## Repair Non-Manifold Edges **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.clean Repair non-manifold edges by removing faces or splitting vertices. ```{py:function} ms.repair_non_manifold_edges(**params) :module: _meshlab Remove non-manifold edges by removing faces (for each non-manifold edge it iteratively removes the smallest area face until it becomes 2-Manifold) or by splitting vertices (each non manifold edges chain will become a border). **Parameters:** - **method** (*enum*, default: `remove_faces`) — Selects whether to repair non manifold edges by removing faces or by splitting vertices. ``` --- (filter-repair-non-manifold-vertices-by-splitting)= ## Repair Non-Manifold Vertices by Splitting **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.clean Split non-manifold vertices until the mesh becomes 2-manifold. ```{py:function} ms.repair_non_manifold_vertices_by_splitting(**params) :module: _meshlab Split non Manifold vertices until it becomes 2-Manifold. **Parameters:** - **vert_disp_ratio** (*double*, default: `0.0`) — This parameter denotes the displacement ratio α. When a vertex is split, it is moved towards the barycenter of the FF-connected faces sharing it by (v-barycenter)*α. Reasonable values are in [0..0.1]. ``` --- (filter-repair-self-intersections-geogram)= ## Repair Self-Intersections (geogram) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.geogram Remove self-intersecting faces and retriangulate the holes using geogram. ```{py:function} ms.repair_self_intersections_geogram(**params) :module: _meshlab Attempts to make a surface conformal by removing intersecting faces and retriangulating the holes they leave, using geogram's exact predicates. The result is created as a new layer. The pass is repeated until no intersection remains or the iteration limit is reached, so a mesh with deeply nested intersections may need more than the default number of iterations. This is the usual way to prepare an input for the geogram boolean filters, which require operands without self-intersections. **Upstream:** [geogram](https://github.com/BrunoLevy/geogram) **License:** BSD-3-Clause **References:** - Bruno Levy. **Geogram: a programming library of geometric algorithms** (2015). [Web](https://github.com/BrunoLevy/geogram) **Parameters:** - **maxIterations** (*int*, default: `3`) — How many times to repeat the remove-and-retriangulate pass before giving up. ``` --- (filter-repair-self-intersections-trueform)= ## Repair Self-Intersections (TrueForm) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.trueform Resolve a mesh's self-intersections into real edges and split faces. ```{py:function} ms.repair_self_intersections_trueform(**params) :module: _meshlab Computes the **arrangement** of the layer against itself: every place the surface passes through itself becomes a real edge, and every crossed face is split along it. This is the principled repair for self-intersecting geometry. Before it, the surface has no well-defined inside — a ray can cross the same sheet twice with nothing recording that they met — which is why self-intersections break booleans, offsetting, signed distance and printing. Afterwards the pieces are properly separated, and *Extract Outer Shell (TrueForm)* can keep the outermost one. Use *Create Polyline from Self-Intersections (TrueForm)* first to see where the problem is, and *Select Self Intersecting Faces* to see how much is affected. The result is a new layer; nothing is removed, so all interior sheets survive as separate geometry. This filter has no parameters. ``` --- (filter-repair-watertight-mesh-meshfix)= ## Repair Watertight Mesh (MeshFix) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.meshfix Repair a raw digitized mesh into a single watertight triangle mesh using MeshFix. ```{py:function} ms.repair_watertight_mesh_meshfix(**params) :module: _meshlab Runs the standard MeshFix repair pipeline: keeps the connected component with the most triangles, fills all holes with refined patches, then repairs degeneracies and self-intersections. The result is created as a new geometry-only layer and preserves the input layer transform. This filter is intended for raw digitized surfaces representing one closed solid. Vertex and face attributes, materials, textures, and polygonal edge markings are not transferred. MeshFix has no cancellation or fine-grained progress API, so only phase-level progress is available. **Upstream:** [MeshFix 2.1](https://github.com/MarcoAttene/MeshFix-V2.1) **License:** GPL-3.0-or-later **References:** - Marco Attene. **A lightweight approach to repairing digitized polygon meshes**. *The Visual Computer* (2010). [DOI](https://doi.org/10.1007/s00371-010-0416-3) This filter has no parameters. ``` --- (filter-split-non-manifold-vertices-trueform)= ## Split Non-Manifold Vertices (TrueForm) **Categories:** `Repair/Topology` **Plugin:** meshlab2.filter.trueform Give every fan of faces at a vertex a vertex of its own. ```{py:function} ms.split_non_manifold_vertices_trueform(**params) :module: _meshlab Separates the surface where it was only ever **pinched**. When the faces around a vertex walk as several fans rather than one, each fan but the first takes a fresh vertex carrying the same coordinates, and that fan's corners are rewired onto it. The fan holding the vertex's smallest face keeps the original id, faces keep their ids, their arity and their winding, and the output points are the input's followed by the minted copies. Nothing moves, so the surface is geometrically identical — only its connectivity changes, and two sheets that merely touched at a point come apart into the separate pieces they always were. **This is a partial repair, by construction.** An edge carried by three or more faces is crossed by no fan, and separating the fans it holds would tear that edge into boundary copies — a different operation with a different cost. Such a vertex is therefore left exactly as it was, and *Select Non-Manifold Vertices (TrueForm)* still names it afterwards. Run that filter before and after to see what was repaired and what remains. The result is a new layer; the original is untouched. This filter has no parameters. ``` --- (filter-dilate-selection)= ## Dilate Selection **Categories:** `Selection/Set Operations` **Plugin:** meshlab2.filter.select Dilate (expand) current selected faces. ```{py:function} ms.dilate_selection(**params) :module: _meshlab Dilate (expand) the current set of selected faces. This filter has no parameters. ``` --- (filter-erode-selection)= ## Erode Selection **Categories:** `Selection/Set Operations` **Plugin:** meshlab2.filter.select Erode (reduce) current selected faces. ```{py:function} ms.erode_selection(**params) :module: _meshlab Erode (reduce) the current set of selected faces. This filter has no parameters. ``` --- (filter-invert-selection)= ## Invert Selection **Categories:** `Selection/Set Operations` **Plugin:** meshlab2.filter.select Invert the current set of selected faces/vertices. ```{py:function} ms.invert_selection(**params) :module: _meshlab **Parameters:** - **InvFaces** (*bool*, default: `@hasSelectedFaces`) — If true the filter will invert the set of selected faces. - **InvVerts** (*bool*, default: `@hasSelectedVerts`) — If true the filter will invert the set of selected vertices. ``` --- (filter-select-all)= ## Select All **Categories:** `Selection/Set Operations` **Plugin:** meshlab2.filter.select Select all the faces/vertices of the current mesh. ```{py:function} ms.select_all(**params) :module: _meshlab **Parameters:** - **allFaces** (*bool*, default: `True`) — If true the filter will select all the faces. - **allVerts** (*bool*, default: `True`) — If true the filter will select all the vertices. ``` --- (filter-select-none)= ## Select None **Categories:** `Selection/Set Operations` **Plugin:** meshlab2.filter.select Clear the current set of selected faces/vertices. ```{py:function} ms.select_none(**params) :module: _meshlab **Parameters:** - **allFaces** (*bool*, default: `True`) — If true the filter will de-select all the faces. - **allVerts** (*bool*, default: `True`) — If true the filter will de-select all the vertices. ``` --- (filter-select-coplanar-faces)= ## Select Coplanar Faces **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Extend the face selection to every face on the plane of the selected ones. ```{py:function} ms.select_coplanar_faces(**params) :module: _meshlab Fits a plane to the currently selected faces, by least squares over their vertices, and adds to the selection every face of the layer whose three vertices all lie within **Distance from plane** of it, whether or not it is connected to the selection. The existing selection is kept. With **Only connected faces**, the selection instead grows from the selected faces across their edges, through faces that are on the plane themselves, so a coplanar region reached only through faces off the plane is left out. The selected faces must themselves lie on one plane. When their RMS distance from the fitted plane is larger than the tolerance, for instance because they come from two different walls, the filter refuses rather than guess a plane. On a noisy surface, select several faces spread over the plane for a steadier fit, and set the tolerance to a few times the noise. **Parameters:** - **maxDistance** (*absperc*, default: `@bboxDiag001`) — A face is added to the selection when all three of its vertices are within this distance of the plane fitted to the selected faces. - **connectedOnly** (*bool*, default: `False`) — Grow the selection from the selected faces across their edges, through faces that are on the plane themselves. When off, every face on the plane is added, wherever it is in the layer. ``` --- (filter-select-edges-by-expression)= ## Select Edges by Expression **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.expression Selects polyline edges for which a boolean expression evaluates true. ```{py:function} ms.select_edges_by_expression(**params) :module: _meshlab Boolean function using muparser lib to select the **real edges of a polyline layer** — the kind produced by the *Create Polyline* filters — not the sides of triangles. Endpoint values use the same names as the first two corners of a face: `x0,y0,z0`/`x1,y1,z1`, `nx0`..`nz1`, `r0,g0,b0,a0`/`r1`..`a1`, `q0,q1`, `vi0,vi1`, `vsel0,vsel1`. The edge itself gives `er,eg,eb,ea` (current color), `eq` (scalar), `ei` (index) and `esel`, plus the derived `elen` (length), `emx,emy,emz` (midpoint) and `edx,edy,edz` (unit direction; zero for a degenerate edge). Bounding-box values `xmin`..`bbdiag` are available as everywhere else. **Parameters:** - **condSelect** (*string*, default: `(elen > 0)`) — Boolean expression evaluated per edge. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-select-faces-by-color)= ## Select Faces by Color **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select part of the mesh based on vertex color. ```{py:function} ms.select_faces_by_color(**params) :module: _meshlab Select part of the mesh based on its color. **Parameters:** - **Color** (*color*, default: `#000000`) — Color that you want to be selected. - **ColorSpace** (*enum*, default: `hsv`) — The color space that the sliders will manipulate. - **Inclusive** (*bool*, default: `True`) — If true only faces with all vertices within range are selected. Otherwise any face with at least one vertex in range is selected. - **PercentRH** (*double*, default: `0.2`) — A float in [0,1] representing accepted variation from selected Red/Hue. - **PercentGS** (*double*, default: `0.2`) — A float in [0,1] representing accepted variation from selected Green/Saturation. - **PercentBV** (*double*, default: `0.2`) — A float in [0,1] representing accepted variation from selected Blue/Value. ``` --- (filter-select-faces-by-edge-length)= ## Select Faces by Edge Length **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select all triangles having an edge longer than threshold. ```{py:function} ms.select_faces_by_edge_length(**params) :module: _meshlab Select all triangles having an edge with length greater or equal than a given threshold. **Parameters:** - **Threshold** (*absperc*, default: `@bboxDiag0005`) — Faces with an edge longer than this threshold will be selected. ``` --- (filter-select-faces-by-expression)= ## Select Faces by Expression **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.expression Selects faces for which a boolean expression evaluates true. ```{py:function} ms.select_faces_by_expression(**params) :module: _meshlab Boolean function using muparser lib to perform faces selection over current mesh.
**Parameters:** - **condSelect** (*string*, default: `(fi == 0)`) — Boolean expression evaluated per face. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-select-faces-by-scalar)= ## Select Faces by Scalar **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select elements using per-face quality range. ```{py:function} ms.select_faces_by_scalar(**params) :module: _meshlab Select all the faces/vertices with within the specified face quality range. **Parameters:** - **minQ** (*double*, default: `@qualityFMin`) — Minimum acceptable quality value. - **maxQ** (*double*, default: `@qualityFMax`) — Maximum acceptable quality value. - **Inclusive** (*bool*, default: `True`) — If true only vertices with all adjacent faces within range are selected. Otherwise any vertex with at least one face in range is selected. ``` --- (filter-select-faces-by-view-angle)= ## Select Faces by View Angle **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select faces according to angle with view direction. ```{py:function} ms.select_faces_by_view_angle(**params) :module: _meshlab Select faces according to the angle between their normal and the view direction. It is used in range map processing to select and delete steep faces parallel to viewdirection. **Parameters:** - **anglelimit** (*double*, default: `75.0`) — Faces with normals at higher angle w.r.t. the view direction are selected. - **usecamera** (*bool*, default: `False`) — Uses the ViewPoint from the camera associated to the current mesh. If there is no camera, an error occurs. - **viewpoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Viewpoint position (ignored when UseCamera is true). ``` --- (filter-select-outliers)= ## Select Outliers **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select outlier vertices using LoOP. ```{py:function} ms.select_outliers(**params) :module: _meshlab Select the vertex classified as outlier using Local Outlier Propabilty measure described in:
'LoOP: Local Outlier Probabilities' Kriegel et al.
CIKM 2009 **Parameters:** - **PropThreshold** (*double*, default: `0.8`) — Threshold to select a vertex. Vertex is selected if LoOP value is above threshold. - **KNearest** (*int*, default: `32`) — Number of neighbors used to compute LoOP. ``` --- (filter-select-vertices-by-expression)= ## Select Vertices by Expression **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.expression Selects vertices for which a boolean expression evaluates true. ```{py:function} ms.select_vertices_by_expression(**params) :module: _meshlab Boolean function using muparser lib to perform vertex selection over current mesh.
**Parameters:** - **condSelect** (*string*, default: `(q < 0)`) — Boolean expression evaluated per vertex. - **randomSeed** (*int*, default: `0`) — Seed for the `rnd()` and `randInt()` helpers, which only matter if your expression calls them. Zero draws a fresh seed on every run; any other value makes the expression exactly reproducible. ``` --- (filter-select-vertices-by-scalar)= ## Select Vertices by Scalar **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.select Select elements using per-vertex quality range. ```{py:function} ms.select_vertices_by_scalar(**params) :module: _meshlab Select all the faces/vertices within the specified vertex quality range. **Parameters:** - **minQ** (*double*, default: `@qualityVMin`) — Minimum acceptable quality value. - **maxQ** (*double*, default: `@qualityVMax`) — Maximum acceptable quality value. - **Inclusive** (*bool*, default: `True`) — If true only faces with all vertices within range are selected. Otherwise any face with at least one vertex in range is selected. ``` --- (filter-select-vertices-inside-mesh-trueform)= ## Select Vertices Inside Mesh (TrueForm) **Categories:** `Selection/by Attribute` **Plugin:** meshlab2.filter.trueform Select the vertices enclosed by another layer. ```{py:function} ms.select_vertices_inside_mesh_trueform(**params) :module: _meshlab Selects every vertex that falls **inside** the enclosing layer's volume. This is the spatial counterpart to selecting by an attribute: crop a scan to a region of interest by modelling a rough box or sphere around it, isolate the part of an assembly within a clearance envelope, or find geometry that has ended up inside a shell it should be outside of. Containment is decided by the **sign of the distance** to the enclosing surface rather than by counting ray crossings, so a vertex lying exactly on the surface is resolved consistently instead of depending on the direction a ray happens to be cast. The enclosing layer must be **closed** for inside to be meaningful. Enable **Select Outside** to invert the test. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The layer whose vertices are selected. - **referenceMesh** (*mesh*, default: `@otherMeshIndex`) — The closed layer that defines inside. - **selectOutside** (*bool*, default: `False`) — Select the vertices outside the enclosing layer instead. - **mode** (*enum*, default: `replace`) — Replace the current selection, or add to and subtract from it. ``` --- (filter-select-border)= ## Select Border **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Select vertices and faces on mesh boundary. ```{py:function} ms.select_border(**params) :module: _meshlab Select vertices and faces on the boundary. This filter has no parameters. ``` --- (filter-select-connected-faces)= ## Select Connected Faces **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Expand selected faces to their connected components. ```{py:function} ms.select_connected_faces(**params) :module: _meshlab Expand the current face selection so that it includes all the faces in the connected components where there is at least a selected face. This filter has no parameters. ``` --- (filter-select-crease-edges-trueform)= ## Select Crease Edges (TrueForm) **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.trueform Select edges whose dihedral angle exceeds a threshold. ```{py:function} ms.select_crease_edges_trueform(**params) :module: _meshlab Marks every edge where the two incident faces meet at more than the given angle — the sharp features of the model. The selection lands on the **per-face edge flags**, which is the same place the other crease filters write, so the result feeds straight into *Create Polyline from Selected Edges*, *Cut Along Crease Edges*, or a feature-preserving remesh. Competing implementation: *Select Crease Edges* does the same with vcglib, with separate thresholds for convex and concave angles; this one uses a single unsigned threshold. **Parameters:** - **angle** (*double*, default: `60.0`) — Dihedral angle above which an edge counts as a crease. - **replaceSelection** (*bool*, default: `True`) — Clear the existing edge selection first instead of adding to it. ``` --- (filter-select-crease-edges-vcglib)= ## Select Crease Edges (vcglib) **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.meshing Select crease edges from dihedral angles. ```{py:function} ms.select_crease_edges_vcglib(**params) :module: _meshlab It select the crease edges of a mesh according to edge dihedral angle.
Angle between face normal is considered signed according to convexity/concavity.Convex angles are positive and concave are negative. **Parameters:** - **AngleDegNeg** (*double*, default: `-45.0`) — Concave dihedral threshold. - **AngleDegPos** (*double*, default: `45.0`) — Convex dihedral threshold. ``` --- (filter-select-faces-from-vertices)= ## Select Faces from Vertices **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Transfer selection from selected vertices to faces. ```{py:function} ms.select_faces_from_vertices(**params) :module: _meshlab Select faces from selected vertices. **Parameters:** - **Inclusive** (*bool*, default: `True`) — If true only faces with all selected vertices are selected. Otherwise any face with at least one selected vertex is selected. ``` --- (filter-select-ill-shaped-faces)= ## Select Ill-Shaped Faces **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Select problematic faces: elongated, flipped, or folded. ```{py:function} ms.select_ill_shaped_faces(**params) :module: _meshlab Select faces with 'problems', like normal inverted w.r.t the surrounding areas, extremely elongated or folded. **Parameters:** - **useAR** (*bool*, default: `True`) — If true, faces with aspect ratio below the limit will be selected. - **ARatio** (*double*, default: `0.02`) — Triangle face aspect ratio [1 (equilateral) - 0 (line)]: face is selected if below this threshold. - **useNF** (*bool*, default: `False`) — If true, adjacent faces with normals forming an angle above the limit are selected. - **NFRatio** (*double*, default: `60.0`) — Angle between adjacent faces: face is selected if above this threshold. - **select_folded_faces** (*bool*, default: `False`) — If true, folded faces created by quadric edge-collapse decimation are selected. - **folded_faces_angle_threshold** (*double*, default: `160.0`) — Angle between face normal and best-fitting plane of neighboring vertices. If above threshold, face is selected. ``` --- (filter-select-non-manifold-edges-trueform)= ## Select Non-Manifold Edges (TrueForm) **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.trueform Select edges shared by more than two faces. ```{py:function} ms.select_non_manifold_edges_trueform(**params) :module: _meshlab Marks every edge with more than two incident faces. Such edges have no well-defined surface either side, which is why they break booleans, offsetting, orientation and most reconstruction — so finding them is usually the first step in diagnosing a mesh that misbehaves for no visible reason. The selection lands on the per-face edge flags, so it can be turned into a polyline with *Create Polyline from Selected Edges* to see exactly where the trouble is. Competing implementation: *Select non Manifold Edges* does the same with vcglib. **Parameters:** - **replaceSelection** (*bool*, default: `True`) — Clear the existing edge selection first instead of adding to it. ``` --- (filter-select-non-manifold-edges-vcglib)= ## Select Non-Manifold Edges (vcglib) **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Select faces and vertices incident on non manifold edges. ```{py:function} ms.select_non_manifold_edges_vcglib(**params) :module: _meshlab Select the faces and the vertices incident on non manifold edges (e.g. edges where more than two faces are incident); note that this function select the components that This filter has no parameters. ``` --- (filter-select-non-manifold-vertices)= ## Select Non-Manifold Vertices **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Select non manifold vertices. ```{py:function} ms.select_non_manifold_vertices(**params) :module: _meshlab Select the non manifold vertices that do not belong to non manifold edges. For example two cones connected by their apex. Vertices incident on non manifold edges are ignored. This filter has no parameters. ``` --- (filter-select-non-manifold-vertices-trueform)= ## Select Non-Manifold Vertices (TrueForm) **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.trueform Select vertices whose faces do not form a single fan. ```{py:function} ms.select_non_manifold_vertices_trueform(**params) :module: _meshlab Marks every vertex whose incident faces are not one **fan** — either an edge at it carries three or more faces, or its faces fall into several pieces that meet at that vertex alone. The second case is the one nothing else finds. Two sheets joined at a single pinched vertex have no non-manifold *edge* at all: every edge is shared by exactly two faces, so *Select Non-Manifold Edges (TrueForm)* reports nothing. The surface still has no well-defined neighbourhood at that point, which is enough to break offsetting, subdivision, parametrization and most reconstruction — and it is exactly the defect that survives every edge-based check. Winding is a separate fact and never enters: a vertex whose faces disagree about which way they wind is not reported for that alone, and a vertex no face names is not reported either. *Split Non-Manifold Vertices (TrueForm)* repairs the pinched case by giving each fan a vertex of its own. **Parameters:** - **replaceSelection** (*bool*, default: `True`) — Clear the existing vertex selection first instead of adding to it. ``` --- (filter-select-self-intersecting-faces)= ## Select Self-Intersecting Faces **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Select only self intersecting faces. ```{py:function} ms.select_self_intersecting_faces(**params) :module: _meshlab This filter has no parameters. ``` --- (filter-select-small-disconnected-components)= ## Select Small Disconnected Components **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.mls Select the small disconnected components of a mesh. ```{py:function} ms.select_small_disconnected_components(**params) :module: _meshlab **Parameters:** - **NbFaceRatio** (*double*, default: `0.1`) — This ratio (between 0 and 1) defines the meaning of small as the threshold ratio between the number of faces of the largest component and the other ones. A larger value will select more components. - **NonClosedOnly** (*bool*, default: `False`) — If enabled, only non-closed connected components are selected. ``` --- (filter-select-vertex-texture-seams)= ## Select Vertex Texture Seams **Categories:** `Selection/by Topology`, `Parametrization` **Plugin:** meshlab2.filter.select Select vertices on texture seams. ```{py:function} ms.select_vertex_texture_seams(**params) :module: _meshlab Colorize only border edges. This filter has no parameters. ``` --- (filter-select-vertices-from-faces)= ## Select Vertices from Faces **Categories:** `Selection/by Topology` **Plugin:** meshlab2.filter.select Transfer selection from selected faces to vertices. ```{py:function} ms.select_vertices_from_faces(**params) :module: _meshlab Select vertices from selected faces. **Parameters:** - **Inclusive** (*bool*, default: `True`) — If true only vertices with all incident faces selected are selected. Otherwise any vertex with at least one incident selected face is selected. ``` --- (filter-select-by-screen-rectangle)= ## Select by Screen Rectangle **Categories:** `Selection/by Visibility` **Plugin:** meshlab2.filter.select Select vertices or faces whose screen projection falls inside a rectangle. ```{py:function} ms.select_by_screen_rectangle(**params) :module: _meshlab Screen-space rubber-band selection. Given a camera and a rectangle in normalized viewport coordinates (origin bottom-left, y up, range 0..1), selects the vertices (or face centroids) of the current mesh that project inside the rectangle. This is the filter committed by the interactive rubber-band tool, and is equally usable from scripting. *Expand to* is what the rubber-band tool's **C** (connected components) and **T** (UV islands) modifiers set: the rectangle only has to graze a piece for all of it to be selected. **Parameters:** - **camera_state** (*camerastate*) — Camera state (MeshLab.CameraState JSON) defining the projection. - **aspect** (*double*, default: `1.0`) — Viewport width/height used to build the projection. - **space** (*enum*, default: `view3d`) — Whether the rectangle is in the 3D view or the UV/parametrization view. - **uv_pan_x** (*double*, default: `0.5`) — UV-view pan (X), used when space = uv. - **uv_pan_y** (*double*, default: `0.5`) — UV-view pan (Y), used when space = uv. - **uv_zoom** (*double*, default: `1.0`) — UV-view zoom, used when space = uv. - **rect_min_x** (*double*, default: `0.0`) — Left edge, normalized [0..1]. - **rect_min_y** (*double*, default: `0.0`) — Bottom edge, normalized [0..1], y up. - **rect_max_x** (*double*, default: `1.0`) — Right edge, normalized [0..1]. - **rect_max_y** (*double*, default: `1.0`) — Top edge, normalized [0..1], y up. - **element** (*enum*, default: `face`) — Whether to select vertices or faces (by centroid). - **mode** (*enum*, default: `replace`) — Replace the current selection, add to it, or subtract from it. - **visible_only** (*bool*, default: `False`) — When selecting faces in the 3D view, keep only faces not occluded from the current viewpoint (ray-traced visibility). - **expand_to** (*enum*, default: `none`) — Grow what the rectangle touched to the whole piece it belongs to, so grazing one triangle takes all of it. *Connected components* follow the mesh's own connectivity. *UV islands* also stop at UV seams, the edges whose two sides have different UVs, so each island is one piece of the UV layout; the mesh needs UVs for it. The growth starts from what the rectangle hit rather than from the finished selection, so it composes with the modes as you would expect: subtract removes the whole piece under the rectangle instead of growing whatever was left behind. Vertices are grown through their faces, so a vertex on a seam takes the islands on both sides. Face-face adjacency is built on demand, so this costs more than a plain drag. ``` --- (filter-select-visible-faces)= ## Select Visible Faces **Categories:** `Selection/by Visibility` **Plugin:** meshlab2.filter.embree Selects faces visible from a user-defined direction. ```{py:function} ms.select_visible_faces(**params) :module: _meshlab Select visible face
This filter displays all visible faces from a given direction, selecting the face is is visible from the point given.This filter utilizes the Embree3 library by INTEL. **Parameters:** - **direction** (*point3f*, default: `[1.0, 1.0, 0.0]`) — Visibility ray direction. ``` --- (filter-select-visible-vertices)= ## Select Visible Vertices **Categories:** `Selection/by Visibility` **Plugin:** meshlab2.filter.select Select the vertices visible from a given viewpoint. ```{py:function} ms.select_visible_vertices(**params) :module: _meshlab Selects the vertices of the current layer that are **visible from a viewpoint**, using the *hidden point removal* operator: the points are inverted through a sphere centred on the viewpoint, and the ones landing on the convex hull of the inverted set are the visible ones. Only vertex positions are used, so this works on a raw point cloud with no faces and no normals — which is what it is for. It is the point-cloud counterpart of *Select Visible Faces*, which needs a surface to cast rays against. **Radius Threshold** sets the inversion sphere radius as `radius * 10^threshold`. Larger values mark more points visible: use a large threshold for dense clouds and a small one for sparse clouds. The selection is **added** to the current one; clear it first for an exact result. Reference: Sagi Katz, Ayellet Tal, Ronen Basri, **Direct Visibility of Point Sets**, ACM Transactions on Graphics 26(3), 2007. **Parameters:** - **radiusThreshold** (*double*, default: `0.0`) — Exponent of the inversion sphere radius (radius * 10^threshold). Larger values mark more points as visible; use a large value for dense clouds, a small one for sparse clouds. - **usecamera** (*bool*, default: `False`) — Uses the ViewPoint from the camera associated to the current mesh. If there is no camera, an error occurs. - **viewpoint** (*point3f*, default: `[0.0, 0.0, 0.0]`) — Viewpoint position (ignored when UseCamera is true). ``` --- (filter-set-texture)= ## Set Texture **Categories:** `Texture/Assignment` **Plugin:** meshlab2.filter.texture Associate an image or generated dummy texture with the current mesh UV coordinates. ```{py:function} ms.set_texture(**params) :module: _meshlab Associates one texture with the current mesh UV parametrization, replacing its existing texture associations. By default, the filter generates a checkerboard that makes UV scale and distortion immediately visible. Disable **Use dummy texture** to select an existing image file instead. **Parameters:** - **use_dummy_texture** (*bool*, default: `True`) — If checked, generate a dummy texture instead of loading an image. Disable it to select an image using 'Texture file'. - **textName** (*fileopen*, default: ``) — Sets the given input image as unique texture of the mesh. - **dummy_img_size** (*int*, default: `512`) — Size in pixel of the square dummy texture. - **dummy_check_size** (*int*, default: `64`) — Size in pixel of the checkerboard or grid cell of the dummy texture. - **dummy_type** (*enum*, default: `checkerboard`) — Choose between a checkerboard, a line grid, and a UV grid whose lines along U are red and along V blue. ``` --- (filter-convert-object-space-normal-map-to-tangent-space)= ## Convert Object-Space Normal Map to Tangent Space **Categories:** `Texture/Conversion` **Plugin:** meshlab2.filter.texture Convert an object-space normal map into a tangent-space normal map for the current mesh UV slot. ```{py:function} ms.convert_object_space_normal_map_to_tangent_space(**params) :module: _meshlab Converts an object-space normal map into a tangent-space normal map using the current mesh geometry, normals, and UV parametrization. The result is suitable for direct use in MeshLab's PBR normal-texture channel. **Parameters:** - **targetTexture** (*textureref*, default: `1`) — Choose the mesh texture slot that owns the UV layout to process. Only faces whose per-wedge texture index uses this slot are converted, and this is also the material slot whose PBR normal channel can be updated. This is separate from the source image because the object-space normal map may be stored as another associated texture. - **sourceNormalMap** (*textureref*, default: `1`) — Choose the associated texture image to interpret as the object-space normal map. Its pixels are sampled through the selected UV / Material Slot. - **targetNormalMap** (*textureoutputref*, default: `tangent_normal.png`) — Choose where the generated tangent-space normal map should go: overwrite an existing associated texture, or create a new texture file and add it to the mesh texture list. - **bindAsPbrNormal** (*bool*, default: `True`) — If enabled, the converted texture is added to the mesh associated texture list and assigned to the selected slot's PBR normal channel. - **invertX** (*bool*, default: `False`) — Invert the tangent-space X channel in the generated normal map. - **invertY** (*bool*, default: `False`) — Invert the tangent-space Y channel in the generated normal map. - **invertZ** (*bool*, default: `False`) — Invert the tangent-space Z channel in the generated normal map. - **normalScale** (*double*, default: `1.0`) — Normal intensity stored in the selected material slot when binding the converted map as a PBR normal texture. ``` --- (filter-pack-texture-images)= ## Pack Texture Images **Categories:** `Texture/Packing`, `Parametrization/Atlas Packing` **Plugin:** meshlab2.filter.texture Combines complete texture images into fewer atlas images and remaps the mesh UVs. ```{py:function} ms.pack_texture_images(**params) :module: _meshlab Combines the complete texture images used by the current mesh into a smaller number of atlas images and creates a new mesh layer referencing the result. Each source image is kept intact, placed as a rectangular region in one output image, and copied without rescaling. The mesh's per-wedge texture indices and UV coordinates are then remapped so every triangle continues to sample the same source pixels from their new atlas location. The original mesh and its textures are left unchanged. This operation packs whole images, not individual UV islands or charts. Use **Defragment Texture Atlas** when the goal is to rearrange or optimize the UV charts themselves. Output image dimensions are determined automatically from the source image sizes and their packed arrangement, so they are not necessarily square or powers of two. **Target textures** specifies the desired number of output atlas images and must be smaller than the number of texture groups actually used by mesh faces. Source images are distributed between those outputs before rectangular packing. **Gutter** reserves the requested number of pixels around every source image. Border pixels are extruded into this area, reducing color bleeding when the atlas is displayed with bilinear filtering. Every face must reference one valid texture consistently across its three wedges, and all UV coordinates must lie inside `[0,1]`. Repeated or tiled texture coordinates cannot be represented safely after whole-image atlas packing, so such meshes are rejected rather than producing altered texture mapping. **Parameters:** - **containerNum** (*int*, default: `1`) — Number of output images. It must be smaller than the number of texture groups actually used by the mesh. - **gutter** (*int*, default: `4`) — Border pixels reserved around every source image. The source image edges are extruded into this area to prevent bilinear-filtering bleed. ``` --- (filter-transfer-abstract-domain-to-another-layer)= ## Transfer Abstract Domain to Another Layer **Categories:** `Transfer/Between Layers` **Plugin:** meshlab2.filter.isoparam Carry an abstract domain from one layer onto another, similar and aligned one, by closest point. ```{py:function} ms.transfer_abstract_domain_to_another_layer(**params) :module: _meshlab Copies a layer's abstract domain onto a second layer -- typically the same object at a different resolution -- by finding, for each target vertex, the closest point on the source parametrization and reading its domain position off that. This is a convenience rather than part of the original technique, and it inherits the limits of closest-point matching: the two layers must be reasonably similar in shape and already aligned, and nothing here registers them for you. Where the surfaces disagree the domain positions will follow the source's geometry rather than the target's. Unlike MeshLab, which moves the domain and leaves the source without one, the source **keeps its own domain** and the target gets an independent copy. **References:** - Nico Pietroni, Marco Tarini, Paolo Cignoni. **Almost Isometric Mesh Parameterization through Abstract Domains**. *IEEE Transactions on Visualization and Computer Graphics* (2010). [DOI](https://doi.org/10.1109/TVCG.2009.96) **Parameters:** - **sourceMesh** (*mesh*) — The layer that already carries an abstract domain. - **targetMesh** (*mesh*) — The layer to receive the parametrization. ``` --- (filter-transfer-color-from-texture-to-vertex-by-closest-point)= ## Transfer Color from Texture to Vertex by Closest Point **Categories:** `Transfer/Between Layers`, `Attribute/Color` **Plugin:** meshlab2.filter.texture Generate vertex colors by sampling texture colors from the same mesh or another mesh. ```{py:function} ms.transfer_color_from_texture_to_vertex_by_closest_point(**params) :module: _meshlab Generates Vertex Color values picking color from a texture (same mesh or another mesh). **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh with associated texture that we want to sample from. - **targetMesh** (*mesh*, default: `@otherMeshIndex`) — The mesh whose vertex color will be filled according to source mesh texture. - **upperBound** (*absperc*, default: `@bboxDiag002`) — Sample points for which we do not find anything within this distance are rejected and not considered for recovering color. - **sourceTexture** (*textureref*, default: `0`) — Choose which associated source texture to sample. Automatic uses the source mesh per-face texture slot assignment. ``` --- (filter-transfer-vertex-attributes-by-closest-point)= ## Transfer Vertex Attributes by Closest Point **Categories:** `Transfer/Between Layers` **Plugin:** meshlab2.filter.sampling Transfer attributes from one mesh to another by closest-point projection. ```{py:function} ms.transfer_vertex_attributes_by_closest_point(**params) :module: _meshlab Transfer the chosen per-vertex attributes from one layer to another. Useful to transfer attributes to different representations of a same object.
For each vertex of the target mesh the closest point (not vertex!) on the source mesh is computed, and the requested interpolated attributes from that source point are copied into the target vertex.
The algorithm assumes that the two meshes are reasonably similar and aligned. **Parameters:** - **SourceMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh that provides the attributes to transfer. - **TargetMesh** (*mesh*, default: `@otherMeshIndex`) — The mesh whose vertices receive the transferred attributes. - **VertexSampling** (*bool*, default: `False`) — If enabled, transfer attributes from the closest source vertex instead of the closest point on the source surface. - **GeomTransfer** (*bool*, default: `False`) — Snap target vertices onto the corresponding closest point on the source. - **NormalTransfer** (*bool*, default: `False`) — Transfer interpolated normals from the source. - **ColorTransfer** (*bool*, default: `True`) — Transfer vertex colors from the source. - **QualityTransfer** (*bool*, default: `False`) — Transfer vertex quality from the source. - **SelectionTransfer** (*bool*, default: `False`) — Select target vertices whose corresponding closest point lies on selected source elements. - **QualityDistance** (*bool*, default: `False`) — Store the transfer distance in the target vertex quality. - **SaveBarycentric** (*bool*, default: `False`) — Store barycentric coordinates and nearest face or vertex indices as per-vertex attributes on the target mesh. - **UpperBound** (*absperc*, default: `@bboxDiag01`) — Closest-point searches farther than this threshold are rejected. ``` --- (filter-transfer-vertex-attributes-to-texture-by-closest-point)= ## Transfer Vertex Attributes to Texture by Closest Point **Categories:** `Transfer/Between Layers`, `Texture` **Plugin:** meshlab2.filter.texture Transfer texture color, vertex color, normals, or quality from one mesh into another mesh texture. ```{py:function} ms.transfer_vertex_attributes_to_texture_by_closest_point(**params) :module: _meshlab Transfer texture color, vertex color or normal from one mesh the texture of another mesh. This may be useful to restore detail lost in simplification, or resample a texture in a different parametrization. **Parameters:** - **sourceMesh** (*mesh*, default: `@currentMeshIndex`) — The mesh that contains the source data that we want to transfer. - **targetMesh** (*mesh*, default: `@otherMeshIndex`) — The mesh whose texture will be filled according to source mesh data. - **AttributeEnum** (*enum*, default: `vertex_color`) — Choose what attribute has to be transferred onto the target texture. You can choose between per-vertex attributes or transfer color information from source mesh texture. - **upperBound** (*absperc*, default: `@bboxDiag002`) — Sample points for which we do not find anything within this distance are rejected and not considered for recovering data. - **textName** (*filesave*, default: `texture.png`) — Base path of the texture image to be created. If more than one target texture slot is used, numeric suffixes are added automatically. - **textW** (*int*, default: `1024`) — The texture width. - **textH** (*int*, default: `1024`) — The texture height. - **overwrite** (*bool*, default: `False`) — If target mesh has associated textures, overwrite them instead of creating new files. - **pullpush** (*bool*, default: `True`) — If enabled the unmapped texture space is colored using a pull-push filling algorithm, otherwise it is left black. - **sourceTexture** (*textureref*, default: `0`) — When Texture Color is selected, choose which associated source texture to sample. Automatic uses the source mesh per-face texture slot assignment. ``` --- (filter-transfer-color-from-current-raster-to-vertex)= ## Transfer Color from Current Raster to Vertex **Categories:** `Transfer/From Rasters`, `Attribute/Color` **Plugin:** meshlab2.filter.color_projection Project the current raster image color onto the mesh vertices. ```{py:function} ms.transfer_color_from_current_raster_to_vertex(**params) :module: _meshlab Projects color information from the current raster onto the mesh vertices using perspective projection. Optionally uses a software depth buffer to restrict projection to visible faces only. **Parameters:** - **usedepth** (*bool*, default: `True`) — If true, a depth buffer is used to restrict projection to visible faces only. - **deptheta** (*double*, default: `0.5`) — Tolerance value for depth buffer comparison (shadow buffer). - **blankColor** (*color*, default: `#00000000`) — Areas that cannot be projected will be filled with this color. If all channels are 0, the original color is preserved. - **preserveoccluded** (*bool*, default: `False`) — If true, depth-occluded vertices keep their original color instead of being assigned the blank color. ``` --- (filter-transfer-color-from-visible-rasters-to-texture)= ## Transfer Color from Visible Rasters to Texture **Categories:** `Transfer/From Rasters`, `Texture` **Plugin:** meshlab2.filter.color_projection Project color from all visible rasters onto a new mesh texture using wedge UV coordinates. ```{py:function} ms.transfer_color_from_visible_rasters_to_texture(**params) :module: _meshlab Projects color information from all visible and valid rasters onto a new texture image, using the mesh's existing wedge UV coordinates. The result is saved as a texture image and associated with the mesh. **Parameters:** - **textName** (*filesave*, default: `projected_texture.png`) — Output texture image file path. - **texsize** (*int*, default: `1024`) — Square texture image size in pixels. Should be a power of 2. - **dorefill** (*bool*, default: `True`) — If true, unfilled areas of the texture atlas are interpolated using PullPush to avoid visible seams when mipmapping. - **deptheta** (*double*, default: `0.5`) — Tolerance value for depth buffer comparison (shadow buffer). - **useangle** (*bool*, default: `True`) — If true, color contribution is weighted by the angle between the surface normal and the view direction. - **usedistance** (*bool*, default: `True`) — If true, color contribution is weighted by the texel distance from the camera. - **useborders** (*bool*, default: `True`) — If true, color contribution is weighted by the pixel distance from the image boundaries. - **usesilhouettes** (*bool*, default: `True`) — If true, color contribution is weighted by the pixel distance from depth discontinuities (silhouettes). - **usealpha** (*bool*, default: `False`) — If true, the alpha channel of the raster image is used as an additional weight. ``` --- (filter-transfer-color-from-visible-rasters-to-vertex)= ## Transfer Color from Visible Rasters to Vertex **Categories:** `Transfer/From Rasters`, `Attribute/Color` **Plugin:** meshlab2.filter.color_projection Project color from all visible rasters onto the mesh vertices with weighted blending. ```{py:function} ms.transfer_color_from_visible_rasters_to_vertex(**params) :module: _meshlab Projects color information from all visible and valid rasters onto the mesh vertices using perspective projection and weighted blending. Weights can account for view angle, distance, image border proximity, depth discontinuities, and image alpha. **Parameters:** - **deptheta** (*double*, default: `0.5`) — Tolerance value for depth buffer comparison (shadow buffer). - **useangle** (*bool*, default: `True`) — If true, color contribution is weighted by the angle between the surface normal and the view direction. - **usedistance** (*bool*, default: `True`) — If true, color contribution is weighted by the vertex distance from the camera. - **useborders** (*bool*, default: `True`) — If true, color contribution is weighted by the pixel distance from the image boundaries. - **usesilhouettes** (*bool*, default: `True`) — If true, color contribution is weighted by the pixel distance from depth discontinuities (silhouettes). - **usealpha** (*bool*, default: `False`) — If true, the alpha channel of the raster image is used as an additional weight. - **blankColor** (*color*, default: `#00000000`) — Areas with no valid projection will be filled with this color. If all channels are 0, the original color is preserved. - **preserveoccluded** (*bool*, default: `False`) — If true, depth-occluded vertices keep their original color instead of being assigned the blank color. ``` --- (filter-transfer-color-from-face-to-vertex)= ## Transfer Color from Face to Vertex **Categories:** `Transfer/Within a Mesh`, `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Transfer face colors to vertex colors. ```{py:function} ms.transfer_color_from_face_to_vertex(**params) :module: _meshlab Face to Vertex color transfer This filter has no parameters. ``` --- (filter-transfer-color-from-mesh-to-face)= ## Transfer Color from Mesh to Face **Categories:** `Transfer/Within a Mesh`, `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Transfer the per-mesh color to face colors. ```{py:function} ms.transfer_color_from_mesh_to_face(**params) :module: _meshlab Mesh to Face color transfer This filter has no parameters. ``` --- (filter-transfer-color-from-texture-to-vertex)= ## Transfer Color from Texture to Vertex **Categories:** `Transfer/Within a Mesh`, `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Sample associated textures into vertex colors. ```{py:function} ms.transfer_color_from_texture_to_vertex(**params) :module: _meshlab Texture to Vertex color transfer **Parameters:** - **sourceTexture** (*textureref*, default: `0`) — Choose which associated texture to sample. Automatic uses each face's per-wedge texture slot assignment, matching MeshLab's multi-texture behavior. ``` --- (filter-transfer-color-from-vertex-to-face)= ## Transfer Color from Vertex to Face **Categories:** `Transfer/Within a Mesh`, `Attribute/Color` **Plugin:** meshlab2.filter.colorproc Transfer vertex colors to face colors. ```{py:function} ms.transfer_color_from_vertex_to_face(**params) :module: _meshlab Vertex to Face color transfer This filter has no parameters. ``` --- (filter-transfer-color-from-vertex-to-texture)= ## Transfer Color from Vertex to Texture **Categories:** `Transfer/Within a Mesh`, `Texture` **Plugin:** meshlab2.filter.texture Bake per-vertex color into texture image(s) using the current UV parametrization. ```{py:function} ms.transfer_color_from_vertex_to_texture(**params) :module: _meshlab Fills the specified texture using per-vertex color data of the mesh. **Parameters:** - **textName** (*filesave*, default: `texture.png`) — Base path of the texture image to be created. If more than one texture slot is used, numeric suffixes are added automatically. - **textW** (*int*, default: `1024`) — The texture width. - **textH** (*int*, default: `1024`) — The texture height. - **overwrite** (*bool*, default: `False`) — If current mesh has associated textures, overwrite them instead of creating new files. - **pullpush** (*bool*, default: `True`) — If enabled the unmapped texture space is colored using a pull-push filling algorithm, otherwise it is left black. ``` --- (filter-transfer-scalar-from-face-to-vertex)= ## Transfer Scalar from Face to Vertex **Categories:** `Transfer/Within a Mesh`, `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Transfer face quality to vertex quality. ```{py:function} ms.transfer_scalar_from_face_to_vertex(**params) :module: _meshlab Face to Vertex quality transfer **Parameters:** - **areaWeight** (*bool*, default: `True`) — If true the vertex quality is computed according to the surface of the involved faces. ``` --- (filter-transfer-scalar-from-vertex-to-face)= ## Transfer Scalar from Vertex to Face **Categories:** `Transfer/Within a Mesh`, `Attribute/Scalar` **Plugin:** meshlab2.filter.colorproc Transfer vertex quality to face quality. ```{py:function} ms.transfer_scalar_from_vertex_to_face(**params) :module: _meshlab Vertex to Face quality transfer This filter has no parameters. ```