Skip to content

blendertk v0.5.42

Choose a tag to compare

@m3trik m3trik released this 31 Jul 00:32
  • 2026-07-30 — no Blender analogue of mayatk's intermediate-shape freeze bug (documented, verified). Maya's cmds.instance shares every shape including the deformer's intermediate (orig) shape, which blocks makeIdentity forever (see mayatk's CHANGELOG). Blender has no intermediate datablock — modifiers evaluate off the single obj.data — so preserved_instances / uninstance have nothing equivalent to fork, and the delete_history opt-in the Maya twin needed is deliberately absent (delete_history was already a documented no-op here). Suites re-verified unchanged: test_node_utils.py / test_xform_utils.py PASS headless.

  • 2026-07-30 — NodeUtils.preserved_instances + freeze_transforms(instance_strategy=...) (mayatk parity — see its CHANGELOG for the mechanism and the failure it fixes). Linked-data twin of the Maya context manager: a group is the objects sharing one datablock, the master's "fork" is data.copy(), and restore re-points every sibling at the master's post-op data with its world matrix compensated (B = post_world⁻¹ @ pre_world, sibling W → W @ B⁻¹) — writing matrix_world absorbs parents / parent-inverse / deltas in one assignment, so the Maya twin's pivot re-pinning and instance-edge surgery have no analogue here. The orphaned original datablock is removed and the fork takes over its name. Triage (skipped up front, reported, untouched): library-linked objects/data, and siblings whose transforms are driven (drivers, action fcurves, unmuted constraints — compact yes/no twin of transform_diag._driving_connections). freeze_transforms — where transform_apply refuses multi-user data outright, so "skip" was the only behavior — gains the same instance_strategy="skip"|"preserve"|"uninstance" (default unchanged). fix_non_orthogonal_axes deliberately does not take the option (divergence documented in its docstring): the Blender fix writes only transform channels, never shared geometry, so linked duplicates were already fixed in place with their instancing intact. test_node_utils.py +11 checks, test_xform_utils.py +7; both suites PASS headless.

  • 2026-07-30 — libpyside: Failed to disconnect … from signal console spam from the Reference Manager header and the Channels table (mayatk twins fixed identically). User-reported from a live session (reference_manager.py:246, refresh_requested()). Two defects, both in idempotent signal re-wiring — mandatory here because the QWidget outlives the slots instance across a reload. (1) Blanket signal.disconnect() on a signal with nothing attached: PySide reports that through warnings.warn, not an exception, so the surrounding except (RuntimeError, TypeError) never suppressed it and every first call printed the line — the header's refresh_requested, and channels' four cellScrub* / cellWheelScrolled bindings (which, unlike the cellChanged / customContextMenuRequested blankets beside them, have no owner but us). Both now drop only their own prior connection, tracked per (widget, key). (2) The tracked-disconnect primitive had the same hole: _rewire_signal dropped its stored QMetaObject.Connection through the signal-instance disconnect(), which expects a slot — handed a Connection it can't match (the reload case: PySide breaks the binding when the old slots instance is collected) it warns and returns rather than raising, so the except was dead code and the warning would simply have come back wearing a Connection repr. Verified against live PySide6, then switched to the static QObject.disconnect() — the API that actually takes a Connection — with a falsy (already-broken) Connection skipped outright. test_blender_ui_handler.py 226/226 (its single-connection regression unchanged) with a warning-free run, test_channels.py 56/56, test_reference_manager.py 64/64.

  • 2026-07-30 — Maya-scene import robustness: tolerant scene open, .mb driver probe, namespace-safe translated shaders, and collision-safe visibility replay. Four hardenings of the pull-direction conversion, each closing a real production edge. (1) Tolerant open (both conversion templates): cmds.file(open=...) raises RuntimeError over missing renderer plugins / unknown nodes even when the scene content loaded — routine for production scenes on a vanilla mayapy — and that killed the whole conversion; _open_scene now verifies via cmds.file(q, sceneName) that the scene actually loaded and tolerates the noise (printed), while a genuinely failed open still raises. (2) scene_has_complex_animation now answers for .mb too (was a blind False): node type names are stored as plain byte strings in the binary, so a chunked, overlap-safe token scan over the same _DRIVER_NODE_TYPES (+ the <node>_visibility curve name) gives binary scenes the same bake-vs-raw browser signal — heuristic by contract, since a false positive only costs an unneeded bake attempt (the Maya-side probe re-decides under "auto"). (3) Namespace-safe created nodes (both templates): a referenced scene's materials are namespaced (loadReferenceDepth="all"), and f"{mat}_fbxsafe" put the translated phong INSIDE that namespace — its exported name's colon then at the mercy of FBX name mangling, silently missing the Blender-side slot match; _ns_safe flattens colons so created phong/standardSurface/bump nodes live at root under names that round-trip verbatim. (4) Visibility collision handling: _collect_baked_visibility keyed the manifest by short name and silently last-writer-won on duplicates — and the Blender-side replay matches by short name, so ONE object's curve would land on BOTH; differing duplicates are now dropped loudly (identical ones merge), no keys beating wrong keys. Also: the four engine entry points expand ~ beside $VAR. test_scene_import.py +10 checks (incl. a behavioral run of the extracted collector against a stub cmds, and .mb scans with a chunk-boundary-straddling token), verified failing pre-fix via stashed-source run; suite PASS under both the venv and headless Blender 5.1.

  • 2026-07-30 — MatUtils.find_unassigned (mayatk parity — see its CHANGELOG for the Maya-side subtlety). Objects carrying no material: no material slots at all, or every slot empty. Blender has the real state Maya has to synthesize — nothing here joins a default shading group — so there's no include_default axis; objects that can't hold materials (empties, lights, cameras) are not reported, since they aren't unshaded geometry. Same objects=None pool convention and object-level scope as find_by_mat_id, whose complement it is. Drives tentacle's materials "No Material" select mode. test_mat_anim_utils.py +6.

  • 2026-07-29 — RizomUV temp payloads move onto ptk.TempArtifacts, and the no-save error diagnoses itself (mirrors mayatk — see its CHANGELOG for the diagnosis). This twin used the same two fixed names as the Maya bridge (rizomuv_exported.fbx / riz_uv_script.lua in the system temp dir), so the two panels were racing each other for one script file — and RizomUV re-reads the -cfi script after launch, so whichever run got overwritten exited 0 without ever reaching ZomSave. The round-trip now allocates both payloads from a "scoped" store (clean run deletes them, a failure keeps them so the script can be opened in RizomUV's Script Editor) and the one-way send from a "detached" one (its session may outlive us, so allocation age-sweeps instead of deleting) — replacing a hand-rolled time.time_ns() tag that TempArtifacts documents as not unique enough alone on Windows. _no_save_diagnosis replaces the old message's promise of a Lua traceback (RizomUV prints nothing in -cfi mode) with the script/FBX paths — both rendered OS-native, they used to mix separators — a comparison of the on-disk script against what was written, and a pointer at RizomUV's Script Editor. _release_temp_payloads re-allocates on the next run, since cleanup untracks what it removed and a cached path would leak. test_rizom_construction.py +10 → 34/34.

  • 2026-07-29 — m_frame step cycle + clip fitting (mayatk parity — see its CHANGELOG for the detail); CamUtils gains get_view_state / set_view_state / fit_camera_clipping. Same contract: m_frame(steps=2, adjust_clipping=True), first press frames, further presses within FRAME_STEP_TIMEOUT step in, the last returns the view exactly where it started, and a pause collapses the cycle to a plain there-and-back toggle (shared ptk.StepToggle). Blender-side differences: the ideal distance comes from view3d.view_selected itself (no per-element fit factors) with the step ramp applied as a dolly on view_distance, and the state snapshotted/restored is the RegionView3D (location / rotation / distance / perspective) plus the viewport's clip planes — SpaceView3D.clip_start/clip_end is what a free view actually clips against, not the camera data adjust_camera_clipping writes — so the fit widens whichever surface is doing the clipping (the lens while locked to a camera, else the viewport's planes) against that surface's own current values, and the snapshot carries the lens planes too or the widening would outlive the view it was made for. Smooth view is suppressed for the framing op, which otherwise animates the view over the next ~200 ms and would fight the step dolly. fit_camera_clipping measures depth from view_location/view_rotation/view_distance rather than rv3d.view_matrix, which is only refreshed at draw time and is still the previous view right after a framing op. test_macros.py +8, test_cam_utils.py +9.

  • 2026-07-29 — Shell Xform tri-state snap (off / grid / shell) + UvUtils.get_neighbor_shell_bounds (mayatk parity — see its CHANGELOG for the detail). Same 3-state ActionOption cycle and the same ptk.MathUtils.next_clear_offset geometry, so the two panels behave identically. The pool is every mesh whose active UV layer name matches the input's, minus the input's own meshes — and unlike the Maya twin that excludes every island of the input, not just the selected ones, because move_uvs shifts an object's whole UV map, so all of its islands travel together and none can be parked against. Linked duplicates are excluded with their shared datablock. Bounds accumulate as a running min/max per island rather than collecting every loop UV. shell_xform_slot_check.py +22 → 43 (park, walk-past, scope-independence, grid fallback, out-of-lane, UV-layer scoping, tri-state shape); test_uv_utils.py +6.