Skip to content

Releases: fernandotonon/QtMeshEditor

3.2.0

15 May 23:56
901c156

Choose a tag to compare

Paint tools — image editing, smart-select, detached editor, per-tool toolbar

This release wraps three rounds of paint-tool work into one cut.

Foreground / Background colors (toolbar swatch)

  • Photoshop / GIMP-style FG/BG swatch in the left toolbar with click-to-pick, ⇄ swap, ◰ reset.
  • Defaults: FG = Fern green (#71BC78), BG = black.
  • Erase tool now paints with the BG color (set BG alpha to 0 for the old "erase to transparent" behaviour).

Smart-select (magic wand)

  • New ✨/wand tool in the toolbar with click-and-drag tolerance scrubbing — drag horizontally during the stroke to widen / narrow the selection live, no separate slider.
  • Selection mask renders on both the 2D thumbnail (yellow tint + black outline) and the 3D model (matching textured overlay).
  • Mask actions (Fill FG / Fill BG / Delete / Invert / All / None) all undoable.
  • Click outside the mesh while Wand is active clears the selection.

Detached Texture Editor window

  • Full-size paint canvas opened from the Inspector — live-syncs with the 3D viewport in both directions.
  • Bottom action bar: Save / Load / Save to Original / mask actions.
  • UV-island toggle on the top toolbar (shared state with the inspector thumbnail).

Per-tool toolbar (3.2.0)

  • Brush, Wand, Bucket, Eraser, Eyedropper, Smudge each have their own left-toolbar button. Green when paint mode is on + target is Texture, grey otherwise.
  • Brush button is now a tool selector — the Off/Vertex/Texture switch in the right Inspector is the only master gate.
  • Square brush shape added to the brush popup. Axis-aligned constant-strength stamp in 2D, cube AABB in 3D. Hover outline matches the shape.
  • Brush radius outline drawn on both the 2D thumbnail and the detached editor canvas.

Non-destructive paint

  • Strokes no longer overwrite the source texture file. Painted pixels live in memory + EmbeddedTextureCache (used by FBX/glTF export) until the user explicitly clicks Save to Original or saves to a new file.

Stability

  • Mesh removal while paint or wand-selection is active no longer crashes.
  • Vertex → Texture target switch tears down the texture session cleanly.
  • Overlay cleanup no longer dereferences potentially-freed entities.
  • Per-tool toolbar wiring no longer captures a stack-local vector by reference (was crashing on the Texture-mode toggle mid-iteration).

Tests

  • New PaintSelectionMask_test (10 cases) covering smart-select, combine modes, bbox/count caching.
  • 6 new cases for the Square brush across TexturePaintBuffer_test and EditableMesh_test.

Pull requests included: #529, #530, #531.

Preview

monk_to_mage_gif.mp4

3.1.0

13 May 14:16
1dc91d9

Choose a tag to compare

Summary

QtMeshEditor 3.1.0 includes the merged work since 3.0.0:

  • #494 GPU memory and VRAM reporting
  • #495 Material Editor dark mode on Linux and opt-in scan simplify
  • #496 textured RSD import/export round-trip
  • #497 draw-call analysis and merge suggestions
  • #498 vertex-cache optimization and ACMR reporting
  • #499 single-pass mesh decimation
  • #500 smooth vertex colours and MAT lit/unlit support
  • #501 Ogre-backed ACMR and per-file cleanup
  • #502 retire Assimp from inspection and route through extractMeshInfo
  • #503 scene-save n-gon round-trip plus the 3.1.0 version bump
  • #504 finish-line Ogre-only --fix path and five new quality rules

Highlights

  • Scene save/load now preserves n-gon face bindings through .scene.gltf and .scene.glb.
  • PS1/RSD support now keeps textured round-trips and lit/unlit state intact.
  • Performance inspection and scan tooling moved further toward Ogre-backed metrics and cleanup.
  • The release version and documentation pins are aligned to 3.1.0.

Preview

RSD Textures, lit/unlit, vertex color smoothing

Blender QtMeshEditor
Screenshot From 2026-05-12 22-18-40 Screenshot From 2026-05-12 22-18-25

Assets from https://github.com/rubixcube6/PlayStation-RSD-exporter-for-Blender-3.2.1

GPU memory and VRAM reporting, vertex-cache optimization and ACMR reporting

image

Decimate (reduce the poly count, like LOD, but for the main mesh)

image

3.0.0

11 May 04:43
ca0d8b3

Choose a tag to compare

Highlights

This release is a major milestone for QtMeshEditor, with a full UI redesign, PBR material workflows, and several new asset and texture tools.

User interface

  • Major UI redesign — refreshed layout, panels, and overall editor experience for a more modern and efficient workflow.

Materials & rendering

  • PBR material support — work with physically based materials in the editor and pipeline, aligned with common game-engine expectations.

Import & formats

  • PlayStation 1 asset support — import and work with RSD, Psy-Q PLY, and MAT data alongside existing mesh formats (see project documentation for format notes).

Texture & image tools

  • Normal map from height — generate tangent-space normal maps from height or bump sources using a Sobel filter, with strength and channel convention options (e.g. OpenGL vs DirectX).
  • Texture channel packing — pack multiple grayscale inputs into a single RGB/RGBA texture (e.g. ORM / MR style workflows) with live preview in the material tools.

Upgrade notes

  • Application version is 3.0.0 (see CMakeLists.txt). Update any pinned CI references (fernandotonon/QtMeshEditor@…, Docker ghcr.io/fernandotonon/qtmesh:…) if you rely on semver-pinned workflows.

Preview

Progress

V1 V2 V3
QtMeshEditor image image

New UI

image

Pack Texture Channels

image

Generate Normal Map

image

Material Editor

image

PlayStation files support

image

Full changelog: compare to the previous release on GitHub, or browse commits on master leading to this tag.

2.36.0

08 May 02:37
34fa50e

Choose a tag to compare

Highlights

Two big things this release:

  • Slice E shipped: PBR material templates (#396). Three new presets — Metallic-Roughness, Specular-Glossiness, Unlit PBR — with the canonical 6-slot layout (albedo / normal_map / metallic / roughness / ao / emissive) wired through GUI, CLI, and MCP. The non-shader slots (albedo, ao, emissive) render via FFP texture-op approximations so they're visibly active in slice E; metallic and roughness get FFP fakes too, with the real BRDF landing in slice F.
  • Editor mode surfaces modernized (#432). New mode bar, inspector tabs, bottom context panel, and clearer "is this a node or mesh transform?" indicator.

Slice E — PBR material templates (#396)

Presets

  • Metallic-Roughness — neutral mid-gray albedo, shininess 40, lighting on
  • Specular-Glossiness — brighter specular response, shininess 60
  • Unlit PBR — lighting off, white diffuse, all 6 slots present for layout consistency
  • All three create the 6 canonical TUS slots (albedo, normal_map, metallic, roughness, ao, emissive) and tag the pass with a pbr_workflow user-object binding so slice F's PBR shader can detect intent without parsing the preset name.

Inspector — new "PBR" category in the Apply Preset panel with M-R, S-G, Unlit chips. Material Editor's 📝 Templates menu also gets three PBR script templates so users can drop the 6-slot layout straight into the script editor.

CLI

qtmesh material model.fbx --preset "Metallic-Roughness" -o out.fbx
qtmesh material --list-presets

Writes a sidecar .material script alongside the output mesh. Non-zero exit codes on missing material or sidecar write failure (used to silently succeed). file.import / file.export breadcrumbs added for parity with other CLI subcommands.

MCPlist_material_presets and apply_material_preset tools. SERVER_VERSION bumped to 1.6.0. Apply tool accepts an optional mesh/entity arg and uses QScopeGuard to restore the prior selection (nodes + sub-entities) even when applyPreset throws.

FFP slot wiring — slice E's "make-something-visible" interim:

Slot Op Effect
albedo MODULATE(TEXTURE, DIFFUSE) textured base colour
ao MODULATE(TEXTURE, DIFFUSE) darkens the lit base (independent of TUS chain order)
emissive ADD(TEXTURE, CURRENT) additive glow, visible with ambient = black
metallic ADD_SIGNED(TEXTURE, CURRENT) brightens / tints toward metal in textured regions
roughness MODULATE_X2(TEXTURE, CURRENT) brightens smooth (low-roughness) regions
normal_map non-FFP wired through SRS_NORMALMAP via RTShaderHelper::applyNormalMap

Slice F replaces these with a real PBR SubRenderState — slot names + workflow tag are forward-compatible.

Bug fixes shipped while iterating slice E

  • Fix: bone-gizmo branch in TransformOperator::mousePressEvent was capturing every translate click once a skinned model auto-selected a bone, then silently returning when boneCanTranslate() was false (rigged non-root bone). Net effect: imported skinned models couldn't be moved at all. Restructured the gate so translate falls through to entity-translate when the selected bone can't translate; rotate/scale always go through the bone path. Extracted decision into TransformOperator::shouldRouteToBoneGizmo for unit testing.
  • Fix: opening the Material Editor silently dropped the normal-map effect because updateMaterialText removed all RTSS-generated techniques without re-wiring SRS_NORMALMAP. The next render regenerated a vanilla RTSS technique. Now re-runs RTShaderHelper::applyNormalMap after dropping the cached techniques.
  • Fix: "Metallic-Roughness".startsWith("Metal") matched the legacy Metal preset path before reaching the PBR branch. Reordered exact-name PBR matches to the top of the chain.
  • Fix: Material::compile() defaults autoManageTextureUnits=true and on Linux CI the first compile in a fresh Ogre::Root could split the 6-TUS pass into multiple hardware passes (cap query returning low value mid-init). Now compiles with autoManageTextureUnits=false to preserve the structural slot count.

Editor mode surfaces (#432)

  • New EditorModeController plus QML mode bar / bottom context panel / inspector tabs.
  • Transform target now explicitly says "Node Placement" vs. "Mesh Geometry"; edit mode always reports Mesh Geometry.
  • Default viewport MSAA bumped to 4×; near-clip default set to 0.01.
  • Focused gtest coverage for the new controller, viewport defaults, and dock-state restoration.

Tests + quality

  • 5 new tests in MaterialPresetLibraryTests covering preset name presence, 6-slot creation, workflow tagging, idempotent re-apply, and per-slot FFP colour-op semantics (PbrSlotColourOpsApproximatePbrSemantics).
  • 5 new TransformOperatorTest cases for shouldRouteToBoneGizmo covering no-bone, rotate/scale always-route, translate-respecting-canTranslate (the bug-fix case), and non-transform states.
  • 5 new CLIPipelineCmdMaterialError cases covering missing args, unknown preset, non-existent file, and the standalone --list-presets exit.
  • SonarCloud quality gate: passed. Coverage on new code: 47.8%.

Versioning

CMakeLists.txt already bumped to 2.36.0 by #432. Sentry + macOS bundle plist + WinGet manifest follow automatically.

🤖 Generated with Claude Code

2.35.0

06 May 01:35
40b7c60

Choose a tag to compare

Highlights

The big one this release: the animation curve editor is now production-ready. Edit Bezier curves in-place, then bake them into Ogre TransformKeyFrames so playback matches the visual. Plus full keyboard/trackpad ergonomics, an explicit Bake menu with adaptive and exact-FPS modes, and CLI/MCP exposure for headless export pipelines.

Also: PlayStation 1 .TMD mesh + .TIM texture import.

Curve editor — finished (#392, #395)

Live editing, no more T-pose blink

  • Drag keyframe squares by value (Y) or time (X); Shift constrains to the dominant axis.
  • Drag tangent handles to reshape curves in real time.
  • setKeyframeValuePreview / moveKeyframePreview write directly during drag without pushing per-event undo commands; one SetKeyframeValueCommand + MoveKeyframeCommand lands on release.
  • Right-click a keyframe square → Bezier / Linear / Stepped / Auto interp-mode menu.

Navigation

  • Two-finger trackpad pan (horizontal = time, vertical = value) via WheelHandler with pixelDelta.
  • Cmd/Ctrl+wheel zooms time, Shift+wheel zooms value, +/− toolbar buttons mirror.
  • ⤢ fits the whole animation to the canvas.
  • Horizontal ScrollBar.AlwaysOn for clips wider than the viewport.

Bake / Reduce

  • New themed dropdown matches the inspector look: Sparse / Medium / Dense (adaptive Douglas-Peucker simplification with per-level baseline pre-decimation so repeat clicks converge), and Set to 10 / 15 / 30 / 60 FPS (re-grids to a uniform N-FPS layout regardless of source density).
  • ResampleCurveCommand snapshots the original curve before stripping interior keys, so non-resampled channels lerp between bracketing original anchors instead of just the segment endpoints — mid-clip poses survive whole-clip bakes.
  • Quaternion components written via curve evaluation are now re-normalized so Ogre's track Slerp doesn't drift.
  • DecimateTrackCommand powers the reduce path with a single-step undo; first/last keyframes always preserved.

Per-animation Bake in the Inspector animation list, sitting next to the Simplify button. One undo macro covers every bone track. Unauthored channels skipped on adaptive modes; fixed-FPS modes process everything.

CLI + MCP exposure (part of #395)

qtmesh anim model.fbx --bake-fps 30 -o uniform.fbx        # re-grid to uniform 30 FPS
qtmesh anim model.fbx --bake-fps 60 --animation \"Run\" -o out.fbx

New MCP tool bake_animation_fps (entity_name / animation_name / fps) — SERVER_VERSION bumped to 1.5.0. Mixamo-style export pipelines can now request a target FPS without opening the GUI.

Animation undo correctness (#390)

  • All keyframe undo commands (BoneTransform, Move, Set, Add, Delete, BulkKeyframe) now resolve their skeleton lazily by entity name through a new SkeletonResolver utility instead of storing a raw Ogre::Skeleton*.
  • Fixes use-after-free crashes when an entity is reloaded or a skeleton is rebuilt while undo entries sit on the stack.
  • Undo commands no-op gracefully when the entity is gone.

Bone-drag regression coverage (#393)

Two new BoneDragRelease tests covering the setUpdate-sequence gap:

  • EntityTickBetweenDragsDoesNotAccumulate drives entity->_updateAnimation() + skeleton->_updateTransforms() between two auto-key-off drags to confirm no leaked state.
  • NeedUpdateBetweenDragsDoesNotAccumulate forces a derived-transform recompute mid-sequence.

PlayStation 1 import (#394)

  • .TMD mesh import/export across GUI + CLI.
  • .TIM texture decode + Material Editor browse-and-load.
  • Sibling *.TIM files auto-apply to per-import TMD/<name> materials when UVs exist.

Notable fixes

  • ThemedComboBox: native top-level popup (Qt 6.8+ popupType: Popup.Window) so long bake menus aren't clipped by their host QQuickWidget; scroll snap-back fixed via highlightFollowsCurrentItem: false.
  • Bake-while-paused no longer flashes the model to T-pose after the post-undo skeleton reset.
  • Whole-animation Bake @ 60 FPS no longer freezes the UI (per-segment dope-sheet refresh storm coalesced into one).
  • The Bake dropdown's last entry was being silently ignored due to a hand-counted upper bound — replaced with index < model.length so the off-by-one can't recur.

Compatibility

  • Qt 6.9.3, Ogre 14.5.x, Assimp 6.0.4 — unchanged from 2.34.
  • MCP SERVER_VERSION 1.4.0 → 1.5.0.

Preview

image image tmd_support_small

PS1 models from: https://mbdesigns.itch.io/ps1-homebrew-source-code-rendering-3d-graphics-with-psyq

2.34.0

04 May 21:35
0f2d9ee

Choose a tag to compare

Highlights

This release lands Phase 5 of the animation system (#260) — a complete in-app animation authoring loop:

  • Bone manipulation gizmo (W/E/R) with auto-key support — drag bones in the viewport, write keyframes automatically.
  • Multi-bone dope sheet with multi-select, copy/paste, bulk move.
  • Per-channel curve editor with selectable interpolation modes.
  • Two-way blend preview + bake-to-clip for layered animation authoring.
  • Playback speed + loop region + auto-key toggle in the Animation Control panel.
  • Full undo/redo for all keyframe and bone-pose edits.

✨ Features

Bone gizmo with W/E/R triad (#385, #386, #388 — slices 1-3 of #358)

  • Click a bone visual in the viewport to select it; rigged + non-rigged bones both pickable.
  • W/E/R drives translate/rotate/scale on the selected bone, anchored to the bone's world frame, following animation playback every frame.
  • Translation safety: rigged non-root bones blocked (would tear the rig); root bones (locomotion) and unrigged sockets (sword/shield/hat) freely translatable.
  • Yellow visualization for skeleton roots in the debug overlay so users can identify them at a glance.
  • Auto-key OFF + animation enabled = drag preview (reverts on release). Auto-key OFF + no animation = T-pose authoring (commits to bind via setInitialState). Auto-key ON = writes keyframe at scrub time.
  • BlendMask muting during drag prevents the curve from fighting the manual edit.

Animation Phase 5 (epic #260)

  • Slice A (#356): playback speed multiplier + loop region (in/out points) + auto-key toggle.
  • Slice B (#361): two-way animation blender with live preview slider; bake to a new clip.
  • Slice C (#373): multi-bone dope sheet showing all tracked bones at a glance.
  • Slice D1 (#375): dope-sheet multi-select with shift/ctrl, copy/paste keyframes (JSON), bulk-move on dt offset.
  • Slice D2 (#377): per-channel rows (Tx, Ty, Tz, Rx, Ry, Rz, Rw, Sx, Sy, Sz) so users see and edit individual channels.
  • Slice D3a/b (#379, #381): curve editor data model + read-only view, then per-channel data + interpolation-mode picker (Bezier / Linear / Stepped / Auto).

Keyframe authoring fixes

  • addKeyframe captures live bone pose (#384): was producing identity-ish keyframes by re-sampling the curve. Now reads the bone's actual local TRS at the slider time.
  • Auto-key toggle (#384): hands-off recording — every transform commit (scene-node or bone) writes a keyframe at the current scrub time.
  • Lazy track creation: editing a non-rigged bone with auto-key on creates the track on first edit, so the pose persists into the animation and survives export.

Undo/redo coverage (#388)

  • New AddKeyframeCommand + DeleteKeyframeCommand make +KF and -KF round-trippable through Ctrl+Z/Ctrl+Shift+Z.
  • New BoneTransformCommand with bindMode flag covers both transient gizmo edits and bind-pose updates (setInitialState).
  • The SkeletonDebug overlay refreshes immediately on undo/redo (was stale until the next animation tick).
  • Bone selection preserved across undo/redo (was resetting to first bone).

Vertex paint UX (#351)

QML falloff slider + vertex color preview toggle for the brush tool. Carried over from the 2.33.0 timeframe.

Quad-mesh follow-up (#346, #354)

  • Vertex colors export with .mesh sidecar materials (#346).
  • Catmull-Clark subdivision no longer wipes painted vertex colors (#354).

🐛 Bug fixes

  • SkeletonDebug toggle off→on crash (#385): leaked instance via mShowSkeleton.remove() had a stale QTimer touching dangling Ogre entities → SIGSEGV. Now delete sd; after the QMap remove.
  • updateAnimationTree cascade reset (#385): QUndoStack::indexChanged was triggering selectAnimation on every undo push, which reset the slider + bone selection. Now early-returns when the tree contents are unchanged.
  • Bone-drag teleport / accumulation (#386): animation tracks were overwriting _setDerivedPosition edits each frame. Mute the curve via BlendMask for the dragged bone, restore exactly the pre-drag mask values on release (preserves layered/masked setups).
  • Parentless-bone _setDerivedPosition is no-op (#386): Ogre skips when mParent == null. Fall back to setPosition() for true skeleton roots.
  • Press-time axis lock (#386): a stale mTransformVector from the previous drag (or cursor drift onto a neighboring arrow) could lock the wrong axis. Now locked at press time, not on first move.
  • Crash after undo + slider scrub (#388): m_selectedTrack was a dangling pointer after AddKeyframeCommand::undo destroyed a lazy-created track. New onUndoRedoCommandApplied() invalidates cached pointers and re-resolves.

🧪 Tests

  • 12 new bone-gizmo / BoneDragRelease tests covering all three release-path semantics (revert / commit / commit-bind), accumulation regressions, and the parentless-bone fallback.
  • 8 new keyframe-undo tests: all three AddKeyframeCommand modes (track-created / keyframe-created / keyframe-updated), DeleteKeyframeCommand round-trip, missing-keyframe defensiveness.
  • 3 integration tests driving real addKeyframe/deleteKeyframe paths through the QUndoStack, including a regression for the crash-after-undo scenario.
  • 4 boneCanTranslate tests (null / root / rigged / unrigged).
  • Test stability fixes (#355): CLI mesh import + headless Ogre tests.
  • Coverage uplift (#359, #348): broader Sonar coverage + ccache for the test build to speed unit-tests-linux.

🔧 Internal

  • New BoneDragRelease helper class extracts bone-drag end-of-drag rules into testable code (revert / commit / commit-bind decision tree).
  • Native quad coverage tests (#353) for topology ops audit (#326).
  • Extensive Codex / CodeRabbit review feedback addressed across the bone-gizmo PRs.

Filed for follow-up

  • #387 (resolved in #388): wrap addKeyframe writes in an undo command — done.
  • #389: replace raw Ogre::Skeleton* in keyframe undo commands with a re-resolveable handle (consistency across all 5 commands; tracked for next iteration).

Preview

image

2.33.0

30 Apr 17:18
fa71a14

Choose a tag to compare

Highlights

This release wraps up the quad-mesh epic (#326) with end-to-end n-gon preservation through FBX and OBJ I/O, plus a final bug-fix sweep from the chunk merge review.

✨ Features

N-gon export (chunk 6 — #349)

Quad and n-gon meshes now survive a full import → edit → export → re-import round trip on FBX and OBJ:

  • Custom binary FBX writer emits PolygonVertexIndex with the FBX last-index-bitwise-NOT polygon-end convention.
  • Assimp-based OBJ exporter emits aiFace with N indices (>3 vertices).
  • Per-submesh n-gon faces stash on the live Ogre::Mesh::UserObjectBindings (qtme.faces.<i>) so they survive across edit-mode commits, even after qtme.source_path is cleared.
  • Edit-mode re-entry rehydrates EditableSubMesh::faces from the binding so post-edit n-gon ops keep working.

Format support matrix

Format Preserves n-gons? Why
FBX ✅ Yes Custom binary writer
OBJ ✅ Yes Assimp respects aiFace arity
glTF / GLB ❌ No Spec only allows TRIANGLES — preserving quads requires FB_ngon_encoding (vendor extension), out of scope
Ogre .mesh ❌ No Format only stores triangle index buffers
Collada / 3DS / STL / PLY / X ❌ No Assimp writers triangulate

Vertex paint UX (#351)

QML falloff slider + vertex color preview toggle for the brush tool.

🐛 Bug fixes (#352 — sweep from PR #347 review)

8 fixes from CodeRabbit / Codex follow-up:

  • Loop cut rejects mixed quad/tri adjacency upfront (was producing one-sided cuts on the quad side). +1 unit test.
  • Wireframe on tri-only submeshes inside mixed meshes now coexists with the n-gon boundary overlay (was disappearing entirely).
  • buildSubMeshBuffers explicitly clears the GPU vertex/index buffers when a submesh has no triangles to draw (fixes stale geometry rendering after deleting the last face).
  • selectedFacesAsHEFaceIndices now compacts invalid-face indices in the per-face mapping (was silently mis-targeting face-mode ops when invalid faces shifted later HE-face indices).
  • canConvertToQuads() predicate replaces the previous !isMeshQuadBased() check on the toolbar (mixed meshes no longer wrongly disable the action).
  • convertToQuads correctly returns non-zero on promote-only runs.
  • deselectFace mirrors selectFace's vertex/edge dilation (no more stuck partial selections after ctrl-deselect).
  • Test fixture uses a real translate instead of Vector3::ZERO so the assertion stays meaningful if zero-delta short-circuit is ever added.

Two items from the sweep tracked for future work: vertex knife OnVertex near-duplicate, subdivideFacesToQuads T-junctions on partial selections.

🔧 Internal

  • CI test build cache (#348): ccache layered on the SonarCloud build-wrapper. unit-tests-linux job dropped from ~25 min to ~7 min on warm cache (97.88% hit rate observed).

Preview

image

2.32.0

29 Apr 16:38
9e970b3

Choose a tag to compare

Highlights

  • Add vertex paint tool in Edit Mode toolbar (after Fill) with brush settings menu (color, radius, strength).
  • Fix vertex color packing/unpacking to ensure correct RGB rendering across render systems/platforms.
  • Add projected brush ring preview that updates on hover for more precise feedback.
  • Improve paint UX (tool exclusivity, cursor behavior) and add Sentry breadcrumbs for paint actions.

Tests

  • Expanded unit test coverage for vertex paint color parsing and vertex color round-trip behavior.

Preview

image

2.31.0

28 Apr 12:59
db45d44

Choose a tag to compare

Highlights

Edit Mode: new topology operations (Phase 4)

  • Merge Vertices: merge at center/first/last, plus merge-by-distance (shortcut: M).
  • Delete / Dissolve: delete selection with X; dissolve with Ctrl/Cmd+X (keeps the surrounding region watertight).
  • Subdivide / Fill: subdivide selected faces/edges; fill selected vertices or closed edge loops. In Edit Mode, F fills when possible, otherwise it falls back to Frame Selection.

Scan/CLI: more robust scan --fix + better reporting

  • Fixes crashes in the FBX redundant-keyframe fix path (safer material handling, better headless Ogre initialization, empty-track guard).
  • Prevents “fixes” that would increase file size: if output is larger it’s reported as [skipped] and the original file is kept.
  • Improved scan output/summary with [fixed] / [skipped] tags, plus totals for bytes saved and keys removed.
  • Redundant keyframe detection default threshold set to 40%.

Viewport defaults

  • FSAA/MSAA now defaults to 0 when unset (users can opt in via settings). This avoids black viewport issues on some Linux installs.

Web

  • Bumped postcss to 8.5.12 (security + fixes).

Preview

image

Notable PRs

  • #325 Fix scan --fix stability + reporting, default FSAA=0 when unset
  • #324 Subdivide + Fill tools
  • #323 Delete + Dissolve tools
  • #312 Merge Vertices tools
  • #322 postcss bump

2.30.0

26 Apr 23:13
ba60ae4

Choose a tag to compare

Highlights

🎞️ Tolerance-based animation simplifier (#310)

A new operation that removes redundant keyframes whose values match the lerp/slerp of their neighbors within tolerance. First/last keys and sharp pose changes are preserved, so Mixamo-style baked clips shed 40–60% of keys without visible drift.

Surfaced everywhere:

  • CLI: qtmesh anim file.fbx --simplify | --analyze, with --preset {conservative|balanced|aggressive} plus per-axis --tolerance and --rotation-tolerance-deg overrides.
  • Scan rule redundant_keyframes_pct: warns when projected savings exceed a threshold; reports "X% redundant keyframes (N/M). Simplify it to save ~Y. Original size: A, projected size: B".
  • MCP tools simplify_animation + analyze_animation (preset + per-axis overrides).
  • Inspector: per-animation Simplify button (✂) plus a per-entity tolerance preset selector. Tooltip previews redundancy % under the current preset.

The default preset is Balanced (~1mm translation, 0.5° rotation). On a Mixamo Rumba Dancing FBX (1.89 MB):

  • Conservative: 7.9% redundant
  • Balanced: 42.1% redundant
  • Aggressive: 63.8% redundant

📦 FBX exports embed textures (#311)

FBX outputs now embed texture data inline via Video.Content, producing a single self-contained file. No more sidecar .material scripts or extracted texture images alongside the .fbx — the Mixamo-style portable export experience now works out of the box.

Other changes

  • MCP SERVER_VERSION bumped to 1.4.0 (new tools).
  • New shared AnimationMerger::tolerancesForPreset so CLI/MCP/Inspector share the preset table.
  • ThemedComboBox now uses ThemeManager so it works in any panel; aliased into the inspector resource prefix.

What's Changed

Preview

image image

Full Changelog: 2.29.0...2.30.0