Dev.Luv Studios

Mirror weights on the meshes that break X-Mirror.

SymmetryFlow mirrors and transfers vertex-group weights across a character — then tells you, group by group, whether the two sides actually match. When they don’t, one button repairs them.

Tested on Blender 3.6 · 4.0 · 4.2 · 4.4 · 4.5 · 5.1GPL-2.0-or-laterSource included
The SymmetryFlow sidebar beside a character head in weight-paint colour, mirrored across the face
The panel and the result, side by side — the L/R balance readout, every mirror option, and the weights they produce.
The problem

Blender’s mirror stops at the first vertex that isn’t an exact twin.

It is coordinate-based and all-or-nothing. On a production character that means the eyelids, lips, ears, teeth, brows and lashes — every part you actually need to get right.

This is not a bug in any Blender version. It has always worked this way. It was built for symmetrical geometry, and a character mesh moves away from being symmetrical as it gets sculpted, edited and assembled.

A face that looks fine and reads wrong. The panel names the pair — the lower eyelids — and one press of Mirror Active Group repairs it.

Two matching engines, chosen automatically.

Auto-Detect tests each group and picks the right one. Above both sits a maximum-matching pass that finds the true set of vertex partners instead of leaving stragglers mislabelled as unpairable.

Topological

Walks the mesh’s own edge connectivity, so it stays correct on posed meshes and shape keys — where the two sides are in completely different places in space and a coordinate mirror cannot pair them at all.

Spatial KD-tree

Queries mirrored positions in O(log N), for the meshes topology cannot handle: disconnected islands, asymmetric edge flow, parts-assembled and shell-split geometry.

A verification layer

The L/R Balance panel reports every pair as Balanced, Mismatched or Distorted. The verdict you read is produced by the same function Quick Fix acts on — report and repair cannot contradict each other.

Select Mirror Group shows the intact side, then the damaged one — Blender draws one group at a time. Mirror Active Group rebuilds it: 179 weights back to 340.
Knowing whether it worked

Most tools mirror. This one tells you whether the mirror landed.

If a region genuinely cannot be mirrored — because one side has no matching vertex at all — it says so, by name, instead of quietly doing something wrong.

Every pair it calls Mismatched carries a Quick Fix button that repairs exactly what the readout is complaining about, and leaves Balanced pairs alone. The verdict and the repair come from the same function, so the panel cannot report a problem the button does not understand.

mFaceEyeLidLowerLeftMismatched · 4
mFaceEyecornerInnerLeftMismatched · 2
L_UPPER_ARMBalanced · 438 / 438
The whole rig at once

Rebuild every pair in one press.

Mirror All L/R Groups pairs every group by name, creates the counterparts that are missing, mirrors each in the auto-detected direction, then runs a self-heal pass against the same metric the panel reports.

L: 0
37 UNPAIRED
→
L: 37
COUNTERPARTS MATCHING
The entire left side of this rig is gone — 37 vertex groups deleted — and one press rebuilds every one of them from the side that still carries weight.
Recorded, not reconstructed

Four of the options, and what each one changes.

Each clip mirrors the same group twice — once with the box unticked, once with it ticked — so what you are looking at is the difference the option makes. All of it recorded against a live Blender session with the pointer pressing the actual buttons; nothing scripted the result into place.

Lash, eyeball and body are separate shells sitting on top of one another. Unconfined, a mirror of the upper eyelid reaches onto the layer behind it. Confine to Mesh Island keeps it on the shell it started on.
Halves not built vertex-for-vertex. Exact matching leaves gaps; Interpolate Symmetrical Weights takes this cheek from 94 weights to 296.
A band of weight the source side cannot account for. Ticked, Clean Unmatched Weights removes it: 463 down to 340, all 123 strays dropped.
Invert Transferred Weights writes every mirrored value as 1 − w. The count cannot move, so the change is entirely in the colour: 433 of 438 hold a different value.
Writing only where it can prove a counterpart

It writes only where it can prove a counterpart.

Restrict to Counterpart Vertices masks the mirror to the source’s weighted vertices and their true counterparts, and refuses to write anywhere else.

On a foot it has almost nothing to refuse — 852 vertices unticked, 851 ticked — so the transfer completes and you see what the option leaves behind rather than what it withholds. It earns its keep where a spatial match would otherwise grab a vertex on the surface behind: a lash in front of an eyelid, an upper lip against a lower one.

The mask stays armed afterwards — 1,702 vertices left selected, exactly the ones the mirror was allowed to touch, ready to paint.

L_FOOT to R_FOOT, unticked then ticked — 852 then 851, and 1,702 vertices left selected behind it.
Lips, eyelids, anything that closes

It stops weight leaking onto the surface behind.

Where two surfaces sit close together — an upper lip resting on a lower one, an eyelid against its lash — a mirror can hand weight to the wrong one simply because it is the nearest point. Verify Normal Alignment checks which way each surface faces and refuses to write onto one facing the opposite way from the source. Strong weights get more leeway, so a noisy surface never costs you a real one.

You normally can’t see this happen: the wrong weight lands on a surface hidden behind another, anywhere two surfaces sit face to face — closed lips, an eyelid against its lash, the inside of the mouth. In this gif, the jaw is nudged until the lower lip pokes through the upper, bringing the hidden surface into view. On the lip corner of the same character it cuts wrong-facing weights from 8 of 92 to 2. It does nothing while Robust Asymmetric Fallback is on, because that option promises never to drop a weight.

57
UNTICKED
→
53
TICKED · 4 HELD BACK
Verify Normal Alignment on the upper lip: 57 weights mirrored with the box unticked, 53 with it ticked; a strip of weight on the lip seam disappears
mFaceLipUpperRight to mFaceLipUpperLeft, unticked then ticked — 57 then 53. Watch the strip of weight on the seam: there unticked, gone ticked.
The case a coordinate mirror cannot do

It works on a rig that is out of rest pose.

Take the armature out of rest pose and the two sides are no longer at mirrored coordinates — there is nothing for a spatial mirror to pair. SymmetryFlow reads the weights from the unposed mesh, so the mirror still lands.

296
BEFORE
→
438
AFTER, ONE PRESS
Shoulder raised 45° — the sides are genuinely not at mirrored coordinates, and the mirror still lands.
HEAD spans both eyelash strips, so there is no counterpart group to take from. Perfect Single Mirror rebuilds the stripped side from the side that still carries weight: 342 back to 684, exactly what was removed.
When there is nothing to copy from

Some groups have no counterpart.

A centre-line group — a head, a spine, an eyelash strip — spans both sides at once, so there is no Arm.L to take from. The fix is to mirror the group onto itself.

Perfect Single Mirror does that in one press, in whichever direction you choose, and reports the same way every other operation does.

Beyond the mirror button

The tools around the mirror.

Mirroring is one button. Most of a rigging afternoon is the work either side of it — finding which pair is wrong, creating the group that does not exist yet, clearing a side to start again. These sit in the same sidebar.

Finding the problem

Select Mismatched Vertices selects every vertex in a pair that disagrees with its counterpart, so you can see the damage rather than read a number. Select Unpairable Vertices selects the ones with no unique partner at all — near-coincident clusters and one-sided detail, which is the structural reason a count gap exists.

Between them they answer the two different questions a gap can raise: is this wrong, or is this simply not mirrorable.

Getting to the other side

Select Mirror Group switches the active group to its counterpart, which is how you compare two sides when Blender will only draw one at a time. Create Missing Groups scans the rig and makes every counterpart that does not exist yet.

Create Missing is the one that turns a half-rigged character into something Mirror All can work on.

Starting over

Clear Active Group Weights empties one group. Delete All L Groups and its Right counterpart remove one whole side.

Blunt by design, and the fastest way to test that a mirror really does rebuild what you think it does — which is exactly how the batch clip further up was made.

Run Diagnostics

A geometric symmetry analysis of the mesh rather than of one group: what is symmetrical, what is not, and a health readout for the rig as a whole. It also raises a Normal Inversion alert when the mesh has flipped normals, which is worth knowing before you blame the mirror.

Run it once on a character you have been handed, before you mirror anything.

Tolerance, worked out for you

Auto-Adjust Tolerance calculates and applies the right matching tolerance for the active group. Optimize All Tolerances walks every group, runs the local diagnostic on each, and settles on one figure that suits the whole character.

For when a pair reads Mismatched and the cause is the search radius rather than the geometry.

Align Pivot to Center

Snaps the object’s origin to the centre of its bounding box.

A coordinate mirror is only as good as the plane it reflects across. If the origin has drifted, this puts it back, and Mirror in World Space handles the cases where it cannot be moved.

All three axes

X, Y and Z. Left to right is the common case, but front to back and top to bottom are both supported, on the topological engine as well as the spatial one.

For props, machinery and anything whose symmetry does not run the way a character’s does.

Export Console Log

Writes the add-on’s diagnostic log stream out as a text file.

If something goes wrong on a mesh nobody else has, this is what turns a support conversation into a fixable report.

Two modes, one panel

Group to Counterpart mirrors a group onto its opposite number. Symmetrize Single Group mirrors a centre-line group onto itself, for a head, a spine or an eyelash strip that spans both sides at once.

The second is the case with no counterpart to copy from, shown further up.

The rest of the panel

Every other option, and when you would reach for it.

These have no clip, and that is deliberate. An option demo is only worth watching when the difference is visible, and for most of these it is not — the work happens on hidden surfaces, in a tolerance, or across a batch. Where a figure is quoted below it was measured on a test character, not estimated.

Auto-Calculate Tolerance

Scales the match radius to the mesh’s own edge length instead of a fixed number, so the same setting means the same thing on a low-poly body and a dense face.

Leave it on unless you are chasing a specific failure by hand. Turning it off reveals Precision Tolerance, which is then yours to set and yours to get wrong.

Topological Mirror

Walks the mesh’s own edge connectivity rather than matching positions in space. The engine behind the posed-rig clip further up.

For posed meshes and shape keys, where the two sides are nowhere near mirrored coordinates. It needs the base topology to be genuinely symmetrical; where it is not, the spatial engine is the one that works.

Auto-Detect Symmetry Mode

Tests each group and picks the topological or the spatial engine for it, instead of you choosing once for the whole character.

On by default, and the reason the Topological Mirror toggle is greyed out until you untick it. Untick only when you want to force one engine and watch what it does.

Auto-Detect Counterparts

Finds the partner group from the active group’s name, covering .L/.R, _L/_R, -L/-R, Left/Right, Lft/Rgt and the matching prefixes.

Untick it to reveal Custom Match Pattern, for a naming convention the built-in table does not cover. A custom pattern is a plain text swap and takes precedence, so set it to your actual convention or leave this ticked.

Mirror in World Space

Transforms coordinates and normals into world space before reflecting them.

For objects that are not sitting at a clean origin — scaled, rotated, or moved off centre. On an object with an identity transform it changes nothing, which is why it has no clip: the test characters are all square to the world.

Use UV Space Mirroring

Matches vertices by their UV layout instead of their position in 3D, and derives its tolerance from UV edge length.

For halves that share a mirrored unwrap but do not line up in space. It is the wrong tool for a limb — measured on three characters it wrote fewer weights than the 3D matcher every time — and it does not bleed onto UV-less or seam vertices.

Auto-Resolve Mismatches

If the first pass leaves mismatches, it runs again with a widened adaptive tolerance rather than handing you the problem.

Useful on meshes where the two sides are close but not exact. It only does anything when the first attempt falls short, which is why it shows no difference on a clean character.

Cache Symmetry Mapping

Builds one shared symmetry map per Mirror All run and applies it to every group in the batch.

Leave it on. Off is not a speed-versus-accuracy trade: on a 14,164-vertex, 167-group rig whose weights were already symmetric, on took 1.8 seconds and changed nothing, while off took 119 seconds, rewrote 11 groups and lost 74 weighted vertices outright. It has no effect on a single-group mirror.

Auto-Clean Micro-Noise

Strips very small stray weights before the mirror runs.

For meshes carrying leftover dust from earlier edits. Do not pair it with Invert Transferred Weights: cleaning happens first, and a weight of 0.003 is meaningful once inverted, becoming roughly 0.997 on the target. The panel warns you when both are on.

Include Near-Zero Weights

Lowers the analysis cutoff from the Minimum Weight Threshold to a fixed 0.000001, so barely-weighted vertices still reach the matcher and the diagnostics.

Turn it on when the balance panel insists a pair is fine and you can see it is not. While it is on the Minimum Weight Threshold is ignored entirely, and the panel greys the field to say so.

What it cannot do.

We would rather you know this before buying than after.

It cannot make an asymmetric mesh symmetrical.

Where one side has no matching vertex, no tool can place a weight exactly. SymmetryFlow names those groups instead of guessing. Robust Asymmetric Fallback closes most of the rest: on the add-on’s own asymmetric fixture it takes the mirrored side from 56% of the source’s weighted vertices to 99%. The last seven vertices of 678 it does not reach.

Vertex counts may differ on faces.

Character faces are often not vertex-aligned across the mirror plane, so a rebuilt side can hold the same weights on a few more vertices. The weights are right; the tally differs.

Hair, lashes and brows take minutes.

Thousands of small overlapping pieces, and the matching work is genuinely large. Blender will look frozen — it is working. SymmetryFlow warns you before it starts, so you can save first or cancel.

Robust Asymmetric Fallback, and what it leaves behind

The first of those three is the one with a tool against it. It writes the vertices a strict counterpart check refuses — part of the gap, never all of it. It sits with the limits rather than the features because the useful thing about it is not that it works, but that it does not finish the job.

With the normal filter verifying counterparts, the ones it cannot confirm are dropped — 378 of the source’s 678. Robust Asymmetric Fallback writes them anyway: 671 of 678, 99% of parity. It is not an approximation — it undoes the filter’s over-rejection on two-sided geometry, where the back of one card faces away from the front of its mirror.

Two downloads. Take one.

Same add-on, same features. They differ only in packaging, because Blender changed its add-on system in 4.2. Don’t unzip either — Blender installs from the zip.

Not Blender 5.0.0 or 5.0.1

Those two releases contain a bug in Blender itself — any add-on that highlights vertices then leaves Weight Paint mode closes Blender instantly, losing unsaved work. We reproduced it with SymmetryFlow completely uninstalled. Blender fixed it in 5.1.

4.2 or newer(Blender 4.2+).zip
3.6, 4.0, 4.1(Blender 3.6–4.1).zip
Edit > Preferences > Add-ons > Install from Disk
Tested on 3.6 LTS, 4.0.0, 4.2.9 LTS, 4.4.0, 4.4.3, 4.5.0, 5.1.2

Stop guessing whether the mirror worked.

Source included, with a full manual, a known-issues document written plainly and with measurements, and the complete changelog.

GPL-2.0-or-later · source included · dev.luv@outlook.com