work: restore shift+spacebar for media play/pause
maybe put in maya config? idk what funiman's preference is
This commit is contained in:
+10
-10
@@ -10,13 +10,13 @@ D:\Work\9 iClone\Amazon\
|
||||
D:\Amazon\00_external-files\
|
||||
N:\1. CHARACTERS\remapping\
|
||||
[Recent]
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Assets\Blends\
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\img-BG\
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Deliverable\still\
|
||||
P:\260423_MukBuddy\Blends\animations\
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\USD\dust\
|
||||
C:\Users\Nathan\Downloads\
|
||||
D:\2026-04-14 BCONNA2026_MARI\
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Deliverable\Stills\
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\
|
||||
A:\1 Amazon_Active_Projects\260513_FSAF_edits_2026\Blends\stills\
|
||||
N:\1. CHARACTERS\remapping\
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\img-BG\
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\
|
||||
T:\1 BlenderAssets\
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Assets\Blends\
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"flamenco_version": {
|
||||
"version": "3.8.5",
|
||||
"shortversion": "3.8.5",
|
||||
"version": "3.10-alpha0 (0c2ec48d)",
|
||||
"shortversion": "3.10-alpha0",
|
||||
"name": "Flamenco",
|
||||
"git": "690bf6ce"
|
||||
"git": "0c2ec48d"
|
||||
},
|
||||
"shared_storage": {
|
||||
"location": "F:\\jobs",
|
||||
|
||||
@@ -17,3 +17,5 @@
|
||||
{NVIDIA Corporation/NVIDIA GeForce RTX 3090/NVIDIA 595.79}=SUPPORTED
|
||||
{NVIDIA Corporation/NVIDIA GeForce GTX 1060 with Max-Q Design/NVIDIA 582.28}=SUPPORTED
|
||||
{Intel/Intel(R) HD Graphics 630/4.6.0 - Build 27.20.100.9664}=SUPPORTED
|
||||
{NVIDIA Corporation/NVIDIA GeForce RTX 4080 SUPER/NVIDIA 596.36}=SUPPORTED
|
||||
{NVIDIA Corporation/NVIDIA GeForce RTX 4080 SUPER/NVIDIA 610.47}=SUPPORTED
|
||||
|
||||
+196
-196
@@ -1,200 +1,200 @@
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_11a.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_11b.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_11c.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Assets\Blends\Pallet_Label.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_9.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_10.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_2a.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\animations\Pallet building_animation 2a.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\animations\Pallet building_animation 2b.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_6c.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_6b.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_6a.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\stills\iPalletization_8.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2026_new\P&S_2026_animation short 2a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\Ambassador_M3_A4_picker_s2.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_3b.blend
|
||||
P:\260423_MukBuddy\Blends\animations\Muk Buddy Animation_gif.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_2a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_2c.blend
|
||||
P:\260423_MukBuddy\Blends\animations\Muk Buddy Animation.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S_safety_refresher_1b-1.blend
|
||||
P:\260423_MukBuddy\Blends\animations\Pak Buddy Animation.blend
|
||||
P:\260423_MukBuddy\Assets\Blends\Spray Paint.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S_safety_refresher_1c_rev2.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S_safety_refresher_1b-2_v3.blend
|
||||
G:\Amazon\2024\240906_amazon-safety-refreshers\blends\P&S\P&S_safety_refresher_1b-2_v3.blend
|
||||
C:\Users\Nathan\Downloads\P&S_safety_refresher_1d_rev2.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 3B_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2B_SPA.blend
|
||||
F:\jobs\Visual 2B_SPA-29zr\Visual 2B_SPA.flamenco.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 6_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5B_alt_vo_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 4A_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\01_opening_SPA.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1aC.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_4b.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_4a.blend
|
||||
A:\1 Amazon_Active_Projects\260513_FSAF_edits_2026\Blends\stills\iAmbassadorM2_3.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1aB.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_3b.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_3a.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_3.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_2.blend
|
||||
A:\1 Amazon_Active_Projects\260528_NonConSplitPickcart\Blends\stills\iNonConSplitPickcart_1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Assets\Blends\City_Sidewalk_1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_CORTEX_1d.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 3.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_LOADOUT_1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 4D.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 4C.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 4B.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 4a.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 2A.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 2A_old.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 2B.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_17.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_16.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_11.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_7.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Assets\Blends\Traffic-Post.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_9.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_15.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_12.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_13.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_14.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_10.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 1A.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\animations\Walker_AP_animation 1B.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Assets\Blends\Delivery_Truck_Openable_v1.1.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Assets\Blends\Delivery_Truck_Openable.blend
|
||||
A:\1 Amazon_Active_Projects\260526_Walker_Leader\Blends\stills\iWalker_AP_4.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1aA.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Assets\Blends\lipsync.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_animation 1_CYCLES.blend
|
||||
A:\1 Amazon_Active_Projects\260421_Pallet_Loading_and_Wrapping\Blends\animations\Pallet wrapping_animation 1aB.blend
|
||||
F:\jobs\Pallet wrapping_animation 1bC\Pallet wrapping_animation 1bC.flamenco.blend
|
||||
F:\jobs\Pallet wrapping_animation 1bA-lyma\Pallet wrapping_animation 1bA.flamenco.blend
|
||||
C:\Users\Nathan\Downloads\Visual 6_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 8_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\Visual 6_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\Visual 8_SPA.blend
|
||||
D:\2026-04-14 BCONNA2026_MARI\Sample Stanford Bunny2.blend
|
||||
D:\2026-04-14 BCONNA2026_MARI\Sample Stanford Bunny1.blend
|
||||
C:\Users\Nathan\Downloads\Sample Stanford Bunny1.blend
|
||||
C:\Users\Nathan\Downloads\Sample Stanford Bunny.blend
|
||||
D:\portfolio\demo.blend
|
||||
D:\2025-12-28 ytshorts gigaproj\Blends\animations\FreddyEpstein\FreddyEpstein.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\06_Watering.blend
|
||||
T:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\06_Watering.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\FT-lipsync_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2D_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2B.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2C.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2D.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_23.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\01 Develop Your Turf Plan\SPA\FT-lipsync.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\01 Develop Your Turf Plan\SPA\01_Blueprint_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\04 Securing Your Seam\SPA\06_FT_Hammering_insert_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\SPA\Visual_0_opening.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 3B.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\SPA\Visual 3B_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\04_stretching pattern.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\Visual 6_INSERT.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\Visual 8 insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\03_FT Shuffle.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\Visual 8 insert2.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\SPA\01_intro_SPA.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\BD2\P&S_BD2_animation 12b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\BD2\P&S_BD2_animation 12a.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\07_compacting.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\03_dirt to gravel.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\09_level ground.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\05_raking.blend
|
||||
P:\250827_FestivalTurf\Assets\Blends\Props\Tools.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\01 Develop Your Turf Plan\01_Blueprint.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 6defgh.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 6bc.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 6a.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\04_Rock Yard.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 6I.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\02 Preparing the Base\01_intro.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_8.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_7.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_7_phone_insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_7_reframe.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_7_phone_insert_alt.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_5_heat_damage_insert_1.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_5.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_4_leaf_blower_insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_4_leaf_blower.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_3_PE_spread.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_2_push_broom.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_2_power_broom.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_3b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_5b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_5aA.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4bC.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4bB.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4bA.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4aB.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4aA_part2.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_4aA.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_3c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_3a_insert2.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_3a_insert1.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_3a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_2c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_SHORT_2a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 4.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 3A.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 5a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 5d.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 5bc.blend
|
||||
F:\jobs\RSR_fluid_unload_animation 5a\RSR_fluid_unload_animation 5a.flamenco.blend
|
||||
A:\@GMT-2026.04.02-18.00.00\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 5a.blend
|
||||
A:\@GMT-2026.04.02-17.00.00\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 5a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 4b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 3C.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 2.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1D.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1b_c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1b_b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1b_a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\animations\RSR_fluid_unload_animation 1b.blend
|
||||
A:\1 Amazon_Active_Projects\260225_Problem-Solve_2026\Blends\animations\PS_2026_animation short 1b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_7d.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_7c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_25b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_25a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24d.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24e.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_16e.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_4b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_16o.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Pallete_Broken_Planks.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Pallete_Broken.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_24b_.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-04-02_13-44_iRSR_fluid_unload_24b.blend
|
||||
T:\1 BlenderAssets\Amazon\Props\Pallete_Broken.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_5c.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_17bA.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13aB.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Assets\Blends\lipsync.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_16d.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13a.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13a_CM.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_5b.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Kyle_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_4c.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Assets\Blends\lanyard_rigged.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_4d.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_16c_vertical.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_16c.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_16e.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_6a.blend
|
||||
T:\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13a.blend
|
||||
F:\jobs\SS_2026_animation_16d-vs40\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Regina_v4.4.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Tote_v2.0.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Set-Dressing\P2B_filler.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\amazon-3Dworld-assets_v4.0.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-04-02_12-09_RSR_fluid_unload_SHORT_3a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-04-02_12-11_RSR_fluid_unload_SHORT_3a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-04-02_12-13_RSR_fluid_unload_SHORT_3a.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_19c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_23b.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_23a.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Long-Pallete.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Shuttle_v2.0.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_19d.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_7.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\i_noncon_OOG_2c.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Blends\stills\iRSR_fluid_unload_19e.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\animations\Dock\DOCK_shrinkwrap_s3.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\animations\Dock\DOCK_shrinkwrap_s4.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\animations\Dock\DOCK_shrinkwrap_s2.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\animations\Dock\DOCK_shrinkwrap_s1.blend
|
||||
A:\1 Amazon_Active_Projects\260326_RSR-Fluid-Unload\Assets\Blends\PAM.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_2_broom.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_1_respray_insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_1_respray.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_0_5_sheering_insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_0_5_talking.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5B_insert.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S_safety_refresher_1d_rev2.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S_safety_refresher_1c.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\SPA_noncon_OOG_short_animation 9a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 9a_v3.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 9a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 3a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Assets\Blends\lipsync.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 1b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2026_new\P&S_2026_animation short 1c.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_2a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_1b.blend
|
||||
T:\260127_Pick-and-Stage_2026_edits\Blends\stills\iP&S_2026_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2026_new\iP&S_2026_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2026_new\iP&S_2026_2a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-03-27_15-23_2026-03-27_15-13_P&S2025_anim_2a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-03-27_15-13_P&S2025_anim_2a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-03-27_15-19_P&S2025_anim_2a.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-03-27_15-21_P&S2025_anim_2a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_3a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_1a.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 6.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\05 Stretch Cut Nail\Visual 6.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5B_alt_vo.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-21_11-46_SS_2026_animation_16d.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_12A.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13bB.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_4b.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13bA.blend
|
||||
F:\jobs\SS_2026_animation_13bA\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Ren_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_13b.blend
|
||||
F:\jobs\SS_2026_animation_13a\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Ren_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Ren_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_8cB.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_15bB.blend
|
||||
A:\1 Amazon_Active_Projects\260506_Safety_School_Transformation_2026\Blends\animations\SS_2026_animation_8cB_vertical.blend
|
||||
P:\260423_MukBuddy\Blends\animations\Pak Buddy Animation_v2_vert.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\bat-ss2026-2b-pack\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Martha_v4.4.blend
|
||||
F:\jobs\FlowCSA_360_1bD-7c6o\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1bD.blend
|
||||
F:\jobs\FlowCSA_360_1bD-to93\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1b_ADTA_D.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_D-ao45\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_D-n9z0\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_D\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_D-jyur\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1b_ADTA_B.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1bB.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1b_ADTA_A.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-13_13-27_FlowCSA_360_1b_ADTA_A.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-13_12-55_FlowCSA_360_1b_ADTA_A.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-13_13-03_FlowCSA_360_1b_ADTA_A.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-13_13-11_FlowCSA_360_1b_ADTA_A.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1bA.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\2026-05-12_17-26_FlowCSA_360_1b_ADTA_B.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_C-jh9z\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_C\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1b_ADTA_C.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_C-sgxq\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_C-n6rw\FlowCSA_360_1b_ADTA_C.blend
|
||||
F:\jobs\FlowCSA_360_1b_ADTA_C-n6rw\_outside_project\A\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
C:\Users\Nathan\AppData\Local\Temp\bat-flow-not-relative-only\_outside_project\a\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon3\Bebe_v1.2.blend
|
||||
A:\1 Amazon_Active_Projects\260420_FLOW_2026\Blends\animations\FlowCSA_360_1bC.blend
|
||||
A:\1 Amazon_Active_Projects\260512_Agile_Gemba\Assets\Blends\Marker.blend
|
||||
C:\Users\Nathan\Downloads\SS_2026_animation_2b.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\stills\iUP_M6_13.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\stills\iUP_M6_12.blend
|
||||
F:\jobs\Pak Buddy Animation_v2\Pak Buddy Animation_v2.flamenco.blend
|
||||
C:\Users\Nathan\Downloads\House.blend
|
||||
C:\Users\Nathan\Downloads\UP_M5_3.blend
|
||||
C:\Users\Nathan\Downloads\UP_M2_animation_d.blend
|
||||
G:\Amazon\2024\240402_Amazon_Coaching&Upstream\Upstream\blends\mod 2\animation 1\iUP_M2_6.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\stills\iUP_M5_6.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\stills\iUP_M2_5.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\stills\iUP_M5_13.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\comp_RR\Visual 2B_SPA_comp_RR.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 2B_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 2B_SPA\Visual 2B_SPA.blend
|
||||
F:\jobs\Visual 2B_SPA-393g\Visual 2B_SPA.blend
|
||||
F:\jobs\Visual_5_SPA-ii75\Visual_5_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_5_SPA.blend
|
||||
F:\jobs\Visual_5_SPA-ki6s\Visual_5_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual_5_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual_5_SPA_106-109.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_2_broom_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final_SPA\Visual_new_final_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final\Visual_new_final.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final_lady_dancer\Visual_new_final_lady_dancer.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final_kid_and_dog\Visual_new_final_kid_and_dog.blend
|
||||
T:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final_alt_shots.blend
|
||||
F:\jobs\Visual_5_SPA-x1ig\Visual_5_SPA.blend
|
||||
F:\jobs\Visual 3A-fec4\Visual 3A.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 3A.blend
|
||||
C:\Users\Nathan\Downloads\Visual_new_final_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_0_5_talking_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_0_opening_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 6_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 5B_alt_vo_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 4A_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 3B_SPA.blend
|
||||
C:\Users\Nathan\Downloads\Visual 2D_SPA.blend
|
||||
F:\jobs\Visual 5_strech_SPA\Visual 5_strech_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5_strech_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 4A_SPA.blend
|
||||
F:\jobs\Visual 3A-snms\Visual 3A.blend
|
||||
C:\Users\Nathan\Downloads\01_opening_SPA.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\01_opening_SPA.blend
|
||||
F:\jobs\Visual 5_strech_SPA\Visual 5_strech_SPA.flamenco.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 5B.blend
|
||||
F:\jobs\Visual 3A-q4ro\Visual 3A.blend
|
||||
F:\jobs\Visual 3A\Visual 3A.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\06 Infill And Powerbrooming\Visual 3B.blend
|
||||
A:\1 Amazon_Active_Projects\260225_Problem-Solve_2026\Assets\Blends\AMZ-warehouse_v6.0_small.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\0TEST.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\UP_M1_animation1C.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\0TEMP.blend
|
||||
A:\1 Amazon_Active_Projects\260225_Problem-Solve_2026\Blends\animations\PS_2026_animation 1CD.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\UP_M1_animation1D.blend
|
||||
C:\Users\Nathan\Downloads\Upstream_LL_animation_new_C.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\Upstream_LL_animation_new_C.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_5D.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\P&S2025_anim_3c.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2024_old\P&S_safety_refresher_3b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2024_old\P&S_safety_refresher_3a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\SOM\SOM_i_noncon_OOG_7b.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\i_noncon_OOG_7b.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\SPA\SPA_i_noncon_OOG_7b.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\SOM_noncon_OOG_short_animation 13a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 13a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\HAT_noncon_OOG_short_animation 13a.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_animation 1_CYCLES.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\SOM\SOM_i_noncon_OOG_9k.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\i_noncon_OOG_9k.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\HAT\HAT_i_noncon_OOG_9k.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\SOM\SOM_i_noncon_OOG_9m.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\i_noncon_OOG_9m.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\i_noncon_OOG_9l.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\HAT\HAT_i_noncon_OOG_9m.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\SOM\SOM_i_noncon_OOG_9l.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\stills\HAT\HAT_i_noncon_OOG_9l.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\UP_M4_S01_b.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\UP_M4_S01_c.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_30b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_31a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_26.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_22b.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_21.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_22_a.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\iP&S2025_19.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\stills\2025_old\i22.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\Ambassador_M3_A4_picker_s1.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\Ambassador_M3_A4_picker_s3.blend
|
||||
C:\Users\Nathan\Downloads\Ambassador_M3_A4_picker_s3.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\Ambassador_M3_A4_coach-s2.blend
|
||||
A:\1 Amazon_Active_Projects\260127_Pick-and-Stage_2026_edits\Blends\animations\2025_old\Ambassador_M3_A4_coach-s1.blend
|
||||
A:\1 Amazon_Active_Projects\260422_Upstream_edits_2026\Blends\animations\M4\UP_M4_S01_2hands.blend
|
||||
G:\Amazon\2024\240402_Amazon_Coaching&Upstream\Upstream\blends\mod 4\UP_M4_S01.blend
|
||||
G:\Amazon\2024\240402_Amazon_Coaching&Upstream\Upstream\blends\mod 4\UP_M4_S01_2hands.blend
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
schema_version = "1.0.0"
|
||||
|
||||
id = "simple_renaming_panel"
|
||||
version = "2.1.5"
|
||||
version = "2.1.6"
|
||||
name = "Simple Renaming"
|
||||
tagline = "Effortlessly rename multiple objects with this simple addon"
|
||||
maintainer = "Matthias Patscheider <patscheider.matthias@gmail.com>"
|
||||
|
||||
@@ -150,12 +150,20 @@ def register():
|
||||
default='X', # Set a default value
|
||||
)
|
||||
|
||||
id_store.renaming_new_name = StringProperty(name="New Name", default='')
|
||||
id_store.renaming_new_name = StringProperty(
|
||||
name="New Name",
|
||||
description="Name pattern for renaming. Use @n for a numbered variable (configure its digits in Preferences). Use # in the Numerate field (right) to set the auto-suffix digit count",
|
||||
default='',
|
||||
)
|
||||
id_store.renaming_search = StringProperty(name='Search', default='')
|
||||
id_store.renaming_replace = StringProperty(name='Replace', default='')
|
||||
id_store.renaming_suffix = StringProperty(name="Suffix", default='')
|
||||
id_store.renaming_prefix = StringProperty(name="Prefix", default='')
|
||||
id_store.renaming_numerate = StringProperty(name="Numerate", default='###')
|
||||
id_store.renaming_numerate = StringProperty(
|
||||
name="Numerate Pattern",
|
||||
description="Pattern for the auto-numeration suffix appended when Numerate is enabled. Each # represents one digit (e.g. ### → 001, 002, …). This does not affect the @n variable",
|
||||
default='###',
|
||||
)
|
||||
|
||||
id_store.renaming_sorting = bpy.props.BoolProperty(
|
||||
name="Sort Target Objects",
|
||||
@@ -169,12 +177,11 @@ def register():
|
||||
|
||||
id_store.renaming_matchcase = BoolProperty(name="Match Case", description="", default=True)
|
||||
id_store.renaming_useRegex = BoolProperty(name="Use Regex", description="", default=False)
|
||||
id_store.renaming_use_enumerate = BoolProperty(name="Numerate",
|
||||
description="Enable and Disable the numeration of objects. This can "
|
||||
"be especially useful in combination with the numeration "
|
||||
"variable @n",
|
||||
default=True,
|
||||
)
|
||||
id_store.renaming_use_enumerate = BoolProperty(
|
||||
name="Numerate",
|
||||
description="Automatically appends an incrementing numeric suffix to each renamed object. Configure the suffix format with # in the Numerate field, and the digit count for the @n variable in Preferences",
|
||||
default=True,
|
||||
)
|
||||
id_store.renaming_base_numerate = IntProperty(name="Step Size", default=1)
|
||||
id_store.renaming_start_number = IntProperty(name="Step Size", default=1)
|
||||
id_store.renaming_digits_numerate = IntProperty(name="Number Length", default=3)
|
||||
|
||||
@@ -53,7 +53,11 @@ class BUTTON_OT_change_key(bpy.types.Operator):
|
||||
|
||||
|
||||
def add_keymap():
|
||||
km = bpy.context.window_manager.keyconfigs.active.keymaps.new(name="Window")
|
||||
wm = bpy.context.window_manager
|
||||
kc = wm.keyconfigs.addon
|
||||
if kc is None:
|
||||
return
|
||||
km = kc.keymaps.new(name="Window")
|
||||
prefs = bpy.context.preferences.addons[base_package].preferences
|
||||
|
||||
kmi = km.keymap_items.new(idname='wm.call_panel', type=prefs.renaming_panel_type, value='PRESS',
|
||||
@@ -76,23 +80,34 @@ def add_key_to_keymap(idname, kmi, km, active=True):
|
||||
def remove_key(context, idname, properties_name):
|
||||
"""Removes addon hotkeys from the keymap"""
|
||||
wm = bpy.context.window_manager
|
||||
km = wm.keyconfigs.active.keymaps['Window']
|
||||
kc = wm.keyconfigs.addon
|
||||
if kc is None:
|
||||
return
|
||||
km = kc.keymaps.get('Window')
|
||||
if km is None:
|
||||
return
|
||||
|
||||
for kmi in km.keymap_items:
|
||||
if kmi.idname == idname and kmi.properties.name == properties_name:
|
||||
km.keymap_items.remove(kmi)
|
||||
items_to_remove = [kmi for kmi in km.keymap_items
|
||||
if kmi.idname == idname and kmi.properties.name == properties_name]
|
||||
for kmi in items_to_remove:
|
||||
km.keymap_items.remove(kmi)
|
||||
|
||||
|
||||
def remove_keymap():
|
||||
"""Removes keys from the keymap. Currently, this is only called when unregistering the addon. """
|
||||
# only works for menus and pie menus
|
||||
wm = bpy.context.window_manager
|
||||
km = wm.keyconfigs.active.keymaps['Window']
|
||||
kc = wm.keyconfigs.addon
|
||||
if kc is None:
|
||||
return
|
||||
km = kc.keymaps.get('Window')
|
||||
if km is None:
|
||||
return
|
||||
|
||||
for kmi in km.keymap_items:
|
||||
if hasattr(kmi.properties, 'name') and kmi.properties.name in ['VIEW3D_PT_tools_renaming_panel',
|
||||
'VIEW3D_PT_tools_type_suffix']:
|
||||
km.keymap_items.remove(kmi)
|
||||
items_to_remove = [kmi for kmi in km.keymap_items
|
||||
if hasattr(kmi.properties, 'name') and kmi.properties.name in
|
||||
{'VIEW3D_PT_tools_renaming_panel', 'VIEW3D_PT_tools_type_suffix'}]
|
||||
for kmi in items_to_remove:
|
||||
km.keymap_items.remove(kmi)
|
||||
|
||||
|
||||
class REMOVE_OT_hotkey(bpy.types.Operator):
|
||||
|
||||
@@ -28,7 +28,12 @@ def add_key(km, idname, properties_name, button_assignment_type, button_assignme
|
||||
def update_key(context, operation, operator_name, property_prefix):
|
||||
# This functions gets called when the hotkey assignment is updated in the preferences
|
||||
wm = context.window_manager
|
||||
km = wm.keyconfigs.active.keymaps["Window"]
|
||||
kc = wm.keyconfigs.addon
|
||||
if kc is None:
|
||||
return
|
||||
km = kc.keymaps.get("Window")
|
||||
if km is None:
|
||||
return
|
||||
|
||||
prefs = context.preferences.addons[base_package].preferences
|
||||
|
||||
@@ -129,7 +134,7 @@ class VIEW3D_OT_renaming_preferences(bpy.types.AddonPreferences):
|
||||
|
||||
numerate_digits: bpy.props.IntProperty(
|
||||
name="Digits",
|
||||
description="Defines digits used for numerating. Number 1 with digits 3 would result in 001",
|
||||
description="Number of digits used for the @n variable in the New Name field (e.g. @n with 3 digits: 001). To configure the auto-suffix digit count, use # characters in the Numerate field instead",
|
||||
default=3,
|
||||
)
|
||||
numerate_step: bpy.props.IntProperty(
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"version": "v1",
|
||||
"blocklist": [],
|
||||
"data": [
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "basedplayblast",
|
||||
"name": "BasedPlayblast",
|
||||
"tagline": "Easily create playblasts from Blender and Flamenco",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/BasedPlayblast",
|
||||
"permissions": {
|
||||
"files": "Import/export files and data"
|
||||
},
|
||||
"tags": [
|
||||
"Animation",
|
||||
"Render",
|
||||
"Workflow",
|
||||
"Video"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/BasedPlayblast/releases/download/v2.6.3/BasedPlayblast.v2.6.3.zip",
|
||||
"archive_size": 49732,
|
||||
"archive_hash": "sha256:078b406105ce6f4802e75233569841e2f73d082e09cd1d954696681ebf72b627"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "rainclouds_bulk_scene_tools",
|
||||
"name": "Raincloud's Bulk Scene Tools",
|
||||
"tagline": "Bulk utilities for optimizing scene data",
|
||||
"version": "0.17.0",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon <raincloudthedragon@gmail.com>",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"website": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools",
|
||||
"permissions": {
|
||||
"files": "Read and write external resources referenced by scenes"
|
||||
},
|
||||
"tags": [
|
||||
"Scene",
|
||||
"Workflow",
|
||||
"Materials"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/Rainys-Bulk-Scene-Tools/releases/download/v0.17.0/Rainys_Bulk_Scene_Tools.v0.17.0.zip",
|
||||
"archive_size": 80981,
|
||||
"archive_hash": "sha256:419433069465b45ea903bd7bb46d89aa28b9c96c541d587d5f3be651a762811f"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "atomic_data_manager",
|
||||
"name": "Atomic Data Manager",
|
||||
"tagline": "Smart cleanup and inspection of Blender data-blocks",
|
||||
"version": "2.6.3",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "4.2.0",
|
||||
"tags": [
|
||||
"utility",
|
||||
"management",
|
||||
"cleanup"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/atomic-data-manager/releases/download/v2.6.3/Atomic_Data_Manager.v2.6.3.zip",
|
||||
"archive_size": 122700,
|
||||
"archive_hash": "sha256:b444463a0443864077abcfe97332406e606a697d3567ac32f85843760da11372"
|
||||
},
|
||||
{
|
||||
"schema_version": "1.0.0",
|
||||
"id": "sheepit_project_submitter",
|
||||
"name": "SheepIt Project Submitter",
|
||||
"tagline": "Submit projects to SheepIt render farm",
|
||||
"version": "0.0.8",
|
||||
"type": "add-on",
|
||||
"maintainer": "RaincloudTheDragon",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"blender_version_min": "3.0.0",
|
||||
"tags": [
|
||||
"render",
|
||||
"farm",
|
||||
"submission",
|
||||
"utility"
|
||||
],
|
||||
"archive_url": "https://github.com/RaincloudTheDragon/sheepit_project_submitter/releases/download/v0.0.8/SheepIt_Project_Submitter.v0.0.8.zip",
|
||||
"archive_size": 47667,
|
||||
"archive_hash": "sha256:93cd8f18456079130c48c66cfd40235f7fe6414f929f59f90670e7a864821110"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -20,7 +20,7 @@
|
||||
bl_info = {
|
||||
"name": "Animation Layers",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (2, 4, 0),
|
||||
"version" : (2, 4, 1),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "Simplifying the NLA editor into an animation layers UI and workflow",
|
||||
@@ -73,7 +73,10 @@ class AnimLayersSceneSettings(bpy.types.PropertyGroup):
|
||||
|
||||
class AnimLayersSettings(bpy.types.PropertyGroup):
|
||||
turn_on: bpy.props.BoolProperty(name="Turn Animation Layers On", description="Turn on and start Animation Layers", default=False, options={'HIDDEN'}, update = anim_layers.turn_animlayers_on, override = {'LIBRARY_OVERRIDABLE'})
|
||||
# Active row in obj.Anim_Layers. Post-migration, 1:1 with NLA-track index.
|
||||
layer_index: bpy.props.IntProperty(update = anim_layers.update_layer_index, options={'LIBRARY_EDITABLE'}, default = 0, override = {'LIBRARY_OVERRIDABLE'})
|
||||
# Schema version. 0 = pre-hierarchical (legacy GROUP rows); 1 = hierarchical (parent_layer refs).
|
||||
schema_version: bpy.props.IntProperty(name="Schema Version", default=0, options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
linked: bpy.props.BoolProperty(name="Linked", description="Duplicate a layer with a linked action", default=False, options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
#Bake settings
|
||||
@@ -125,13 +128,31 @@ class AnimLayersItems(bpy.types.PropertyGroup):
|
||||
|
||||
action_range: bpy.props.FloatVectorProperty(name='action range', description="used to check if layer needs to update frame range", override = {'LIBRARY_OVERRIDABLE'}, size = 2)
|
||||
custom_frame_range: bpy.props.BoolProperty(name="Custom Frame Range", description="Use a custom frame range per layer instead of the scene frame range", default=False, options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_frame_range)
|
||||
|
||||
|
||||
frame_start: bpy.props.FloatProperty(name='Action Start Frame', description="First frame of the layer's action",min = 0, default=0, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_frame_start)
|
||||
frame_end: bpy.props.FloatProperty(name='Action End Frame', description="End frame of the layer's action", default=0, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_frame_end)
|
||||
speed: bpy.props.FloatProperty(name='Speed of the action', description="Speed of the action strip", default = 1, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_speed)
|
||||
offset: bpy.props.FloatProperty(name='Offset when the action starts', description="Offseting the whole layer animation", default = 0, precision = 2, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_offset)
|
||||
repeat: bpy.props.FloatProperty(name="Repeat", description="Repeat the action", min = 0.1, default = 1, options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'}, update = anim_layers.layer_repeat)
|
||||
|
||||
# Hierarchical layer fields. Every layer is NLA-backed; a layer is a
|
||||
# "group" iff something else points to it via parent_layer.
|
||||
expanded: bpy.props.BoolProperty(name="Expanded", description="Show this layer's children in the UI list", default=True, options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
parent_layer: bpy.props.StringProperty(name="Parent Layer", description="Name of this layer's parent (empty = root)", default="", options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
group_color: bpy.props.FloatVectorProperty(name="Group Color", subtype='COLOR', size=4, min=0.0, max=1.0, default=(0.3, 0.5, 0.8, 1.0), options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
# Dynamic-enum dropdown for picking parent_layer in the UI. The setter
|
||||
# refuses cycles (self + descendants are excluded from the options).
|
||||
assigned_group: bpy.props.EnumProperty(name='Parent', description='Set this layer\'s parent (None = root)',
|
||||
items=anim_layers.layer_group_enum_items, get=anim_layers.layer_group_get, set=anim_layers.layer_group_set,
|
||||
options={'HIDDEN'})
|
||||
# Legacy field for pre-migration data. Read by migrate_object_to_hierarchical
|
||||
# and ignored thereafter. Schema retained so old .blend files load cleanly.
|
||||
type: bpy.props.EnumProperty(name="Item Type (legacy)", default='LAYER',
|
||||
items=[('LAYER', 'Layer', 'NLA-backed layer'),
|
||||
('GROUP', 'Group', 'Legacy phantom group row')],
|
||||
options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
parent_group: bpy.props.StringProperty(name="Parent Group (legacy)", description="Pre-migration field. Read once by the schema-v1 migration, then unused.", default="", options={'HIDDEN'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
|
||||
class AnimLayersObjects(bpy.types.PropertyGroup):
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_check": "2026-04-21 12:47:39.126086",
|
||||
"backup_date": "April-21-2026",
|
||||
"last_check": "2026-05-27 14:41:11.263249",
|
||||
"backup_date": "May-27-2026",
|
||||
"update_ready": false,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
bl_info = {
|
||||
"name": "Animation Layers",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (2, 3, 8),
|
||||
"version" : (2, 4, 0),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "Simplifying the NLA editor into an animation layers UI and workflow",
|
||||
@@ -153,7 +153,6 @@ def update_panel(self, context):
|
||||
bpy.utils.unregister_class(panel)
|
||||
|
||||
for panel in panels:
|
||||
#print (panel.bl_category)
|
||||
panel.bl_category = context.preferences.addons[__name__].preferences.category
|
||||
bpy.utils.register_class(panel)
|
||||
|
||||
@@ -176,8 +175,9 @@ class AnimLayersAddonPreferences(bpy.types.AddonPreferences):
|
||||
items = [('ANIMLAYERS', 'Anim Layers Settings', 'Use Anim Layers properties to adjust custom frame range'),
|
||||
('NLA', 'NLA Settings', 'Use the nla properties to adjust custom frame range')])
|
||||
|
||||
lock_nlatracks: bpy.props.BoolProperty(name="Automatically lock the nla tracks for safety measures", description="Automatically lock nla tracks when creating layers for safety", default = True)
|
||||
|
||||
lock_nlatracks: bpy.props.BoolProperty(name="Automatically lock the NLA tracks", description="Automatically lock nla tracks when creating layers for safety", default = True)
|
||||
auto_custom_range: bpy.props.BoolProperty(name="Switch automatically to custom frame range when editing NLA Strips", description="Automatically use custom frame range when adjusting NLA Strips manually", default = False)
|
||||
|
||||
#Property for ClearActiveAction
|
||||
proceed: bpy.props.EnumProperty(name="Choose how to proceed", description="Select an option how to proceed with Anim Layers", override = {'LIBRARY_OVERRIDABLE'},
|
||||
items = [
|
||||
@@ -260,8 +260,9 @@ class AnimLayersAddonPreferences(bpy.types.AddonPreferences):
|
||||
row.label(text = "Custom Frame Range Settings")
|
||||
row.prop(self, "frame_range_settings", text = '')
|
||||
|
||||
col.prop(self, "lock_nlatracks")
|
||||
|
||||
row = col.row()
|
||||
row.prop(self, "auto_custom_range")
|
||||
row.prop(self, "lock_nlatracks")
|
||||
|
||||
classes = (AnimLayersSettings, AnimLayersSceneSettings, AnimLayersItems, AnimLayersObjects)
|
||||
|
||||
|
||||
@@ -399,7 +399,7 @@ def get_fcu_layer_keyframes(obj, context, track):
|
||||
keyframes = []
|
||||
# fcurves = get_fcurves(track.strips[0].action)
|
||||
# fcurves = track.strips[0].action.fcurves
|
||||
fcurves = get_fcurves(obj, track.strips[0].action)
|
||||
fcurves = get_fcurves(obj, track.strips[0].action, obj.als.data_type)
|
||||
#store all the keyframe locations from the fcurves of the layer
|
||||
for fcu in fcurves:
|
||||
if fcu.group is not None:
|
||||
@@ -1546,6 +1546,8 @@ def strip_action_recalc(self, strip):
|
||||
|
||||
###################################################### HELPER FUNCTIONS ################################################
|
||||
def redraw_areas(areas):
|
||||
if not len(bpy.context.window_manager.windows):
|
||||
return
|
||||
for area in bpy.context.window_manager.windows[0].screen.areas:
|
||||
if area.type in areas:
|
||||
area.tag_redraw()
|
||||
@@ -1621,7 +1623,7 @@ def select_layer_bones(self, context):
|
||||
|
||||
###################################################### CLASSES ###########################################################
|
||||
class SelectBonesInLayer(bpy.types.Operator):
|
||||
"""Select bones with keyframes in the current layer"""
|
||||
"""Select bones with keyframes in the current layer, use shift to add to the current selection"""
|
||||
bl_idname = "anim.bones_in_layer"
|
||||
bl_label = "Select layer bones"
|
||||
bl_icon = "BONE_DATA"
|
||||
@@ -1864,18 +1866,9 @@ class AutoCustomFrameRange(bpy.types.Operator):
|
||||
# return {'CANCELLED'}
|
||||
|
||||
def restore(self, context):
|
||||
if hasattr(subscriptions, 'frame_range'):
|
||||
frame_start, frame_end = subscriptions.frame_range
|
||||
|
||||
else:
|
||||
frame_start, frame_end = subscriptions.get_frame_range(context.scene)
|
||||
print('restore')
|
||||
subscriptions.frameend_update_callback()
|
||||
|
||||
self.strip.repeat = 1 #change strip repeat but keep self.repeat value stored
|
||||
self.strip.use_reverse = False
|
||||
self.strip.frame_start = frame_start
|
||||
self.strip.scale = self.layer.speed
|
||||
self.strip.frame_end = frame_end
|
||||
# update_action_frame_range(frame_start, frame_end, layer, strip)
|
||||
subscriptions.subscriptions_add(context.scene)
|
||||
|
||||
def update_action_list(scene):
|
||||
@@ -2596,9 +2589,7 @@ class RemoveFcurves(bpy.types.Operator):
|
||||
if mod.type == 'CYCLES':
|
||||
fcu.modifiers.remove(mod)
|
||||
fcu.update()
|
||||
for area in context.window_manager.windows[0].screen.areas:
|
||||
if area.type == 'GRAPH_EDITOR' or area.type == 'VIEW_3D':
|
||||
area.tag_redraw()
|
||||
redraw_areas(['GRAPH_EDITOR', 'VIEW_3D'])
|
||||
break
|
||||
return {'FINISHED'}
|
||||
|
||||
@@ -3301,25 +3292,36 @@ def copy_action(action):
|
||||
|
||||
return new_action
|
||||
|
||||
def get_obj_slot(obj, action, data_type = 'OBJECT'):
|
||||
def get_obj_slot(obj, action, data_type = None):
|
||||
'''Get the slot in the action that this object is using either it's object, or shapekeys'''
|
||||
|
||||
if data_type is None:
|
||||
data_type = obj.als.data_type
|
||||
|
||||
if not hasattr(action, 'slots'):
|
||||
return None
|
||||
|
||||
if not len(action.slots):
|
||||
# If no slots exist, create one for the object and return it
|
||||
slot = add_action_slot(obj, action)
|
||||
return slot
|
||||
|
||||
# data_type = obj.als.data_type
|
||||
for slot in action.slots:
|
||||
if slot.target_id_type != data_type:
|
||||
continue
|
||||
# if obj.als.data_type == 'OBJECT' and obj in slot.users():
|
||||
# return slot
|
||||
|
||||
if data_type == 'KEY' and obj.data.shape_keys in slot.users():
|
||||
return slot
|
||||
elif obj in slot.users():
|
||||
return slot
|
||||
|
||||
return None
|
||||
|
||||
return add_action_slot(obj, action)
|
||||
|
||||
def get_fcurves(obj: bpy.types.Object, action: bpy.types.Action, data_type = 'OBJECT'):
|
||||
def get_fcurves(obj: bpy.types.Object, action: bpy.types.Action, data_type = None):
|
||||
|
||||
if data_type is None:
|
||||
data_type = obj.als.data_type
|
||||
|
||||
if hasattr(action, 'layers'):
|
||||
slot = get_obj_slot(obj, action, data_type)
|
||||
@@ -3335,10 +3337,13 @@ def get_fcurves(obj: bpy.types.Object, action: bpy.types.Action, data_type = 'OB
|
||||
return action.fcurves
|
||||
return []
|
||||
|
||||
def get_channelbag(obj: bpy.types.Object, action: bpy.types.Action, data_type = 'OBJECT'):
|
||||
def get_channelbag(obj: bpy.types.Object, action: bpy.types.Action, data_type = None):
|
||||
'''Getting the container of the fcurves, either the action or channelbag
|
||||
Using this when adding a new group to the action'''
|
||||
|
||||
if data_type is None:
|
||||
data_type = obj.als.data_type
|
||||
|
||||
if hasattr(action, 'layers'):
|
||||
slot = get_obj_slot(obj, action, data_type)
|
||||
channelbag = None
|
||||
|
||||
+4
-4
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"last_check": "2026-04-21 12:47:39.126086",
|
||||
"backup_date": "March-27-2026",
|
||||
"last_check": "2026-05-27 14:41:11.263249",
|
||||
"backup_date": "April-21-2026",
|
||||
"update_ready": true,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
"just_updated": false,
|
||||
"version_text": {
|
||||
"link": "https://gitlab.com/api/v4/projects/22294607/repository/archive.zip?sha=dddd6932039b8a3e5fae3ce2de957f21a5942c84",
|
||||
"link": "https://gitlab.com/api/v4/projects/22294607/repository/archive.zip?sha=321d411a449bc9acee2a759e30cd3d0f36bbd2ab",
|
||||
"version": [
|
||||
2,
|
||||
4,
|
||||
0
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -645,6 +645,7 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
baked_action = track.strips[0].action
|
||||
clean_no_user_slots(baked_action)
|
||||
#create the baked fcurve
|
||||
# baked_channelbag = anim_layers.get_channelbag(obj, baked_action, obj.als.data_type)
|
||||
baked_channelbag = anim_layers.get_channelbag(obj, baked_action)
|
||||
baked_fcurves = baked_channelbag.fcurves
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ def animlayers_frame(scene, context):
|
||||
scene['framerange_preview'] = scene.use_preview_range
|
||||
frameend_update_callback()
|
||||
return
|
||||
|
||||
frame_start, frame_end = bake_ops.frame_start_end(scene)
|
||||
# frame_start, frame_end = get_frame_range(scene)
|
||||
reset_subscription = False
|
||||
@@ -106,7 +105,6 @@ def animlayers_frame(scene, context):
|
||||
for i, track in enumerate(nla_tracks):
|
||||
if len(track.strips) != 1:
|
||||
continue
|
||||
|
||||
#checks if the layer has a custom frame range
|
||||
layer = obj.Anim_Layers[i]
|
||||
if layer.custom_frame_range:
|
||||
@@ -127,6 +125,7 @@ def animlayers_frame(scene, context):
|
||||
if strip.frame_start < 0:
|
||||
strip.frame_start = 0
|
||||
anim_layers.update_action_frame_range(0, frame_end, layer, strip)
|
||||
return
|
||||
anim_layers.update_action_frame_range(strip.frame_start, current + 10.0, layer, strip)
|
||||
strip.frame_end = current + 10.0
|
||||
|
||||
@@ -231,6 +230,9 @@ def track_layer_synchronization(obj, nla_tracks):
|
||||
if obj.als.layer_index > len(obj.Anim_Layers)-1:
|
||||
obj.als.layer_index = len(obj.Anim_Layers)-1
|
||||
|
||||
if not bpy.context.preferences.addons[__package__].preferences.auto_custom_range:
|
||||
return
|
||||
|
||||
#update new layer with strip settings
|
||||
frame_start, frame_end = get_frame_range(bpy.context.scene)
|
||||
|
||||
@@ -243,7 +245,6 @@ def track_layer_synchronization(obj, nla_tracks):
|
||||
continue
|
||||
if (strip.frame_start, strip.frame_end) != (frame_start, frame_end):
|
||||
subscriptions_remove()
|
||||
# print(f'strip.frame_start {strip.frame_start} strip.frame_end {strip.frame_end} frame_start {frame_start} frame_end {frame_end}')
|
||||
bpy.ops.anim.custom_frame_range_warning('INVOKE_DEFAULT')
|
||||
return
|
||||
|
||||
@@ -311,11 +312,16 @@ def sync_frame_range(scene, track, layer):
|
||||
return
|
||||
|
||||
#Turn on custom frame range if the current strip is not following the scene frame range
|
||||
# Should be activated when nla strips are edited manually in the nla editor, only when auto custom range is turned on, otherwise just update the strip frame range to the scene frame range
|
||||
if (round(strip.frame_start, 2), round(strip.frame_end, 2)) != (round(frame_start, 2), round(frame_end, 2)):
|
||||
subscriptions_remove()
|
||||
# print('315 custom frame range')
|
||||
bpy.ops.anim.custom_frame_range_warning('INVOKE_DEFAULT')
|
||||
return
|
||||
if bpy.context.preferences.addons[__package__].preferences.auto_custom_range:
|
||||
subscriptions_remove()
|
||||
# print('321 custom frame range')
|
||||
bpy.ops.anim.custom_frame_range_warning('INVOKE_DEFAULT')
|
||||
return
|
||||
else:
|
||||
frameend_update_callback()
|
||||
return
|
||||
|
||||
def sync_strip_range(scene):
|
||||
'''Checking all the strips if a value was changed in the nla (not including UI changes)
|
||||
@@ -356,7 +362,6 @@ def sync_strip_range(scene):
|
||||
if (strip_frame_start, round(strip_frame_end, 2)) != (frame_start, float(frame_end)):
|
||||
subscriptions_remove()
|
||||
# print('357 custom_frame_range_warning ')
|
||||
# print(f'strip_frame_start {strip_frame_start} strip_frame_end {round(strip_frame_end, 2)} frame_start {frame_start} frame_end {float(frame_end)}')
|
||||
bpy.ops.anim.custom_frame_range_warning('INVOKE_DEFAULT')
|
||||
return
|
||||
|
||||
@@ -567,7 +572,6 @@ def subscribe_to_preview_frame_end(scene):
|
||||
# Subscribing to preview frame end since it's not registering in the depsgraph
|
||||
subscribe_preview_end = scene.path_resolve("frame_preview_end", False)
|
||||
subscribe_use_preview = scene.path_resolve("use_preview_range", False)
|
||||
# print('subscribe_to_preview_frame_end')
|
||||
for subscribe in [subscribe_preview_end, subscribe_use_preview]:
|
||||
|
||||
bpy.msgbus.subscribe_rna(
|
||||
|
||||
BIN
Binary file not shown.
@@ -180,10 +180,11 @@ def smart_bake(context):
|
||||
fcurves = anim_layers.get_fcurves(obj, track.strips[0].action)
|
||||
total_iterations += len(fcurves)
|
||||
|
||||
wm.progress_begin(0, total_iterations)
|
||||
wm.progress_begin(0, total_iterations)
|
||||
processed = 0
|
||||
|
||||
for layer, track in zip(obj.Anim_Layers, anim_data.nla_tracks):
|
||||
layer_items = [l for l in obj.Anim_Layers if l.type == 'LAYER']
|
||||
for layer, track in zip(layer_items, anim_data.nla_tracks):
|
||||
if track.mute:
|
||||
continue
|
||||
if len(track.strips) != 1 or track.strips[0].action is None:
|
||||
@@ -242,9 +243,9 @@ def smart_bake(context):
|
||||
smartkeys = smart_start_end(smartkeys, strip.frame_start, strip.frame_end)
|
||||
smartkeys = remove_outofrange_keys(smartkeys, strip.frame_start, strip.frame_end)
|
||||
|
||||
#if the strip is cutting with a different strip, then add keyframes in the cut
|
||||
#if the strip is cutting with a different strip, then add keyframes in the cut
|
||||
for layercut in obj.Anim_Layers:
|
||||
if layercut.mute or not layercut.custom_frame_range or layercut == layer:
|
||||
if layercut.type == 'GROUP' or layercut.mute or not layercut.custom_frame_range or layercut == layer:
|
||||
continue
|
||||
if strip_start < layercut.frame_start < strip_end:
|
||||
smartkeys = smart_start_end(smartkeys, (layercut.frame_start-1), strip.frame_end-1)
|
||||
@@ -407,7 +408,7 @@ def unmute_modifiers(obj, nla_tracks, modifier_rec):
|
||||
for mod in fcu.modifiers:
|
||||
if mod in modifier_rec:
|
||||
mod.mute = False
|
||||
elif obj.als.mergefcurves and track == nla_tracks[obj.als.layer_index]:
|
||||
elif obj.als.mergefcurves and track == nla_tracks[anim_layers.nla_idx(obj)]:
|
||||
mod.mute = True
|
||||
|
||||
def invisible_layers(b_layers):
|
||||
@@ -426,7 +427,14 @@ def select_keyframed_bones(self, context, obj):
|
||||
if obj.mode != 'POSE':
|
||||
bpy.ops.object.posemode_toggle()
|
||||
bpy.ops.pose.select_all(action='DESELECT')
|
||||
for i in range(0, obj.als.layer_index+1):
|
||||
# Iterate over LAYER rows up to (and including) the active row, skipping
|
||||
# group headers (they have no NLA track and no bones to select).
|
||||
current_row = obj.als.layer_index
|
||||
for i, it in enumerate(obj.Anim_Layers):
|
||||
if i > current_row:
|
||||
break
|
||||
if it.type != 'LAYER':
|
||||
continue
|
||||
obj.als['layer_index'] = i
|
||||
anim_layers.select_layer_bones(self, context)
|
||||
|
||||
@@ -446,7 +454,7 @@ def smartbake_apply(obj, nla_tracks, fcu_keys, extrapolations):
|
||||
#apply smartbake for blenders bake
|
||||
#smart bake - delete unnecessery keyframes:
|
||||
# transform_types = ['location', 'rotation_euler', 'rotation_quaternion', 'scale']
|
||||
strip = nla_tracks[obj.als.layer_index].strips[0]
|
||||
strip = nla_tracks[anim_layers.nla_idx(obj)].strips[0]
|
||||
# if strip.action is None:
|
||||
# return
|
||||
|
||||
@@ -641,7 +649,7 @@ def AL_bake(frame_start, frame_end, nla_tracks, fcu_keys, additive, step, action
|
||||
return
|
||||
anim_data = anim_layers.anim_data_type(obj)
|
||||
# baked_action = anim_data.action
|
||||
track = nla_tracks[obj.als.layer_index]
|
||||
track = nla_tracks[anim_layers.nla_idx(obj)]
|
||||
baked_action = track.strips[0].action
|
||||
clean_no_user_slots(baked_action)
|
||||
#create the baked fcurve
|
||||
@@ -1065,10 +1073,18 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
bl_idname = "anim.layers_merge_down"
|
||||
bl_label = "Merge_Layers_Down"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
|
||||
step: bpy.props.IntProperty(name='Step', description='Bake every number of frame steps', default=1)
|
||||
actioncopy: bpy.props.BoolProperty(name='Copy original merged action', description='Create a copy of the original action that is being overwritten', default = False)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
if obj is None:
|
||||
return False
|
||||
# Disable when active row is a group header — merge only applies to NLA-backed layers.
|
||||
return anim_layers.is_layer_row_active(obj)
|
||||
|
||||
def invoke(self, context, event):
|
||||
obj = context.object
|
||||
bake_range_type(context.scene.als, context)
|
||||
@@ -1143,7 +1159,8 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
|
||||
# Incase the strips are shorter then the keyframe range (because scene is shorter)
|
||||
# Then updating the strips length
|
||||
for layer, track in zip(obj.Anim_Layers, anim_data.nla_tracks):
|
||||
layer_items = [l for l in obj.Anim_Layers if l.type == 'LAYER']
|
||||
for layer, track in zip(layer_items, anim_data.nla_tracks):
|
||||
if layer.custom_frame_range:
|
||||
continue
|
||||
if len(track.strips) != 1:
|
||||
@@ -1181,7 +1198,7 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
if obj.als.direction == 'DOWN':
|
||||
obj.als.layer_index = 0
|
||||
baked_layer = None
|
||||
strip = anim_data.nla_tracks[obj.als.layer_index].strips[0]
|
||||
strip = anim_data.nla_tracks[anim_layers.nla_idx(obj)].strips[0]
|
||||
action = strip.action
|
||||
if hasattr(strip, 'action_slot'):
|
||||
action_slot = strip.action_slot
|
||||
@@ -1190,21 +1207,29 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
#if baking to a new layer then setup the new index and layer
|
||||
elif obj.als.operator == 'NEW':
|
||||
self.actioncopy = False
|
||||
# `add_at_nla` is the NLA-track index passed to add_animlayer.
|
||||
if obj.als.direction == 'UP' and additive and 'REPLACE' in blendings:
|
||||
obj.als.layer_index = layer_index + blendings.index('REPLACE') - 1
|
||||
add_at_nla = layer_index + blendings.index('REPLACE') - 1
|
||||
elif obj.als.direction == 'UP' or obj.als.direction == 'ALL':
|
||||
obj.als.layer_index = len(obj.Anim_Layers)-1
|
||||
add_at_nla = anim_layers.nla_layer_count(obj) - 1
|
||||
else:
|
||||
add_at_nla = anim_layers.nla_idx(obj)
|
||||
|
||||
layer_names = [layer.name for layer in obj.Anim_Layers]
|
||||
baked_layer = anim_layers.add_animlayer(layer_name = anim_layers.unique_name(layer_names, 'Baked_Layer') , duplicate = False, index = obj.als.layer_index, blend_type = blend)
|
||||
layer_names = [layer.name for layer in obj.Anim_Layers if layer.type == 'LAYER']
|
||||
baked_layer = anim_layers.add_animlayer(layer_name = anim_layers.unique_name(layer_names, 'Baked_Layer') , duplicate = False, index = add_at_nla, blend_type = blend)
|
||||
anim_layers.register_layers(obj, nla_tracks)
|
||||
|
||||
obj.als.layer_index += 1
|
||||
|
||||
# Point layer_index at the newly-added baked layer's collection row.
|
||||
if baked_layer is not None:
|
||||
for ridx, it in enumerate(obj.Anim_Layers):
|
||||
if it.type == 'LAYER' and it.name == baked_layer.name:
|
||||
obj.als.layer_index = ridx
|
||||
break
|
||||
|
||||
#remove subsciption again after adding a layer there was new subsciption applied
|
||||
subscriptions.subscriptions_remove()
|
||||
|
||||
track = nla_tracks[obj.als.layer_index]
|
||||
track = nla_tracks[anim_layers.nla_idx(obj)]
|
||||
#use internal bake
|
||||
if obj.als.baketype =='NLA':
|
||||
modifier_rec, extrapolations = mute_modifiers(obj, nla_tracks)
|
||||
@@ -1282,7 +1307,7 @@ class MergeAnimLayerDown(bpy.types.Operator):
|
||||
strip.action_slot = anim_layers.get_obj_slot(obj, action)
|
||||
|
||||
#reset layer settings
|
||||
baked_layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
baked_layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
baked_layer.repeat, baked_layer.speed, baked_layer.offset = 1, 1, 0
|
||||
strip.use_sync_length = False
|
||||
if baked_layer.custom_frame_range:
|
||||
|
||||
@@ -106,7 +106,10 @@ def animlayers_frame(scene, context):
|
||||
if len(track.strips) != 1:
|
||||
continue
|
||||
#checks if the layer has a custom frame range
|
||||
layer = obj.Anim_Layers[i]
|
||||
row_idx = anim_layers.layer_to_row_index(obj, i)
|
||||
if row_idx < 0 or row_idx >= len(obj.Anim_Layers):
|
||||
continue
|
||||
layer = obj.Anim_Layers[row_idx]
|
||||
if layer.custom_frame_range:
|
||||
continue
|
||||
if not reset_subscription:
|
||||
@@ -169,6 +172,10 @@ def check_handler(scene):
|
||||
return
|
||||
anim_layers.add_obj_to_animlayers(obj, [item.object for item in scene.AL_objects])
|
||||
nla_tracks = anim_data.nla_tracks
|
||||
# When the active UIList row is a group header (no NLA track of its own),
|
||||
# skip the LAYER-specific syncs below — they assume a real layer.
|
||||
if not anim_layers.is_layer_row_active(obj):
|
||||
return
|
||||
layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
active_action_update(obj, anim_data, nla_tracks)
|
||||
#check if a keyframe was removed
|
||||
@@ -189,7 +196,7 @@ def check_handler(scene):
|
||||
if track_layer_synchronization(obj, nla_tracks):
|
||||
return
|
||||
|
||||
track = nla_tracks[obj.als.layer_index]
|
||||
track = nla_tracks[anim_layers.nla_idx(obj)]
|
||||
|
||||
sync_frame_range(scene, track, layer)
|
||||
# sync_strip_range(scene)
|
||||
@@ -217,18 +224,20 @@ def check_handler(scene):
|
||||
anim_layers.hide_view_all_keyframes(obj, anim_data)
|
||||
check_selected_bones(obj)
|
||||
|
||||
influence_check(nla_tracks[obj.als.layer_index])
|
||||
influence_check(nla_tracks[anim_layers.nla_idx(obj)])
|
||||
|
||||
def track_layer_synchronization(obj, nla_tracks):
|
||||
'''check if track and layers are synchronized, running only when adding/removing tracks via the nla'''
|
||||
|
||||
if len(nla_tracks) == len(obj.Anim_Layers):
|
||||
if len(nla_tracks) == anim_layers.nla_layer_count(obj):
|
||||
return False
|
||||
|
||||
new_layers_names = set(track.name for track in nla_tracks).difference(set(layer.name for layer in obj.Anim_Layers))
|
||||
|
||||
layer_items = [layer for layer in obj.Anim_Layers if layer.type == 'LAYER']
|
||||
new_layers_names = set(track.name for track in nla_tracks).difference(set(layer.name for layer in layer_items))
|
||||
anim_layers.visible_layers(obj, nla_tracks)
|
||||
if obj.als.layer_index > len(obj.Anim_Layers)-1:
|
||||
obj.als.layer_index = len(obj.Anim_Layers)-1
|
||||
row_count = len(obj.Anim_Layers)
|
||||
if row_count and obj.als.layer_index > row_count - 1:
|
||||
obj.als.layer_index = row_count - 1
|
||||
|
||||
if not bpy.context.preferences.addons[__package__].preferences.auto_custom_range:
|
||||
return
|
||||
@@ -261,9 +270,9 @@ def active_action_update(obj, anim_data, nla_tracks):
|
||||
anim_data.action = None
|
||||
subscriptions_add(bpy.context.scene)
|
||||
return
|
||||
if anim_data.action == nla_tracks[obj.als.layer_index].strips[0].action:
|
||||
if anim_data.action == nla_tracks[anim_layers.nla_idx(obj)].strips[0].action:
|
||||
return
|
||||
if not len(nla_tracks[obj.als.layer_index].strips):
|
||||
if not len(nla_tracks[anim_layers.nla_idx(obj)].strips):
|
||||
return
|
||||
if not anim_data.action or anim_data.is_property_readonly('action'):
|
||||
return
|
||||
@@ -434,7 +443,7 @@ def influence_sync(scene, obj, nla_tracks):
|
||||
if action.name == scene.name + 'Action' and not len(scene.animation_data.nla_tracks) and not len(fcurves):
|
||||
bpy.data.actions.remove(action)
|
||||
|
||||
strip = nla_tracks[obj.als.layer_index].strips[0]
|
||||
strip = nla_tracks[anim_layers.nla_idx(obj)].strips[0]
|
||||
if strip.fcurves[0].mute:
|
||||
return
|
||||
strip.fcurves[0].lock = False
|
||||
@@ -546,9 +555,10 @@ def frameend_update_callback():
|
||||
for anim_data in anim_datas:
|
||||
if anim_data is None:
|
||||
continue
|
||||
if len(anim_data.nla_tracks) != len(obj.Anim_Layers):
|
||||
if len(anim_data.nla_tracks) != anim_layers.nla_layer_count(obj):
|
||||
continue
|
||||
for layer, track in zip(obj.Anim_Layers, anim_data.nla_tracks):
|
||||
layer_items = [l for l in obj.Anim_Layers if l.type == 'LAYER']
|
||||
for layer, track in zip(layer_items, anim_data.nla_tracks):
|
||||
if layer.custom_frame_range:
|
||||
continue
|
||||
if len(track.strips) != 1:
|
||||
@@ -653,10 +663,12 @@ def action_name_callback():
|
||||
nla_tracks = anim_data.nla_tracks
|
||||
if not len(nla_tracks):
|
||||
return
|
||||
layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
if not len(nla_tracks[obj.als.layer_index].strips):
|
||||
if not anim_layers.is_layer_row_active(obj):
|
||||
return
|
||||
action = nla_tracks[obj.als.layer_index].strips[0].action
|
||||
layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
if not len(nla_tracks[anim_layers.nla_idx(obj)].strips):
|
||||
return
|
||||
action = nla_tracks[anim_layers.nla_idx(obj)].strips[0].action
|
||||
if action is None:
|
||||
return
|
||||
if not obj.als.auto_rename or layer.name == action.name:
|
||||
@@ -774,10 +786,10 @@ def slot_update_callback():
|
||||
if not len(obj.Anim_Layers):
|
||||
return
|
||||
|
||||
if not len(anim_data.nla_tracks[obj.als.layer_index].strips):
|
||||
if not len(anim_data.nla_tracks[anim_layers.nla_idx(obj)].strips):
|
||||
return
|
||||
|
||||
strip = anim_data.nla_tracks[obj.als.layer_index].strips[0]
|
||||
strip = anim_data.nla_tracks[anim_layers.nla_idx(obj)].strips[0]
|
||||
anim_data.action_slot = strip.action_slot
|
||||
|
||||
|
||||
@@ -848,9 +860,11 @@ def strip_settings_callback():
|
||||
return
|
||||
|
||||
# sync_strip_range()
|
||||
if not len(anim_data.nla_tracks[obj.als.layer_index].strips):
|
||||
if not anim_layers.is_layer_row_active(obj):
|
||||
return
|
||||
strip = anim_data.nla_tracks[obj.als.layer_index].strips[0]
|
||||
if not len(anim_data.nla_tracks[anim_layers.nla_idx(obj)].strips):
|
||||
return
|
||||
strip = anim_data.nla_tracks[anim_layers.nla_idx(obj)].strips[0]
|
||||
layer = obj.Anim_Layers[obj.als.layer_index]
|
||||
|
||||
update_strip_layer_settings(strip, layer)
|
||||
|
||||
@@ -71,6 +71,7 @@ def draw_wgt(scale, bone, shape = 'sphere'):
|
||||
shape = shape.lower()
|
||||
|
||||
mesh.from_pydata(np.array(shapes[shape]['vertices'])*scale , shapes[shape]['edges'], shapes[shape]['faces'])
|
||||
# print('draw shape scale ', scale)
|
||||
shape_obj['WGT_TempCtrl'] = True
|
||||
return shape_obj
|
||||
|
||||
@@ -204,28 +205,27 @@ def tempctrl_shape_type(self, context):
|
||||
ctrl.custom_shape_translation = (0, 0, 0)
|
||||
ctrl.custom_shape_rotation_euler = (0, 0, 0)
|
||||
continue
|
||||
|
||||
if org_bone.custom_shape_transform is not None:# and ctrl.custom_shape_transform is None:
|
||||
|
||||
if org_bone.custom_shape_transform is not None and ctrl.custom_shape_transform is None:
|
||||
#check if the transform bone shape already exists
|
||||
transform_bonename = org_bone.custom_shape_transform.name
|
||||
if transform_bonename in ctrl.id_data.pose.bones:
|
||||
# If it already exists then find it
|
||||
ctrl.custom_shape_transform = ctrl.id_data.pose.bones[transform_bonename]
|
||||
else:
|
||||
#add an extra transform bone, if it doesnt exist
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
boneshape = add_ctrl_bone(rig, org_bone.custom_shape_transform, rig.data.edit_bones[ctrl.name].parent, '')
|
||||
transform_bonename = boneshape.name
|
||||
add_bone_to_collection(rig, boneshape)
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
|
||||
continue
|
||||
#add an extra transform bone, if it doesnt exist
|
||||
rig = ctrl.id_data
|
||||
posebone = rig.pose.bones[transform_bonename]
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
boneshape = add_ctrl_bone(rig, org_bone.custom_shape_transform, rig.data.edit_bones[ctrl.name].parent, '')
|
||||
bone_name = boneshape.name
|
||||
add_bone_to_collection(rig, boneshape)
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
posebone = rig.pose.bones[bone_name]
|
||||
constraint_add(posebone, org_bone.custom_shape_transform, 'COPY_TRANSFORMS')
|
||||
ctrl.custom_shape_transform = posebone
|
||||
else:
|
||||
# scale = (length_avg / ctrl.length)*0.4 + 0.4
|
||||
scale = 1
|
||||
# print('drawing shape in scale of ', scale)
|
||||
ctrl.custom_shape = draw_wgt(scale, ctrl, shape = self.shape_type)
|
||||
ctrl.custom_shape_scale_xyz = tuple([self.shape_size]*3)
|
||||
ctrl.custom_shape_transform = None
|
||||
@@ -1466,11 +1466,6 @@ def smartbake_to_ik(context, posebones, chain, sb):
|
||||
|
||||
#create the fcurves and add them to smartfcurves
|
||||
for ctrl in ctrls:
|
||||
if ctrl == chain.ik_tip and ctrl != chain.ik_ctrl:
|
||||
continue
|
||||
# if chain.pole_bone and ctrl == chain.base_bone:
|
||||
# continue
|
||||
|
||||
ctrl_action = ctrl.id_data.animation_data.action
|
||||
path = ctrl.path_from_id()
|
||||
rot = Tools.rot_mode_to_channel(ctrl.rotation_mode)
|
||||
@@ -1909,7 +1904,7 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
|
||||
#Store the influence and set them to 0 before calculating the matrix without the constraint (to get the offset)
|
||||
con_influence = get_con_influence(constrained)
|
||||
|
||||
if chain and chain.pole_bone is not None:
|
||||
if chain:
|
||||
# Adding the pole bone to the end of the list
|
||||
bones_matrices.update({chain.pole_bone : None})
|
||||
bones_matrices[chain.pole_bone] = bones_matrices.pop(chain.pole_bone)
|
||||
@@ -1929,23 +1924,11 @@ def smartbake_write_keyframes(scene, smartframes, smartfcus, chain = None, bake_
|
||||
else:
|
||||
# Get the rest of the bones to check if they are children and if we need viewlayer update
|
||||
bones = set(bones_matrices.keys()).difference(pasted_bones)
|
||||
|
||||
|
||||
# Calculating pole target matrix after other bones were calcluated
|
||||
if chain and bone == chain.pole_bone:
|
||||
base_bone = chain.base_bone
|
||||
ik_tip = chain.ik_tip
|
||||
angle = chain.base_bone.vector.angle(chain.ik_tip.vector)
|
||||
|
||||
if not round(angle):
|
||||
# continue
|
||||
# If the angle is flat then use the position of the pole relative to the rest position base bone
|
||||
relative_matrix = base_bone.bone.matrix_local.inverted() @ chain.pole_bone.bone.matrix_local
|
||||
matrix = base_bone.matrix @ relative_matrix
|
||||
# print(frame, 'angle is 0 using base bone matrix')
|
||||
|
||||
else:
|
||||
bpy.context.view_layer.update()
|
||||
matrix = find_pole_vector(base_bone, ik_tip, chain.pole_bone, chain.step)
|
||||
bpy.context.view_layer.update()
|
||||
matrix = find_pole_vector(chain.base_bone, chain.ik_tip, chain.pole_bone, chain.step)
|
||||
|
||||
Tools.paste_bone_matrix(bone, matrix, constrained, bones, x_filter = False)
|
||||
pasted_bones.add(bone)
|
||||
@@ -4151,7 +4134,7 @@ def assign_setup_ids(self, context, ctrls, selected, child_ctrls, setup, setup_i
|
||||
#Assign group, color, matrix and setup ids in pose mode
|
||||
for ctrl, bone in zip(ctrls, selected):
|
||||
ctrl.matrix = get_relative_ws_matrix(bone, ctrl)
|
||||
|
||||
|
||||
#assign the controller to a group
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
ctrl.bone_group = ctrl_group
|
||||
@@ -4193,7 +4176,6 @@ def assign_setup_ids(self, context, ctrls, selected, child_ctrls, setup, setup_i
|
||||
|
||||
#get custom shape and assign the matrix
|
||||
if bone.custom_shape_transform and self.shape_type == 'ORIGINAL':
|
||||
obj_mat = bone.id_data.matrix_world
|
||||
ot_bone = bone.custom_shape_transform.name
|
||||
#Get the original override transform bone
|
||||
target = bone.id_data.pose.bones[ot_bone]
|
||||
@@ -5328,16 +5310,14 @@ def pole_prop_edit(self, context):
|
||||
else:
|
||||
add_bone_to_collection(rig, rig.data.edit_bones[chain.base_bone.name], col_name = 'IK Ctrls', visible = True)
|
||||
#remove the pole bone and switch to base bone
|
||||
if chain.pole_bone is None:
|
||||
if not hasattr(chain, 'pole_bone'):
|
||||
continue
|
||||
rig.data.edit_bones.remove(rig.data.edit_bones[chain.pole_bone_name])
|
||||
#remove from ctrls and append base bone instead
|
||||
if chain.pole_bone in ctrls:
|
||||
ctrls.remove(chain.pole_bone)
|
||||
ctrls.append(chain.base_bone)
|
||||
|
||||
chain.pole_bone = chain.pole_bone_name = None
|
||||
# del chain.pole_bone, chain.pole_bone_name
|
||||
del chain.pole_bone, chain.pole_bone_name
|
||||
|
||||
#Remove child ctrls
|
||||
if btc.child:
|
||||
@@ -5350,17 +5330,13 @@ def pole_prop_pose(self, context):
|
||||
if not btc.pole_target:
|
||||
chain.base_bone.btc.org = 'CTRL'
|
||||
|
||||
# if not hasattr(chain, 'pole_bone'):
|
||||
# continue
|
||||
if not chain.pole_bone:
|
||||
continue
|
||||
if not chain.pole_bone_name:
|
||||
continue
|
||||
chain.pole_bone = chain.pole_bone_name = None
|
||||
# del chain.pole_bone
|
||||
# if hasattr(chain,'pole_bone_name'):
|
||||
# chain.pole_bone_name
|
||||
# continue
|
||||
if not hasattr(chain, 'pole_bone'):
|
||||
continue
|
||||
|
||||
del chain.pole_bone
|
||||
if hasattr(chain,'pole_bone_name'):
|
||||
chain.pole_bone_name
|
||||
continue
|
||||
|
||||
pole_posebone_update(chain, ctrls)
|
||||
if chain.base_bone in ctrls:
|
||||
@@ -5437,9 +5413,7 @@ def ik_ctrl_orientation(self, context):
|
||||
|
||||
def pole_posebone_update(chain, ctrls):
|
||||
'''update pole bone properties in the pole prop and add ik prop'''
|
||||
# if not hasattr(chain, 'pole_bone_name'):
|
||||
# return
|
||||
if not chain.pole_bone_name:
|
||||
if not hasattr(chain, 'pole_bone_name'):
|
||||
return
|
||||
|
||||
chain.pole_bone = rig.pose.bones[chain.pole_bone_name]
|
||||
@@ -5473,8 +5447,6 @@ def update_axis_prop(self, context):
|
||||
|
||||
if not hasattr(chain, 'pole_bone_name'):
|
||||
continue
|
||||
if not chain.pole_bone_name:
|
||||
continue
|
||||
pole_matrix = find_pole_vector(base_bone, ik_tip, ik_tip, chain.step)
|
||||
|
||||
#pole matrix orientation to world by default
|
||||
@@ -5579,6 +5551,15 @@ def add_pole_bone(self, context, rig, chain):
|
||||
new_rot = mathutils.Euler((0, 0, 0), 'XYZ')
|
||||
pole_matrix = Matrix.LocRotScale(loc, new_rot, scale)
|
||||
|
||||
#In case of a flat IK skip adding a pole bone and use base bone instead
|
||||
# if pole_matrix.translation == chain.ik_tip.matrix.translation:
|
||||
# print('no pole bone')
|
||||
# self.report({'ERROR'}, "Can't add Pole Ctrl because of a flat IK chain")
|
||||
# chain.pole_bone = None
|
||||
# add_bone_to_collection(rig, chain.base_bone, col_name = 'IK Ctrls', visible = True)
|
||||
# btc['pole_target'] = False
|
||||
# return
|
||||
|
||||
pole_bone_name = chain.org_bones[-2].name + '_Pole' if len(chain.org_bones) > 1 else chain.org_bones[0].name + '_Pole'
|
||||
chain.pole_bone = rig.data.edit_bones.new(pole_bone_name)
|
||||
|
||||
@@ -5601,9 +5582,7 @@ def pole_offset(self, context):
|
||||
global ik_chains, ctrls, child_names
|
||||
|
||||
for chain in ik_chains:
|
||||
# if not hasattr(chain, 'pole_bone_name'):
|
||||
# continue
|
||||
if not chain.pole_bone_name:
|
||||
if not hasattr(chain, 'pole_bone_name'):
|
||||
continue
|
||||
chain.pole_bone = rig.pose.bones[chain.pole_bone_name]
|
||||
|
||||
@@ -5642,7 +5621,7 @@ def add_ik_prop_edit(self, context):
|
||||
chain.ik_tip_name = chain.ik_tip.name
|
||||
|
||||
#remove the pole bone
|
||||
if btc.pole_target and chain.pole_bone_name:
|
||||
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
|
||||
#removing and adding the pole_target without calling the whole pole prop update
|
||||
ctrls.remove(chain.pole_bone)
|
||||
rig.data.edit_bones.remove(rig.data.edit_bones[chain.pole_bone_name])
|
||||
@@ -5675,7 +5654,7 @@ def add_ik_prop_pose(self, context):
|
||||
chain.ik_ctrl.btc.org = 'CTRL'
|
||||
|
||||
chain.ik_ctrl.color.palette = context.scene.btc.color_set
|
||||
if btc.pole_target and chain.pole_bone_name: #hasattr(chain, 'pole_bone_name'):
|
||||
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
|
||||
pole_posebone_update(chain, ctrls)
|
||||
|
||||
add_bone_to_collection(rig, chain.ik_ctrl, col_name = 'IK Ctrls', visible = True)
|
||||
@@ -5803,7 +5782,7 @@ class TempIK(bpy.types.Operator):
|
||||
# for ctrl in ctrls:
|
||||
# add_bone_to_collection(rig, ctrl, col_name = 'ORG', visible = True)
|
||||
chain = IK_Chain(hierarchy, ctrls, root_ctrl)
|
||||
|
||||
|
||||
#if only one bone is selected in the chain then add an extra control automatically
|
||||
if len(hierarchy) == 1:
|
||||
add_ik_ctrl = True
|
||||
@@ -5812,7 +5791,7 @@ class TempIK(bpy.types.Operator):
|
||||
for i, ctrl in enumerate(ctrls[:-1]):
|
||||
ctrls[i+1].tail = ctrl.head
|
||||
context.view_layer.update()
|
||||
# return {'FINISHED'}
|
||||
|
||||
switch_layers(rig, chain.ik_tip, [31])
|
||||
add_bone_to_collection(rig, chain.ik_tip)
|
||||
add_bone_to_collection(rig, chain.ik_ctrl, col_name = 'IK Ctrls', visible = True)
|
||||
@@ -5821,7 +5800,7 @@ class TempIK(bpy.types.Operator):
|
||||
# rig.data.collections['ORG'].is_visible = False
|
||||
|
||||
ik_chains.append(chain)
|
||||
|
||||
|
||||
btc['add_ik_ctrl'] = add_ik_ctrl
|
||||
if add_ik_ctrl:
|
||||
add_ik_prop_edit(self, context)
|
||||
@@ -5845,7 +5824,8 @@ class TempIK(bpy.types.Operator):
|
||||
|
||||
####################################################################
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
|
||||
|
||||
|
||||
setup_ids = set()
|
||||
|
||||
if btc.root:
|
||||
@@ -5878,22 +5858,20 @@ class TempIK(bpy.types.Operator):
|
||||
# #assign the matrix
|
||||
distance = (bone.id_data.matrix_world @ bone.bone.matrix_local).inverted() @ ctrl.bone.matrix_local.copy()
|
||||
ctrl.matrix = bone.id_data.matrix_world @ bone.matrix @ distance
|
||||
# context.view_layer.update()
|
||||
|
||||
ctrl.color.palette = btc.color_set
|
||||
|
||||
add_bone_setup_id(chain.ik_ctrl, False, setup, 'CTRL', setup_id, org_id = chain.ik_ctrl.btc.org_id)
|
||||
|
||||
|
||||
if add_ik_ctrl:
|
||||
add_ik_prop_pose(self, context)
|
||||
|
||||
|
||||
context.view_layer.update()
|
||||
pole_prop_pose(self, context)
|
||||
|
||||
# child_prop_pose(context)
|
||||
if context.scene.btc.child:
|
||||
child_prop(context.scene.btc, context)
|
||||
|
||||
# return {'FINISHED'}
|
||||
self.ik_chains = ik_chains
|
||||
tempctrl_shape_type(self, context)
|
||||
|
||||
@@ -5907,7 +5885,7 @@ class TempIK(bpy.types.Operator):
|
||||
if 'ctrls' not in globals():
|
||||
self.report({'INFO'},'Not available. Please update the Temp Ctrls from the addon panel')
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
btc = context.scene.btc
|
||||
controlled_objs = {item.controlled for item in context.scene.btc.ctrl_items if item.controlled}
|
||||
hidden_objs = {obj for obj in context.view_layer.objects if obj and obj.hide_get()}
|
||||
@@ -5974,7 +5952,7 @@ class TempIK(bpy.types.Operator):
|
||||
rig.data.edit_bones[ctrl.name].parent = rig.data.edit_bones[chain.ctrls[i+1].name]
|
||||
|
||||
#updating the polebone position with the offset
|
||||
if btc.pole_target and chain.pole_bone_name: #hasattr(chain, 'pole_bone_name'):
|
||||
if btc.pole_target and hasattr(chain, 'pole_bone_name'):
|
||||
pole_bone = rig.data.edit_bones[chain.pole_bone_name]
|
||||
base_bone = rig.data.edit_bones[chain.base_bone_name]
|
||||
ik_tip = rig.data.edit_bones[chain.ik_tip_name]
|
||||
@@ -6103,8 +6081,7 @@ class TempIK(bpy.types.Operator):
|
||||
#add the ik constraint to the ctrls
|
||||
ik_con = constraint_add(chain.ik_tip, chain.ik_ctrl if not btc.child else chain.ik_child_ctrl, 'IK')
|
||||
|
||||
if chain.pole_bone:
|
||||
chain.pole_angle = get_pole_angle(chain.base_bone, chain.ik_tip, chain.pole_bone.matrix.translation)
|
||||
chain.pole_angle = get_pole_angle(chain.base_bone, chain.ik_tip, chain.pole_bone.matrix.translation)
|
||||
|
||||
ik_con.chain_count = chain.length(btc.add_ik_ctrl)
|
||||
#setup the ik constraint
|
||||
@@ -6339,8 +6316,6 @@ class IK_Chain:
|
||||
self.ik_ctrl_name = self.ik_ctrl.name
|
||||
self.base_bone_name = self.base_bone.name
|
||||
self.ik_tip_name = self.ik_tip.name
|
||||
self.pole_bone = None
|
||||
self.pole_bone_name = None
|
||||
|
||||
self.step = get_step(hierarchy[0].id_data)
|
||||
|
||||
@@ -6362,7 +6337,7 @@ class IK_Chain:
|
||||
self.parent = rig.pose.bones[self.parent_name]
|
||||
if hasattr(self, 'root_name'):
|
||||
self.root_ctrl = rig.pose.bones[self.root_name]
|
||||
if self.pole_bone_name:
|
||||
if hasattr(self, 'pole_bone_name'):
|
||||
self.pole_bone = rig.pose.bones[self.pole_bone_name]
|
||||
# if hasattr(self, 'pole_bone_ref_name'):
|
||||
# self.pole_bone_ref = rig.pose.bones[self.pole_bone_ref_name]
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
bl_info = {
|
||||
"name": "AnimToolBox",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (0, 2, 3),
|
||||
"version" : (0, 2, 0),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "A set of animation tools",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_check": "2026-02-09 15:54:54.419194",
|
||||
"backup_date": "February-9-2026",
|
||||
"last_check": "",
|
||||
"backup_date": "",
|
||||
"update_ready": false,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import bpy
|
||||
|
||||
class GizmoSizeUp(bpy.types.Operator):
|
||||
"""Share keyframes between all the selected objects and bones"""
|
||||
bl_idname = "view3d.gizmo_size_up"
|
||||
bl_label = "Gizmo_Size_Up"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
context.preferences.view.gizmo_size += context.scene.animtoolbox.gizmo_size
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
class GizmoSizeDown(bpy.types.Operator):
|
||||
"""Share keyframes between all the selected objects and bones"""
|
||||
bl_idname = "view3d.gizmo_size_down"
|
||||
bl_label = "Gizmo_Size_Down"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
context.preferences.view.gizmo_size -= context.scene.animtoolbox.gizmo_size
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
########################################################################################################################
|
||||
|
||||
def clear_isolate_pose_mode(scene):
|
||||
if not len(scene.animtoolbox.isolated):
|
||||
return
|
||||
for obj in scene.animtoolbox.isolated:
|
||||
if not obj.hidden:
|
||||
continue
|
||||
obj.hidden.hide_set(False)
|
||||
scene.animtoolbox.isolated.clear()
|
||||
scene.animtoolbox.active_obj = None
|
||||
|
||||
def isolate_pose_mode(scene):
|
||||
context = bpy.context
|
||||
#return when going out of isolate pose or when active object is not in pose mode
|
||||
if not scene.animtoolbox.isolate_pose_mode or context.active_object.mode != 'POSE':
|
||||
clear_isolate_pose_mode(scene)
|
||||
return
|
||||
|
||||
#handler continue only if the active object is None otherwise it collects all armature objects
|
||||
if scene.animtoolbox.active_obj is None:
|
||||
scene.animtoolbox.active_obj = context.active_object
|
||||
else:
|
||||
return
|
||||
|
||||
isolated = scene.animtoolbox.isolated
|
||||
for obj in context.view_layer.objects:
|
||||
if obj.type != 'ARMATURE':
|
||||
continue
|
||||
if obj.hide_get():
|
||||
continue
|
||||
rig = isolated.add()
|
||||
if obj.mode == 'POSE':
|
||||
rig.selected = obj
|
||||
else:
|
||||
rig.hidden = obj
|
||||
obj.hide_set(True)
|
||||
|
||||
class IsolatePoseMode(bpy.types.Operator):
|
||||
"""Isolates armatures during pose mode"""
|
||||
bl_idname = "anim.isolate_pose_mode"
|
||||
bl_label = "Isolate Pose Mode"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def execute(self, context):
|
||||
|
||||
# If the modal is already running, then don't run it the second time
|
||||
scene = context.scene
|
||||
if scene.animtoolbox.isolate_pose_mode:
|
||||
if isolate_pose_mode in bpy.app.handlers.depsgraph_update_pre:
|
||||
clear_isolate_pose_mode(scene)
|
||||
bpy.app.handlers.depsgraph_update_pre.remove(isolate_pose_mode)
|
||||
scene.animtoolbox.isolate_pose_mode = False
|
||||
return {'FINISHED'}
|
||||
|
||||
scene.animtoolbox.isolate_pose_mode = True
|
||||
isolate_pose_mode(scene)
|
||||
if isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre:
|
||||
bpy.app.handlers.depsgraph_update_pre.append(isolate_pose_mode)
|
||||
return {'FINISHED'}
|
||||
|
||||
class SwitchBoneCollectionsVisibility(bpy.types.Operator):
|
||||
"""Turn all bone collections visible and then press again to switch back"""
|
||||
bl_idname = "anim.switch_collections_visibility"
|
||||
bl_label = "Bone Collections Visibility"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.app.version >= (4, 0, 0)
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
if obj.type != 'ARMATURE':
|
||||
return {'CANCELLED'}
|
||||
if not obj.animation_data:
|
||||
self.report({'INFO'}, 'No animation is available')
|
||||
return {'CANCELLED'}
|
||||
|
||||
if not obj.animation_data.action:
|
||||
self.report({'INFO'}, 'No animation is available')
|
||||
return {'CANCELLED'}
|
||||
|
||||
collections = obj.data.collections
|
||||
|
||||
if not len(collections):
|
||||
self.report({'INFO'}, 'No collections are available')
|
||||
return {'CANCELLED'}
|
||||
#check if there are collections that are marked with
|
||||
tagged_col = ['atb' in col.keys() for col in collections]
|
||||
atb_ui = context.scene.animtoolbox
|
||||
|
||||
if any(tagged_col) and atb_ui.col_vis:
|
||||
#collections are already marked so return to previous collection visibilty
|
||||
for col in collections:
|
||||
if 'atb' in col.keys():
|
||||
col.is_visible = col['atb']
|
||||
del col['atb']
|
||||
atb_ui.col_vis = False
|
||||
else:
|
||||
#Mark visible collections and turn collections with animated bones on
|
||||
animated_bones = set()
|
||||
start = 'pose.bones["'
|
||||
end = '"]'
|
||||
#get all the animated bones from the fcurves
|
||||
for fcu in obj.animation_data.action.fcurves:
|
||||
start_index = fcu.data_path.find(start)
|
||||
end_index = fcu.data_path.find(end)
|
||||
#if it's not a posebone fcurve then skip
|
||||
if start_index == -1 or end_index == -1:
|
||||
continue
|
||||
animated_bones.add(fcu.data_path[start_index + len(start):end_index])
|
||||
|
||||
#check if the collecetion that is turned off has animated bones
|
||||
find_anim = []
|
||||
for col in collections:
|
||||
for bone in col.bones:
|
||||
if bone.name in animated_bones and not col.is_visible:
|
||||
# print(bone.name, 'in ', col.name)
|
||||
find_anim.append(col)
|
||||
break
|
||||
|
||||
if not find_anim:
|
||||
self.report({'INFO'}, 'No collections with animated bones and no visibility are found')
|
||||
return {'CANCELLED'}
|
||||
|
||||
#Turn on collections without visiblity
|
||||
for col in collections:
|
||||
if col in find_anim:
|
||||
#tag visibility
|
||||
col['atb'] = col.is_visible
|
||||
col.is_visible = True
|
||||
|
||||
atb_ui.col_vis = True
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
classes = (GizmoSizeUp, GizmoSizeDown, IsolatePoseMode, SwitchBoneCollectionsVisibility)
|
||||
|
||||
def register():
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
def unregister():
|
||||
from bpy.utils import unregister_class
|
||||
for cls in classes:
|
||||
unregister_class(cls)
|
||||
@@ -1,549 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import bpy
|
||||
from mathutils import Matrix, Vector
|
||||
from math import radians
|
||||
import numpy
|
||||
|
||||
def draw_wgt(boneLength, bone):
|
||||
suffix = bone.id_data.name + '_' + bone.name
|
||||
if 'WGTB_object' + suffix in bpy.data.objects:
|
||||
obj = bpy.data.objects['WGTB_object'] + suffix
|
||||
if 'WGTB_shape' + suffix in obj.data.name:
|
||||
return obj
|
||||
mesh = bpy.data.meshes.new('WGTB_shape_' + suffix)
|
||||
obj = bpy.data.objects.new('WGTB_object_' + suffix, mesh)
|
||||
#coordinates of the sphere widget shape
|
||||
sphere = {"edges": [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 14], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [19, 20], [20, 21], [21, 22], [22, 23], [0, 23], [24, 25], [25, 26], [26, 27], [27, 28], [28, 29], [29, 30], [30, 31], [31, 32], [32, 33], [33, 34], [34, 35], [35, 36], [36, 37], [37, 38], [38, 39], [39, 40], [40, 41], [41, 42], [42, 43], [43, 44], [44, 45], [45, 46], [46, 47], [24, 47], [48, 49], [49, 50], [50, 51], [51, 52], [52, 53], [53, 54], [54, 55], [55, 56], [56, 57], [57, 58], [58, 59], [59, 60], [60, 61], [61, 62], [62, 63], [63, 64], [64, 65], [65, 66], [66, 67], [67, 68], [68, 69], [69, 70], [70, 71], [48, 71]],
|
||||
"vertices": [[0.0, 0.10000002384185791, 0.0], [-0.025881901383399963, 0.09659260511398315, 0.0], [-0.050000011920928955, 0.08660250902175903, 0.0], [-0.07071065902709961, 0.07071065902709961, 0.0], [-0.08660256862640381, 0.04999998211860657, 0.0], [-0.09659260511398315, 0.025881901383399963, 0.0], [-0.10000002384185791, 7.549793679118011e-09, 0.0], [-0.09659260511398315, -0.02588188648223877, 0.0], [-0.08660256862640381, -0.04999998211860657, 0.0], [-0.07071071863174438, -0.07071065902709961, 0.0], [-0.050000011920928955, -0.08660250902175903, 0.0], [-0.02588193118572235, -0.09659260511398315, 0.0], [-3.894143674187944e-08, -0.10000002384185791, 0.0], [0.025881856679916382, -0.09659260511398315, 0.0], [0.04999995231628418, -0.08660256862640381, 0.0], [0.07071065902709961, -0.07071071863174438, 0.0], [0.08660250902175903, -0.05000004172325134, 0.0], [0.09659254550933838, -0.025881946086883545, 0.0], [0.10000002384185791, -4.649123752642481e-08, 0.0], [0.09659260511398315, 0.025881856679916382, 0.0], [0.08660256862640381, 0.04999995231628418, 0.0], [0.07071071863174438, 0.07071065902709961, 0.0], [0.05000007152557373, 0.08660250902175903, 0.0], [0.025881975889205933, 0.09659254550933838, 0.0], [0.0, 7.450580596923828e-09, 0.10000002384185791], [-0.025881901383399963, 7.450580596923828e-09, 0.09659260511398315], [-0.050000011920928955, 7.450580596923828e-09, 0.08660250902175903], [-0.07071065902709961, 7.450580596923828e-09, 0.07071065902709961], [-0.08660256862640381, 3.725290298461914e-09, 0.04999998211860657], [-0.09659260511398315, 1.862645149230957e-09, 0.025881901383399963], [-0.10000002384185791, 8.881784197001252e-16, 7.549793679118011e-09], [-0.09659260511398315, -1.862645149230957e-09, -0.02588188648223877], [-0.08660256862640381, -3.725290298461914e-09, -0.04999998211860657], [-0.07071071863174438, -7.450580596923828e-09, -0.07071065902709961], [-0.050000011920928955, -7.450580596923828e-09, -0.08660250902175903], [-0.02588193118572235, -7.450580596923828e-09, -0.09659260511398315], [-3.894143674187944e-08, -7.450580596923828e-09, -0.10000002384185791], [0.025881856679916382, -7.450580596923828e-09, -0.09659260511398315], [0.04999995231628418, -7.450580596923828e-09, -0.08660256862640381], [0.07071065902709961, -7.450580596923828e-09, -0.07071071863174438], [0.08660250902175903, -3.725290298461914e-09, -0.05000004172325134], [0.09659254550933838, -1.862645149230957e-09, -0.025881946086883545], [0.10000002384185791, -3.552713678800501e-15, -4.649123752642481e-08], [0.09659260511398315, 1.862645149230957e-09, 0.025881856679916382], [0.08660256862640381, 3.725290298461914e-09, 0.04999995231628418], [0.07071071863174438, 7.450580596923828e-09, 0.07071065902709961], [0.05000007152557373, 7.450580596923828e-09, 0.08660250902175903], [0.025881975889205933, 7.450580596923828e-09, 0.09659254550933838], [-7.450580596923828e-09, 4.440892098500626e-16, 0.10000002384185791], [-9.313225746154785e-09, -0.025881901383399963, 0.09659260511398315], [-1.1175870895385742e-08, -0.050000011920928955, 0.08660250902175903], [-1.4901161193847656e-08, -0.07071065902709961, 0.07071065902709961], [-7.450580596923828e-09, -0.08660256862640381, 0.04999998211860657], [-7.450580596923828e-09, -0.09659260511398315, 0.025881901383399963], [-7.450580596923828e-09, -0.10000002384185791, 7.549793679118011e-09], [-7.450580596923828e-09, -0.09659260511398315, -0.02588188648223877], [0.0, -0.08660256862640381, -0.04999998211860657], [0.0, -0.07071071863174438, -0.07071065902709961], [3.725290298461914e-09, -0.050000011920928955, -0.08660250902175903], [5.587935447692871e-09, -0.02588193118572235, -0.09659260511398315], [7.450577044210149e-09, -3.894143674187944e-08, -0.10000002384185791], [9.313225746154785e-09, 0.025881856679916382, -0.09659260511398315], [1.1175870895385742e-08, 0.04999995231628418, -0.08660256862640381], [1.4901161193847656e-08, 0.07071065902709961, -0.07071071863174438], [7.450580596923828e-09, 0.08660250902175903, -0.05000004172325134], [7.450580596923828e-09, 0.09659254550933838, -0.025881946086883545], [7.450580596923828e-09, 0.10000002384185791, -4.649123752642481e-08], [7.450580596923828e-09, 0.09659260511398315, 0.025881856679916382], [0.0, 0.08660256862640381, 0.04999995231628418], [0.0, 0.07071071863174438, 0.07071065902709961], [-3.725290298461914e-09, 0.05000007152557373, 0.08660250902175903], [-5.587935447692871e-09, 0.025881975889205933, 0.09659254550933838]], "faces": []}
|
||||
mesh.from_pydata(numpy.array(sphere['vertices'])*[boneLength, boneLength, boneLength] , sphere['edges'], sphere['faces'])
|
||||
|
||||
return obj
|
||||
|
||||
def add_driver(obj, posebone, control, target, path, multiply = ''):
|
||||
|
||||
if isinstance(target, tuple):
|
||||
attr = posebone.driver_add(target[0], target[1])
|
||||
else:
|
||||
attr = posebone.driver_add(target)
|
||||
|
||||
var = attr.driver.variables.new()
|
||||
|
||||
var.targets[0].id = obj
|
||||
var.targets[0].data_path = 'pose.bones["' + control +'"].'+ path
|
||||
attr.driver.expression = var.name + multiply
|
||||
|
||||
def dup_values(source, target):
|
||||
if hasattr(source, 'parent'):
|
||||
target.parent = source.parent
|
||||
for prop in dir(source):
|
||||
if not hasattr(target, prop):
|
||||
continue
|
||||
value = getattr(source, prop)
|
||||
if type(value) not in {int, float, bool, str, Vector, Matrix, bpy.types.Object}:
|
||||
continue
|
||||
if '__' in prop[:2] and '__' in prop[-2:]:
|
||||
continue
|
||||
if target.is_property_readonly(prop):
|
||||
continue
|
||||
setattr(target, prop, value)
|
||||
|
||||
return target
|
||||
|
||||
def dup_constraints(source, target):
|
||||
if not source.constraints.items():
|
||||
return
|
||||
for source_con in source.constraints:
|
||||
target_con = target.constraints.new(source_con.type)
|
||||
dup_values(source_con, target_con)
|
||||
|
||||
def add_vis_bone_con(obj, bone_vis_name, bone_wgt_name):
|
||||
bone_vis = obj.pose.bones[bone_vis_name]
|
||||
con = bone_vis.constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
con.subtarget = bone_wgt_name
|
||||
|
||||
return bone_vis
|
||||
|
||||
class target:
|
||||
def __init__(self, bone):
|
||||
self.name = bone.name
|
||||
self.point = tuple(bone.tail)
|
||||
self.ctrl = 'TRGT_' + bone.name
|
||||
if bone.parent:
|
||||
self.parent = bone.parent.name
|
||||
#print('assign parent to target ', self.name, self.ctrl, self.parent)
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.point < other.point
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.point)
|
||||
|
||||
def __eq__(self, other):
|
||||
#if not isinstance(other, type(self)):
|
||||
# return NotImplemented
|
||||
return self.point == other.point
|
||||
|
||||
class parent:
|
||||
def __init__(self, bone):
|
||||
self.name = bone.name
|
||||
self.point = tuple(bone.head)
|
||||
self.ctrl = 'CTRL_' + bone.name
|
||||
if bone.parent:
|
||||
self.parent = bone.parent.name
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.point < other.point
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.point)
|
||||
|
||||
def __eq__(self, other):
|
||||
#if not isinstance(other, type(self)):
|
||||
# return NotImplemented
|
||||
return self.point == other.point
|
||||
|
||||
class constraint_dup:
|
||||
def __init__(self, bone, con):
|
||||
self.name = con.name
|
||||
self.target = con.target
|
||||
self.subtarget = con.subtarget
|
||||
self.bone = bone.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.bone)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.bone == other.bone
|
||||
|
||||
def bone_orientation(source, target, value):
|
||||
source.align_orientation(target)
|
||||
x, y, z = source.matrix.to_3x3().col
|
||||
R = (Matrix.Translation(source.head) @ Matrix.Rotation(radians(value), 4, x) @ Matrix.Translation(-source.head))
|
||||
source.transform(R, roll = False)
|
||||
source.align_roll(target.vector)
|
||||
|
||||
def find_ctrl(bone, controls):
|
||||
i = list(controls).index(bone)
|
||||
bone.ctrl = list(controls)[i].ctrl
|
||||
|
||||
return bone.ctrl
|
||||
|
||||
def add_controlers(self, obj, parents, targets):
|
||||
|
||||
#controls = set(parents).union(targets)
|
||||
controls = set(parents + targets)
|
||||
|
||||
#create hierarchy
|
||||
for bone in controls:
|
||||
editbone = obj.data.edit_bones[bone.name]
|
||||
if editbone.parent is None:
|
||||
continue
|
||||
parentnames = [bone.name for bone in parents]
|
||||
#if a target and its parent are part of the hierarchy then linked to its own bone parent
|
||||
if bone in targets and bone not in parents and editbone.parent.name in parentnames:
|
||||
parentbone = parent(editbone)
|
||||
else:
|
||||
parentbone = parent(editbone.parent)
|
||||
|
||||
if parentbone in controls and parentbone != bone:
|
||||
bone.parent = find_ctrl(parentbone, controls)
|
||||
else:
|
||||
bone.parent = editbone.parent.name
|
||||
|
||||
|
||||
edit_bones = obj.data.edit_bones
|
||||
for bone in controls:
|
||||
editbone = edit_bones[bone.name]
|
||||
ctrl = obj.data.edit_bones.new(bone.ctrl)
|
||||
ctrl.head = bone.point
|
||||
ctrl.tail = bone.point
|
||||
ctrl.tail[2] = bone.point[2] + (editbone.length / 3)
|
||||
ctrl.bbone_x = editbone.bbone_x
|
||||
ctrl.bbone_z = editbone.bbone_z
|
||||
ctrl.use_deform = False
|
||||
if self.bone_align:
|
||||
angle = 90 if self.align_90 else 0
|
||||
bone_orientation(ctrl, editbone, angle)
|
||||
if angle == 90:
|
||||
ctrl.align_roll(editbone.vector)
|
||||
else:
|
||||
ctrl.roll = editbone.roll
|
||||
|
||||
#apply hierarchy
|
||||
for bone in parents:
|
||||
editbone = edit_bones[bone.name]
|
||||
ctrl_name = find_ctrl(bone, controls)
|
||||
ctrl = edit_bones[ctrl_name]
|
||||
editbone.parent = ctrl
|
||||
|
||||
for bone in controls:
|
||||
ctrl = edit_bones[bone.ctrl]
|
||||
if hasattr(bone, 'parent'):
|
||||
ctrl.parent = edit_bones[bone.parent]
|
||||
|
||||
return controls
|
||||
|
||||
def pose_bbone_setup(bone, posebone, bbone_group = None):
|
||||
#add the custom shape to the widget bones
|
||||
custom_shape = draw_wgt(bone['length'], posebone)
|
||||
posebone.custom_shape = custom_shape
|
||||
posebone.use_custom_shape_bone_size = False
|
||||
if bbone_group:
|
||||
posebone.bone_group = bbone_group
|
||||
posebone.rotation_mode = 'XZY'
|
||||
posebone.lock_rotation[0] = True
|
||||
posebone.lock_rotation[2] = True
|
||||
|
||||
#####MAIN####
|
||||
class BboneWidgets(bpy.types.Operator):
|
||||
"""Add Bbone widget controls to the selected bones"""
|
||||
bl_idname = "armature.add_bbone_widgets"
|
||||
bl_label = "Add_Bbone_widgets"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.context.object.type == 'ARMATURE'
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
|
||||
obj.data.display_type = 'BBONE'
|
||||
|
||||
bones = []
|
||||
parentlayers = [False if i != 24 else True for i in range(32)]
|
||||
wgtlayers = [True if i == 0 else False for i in range(32)]
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
obj.data.use_mirror_x = False
|
||||
for bone in obj.data.edit_bones:
|
||||
if not bone.select:
|
||||
continue
|
||||
if bone.bbone_segments == 1:
|
||||
bone.bbone_segments = 10
|
||||
bone.bbone_handle_type_start = 'TANGENT'
|
||||
bone.bbone_handle_type_end = 'TANGENT'
|
||||
bone_name = bone.name
|
||||
#add parent bone to the Bbone widgets
|
||||
parent = obj.data.edit_bones.new('WGTB_parent_'+ bone_name)
|
||||
parent_name = parent.name
|
||||
dup_values(bone, parent)
|
||||
parent.name = parent_name
|
||||
parent.select = False
|
||||
parent.select_head = False
|
||||
parent.select_tail = False
|
||||
|
||||
#change layer of the parent bone
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
parent.layers = parentlayers
|
||||
|
||||
#add bbone widget bones
|
||||
head_widget = obj.data.edit_bones.new('Bhead_'+ bone.name)
|
||||
head_widget.parent = parent
|
||||
#head_widget.head = bone.head
|
||||
head_widget.head = bone.head + (bone.tail - bone.head) * 0.25
|
||||
#head_widget.tail = (bone.tail - bone.head)/10
|
||||
head_widget.length = bone.length * 0.1
|
||||
head_widget.bbone_x = bone.bbone_x
|
||||
head_widget.bbone_z = bone.bbone_z
|
||||
head_widget.align_orientation(bone)
|
||||
head_widget.inherit_scale = 'NONE'
|
||||
head_name = head_widget.name
|
||||
|
||||
tail_widget = obj.data.edit_bones.new('Btail_'+ bone.name)
|
||||
tail_widget.parent = parent
|
||||
#tail_widget.head = bone.tail
|
||||
tail_widget.head = bone.head + (bone.tail - bone.head) * 0.75
|
||||
#tail_widget.tail = bone.tail - (bone.tail - bone.head)/10
|
||||
tail_widget.length = bone.length * 0.1
|
||||
tail_widget.bbone_x = bone.bbone_x
|
||||
tail_widget.bbone_z = bone.bbone_z
|
||||
tail_widget.align_orientation(bone)
|
||||
tail_widget.inherit_scale = 'NONE'
|
||||
tail_name = tail_widget.name
|
||||
|
||||
#add vis bones
|
||||
head_vis = obj.data.edit_bones.new('Bhead_vis_'+ bone.name)
|
||||
head_vis.parent = parent
|
||||
head_vis.head = bone.head
|
||||
head_vis.tail = head_widget.head
|
||||
head_vis.bbone_x = bone.bbone_x*0.1
|
||||
head_vis.bbone_z = bone.bbone_z*0.1
|
||||
|
||||
#head_vis_name = head_vis.name
|
||||
head_vis.hide_select = True
|
||||
head_vis.use_deform = False
|
||||
tail_vis = obj.data.edit_bones.new('Btail_vis_'+ bone.name)
|
||||
tail_vis.parent = parent
|
||||
tail_vis.head = bone.tail
|
||||
tail_vis.tail = tail_widget.head
|
||||
tail_vis.bbone_x = bone.bbone_x*0.1
|
||||
tail_vis.bbone_z = bone.bbone_z*0.1
|
||||
|
||||
#tail_vis_name = tail_vis.name
|
||||
tail_vis.hide_select = True
|
||||
|
||||
tail_vis.use_deform = False
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
tail_widget.layers = wgtlayers
|
||||
head_widget.layers = wgtlayers
|
||||
head_vis.layers = wgtlayers
|
||||
tail_vis.layers = wgtlayers
|
||||
|
||||
bones.append({'name': bone_name, 'parent': parent_name, 'head': head_name, 'tail': tail_name, 'head_vis': head_vis.name, 'tail_vis': tail_vis.name, 'length': bone.length})
|
||||
|
||||
#####POSE MODE#######
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
bone_groups = obj.pose.bone_groups
|
||||
if 'BBone Widgets' not in bone_groups:
|
||||
bbone_group = bone_groups.new(name = 'BBone Widgets')
|
||||
bbone_group.color_set = 'THEME09'
|
||||
else:
|
||||
bbone_group = bone_groups['BBone Widgets']
|
||||
else:
|
||||
bbone_group = None
|
||||
|
||||
for bone in bones:
|
||||
posebone = obj.pose.bones[bone['name']]
|
||||
# Prepare parent bone in pose mode
|
||||
poseparent = obj.pose.bones[bone['parent']]
|
||||
#disable use deform
|
||||
obj.data.bones[bone['parent']].use_deform = False
|
||||
obj.data.bones[bone['head']].use_deform = False
|
||||
obj.data.bones[bone['tail']].use_deform = False
|
||||
|
||||
pose_bbone_setup(bone, obj.pose.bones[bone['head']], bbone_group)
|
||||
pose_bbone_setup(bone, obj.pose.bones[bone['tail']], bbone_group)
|
||||
|
||||
dup_constraints(posebone, poseparent)
|
||||
|
||||
#add all the drivers
|
||||
add_driver(obj, posebone, bone['head'], 'bbone_curveinx', 'location.x')
|
||||
add_driver(obj, posebone, bone['head'], 'bbone_curveinz', 'location.z')
|
||||
add_driver(obj, posebone, bone['head'], 'bbone_easein', 'location.y', '*5/'+ str(bone['length']))
|
||||
add_driver(obj, posebone, bone['head'], 'bbone_rollin', 'rotation_euler.y')
|
||||
add_driver(obj, posebone, bone['head'], ('bbone_scalein', 0), 'scale.x')
|
||||
add_driver(obj, posebone, bone['head'], ('bbone_scalein', 1), 'scale.y')
|
||||
add_driver(obj, posebone, bone['head'], ('bbone_scalein', 2), 'scale.z')
|
||||
|
||||
add_driver(obj, posebone, bone['tail'], 'bbone_curveoutx', 'location.x')
|
||||
add_driver(obj, posebone, bone['tail'], 'bbone_curveoutz', 'location.z')
|
||||
add_driver(obj, posebone, bone['tail'], 'bbone_easeout', 'location.y', '*-5/'+ str(bone['length']))
|
||||
add_driver(obj, posebone, bone['tail'], 'bbone_rollout', 'rotation_euler.y')
|
||||
add_driver(obj, posebone, bone['tail'], ('bbone_scaleout', 0), 'scale.x')
|
||||
add_driver(obj, posebone, bone['tail'], ('bbone_scaleout', 1), 'scale.y')
|
||||
add_driver(obj, posebone, bone['tail'], ('bbone_scaleout', 2), 'scale.z')
|
||||
|
||||
#add constraints to visual bones
|
||||
head_vis = add_vis_bone_con(obj, bone['head_vis'], bone['head'])
|
||||
tail_vis = add_vis_bone_con(obj, bone['tail_vis'], bone['tail'])
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
head_vis.bone_group = bbone_group
|
||||
tail_vis.bone_group = bbone_group
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class ChainControls(bpy.types.Operator):
|
||||
"""Add parent and target controls to the selected bones to create a chain control"""
|
||||
bl_idname = "armature.add_chain_ctrls"
|
||||
bl_label = "Add_Chain_Controls"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
parents: bpy.props.BoolProperty(name = 'Add Parents', description = "Align the controls 90 degrees to the original bones", default = True)
|
||||
targets: bpy.props.BoolProperty(name = 'Add Targets', description = "Align the controls 90 degrees to the original bones", default = True)
|
||||
keep_hierarchy: bpy.props.BoolProperty(name = 'Keep Hierarchy', description = "Keep the controls in the hierarchy of the original bones", default = True)
|
||||
bone_align: bpy.props.BoolProperty(name = 'Align to Bones', description = "Align the controls to the original bones", default = True)
|
||||
align_90: bpy.props.BoolProperty(name = '+90°', description = "Align the controls 90 degrees to the original bones", default = True)
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.context.object.type == 'ARMATURE'
|
||||
def invoke(self, context, event):
|
||||
#obj = context.object
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self, width = 200)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
row = layout.row()
|
||||
row.label(text = 'Add Control Bones')
|
||||
row = layout.row()
|
||||
row.prop(self, 'parents') #text = 'Size'
|
||||
row.prop(self, 'targets')
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.prop(self, 'keep_hierarchy')
|
||||
row = layout.row()
|
||||
row.prop(self, 'bone_align')
|
||||
if self.bone_align:
|
||||
row.prop(self, 'align_90', toggle=True)
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.object
|
||||
targets = []
|
||||
parents = []
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
edit_bones = bpy.context.selected_editable_bones
|
||||
#create list of parent and target objects
|
||||
for bone in edit_bones:
|
||||
bone.use_connect = False
|
||||
if self.targets:
|
||||
targets.append(target(bone))
|
||||
if self.parents:
|
||||
parents.append(parent(bone))
|
||||
|
||||
controls = add_controlers(self, obj, parents, targets)
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
|
||||
#Add the bone group for the ctrls if doesn't exist
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
bone_groups = obj.pose.bone_groups
|
||||
if 'Ctrl Bones' not in bone_groups:
|
||||
ctrl_group = bone_groups.new(name = 'Ctrl Bones')
|
||||
ctrl_group.color_set = 'THEME01'
|
||||
else:
|
||||
ctrl_group = bone_groups['Ctrl Bones']
|
||||
|
||||
for bone in controls:
|
||||
posebone = obj.pose.bones[bone.ctrl]
|
||||
if bpy.app.version < (4, 0, 0):
|
||||
posebone.bone_group = ctrl_group
|
||||
else:
|
||||
posebone.color.palette = 'THEME01'
|
||||
|
||||
if self.targets:
|
||||
for bone in targets:
|
||||
#update from the controls set
|
||||
ctrl = find_ctrl(bone, controls)
|
||||
posebone = obj.pose.bones[bone.name]
|
||||
|
||||
con = posebone.constraints.new('STRETCH_TO')
|
||||
con.target = obj
|
||||
|
||||
con.subtarget = ctrl
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
class MergeRigs(bpy.types.Operator):
|
||||
"""Merge selected rigs to active and keep hierarchy and constraints for shared bones"""
|
||||
bl_idname = "armature.merge"
|
||||
bl_label = "Merge_Rigs"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return bpy.context.object.type == 'ARMATURE'
|
||||
|
||||
def execute(self, context):
|
||||
target_obj = context.object
|
||||
|
||||
if target_obj.type != 'ARMATURE':
|
||||
return {"CANCELLED"}
|
||||
|
||||
target_bones = set([bone.name for bone in target_obj.data.bones])
|
||||
constraints = []
|
||||
childrens = {}
|
||||
|
||||
#Store children and constraints
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj.type != 'ARMATURE':
|
||||
continue
|
||||
if obj == target_obj:
|
||||
continue
|
||||
#create a set of all the similiar bones in all the rigs
|
||||
obj_bones = set([bone.name for bone in obj.data.bones])
|
||||
shared_bones = target_bones.intersection(obj_bones)
|
||||
|
||||
#find all the constraints and children
|
||||
for bone in obj.pose.bones:
|
||||
#store all the constraints
|
||||
for con in bone.constraints:
|
||||
if not hasattr(con, 'subtarget'):
|
||||
continue
|
||||
if con.target == obj and con.subtarget in shared_bones:
|
||||
constraints.append(constraint_dup(bone, con))
|
||||
if bone.name in shared_bones:
|
||||
for child in bone.children:
|
||||
if child.name in childrens:
|
||||
continue
|
||||
childrens.update({child.name : bone.name})
|
||||
|
||||
#remove shared bones
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj.type != 'ARMATURE':
|
||||
continue
|
||||
if obj == target_obj:
|
||||
continue
|
||||
for bone in shared_bones:
|
||||
if bone not in obj.data.edit_bones:
|
||||
continue
|
||||
obj.data.edit_bones.remove(obj.data.edit_bones[bone])
|
||||
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
bpy.ops.object.join()
|
||||
|
||||
#restore constraints
|
||||
for con_dup in constraints:
|
||||
if con_dup.bone in target_bones:
|
||||
continue
|
||||
if con_dup.bone not in target_obj.pose.bones:
|
||||
continue
|
||||
#print('constraint on ',con_dup.bone, con_dup.name)
|
||||
posebone = target_obj.pose.bones[con_dup.bone]
|
||||
if con_dup.name not in posebone.constraints:
|
||||
continue
|
||||
con = posebone.constraints[con_dup.name]
|
||||
con.target = target_obj
|
||||
con.subtarget = con_dup.subtarget
|
||||
|
||||
#reparent all child bones
|
||||
bpy.ops.object.mode_set(mode = 'EDIT')
|
||||
for child, parent in childrens.items():
|
||||
target_obj.data.edit_bones[child].parent = target_obj.data.edit_bones[parent]
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
classes = (MergeRigs,BboneWidgets, ChainControls)
|
||||
def register():
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
# bpy.utils.register_class(BboneWidgets)
|
||||
# bpy.utils.register_class(ChainControls)
|
||||
# bpy.utils.register_class(RiggerToolBox_PT_Panel)
|
||||
|
||||
def unregister():
|
||||
from bpy.utils import unregister_class
|
||||
for cls in classes:
|
||||
unregister_class(cls)
|
||||
# bpy.utils.unregister_class(BboneWidgets)
|
||||
# bpy.utils.unregister_class(ChainControls)
|
||||
# bpy.utils.unregister_class(RiggerToolBox_PT_Panel)
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,534 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
bl_info = {
|
||||
"name": "AnimToolBox",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (0, 0, 8),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "A set of animation tools",
|
||||
"wiki_url": "",
|
||||
"category": "Animation"}
|
||||
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
if "Rigger_Toolbox" in locals():
|
||||
importlib.reload(Rigger_Toolbox)
|
||||
if "TempCtrls" in locals():
|
||||
importlib.reload(TempCtrls)
|
||||
if "Tools" in locals():
|
||||
importlib.reload(Tools)
|
||||
if "Display" in locals():
|
||||
importlib.reload(Display)
|
||||
if "emp" in locals():
|
||||
importlib.reload(emp)
|
||||
if "multikey" in locals():
|
||||
importlib.reload(multikey)
|
||||
if "Rigger_Toolbox" in locals():
|
||||
importlib.reload(Rigger_Toolbox)
|
||||
if "ui" in locals():
|
||||
importlib.reload(ui)
|
||||
if "addon_updater_ops" in locals():
|
||||
importlib.reload(addon_updater_ops)
|
||||
|
||||
import bpy
|
||||
from . import addon_updater_ops
|
||||
from . import TempCtrls
|
||||
from . import Rigger_Toolbox
|
||||
from . import Tools
|
||||
from . import Display
|
||||
from . import emp
|
||||
from . import ui
|
||||
from . import multikey
|
||||
from . import Rigger_Toolbox
|
||||
from pathlib import Path
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
from bpy.app.handlers import persistent
|
||||
import os
|
||||
|
||||
|
||||
class TempCtrlsItems(bpy.types.PropertyGroup):
|
||||
#located at context.scene.btc.ctrl_items
|
||||
controlled: bpy.props.PointerProperty(name = "controlled object", description = "rigs and objects that are being controlled", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
controller: bpy.props.PointerProperty(name = "controller object", description = "rigs and objects that are controling", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
class TempCtrlsSceneSettings(bpy.types.PropertyGroup):
|
||||
#located at context.scene.btc
|
||||
root: bpy.props.BoolProperty(name = "Root Empty", description = "Add a root to the empties ", default = False, override = {'LIBRARY_OVERRIDABLE'}, update = TempCtrls.root_prop)
|
||||
root_bone: bpy.props.StringProperty(name = "Root bone", description = "Root empty as a root bone ", override = {'LIBRARY_OVERRIDABLE'}, update = TempCtrls.root_update)
|
||||
root_object: bpy.props.PointerProperty(name = "Root object", description = "Root empty as a root object ", update = TempCtrls.root_update, type = bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
ctrl_type: bpy.props.EnumProperty(name = 'Controllers', description="Select empties or a bone with a new rig to bake to", items = [('BONE', 'Bone','Bake to bones','BONE_DATA', 0), ('EMPTY', 'Empty', 'Bake to empties', 'EMPTY_ARROWS', 1)])
|
||||
ctrl_items: bpy.props.CollectionProperty(type = TempCtrlsItems, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
||||
|
||||
bake_range_type: bpy.props.EnumProperty(name = 'Bake Range', description="Use either scene, actions length or custom frame range", default = 'KEYFRAMES', update= TempCtrls.update_range_type,
|
||||
items = [('SCENE', 'Scene Range', 'Bake to the scene range'), ('KEYFRAMES', 'Keyframes Range', 'Bake all the keyframes in the layers'), ('CUSTOM', 'Custom', 'Enter a custom frame range')], override = {'LIBRARY_OVERRIDABLE'})
|
||||
bake_range: bpy.props.IntVectorProperty(name='Frame Range', description='Bake to a custom frame range', size = 2, update= TempCtrls.update_bake_range)
|
||||
bake_layers: bpy.props.BoolProperty(name = "Bake Layers", description = "Use keyframes from all the layers to include in the bake", default = False)
|
||||
|
||||
target: bpy.props.EnumProperty(name = 'Affect', description="Cleanup created constraints and empties", default = 1,
|
||||
items = [('ALL', 'All Ctrl Rigs','Bake to all Ctrl Rigs', 0),
|
||||
('SELECTED', 'Selected Chains','Bake to only selected chain controlls', 1),
|
||||
('RELATIVE', 'Relative Ctrls Rig','Bake to the Relative Control rigs', 2)])
|
||||
# ('CONSTRAINTS', 'Constraints', 'Clean all the bone constraints', 3),
|
||||
# ('CONTROLLERS', 'Controllers', 'Remove all the baked empties', 4)])
|
||||
|
||||
selection: bpy.props.EnumProperty(name = 'Select', description="Select all controls, original bones or their relative", default = 'CONTROLLERS',
|
||||
items = [('RELATIVE_CTRLS', 'Relative Ctrls','Select the Relative controller to your current selection', 0),
|
||||
('RELATIVE_CONSTRAINED', 'Relative Constrained','Select the Relative original constrained bone to your current selection', 1),
|
||||
('CONTROLLERS', 'All Ctrls', 'Select all the controller bones or empties', 2), ('CONSTRAINED', 'All Constrained', 'Select all the original constrained bones', 3)])
|
||||
|
||||
#smartbake setting
|
||||
linksettings: bpy.props.BoolProperty(name = "Link Settings", description = "Link Settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bakesettings: bpy.props.BoolProperty(name = "bake settings", description = "bake settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
cleansettings: bpy.props.BoolProperty(name = "clean settings", description = "clean settings", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
smartbake: bpy.props.BoolProperty(name = "Smart Bake", description = "Keep Original Frame count", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
inbetween_keyframes: bpy.props.IntProperty(name = "Inbetween Keyframes", description = "Add inbetween keyframes", default = 0, override = {'LIBRARY_OVERRIDABLE'})
|
||||
from_origin: bpy.props.BoolProperty(name = "From Origin", description = "Use Keyframes from Original Bone", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
from_ctrl: bpy.props.BoolProperty(name = "From Controller", description = "Use Keyframes from Controller Bone", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
clean_ctrls: bpy.props.BoolProperty(name = "Remove Ctrls", description = "Remove Controls", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
clean_constraints: bpy.props.BoolProperty(name = "Remove Constraints", description = "Remove Constraints", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
rebake_to_org: bpy.props.BoolProperty(name = "ReBake connections to original bones", description = "ReBake ctrls from connected chains current anim to the original bones", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
link_to: bpy.props.EnumProperty(name = 'Link to Chain', description="Link to begining of an active chain or the tip of the chain", default = 1,
|
||||
items = [('BASE', 'Base','Link to the base of the active chain', 0), ('TIP', 'Tip', 'Link to the tip of the chain', 1)])
|
||||
# link_from: bpy.props.EnumProperty(name = 'Link to Chain', description="Link to begining of an active chain or the tip of the chain", default = 0,
|
||||
# items = [('BASE', 'Base','Link to the base of the active chain', 0), ('TIP', 'Tip', 'Link to the tip of the chain', 1)])
|
||||
|
||||
shape_size: bpy.props.FloatProperty(name='Size', description="Multiple factor for the shape size of the temp controls", update = TempCtrls.tempctrl_shapesize, min = 0.001, default = 1.5, override = {'LIBRARY_OVERRIDABLE'})#
|
||||
shape_type: bpy.props.EnumProperty(name = 'Shape Type', description="Display type for the controls", items = TempCtrls.ctrl_shape_items, update = TempCtrls.tempctrl_shape_type)
|
||||
color_set: bpy.props.EnumProperty(name="Bone Color Set", description="Choose a bone color set", items = TempCtrls.get_bone_color_sets, update = TempCtrls.update_bone_color, default = 9)
|
||||
|
||||
add_ik_ctrl: bpy.props.BoolProperty(name = 'Add an Extra IK Ctrl Bone', description = "Adds an extra bone ctrl as the ik ctrl", default = False, update = TempCtrls.add_ik_prop)
|
||||
pole_target: bpy.props.BoolProperty(name = 'Add Pole Target', description = "Adding Pole Target to the IK Chain", default = True, update = TempCtrls.pole_prop)
|
||||
pole_offset: bpy.props.FloatProperty(name="Offset", description="Offset the bone in the axis direction", default=1.0, update = TempCtrls.pole_offset)
|
||||
child: bpy.props.BoolProperty(name = 'Add extra child Ctrls', description = "Add an child control for an overlay control", default = False, update = TempCtrls.child_prop)
|
||||
orientation: bpy.props.BoolProperty(name = 'Use World Space Orientation', description = "Orient the bones to world space instead of to the original bones", default = True)
|
||||
|
||||
# enabled: bpy.props.BoolProperty(name = 'Switch On / Off', description = "Enabling and Disabling Temp Ctrls influence", default = True)
|
||||
|
||||
class TempCtrlsBoneSettings(bpy.types.PropertyGroup):
|
||||
#located at obj.pose.bones[##].btc
|
||||
root: bpy.props.BoolProperty(name = "Root Bone", description = "Bone is marked as the root bone", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
child: bpy.props.BoolProperty(name = "Child Bone", description = "Bone is marked as a child bone inside the setup", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
org_id: bpy.props.IntProperty(name = "Originate ID", description = "ID number of the bone the ctrl originates from", override = {'LIBRARY_OVERRIDABLE'})
|
||||
setup_id: bpy.props.IntProperty(name = "Setup ID", description = "ID number of the current chain setup", override = {'LIBRARY_OVERRIDABLE'})
|
||||
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of", override = {'LIBRARY_OVERRIDABLE'},
|
||||
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
||||
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
||||
('WORLDSPACE_CURSOR', 'World Space Cursor Ctrl','World Space Cursor pivot', 2),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 3),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 4),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 5),
|
||||
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 6),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 7),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 9),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 10),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 11)])
|
||||
|
||||
#using org mostly to decide if it needs a custom shape
|
||||
org: bpy.props.EnumProperty(name = 'Org Type', description="Describes what if the function of the bone", override = {'LIBRARY_OVERRIDABLE'},
|
||||
items = [('CTRL', 'Controller Bone','Controller Bone', 0),
|
||||
('ORG', 'Original Bone','Original Bone', 1),
|
||||
('MCH', 'Mechanical Bone','Mechanical Bone', 2),
|
||||
('NONE', 'Nothing applied','Nothing applied', 3)])
|
||||
|
||||
shape: bpy.props.BoolProperty(name = "Apply shape", description = "Mark if the bone needs a shape", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
class TempCtrlsOrgIds(bpy.types.PropertyGroup):
|
||||
# A collection of the org ids used in each setup. Org ID is the direct connection
|
||||
# between original bones and ctrls
|
||||
pass
|
||||
|
||||
class TempCtrlsObjectSetups(bpy.types.PropertyGroup):
|
||||
#located at obj.animtoolbox.ctrl_setups
|
||||
#name: using string of the id
|
||||
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of",
|
||||
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
||||
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
||||
('WORLDSPACE_CURSOR', 'World Space Cursor Ctrl','World Space Cursor pivot', 2),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 3),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 4),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 5),
|
||||
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 6),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 7),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 9),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 10),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 11)])
|
||||
|
||||
org_ids: bpy.props.CollectionProperty(type = TempCtrlsOrgIds)
|
||||
|
||||
class MultikeyProperties(bpy.types.PropertyGroup):
|
||||
|
||||
selectedbones: bpy.props.BoolProperty(name="Selected Bones", description="Affect only selected bones", default=True, options={'HIDDEN'})
|
||||
handletype: bpy.props.BoolProperty(name="Keep handle types", description="Keep handle types", default=False, options={'HIDDEN'})
|
||||
scale: bpy.props.FloatProperty(name="Scale Factor", description="Scale percentage of the average value", default=1.0, update = multikey.scale_value)
|
||||
randomness: bpy.props.FloatProperty(name="Randomness", description="Random Threshold of keyframes", default=0.1, min=0.0, max = 1.0, update = multikey.random_value)
|
||||
|
||||
class AnimToolBoxObjectSettings(bpy.types.PropertyGroup):
|
||||
|
||||
controlled: bpy.props.PointerProperty(name = 'Controlled Rig', description="Adding the rig object that is being controlled by the current object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
controller: bpy.props.PointerProperty(name = 'Controller Rig', description="Adding the rig object that is used as the temp control object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
ctrl_setups: bpy.props.CollectionProperty(type = TempCtrlsObjectSetups, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
||||
ctrls_enabled: bpy.props.BoolProperty(name = 'Temp Ctrls Switch', description = "Enabling and Disabling Temp Ctrls influence", default = True)
|
||||
# influence: bpy.props.FloatProperty(name = "Influence Slider for the Temp Ctrls", description = "Switching the influence slider for the temp ctrls", default = 1, min = 0.0, max = 1.0)
|
||||
|
||||
#Used for Bake to Empties
|
||||
# org_id: bpy.props.IntProperty(name = "Originate ID", description = "ID number of the bone the ctrl originates from", override = {'LIBRARY_OVERRIDABLE'})
|
||||
setup_id: bpy.props.IntProperty(name = "Setup ID", description = "ID number of the current chain setup", override = {'LIBRARY_OVERRIDABLE'})
|
||||
root: bpy.props.BoolProperty(name = "Root Empty", description = "Empty is marked as the root ctrl", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
child: bpy.props.BoolProperty(name = "Child Empty", description = "Empty is marked as a child bone inside the setup", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
keyframes_offset: bpy.props.FloatProperty(name = "Keyframes Offset", description = "Interactive slider to offset keyframes back and forth ", default = 0)
|
||||
|
||||
class IsolatedRigs(bpy.types.PropertyGroup):
|
||||
|
||||
hidden: bpy.props.PointerProperty(name = "Hidden Rigs", description = "List of Rigs that are hidden during pose mode isolation", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
selected: bpy.props.PointerProperty(name = "Selected Rigs", description = "List of Rigs that are hidden during pose mode isolation", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
class AnimToolBoxUILayout(bpy.types.PropertyGroup):
|
||||
'''Layout properties for the UI'''
|
||||
quick_menu: bpy.props.BoolProperty(name = "Use Quick Menu", description = "Opens header menu with only icon", default = False)
|
||||
copy_paste_matrix: bpy.props.BoolProperty(name = "Copy Matrix Menu", description = "Opens the menu for copy paste matrices", default = True)
|
||||
copy_paste_world: bpy.props.BoolProperty(name = "Copy Paste World Matrix", description = "Copy and Paste the World Matrix", default = False, update = Tools.copy_paste_world_update)
|
||||
copy_paste_relative: bpy.props.BoolProperty(name = "Copy Paste Relative Matrix", description = "Copy and Paste the Matrix relative to the active bone", default = False, update = Tools.copy_paste_relative_update)
|
||||
Inbetweens: bpy.props.BoolProperty(name = "Blendings/Inbetweens", description = "Opens the menu for Inbetweens", default = True)
|
||||
gizmo_size: bpy.props.BoolProperty(name = "Gizmo size", description = "Change the Gizmo size using alt +/- hotkeys", default = False)
|
||||
# temp_ctrls: bpy.props.BoolProperty(name = "Temp Ctrls", description = "Open Temp Ctrls", default = False)
|
||||
temp_ctrls_switch: bpy.props.BoolProperty(name = "Temp Ctrls Switch", description = "Temp Ctrls Switch", default = True)
|
||||
temp_ctrls_shapes: bpy.props.BoolProperty(name = "Temp Ctrls Shapes", description = "Temp Ctrls Shapes", default = True)
|
||||
|
||||
markers_retimer: bpy.props.BoolProperty(name = "Marker Retimer", description = "Flag when marker retimer turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
relative_cursor: bpy.props.BoolProperty(name = "Relative Cursor Mode", description = "Cursor moves relative to the selection", default = False)
|
||||
|
||||
is_dragging: bpy.props.BoolProperty(default = False)
|
||||
#using Blending sliders in the window manager to avoid undo issues with modal operators
|
||||
inbetween_worldmatrix: bpy.props.FloatProperty(name='Inbetween World Matrix', description="Adds an inbetween of the World Matrix to the Layer's neighbor keyframes", soft_min = -1, soft_max = 1, default=0.0, update = Tools.add_inbetween_worldmatrix, override = {'LIBRARY_OVERRIDABLE'})
|
||||
blend_mirror: bpy.props.FloatProperty(name='Blend Mirror', description="Blend into the mirrored pose", soft_min = 0, soft_max = 1, default=0, step = 1, update = Tools.blend_to_mirror, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
multikey: bpy.props.PointerProperty(type = MultikeyProperties, options={'LIBRARY_EDITABLE'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
class AnimToolBoxGlobalSettings(bpy.types.PropertyGroup):
|
||||
#context.scene.animtoolbox
|
||||
marker_frame_range: bpy.props.BoolProperty(name = "Marker Frame Range", description = "Flag when marker frame range turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bake_frame_range: bpy.props.BoolProperty(name = "Bake Frame Range", description = "Flag when marker bake range turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
# markers_retimer: bpy.props.BoolProperty(name = "Marker Retimer", description = "Flag when marker retimer turned on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
keyframes_offset: bpy.props.FloatProperty(name = "Keyframes Offset", description = "Interactive slider to offset keyframes back and forth ", soft_max = 2, soft_min = -2, default = 0, update = Tools.keyframes_offset_slider)
|
||||
rotation_mode: bpy.props.EnumProperty(name = 'Rotation Mode', description="Describes what kind of setup the bone is part of", override = {'LIBRARY_OVERRIDABLE'},
|
||||
items = [('QUATERNION', 'Quaternion','Quaternion Rotation Order - No Gimbal Lock', 0),
|
||||
('XYZ', 'XYZ', 'XYZ Rotation Order', 1), ('XZY', 'XZY','XZY Rotation Order', 2),
|
||||
('YXZ', 'YXZ','YXZ Rotation Order', 3), ('YZX', 'YZX', 'YZX Rotation Order', 4),
|
||||
('ZXY', 'ZXY', 'ZXY Rotation Order', 5), ('ZYX', 'ZYX', 'ZYX Rotation Order', 6),
|
||||
('AXIS_ANGLE', 'AXIS_ANGLE', 'Axis Angle Rotation Order', 7)])
|
||||
|
||||
isolate_pose_mode: bpy.props.BoolProperty(name = "Isolate rig in pose mode", description = "Isolates the rig during pose mode, rigs in object mode are hidden", default = False)
|
||||
active_obj: bpy.props.PointerProperty(name = "Active Object", description = "Current Active Object", type=bpy.types.Object, override = {'LIBRARY_OVERRIDABLE'})
|
||||
isolated: bpy.props.CollectionProperty(type = IsolatedRigs, override = {'LIBRARY_OVERRIDABLE', 'USE_INSERTION'})
|
||||
|
||||
#Blendings
|
||||
inbetweener : bpy.props.FloatProperty(name='Inbetween Keyframe', description="Adds an inbetween Keyframe between the Layer's neighbor keyframes", soft_min = -1, soft_max = 1, default=0.0, options = set(), update = Tools.add_inbetween_key, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
gizmo_size: bpy.props.IntProperty(name = "Add to Gizmo Size", description = "Addition to Gizmo Size", max = 100, min = -100, default = 10)
|
||||
|
||||
#Copy/Pase Matrix
|
||||
range_type: bpy.props.EnumProperty(name = 'Paste to Frames', description="Paste to current frame or a range of frames.", update = Tools.bake_range_type,
|
||||
items = [('CURRENT', 'Current Frame','Paste Matrix to only current frame', 0),
|
||||
('SELECTED', 'Selected Keyframe','Paste Matrix to only selected keyframes', 1),
|
||||
('RANGE', 'Frame Range','Paste Matrix to a Frame Range', 2)])
|
||||
bake_frame_start: bpy.props.IntProperty(name = "Bake Frame Start", description = "Define the start frame to paste the matrix", min = 0, update = Tools.bake_frame_start_limit)
|
||||
bake_frame_end: bpy.props.IntProperty(name = "Bake Frame End", description = "Define the end frame to paste the matrix", min = 0, update = Tools.bake_frame_end_limit)
|
||||
|
||||
filter_location: bpy.props.BoolVectorProperty(name="Location", description="Filter Location properties", default=(False, False, False), size = 3, options={'HIDDEN'}, update = Tools.filter_name_update)
|
||||
filter_rotation: bpy.props.BoolVectorProperty(name="Rotation", description="Filter Rotation properties", default=(False, False, False, False), size = 4, options={'HIDDEN'}, update = Tools.filter_name_update)
|
||||
filter_scale: bpy.props.BoolVectorProperty(name="Scale", description="Filter Scale properties", default=(False, False, False), size = 3, options={'HIDDEN'}, update = Tools.filter_name_update)
|
||||
#The name displayed on the filter button
|
||||
filter_name: bpy.props.StringProperty(name="Filter Name", description="Change the name of the button while chaging the filter options", default= "", options={'HIDDEN'})
|
||||
filter_custom_props: bpy.props.BoolProperty(name = "Filter Custom Properties", description = "Filter custom properties", default = False)
|
||||
filter_keyframes: bpy.props.BoolProperty(name = "Filter Aelected Keyframes", description = "Filter selected keyframes for specific tools", default = False)
|
||||
|
||||
col_vis: bpy.props.BoolProperty(name = "Animated collections visibility", description = "Display if animated collections are turned on or off", default = False)
|
||||
|
||||
@addon_updater_ops.make_annotations
|
||||
class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
||||
# this must match the addon name, use '__package__'
|
||||
# when defining this in a submodule of a python package.
|
||||
bl_idname = __package__
|
||||
|
||||
category: bpy.props.StringProperty(
|
||||
name="Tab Category",
|
||||
description="Choose a name for the category of the panel",
|
||||
default="Animation",
|
||||
update=ui.update_panel
|
||||
)
|
||||
|
||||
quick_menu: bpy.props.BoolProperty(name = "Use Quick Menu", description = "Opens header menu with only icon", default = False)
|
||||
riggertoolbox: bpy.props.BoolProperty(name = "RiggerToolBox", description = "Include RiggerToolbox (experimental)", default = False, update = ui.add_riggertoolbox)
|
||||
multikey: bpy.props.BoolProperty(name = "Multikey", description = "Include Multikey for adju\sting multiply keyframes", default = False, update = ui.add_multikey)
|
||||
|
||||
#Temp Ctrls properties
|
||||
in_front: bpy.props.BoolProperty(name = "Always In Front", description = "Set Temp Ctrls to be always in front", default = True)
|
||||
clear_setup : bpy.props.BoolProperty(name = "Clear Selection Before Creating New Temp Ctrls", description = "Clear old setup when adding Temp ctrls to an existing chain", default = False)
|
||||
|
||||
#Editable motion path
|
||||
keyframes_range: bpy.props.IntProperty(name = "Keyframe Range", description = "The range of distance from the keyframes while hovering over them", min = 5, max = 100, default = 15)
|
||||
mp_pref: bpy.props.BoolProperty(name = "Editable Motion Path Colors Theme", description = "Set the Color them of editable motion path visualization", default = False)
|
||||
mp_keyframe_color: bpy.props.FloatVectorProperty(name="Keyframes", subtype='COLOR', default=(1.0, 1.0, 0.0, 1.0), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_handle_color: bpy.props.FloatVectorProperty(name="Handles", subtype='COLOR', default=(1.0, 0.8, 0.2, 1.0), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_remove_color: bpy.props.FloatVectorProperty(name="Remove Keyframes", subtype='COLOR', default=(0.0, 0.5, 1.0, 1.0), size=4, min=0.0, max=1.0, description="Keyframe color displayed before removing")
|
||||
mp_hover_color: bpy.props.FloatVectorProperty(name="Hover", subtype='COLOR', default=(1.0, 0.4, 0.2, 1.0), size=4, min=0.0, max=1.0, description="Color during Hovering")
|
||||
mp_handle_selection_color: bpy.props.FloatVectorProperty(name="Handles Selection", subtype='COLOR', default=(0.8, 0.65, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_key_selection_color: bpy.props.FloatVectorProperty(name="Keyframe Selection", subtype='COLOR', default=(0.8, 0.8, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Keyframe selection color")
|
||||
|
||||
# addon updater preferences from `__init__`, be sure to copy all of them
|
||||
auto_check_update: bpy.props.BoolProperty(
|
||||
name = "Auto-check for Update",
|
||||
description = "If enabled, auto-check for updates using an interval",
|
||||
default = True,
|
||||
)
|
||||
|
||||
updater_interval_months: bpy.props.IntProperty(
|
||||
name='Months',
|
||||
description = "Number of months between checking for updates",
|
||||
default=0,
|
||||
min=0
|
||||
)
|
||||
updater_interval_days: bpy.props.IntProperty(
|
||||
name='Days',
|
||||
description = "Number of days between checking for updates",
|
||||
default=7,
|
||||
min=0,
|
||||
|
||||
)
|
||||
updater_interval_hours: bpy.props.IntProperty(
|
||||
name='Hours',
|
||||
description = "Number of hours between checking for updates",
|
||||
default=0,
|
||||
min=0,
|
||||
max=23
|
||||
)
|
||||
updater_interval_minutes: bpy.props.IntProperty(
|
||||
name='Minutes',
|
||||
description = "Number of minutes between checking for updates",
|
||||
default=0,
|
||||
min=0,
|
||||
max=59
|
||||
)
|
||||
|
||||
#Draw the UI in the preferences
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
addon_updater_ops.update_settings_ui(self, context)
|
||||
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
|
||||
col.label(text="Tab Category:")
|
||||
col.prop(self, "category", text="")
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.prop(self, "quick_menu", text="Use Quick Icons Menu")
|
||||
|
||||
layout.separator()
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.label(text = 'Temp Ctrls: ')
|
||||
row = box.row()
|
||||
row.prop(self, 'clear_setup')
|
||||
row.prop(self, 'in_front')
|
||||
|
||||
layout.separator()
|
||||
box = layout.box()
|
||||
col = box.column()
|
||||
col.prop(self, 'mp_pref', icon = 'DOWNARROW_HLT', text = 'Editable Motion Path Preferences')
|
||||
if self.mp_pref:
|
||||
col.prop(self, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
col.label(text = 'Colors Theme')
|
||||
row = box.row()
|
||||
row.prop(self, 'mp_keyframe_color')
|
||||
row.prop(self, 'mp_handle_color')
|
||||
row.prop(self, 'mp_remove_color')
|
||||
row = box.row()
|
||||
row.prop(self, 'mp_hover_color')
|
||||
row.prop(self, 'mp_key_selection_color')
|
||||
row.prop(self, 'mp_handle_selection_color')
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.label(text = 'Include Extras: ')
|
||||
row = layout.row()
|
||||
row.prop(self, "multikey", text="Multikey - Edit Multiply keyframes")
|
||||
row.prop(self, "riggertoolbox", text="RiggerToolBox (Experimental)")
|
||||
|
||||
@persistent
|
||||
def loadanimtoolbox_pre(self, context):
|
||||
scene = bpy.context.scene
|
||||
dns = bpy.app.driver_namespace
|
||||
if scene.animtoolbox.bake_frame_range:
|
||||
scene.animtoolbox.bake_frame_range = False
|
||||
|
||||
if scene.emp.motion_path:
|
||||
scene.emp.motion_path = False
|
||||
bpy.context.workspace.status_text_set(None)
|
||||
if 'mp_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('mp_dh')
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
if 'markers_retimer_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['markers_retimer_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('markers_retimer_dh')
|
||||
|
||||
#remove the motion path app handler if it's still inside
|
||||
if emp.mp_value_update in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(emp.mp_value_update)
|
||||
if emp.mp_frame_change in bpy.app.handlers.frame_change_post:
|
||||
bpy.app.handlers.frame_change_post.remove(emp.mp_frame_change)
|
||||
if emp.mp_undo_update in bpy.app.handlers.undo_pre:
|
||||
bpy.app.handlers.undo_pre.remove(emp.mp_undo_update)
|
||||
|
||||
@persistent
|
||||
def loadanimtoolbox_post(self, context):
|
||||
scene = bpy.context.scene
|
||||
dns = bpy.app.driver_namespace
|
||||
if scene.animtoolbox.isolate_pose_mode:
|
||||
if Display.isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre:
|
||||
bpy.app.handlers.depsgraph_update_pre.append(Display.isolate_pose_mode)
|
||||
|
||||
if scene.emp.motion_path:
|
||||
scene.emp.motion_path = False
|
||||
bpy.context.workspace.status_text_set(None)
|
||||
if 'mp_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('mp_dh')
|
||||
# Reset keyframe selection for motion paths it is not used in window manager
|
||||
# Because it is used for undo
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
Tools.selection_order(self, context)
|
||||
|
||||
classes = (TempCtrlsItems, TempCtrlsOrgIds, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties,
|
||||
IsolatedRigs, AnimToolBoxObjectSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
|
||||
|
||||
addon_keymaps = []
|
||||
|
||||
def register():
|
||||
# Note that preview collections returned by bpy.utils.previews
|
||||
# are regular py objects - you can use them to store custom data.
|
||||
|
||||
addon_updater_ops.register(bl_info)
|
||||
register_class(AnimToolBoxPreferences)
|
||||
addon_updater_ops.make_annotations(AnimToolBoxPreferences) # to avoid blender 2.8 warnings
|
||||
TempCtrls.register()
|
||||
Tools.register()
|
||||
Display.register()
|
||||
emp.register()
|
||||
|
||||
ui.register_custom_icon()
|
||||
|
||||
for cls in classes:
|
||||
# print(cls)
|
||||
register_class(cls)
|
||||
|
||||
bpy.types.Scene.btc = bpy.props.PointerProperty(type = TempCtrlsSceneSettings, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bpy.types.PoseBone.btc = bpy.props.PointerProperty(type = TempCtrlsBoneSettings, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bpy.types.Object.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxObjectSettings, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bpy.types.Scene.animtoolbox = bpy.props.PointerProperty(type = AnimToolBoxGlobalSettings, override = {'LIBRARY_OVERRIDABLE'})
|
||||
bpy.types.WindowManager.atb_ui = bpy.props.PointerProperty(type = AnimToolBoxUILayout, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
ui.update_panel(None, bpy.context)
|
||||
ui.add_multikey(None, bpy.context)
|
||||
ui.add_riggertoolbox(None, bpy.context)
|
||||
|
||||
if loadanimtoolbox_pre not in bpy.app.handlers.load_pre:
|
||||
bpy.app.handlers.load_pre.append(loadanimtoolbox_pre)
|
||||
if loadanimtoolbox_post not in bpy.app.handlers.load_post:
|
||||
bpy.app.handlers.load_post.append(loadanimtoolbox_post)
|
||||
|
||||
if Tools.selection_order not in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.append(Tools.selection_order)
|
||||
|
||||
#Make sure TAB hotkey in the NLA goes into full stack mode
|
||||
wm = bpy.context.window_manager
|
||||
kc = wm.keyconfigs.addon
|
||||
km = kc.keymaps.new(name= '3D View', space_type= 'VIEW_3D')
|
||||
if 'view3d.gizmo_size_up' not in km.keymap_items:
|
||||
kmi = km.keymap_items.new('view3d.gizmo_size_up', type= 'NUMPAD_PLUS', value= 'PRESS', alt = True, repeat = True)
|
||||
addon_keymaps.append((km, kmi))
|
||||
if 'view3d.gizmo_size_down' not in km.keymap_items:
|
||||
kmi = km.keymap_items.new('view3d.gizmo_size_down', type= 'NUMPAD_MINUS', value= 'PRESS', alt = True, repeat = True)
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
#Add Tools to the Toolbar
|
||||
bpy.utils.register_tool(ui.KeyframeOffsetTool, separator=True)
|
||||
|
||||
#Add tools to the menu
|
||||
bpy.types.VIEW3D_MT_editor_menus.append(ui.draw_menu)
|
||||
|
||||
def unregister():
|
||||
for pcoll in ui.preview_collections.values():
|
||||
bpy.utils.previews.remove(pcoll)
|
||||
ui.preview_collections.clear()
|
||||
|
||||
#addon_updater_ops.unregister()
|
||||
addon_updater_ops.unregister()
|
||||
unregister_class(AnimToolBoxPreferences)
|
||||
|
||||
TempCtrls.unregister()
|
||||
# Rigger_Toolbox.unregister()
|
||||
Tools.unregister()
|
||||
Display.unregister()
|
||||
emp.unregister()
|
||||
|
||||
ui.add_multikey(None, bpy.context)
|
||||
ui.add_riggertoolbox(None, bpy.context)
|
||||
|
||||
for cls in classes:
|
||||
unregister_class(cls)
|
||||
|
||||
bpy.utils.unregister_tool(ui.KeyframeOffsetTool)
|
||||
|
||||
#Remove the header menu ui
|
||||
bpy.types.VIEW3D_MT_editor_menus.remove(ui.draw_menu)
|
||||
|
||||
del bpy.types.Scene.btc
|
||||
# del bpy.types.Bone.btc
|
||||
del bpy.types.Object.animtoolbox
|
||||
del bpy.types.Scene.animtoolbox
|
||||
if hasattr(bpy.types.Object, 'keyframes_offset'):
|
||||
del bpy.types.Object.keyframes_offset
|
||||
if hasattr(bpy.types.PoseBone, 'keyframes_offset'):
|
||||
del bpy.types.PoseBone.keyframes_offset
|
||||
|
||||
if loadanimtoolbox_pre in bpy.app.handlers.load_pre:
|
||||
bpy.app.handlers.load_pre.remove(loadanimtoolbox_pre)
|
||||
if loadanimtoolbox_post in bpy.app.handlers.load_post:
|
||||
bpy.app.handlers.load_post.remove(loadanimtoolbox_post)
|
||||
if Tools.selection_order in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(Tools.selection_order)
|
||||
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"last_check": "2026-02-09 15:54:54.419194",
|
||||
"backup_date": "September-23-2025",
|
||||
"update_ready": true,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
"just_updated": false,
|
||||
"version_text": {
|
||||
"link": "https://gitlab.com/api/v4/projects/45739913/repository/archive.zip?sha=7a9ad24a463bf1c8ae095ec853409979344e0738",
|
||||
"version": [
|
||||
0,
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,527 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import bpy
|
||||
import random
|
||||
import numpy as np
|
||||
from mathutils import Quaternion
|
||||
from . import Tools
|
||||
|
||||
def attr_default(obj, fcu_key):
|
||||
#check if the fcurve source belongs to a bone or obj
|
||||
if fcu_key[0][:10] == 'pose.bones':
|
||||
transform = fcu_key[0].split('.')[-1]
|
||||
attr = fcu_key[0].split('"')[-2]
|
||||
bone = fcu_key[0].split('"')[1]
|
||||
|
||||
if bone in obj.pose.bones:
|
||||
source = obj.pose.bones[bone]
|
||||
#if the bone not found still calculate the default based on the path
|
||||
elif '.rotation_quaternion' in fcu_key[0]:
|
||||
return [1.0, 0.0, 0.0, 0.0]
|
||||
elif '.scale' in fcu_key[0]:
|
||||
return [1.0, 1.0, 1.0]
|
||||
else:
|
||||
return [0]
|
||||
|
||||
#in case of shapekey animation
|
||||
elif fcu_key[0][:10] == 'key_blocks':
|
||||
attr = fcu_key[0].split('"')[1]
|
||||
if attr not in obj.data.shape_keys.key_blocks:
|
||||
return [0]
|
||||
shapekey = obj.data.shape_keys.key_blocks[attr]
|
||||
return [0] if shapekey.slider_min <= 0 else shapekey.slider_min
|
||||
#in case of transforms in object mode
|
||||
else:# fcu_key[0] in transform_types:
|
||||
source = obj
|
||||
transform = fcu_key[0]
|
||||
|
||||
#check when it's transform property of Blender
|
||||
if transform in source.bl_rna.properties.keys():
|
||||
if hasattr(source.bl_rna.properties[transform], 'default_array'):
|
||||
if len(source.bl_rna.properties[transform].default_array) > fcu_key[1]:
|
||||
attrvalue = source.bl_rna.properties[transform].default_array
|
||||
return attrvalue
|
||||
|
||||
#in case of property on object
|
||||
elif len(fcu_key[0].split('"')) > 1:
|
||||
if fcu_key[0].split('"')[1] in obj.keys():
|
||||
attr = fcu_key[0].split('"')[1]
|
||||
|
||||
if 'attr' not in locals():
|
||||
return [0]
|
||||
|
||||
#since blender 3 access to custom property settings changed
|
||||
if attr in source:
|
||||
if not isinstance(source[attr], float) and not isinstance(source[attr], int):
|
||||
return [0]
|
||||
id_attr = source.id_properties_ui(attr).as_dict()
|
||||
attrvalue = id_attr['default']
|
||||
return [attrvalue]
|
||||
|
||||
return [0]
|
||||
|
||||
def store_handles(key):
|
||||
#storing the distance between the handles bezier to the key value
|
||||
handle_r = key.handle_right[1] - key.co[1]
|
||||
handle_l = key.handle_left[1] - key.co[1]
|
||||
|
||||
return handle_r, handle_l
|
||||
|
||||
def apply_handles(key, handle_r, handle_l):
|
||||
key.handle_right[1] = key.co[1] + handle_r
|
||||
key.handle_left[1] = key.co[1] + handle_l
|
||||
|
||||
def selected_bones_filter(obj, fcu_data_path):
|
||||
if not bpy.context.window_manager.atb_ui.multikey.selectedbones:
|
||||
#if not obj.als.onlyselected:
|
||||
return False
|
||||
if obj.mode != 'POSE':
|
||||
return True
|
||||
transform_types = ['location', 'rotation_euler', 'rotation_quaternion', 'scale']
|
||||
#filter selected bones if option is turned on
|
||||
bones = [bone.path_from_id() for bone in bpy.context.selected_pose_bones]
|
||||
if fcu_data_path.split('].')[0]+']' not in bones and fcu_data_path not in transform_types:
|
||||
return True
|
||||
|
||||
# def filter_properties(obj, fcu):
|
||||
# 'Filter the W X Y Z attributes of the transform properties'
|
||||
# transform = fcu.data_path.split('"].')[1] if obj.mode == 'POSE' else fcu.data_path
|
||||
# index = fcu.array_index
|
||||
# if 'rotation' in transform:
|
||||
# if transform == 'rotation_euler':
|
||||
# index -= 1
|
||||
# transform = 'rotation'
|
||||
# transform = 'filter_' + transform
|
||||
# if not hasattr(bpy.context.scene.multikey, transform):
|
||||
# return False
|
||||
# attr = getattr(bpy.context.scene.multikey, transform)
|
||||
# #print(fcu.data_path, index, transform, attr[index])
|
||||
# return True if attr[index] else False
|
||||
|
||||
def add_value(key, value):
|
||||
if key.select_control_point:
|
||||
#store handle values in relative to the keyframe value
|
||||
handle_r, handle_l = store_handles(key)
|
||||
|
||||
key.co[1] += value
|
||||
apply_handles(key, handle_r, handle_l)
|
||||
|
||||
#calculate the difference between current value and the fcurve value
|
||||
def add_diff(fcurves, path, current_value, eval_array):
|
||||
array_value = current_value - eval_array
|
||||
if not any(array_value):
|
||||
return
|
||||
|
||||
for i, value in enumerate(array_value):
|
||||
fcu = fcurves.find(path, index = i)
|
||||
if fcu is None or Tools.filter_properties(bpy.context.scene.animtoolbox, fcu):
|
||||
continue
|
||||
for key in fcu.keyframe_points:
|
||||
add_value(key, value)
|
||||
fcu.update()
|
||||
|
||||
class ScaleValuesOp(bpy.types.Operator):
|
||||
"""Modal operator used while scale value is running before release"""
|
||||
bl_idname = "animtoolbox.multikey_scale_value"
|
||||
bl_label = "Scale Values"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
#reset the values for dragging
|
||||
self.stop = False
|
||||
ui = context.window_manager.atb_ui
|
||||
ui['is_dragging'] = True
|
||||
self.avg_value = dict()
|
||||
#dictionary of the keyframes and their original INITIAL values
|
||||
self.keyframes_values = dict()
|
||||
self.keyframes_handle_right = dict()
|
||||
self.keyframes_handle_left = dict()
|
||||
|
||||
#the average value for each fcurve
|
||||
self.keyframes_avg_value = dict()
|
||||
|
||||
for obj in context.selected_objects:
|
||||
if obj.animation_data.action is None:
|
||||
continue
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
if obj.mode == 'POSE':
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
if Tools.filter_properties(context.scene.animtoolbox, fcu):
|
||||
continue
|
||||
|
||||
#avg and value list per fcurve
|
||||
avg_value = []
|
||||
value_list = []
|
||||
for key in fcu.keyframe_points:
|
||||
if key.select_control_point:
|
||||
value_list.append(key.co[1])
|
||||
self.keyframes_values.update({key : key.co[1]})
|
||||
self.keyframes_handle_right.update({key : key.handle_right[1]})
|
||||
self.keyframes_handle_left.update({key : key.handle_left[1]})
|
||||
|
||||
if len(value_list)>1:
|
||||
#the average value with the scale property added to it
|
||||
avg_value = sum(value_list) / len(value_list)
|
||||
|
||||
for key in fcu.keyframe_points:
|
||||
if key.select_control_point:
|
||||
self.keyframes_avg_value.update({key : avg_value})
|
||||
|
||||
if not self.keyframes_avg_value:
|
||||
ui['is_dragging'] = False
|
||||
ui.multikey['scale'] = 1
|
||||
Tools.redraw_areas(['VIEW_3D'])
|
||||
return {'CANCELLED'}
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, context, event):
|
||||
|
||||
ui = context.window_manager.atb_ui
|
||||
scale = ui.multikey.scale
|
||||
|
||||
#Quit the modal operator when the slider is released
|
||||
if self.stop:
|
||||
ui['is_dragging'] = False
|
||||
ui.multikey['scale'] = 1
|
||||
Tools.redraw_areas(['VIEW_3D'])
|
||||
#modal is being cancelled because of undo issue with the modal running through the property
|
||||
return {'FINISHED'}
|
||||
|
||||
if event.value == 'RELEASE': # Stop the modal on next frame. Don't block the event since we want to exit the field dragging
|
||||
self.stop = True
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
for key, key_value in self.keyframes_values.items():
|
||||
if not key.select_control_point:
|
||||
continue
|
||||
if key not in self.keyframes_avg_value:
|
||||
continue
|
||||
avg_value = self.keyframes_avg_value[key]
|
||||
handle_right_value = self.keyframes_handle_right[key]
|
||||
handle_left_value = self.keyframes_handle_left[key]
|
||||
|
||||
#add the value of the distance from the average * scale factor
|
||||
key.co[1] = avg_value + ((key_value - avg_value)*scale)
|
||||
key.handle_right[1] = avg_value + ((handle_right_value - avg_value)*scale)
|
||||
key.handle_left[1] = avg_value + ((handle_left_value - avg_value)*scale)
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def scale_value(self, context):
|
||||
|
||||
ui = context.window_manager.atb_ui
|
||||
if ui.is_dragging:
|
||||
return
|
||||
obj = context.object
|
||||
|
||||
if obj is None:
|
||||
self['scale'] = 1
|
||||
return
|
||||
action = obj.animation_data.action
|
||||
|
||||
if action is None:
|
||||
self['scale'] = 1
|
||||
return
|
||||
|
||||
if context.mode == 'POSE' and not context.selected_pose_bones:
|
||||
self['scale'] = 1
|
||||
return
|
||||
|
||||
bpy.ops.animtoolbox.multikey_scale_value('INVOKE_DEFAULT')
|
||||
|
||||
def random_value(self, context):
|
||||
|
||||
for obj in context.selected_objects:
|
||||
if obj.animation_data.action is None:
|
||||
continue
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
if obj.mode == 'POSE':
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
if Tools.filter_properties(context.scene.animtoolbox, fcu):
|
||||
continue
|
||||
value_list = []
|
||||
threshold = bpy.context.window_manager.atb_ui.multikey.randomness
|
||||
for key in fcu.keyframe_points:
|
||||
if key.select_control_point == True:
|
||||
value_list.append(key.co[1])
|
||||
|
||||
if len(value_list) > 0:
|
||||
value = max(value_list)- min(value_list)
|
||||
for key in fcu.keyframe_points:
|
||||
add_value(key, value * random.uniform(-threshold, threshold))
|
||||
fcu.update()
|
||||
|
||||
self['randomness'] = 0.1
|
||||
|
||||
|
||||
def evaluate_combine(data_path, added_array, eval_array, array_default, influence):
|
||||
|
||||
if 'scale' in data_path:
|
||||
eval_array = eval_array * (added_array / array_default) ** influence
|
||||
elif 'rotation_quaternion' in data_path:
|
||||
#multiply first the influence with the w separatly
|
||||
added_array[0] = added_array[0] + (1- added_array[0])*(1 - influence)
|
||||
added_array[1:] *= influence
|
||||
eval_array = np.array(Quaternion(eval_array) @ Quaternion(added_array))# ** influence
|
||||
#if it's a custom property
|
||||
elif 'rotation_euler' not in data_path and 'location' not in data_path:
|
||||
eval_array = eval_array + (added_array - array_default) * influence
|
||||
|
||||
return eval_array
|
||||
|
||||
def evaluate_array(fcurves, fcu_path, frame, array_default = [0, 0, 0]):
|
||||
'''Create an array from all the indexes'''
|
||||
|
||||
array_len = len(array_default)
|
||||
|
||||
#assigning the default array in case
|
||||
fcu_array = array_default.copy()
|
||||
#get the missing arrays in case quaternion is not complete
|
||||
for i in range(array_len):
|
||||
fcu = fcurves.find(fcu_path, index = i)
|
||||
if fcu is None:
|
||||
continue
|
||||
fcu_array[i] = fcu.evaluate(frame)
|
||||
|
||||
if (fcu_array == array_default).all():
|
||||
return None
|
||||
return np.array(fcu_array)
|
||||
|
||||
def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
'''Calculate the evaluation of all the layers when using the nla'''
|
||||
|
||||
if not hasattr(anim_data, 'nla_tracks') or not anim_data.use_nla:
|
||||
return None
|
||||
nla_tracks = anim_data.nla_tracks
|
||||
if not len(nla_tracks):
|
||||
return None
|
||||
frame = context.scene.frame_current
|
||||
blend_types = {'ADD' : '+', 'SUBTRACT' : '-', 'MULTIPLY' : '*'}
|
||||
fcu_path = fcu.data_path
|
||||
|
||||
eval_array = array_default.copy()
|
||||
|
||||
for track in nla_tracks:
|
||||
if track.mute:
|
||||
continue
|
||||
if not len(track.strips):
|
||||
continue
|
||||
for strip in track.strips:
|
||||
if not strip.frame_start < frame < strip.frame_end:
|
||||
continue
|
||||
action = strip.action
|
||||
if action is None:
|
||||
continue
|
||||
blend_type = strip.blend_type
|
||||
|
||||
#get the influence value either from the attribute or the fcurve. function coming from bake
|
||||
influence = strip.influence
|
||||
if len(strip.fcurves):
|
||||
if not strip.fcurves[0].mute and len(strip.fcurves[0].keyframe_points):
|
||||
influence = strip.fcurves[0].evaluate(frame)
|
||||
|
||||
#evaluate the frame according to the strip settings
|
||||
frame_eval = frame
|
||||
#change the frame if the strip is on hold
|
||||
if frame < strip.frame_start:
|
||||
if strip.extrapolation == 'HOLD':
|
||||
frame_eval = strip.frame_start
|
||||
elif frame >= strip.frame_end:
|
||||
if strip.extrapolation == 'HOLD' or strip.extrapolation == 'HOLD_FORWARD':
|
||||
frame_eval = strip.frame_end
|
||||
|
||||
last_frame = strip.frame_start + (strip.frame_end - strip.frame_start) / strip.repeat
|
||||
|
||||
if strip.repeat > 1 and (frame) >= last_frame:
|
||||
action_range = (strip.action_frame_end * strip.scale - strip.action_frame_start * strip.scale)
|
||||
frame_eval = (((frame_eval - strip.frame_start) % (action_range)) + strip.frame_start)
|
||||
|
||||
if strip.use_reverse:
|
||||
frame_eval = last_frame - (frame_eval - strip.frame_start)
|
||||
offset = (strip.frame_start * 1/strip.scale - strip.action_frame_start) * strip.scale
|
||||
frame_eval = strip.frame_start * 1/strip.scale + (frame_eval - strip.frame_start) * 1/strip.scale - offset * 1/strip.scale
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
eval_array = evaluate_blend_type(fcurves, eval_array, fcu_path, frame_eval, influence, array_default, blend_type, blend_types)
|
||||
|
||||
#Adding an extra layer from the action outside and on top of the nla
|
||||
tweak_mode = anim_data.use_tweak_mode
|
||||
if tweak_mode:
|
||||
anim_data.use_tweak_mode = False
|
||||
|
||||
action = anim_data.action
|
||||
if action:
|
||||
influence = anim_data.action_influence
|
||||
blend_type = anim_data.action_blend_type
|
||||
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
eval_array = evaluate_blend_type(fcurves, eval_array, fcu_path, frame, influence, array_default, blend_type, blend_types)
|
||||
anim_data.use_tweak_mode = tweak_mode
|
||||
|
||||
return eval_array
|
||||
|
||||
|
||||
def evaluate_blend_type(fcurves, eval_array, fcu_path, frame, influence,
|
||||
array_default, blend_type, blend_types):
|
||||
'''Calculate the value based on the blend type'''
|
||||
|
||||
fcu_array = evaluate_array(fcurves, fcu_path, frame, array_default)
|
||||
if fcu_array is None:
|
||||
return eval_array
|
||||
###EVALUATION###
|
||||
if blend_type =='COMBINE':
|
||||
if 'location' in fcu_path or 'rotation_euler' in fcu_path:
|
||||
blend_type = 'ADD'
|
||||
if blend_type =='REPLACE':
|
||||
eval_array = eval_array * (1 - influence) + fcu_array * influence
|
||||
elif blend_type =='COMBINE':
|
||||
eval_array = evaluate_combine(fcu_path, fcu_array, eval_array, array_default, influence)
|
||||
else:
|
||||
eval_array = eval('eval_array' + blend_types[blend_type] + 'fcu_array' + '*' + str(influence))
|
||||
|
||||
return eval_array
|
||||
|
||||
def evaluate_value(self, context):
|
||||
ui = context.window_manager.atb_ui
|
||||
for obj in context.selected_objects:
|
||||
|
||||
anim_data = obj.animation_data
|
||||
if anim_data is None:
|
||||
return
|
||||
if anim_data.action is None:
|
||||
return
|
||||
|
||||
action = obj.animation_data.action
|
||||
fcu_paths = []
|
||||
transformations = ["rotation_quaternion","rotation_euler", "location", "scale"]
|
||||
if obj.mode == 'POSE':
|
||||
bonelist = context.selected_pose_bones if ui.multikey.selectedbones else obj.pose.bones
|
||||
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
for fcu in fcurves:
|
||||
if fcu in fcu_paths:
|
||||
continue
|
||||
current_value = None
|
||||
if Tools.filter_properties(context.scene.animtoolbox, fcu):
|
||||
continue
|
||||
if obj.mode == 'POSE':
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
continue
|
||||
|
||||
for bone in bonelist:
|
||||
#find the fcurve of the bone
|
||||
if fcu.data_path.rfind(bone.name) != 12 or fcu.data_path[12 + len(bone.name)] != '"':
|
||||
continue
|
||||
path_split = fcu.data_path.split('"].')
|
||||
|
||||
if len(path_split) <= 1:
|
||||
continue
|
||||
else:
|
||||
transform = fcu.data_path.split('"].')[1]
|
||||
if transform not in transformations:
|
||||
continue
|
||||
current_value = getattr(obj.pose.bones[bone.name], transform)
|
||||
else:
|
||||
transform = fcu.data_path
|
||||
current_value = getattr(obj, transform)
|
||||
#In case it was completly filtered out and not current value available
|
||||
if not current_value:
|
||||
continue
|
||||
|
||||
array_default = np.array(attr_default(obj, (fcu.data_path, fcu.array_index)))
|
||||
eval_array = evaluate_layers(context, obj, anim_data, fcu, array_default)
|
||||
if eval_array is None:
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
eval_array = evaluate_array(fcurves, fcu.data_path, context.scene.frame_current, array_default)
|
||||
|
||||
#calculate the difference between current value and the fcurve value
|
||||
add_diff(fcurves, fcu.data_path, np.array(current_value), eval_array)
|
||||
|
||||
class MULTIKEY_OT_Multikey(bpy.types.Operator):
|
||||
"""Edit all selected keyframes"""
|
||||
bl_label = "Edit Selected Keyframes"
|
||||
bl_idname = "animtoolbox.multikey"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object and context.active_object.animation_data and bpy.context.scene.tool_settings.use_keyframe_insert_auto == False
|
||||
|
||||
def execute(self, context):
|
||||
evaluate_value(self, context)
|
||||
return {'FINISHED'}
|
||||
|
||||
class MultikeyProperties(bpy.types.PropertyGroup):
|
||||
|
||||
selectedbones: bpy.props.BoolProperty(name="Selected Bones", description="Affect only selected bones", default=True, options={'HIDDEN'})
|
||||
handletype: bpy.props.BoolProperty(name="Keep handle types", description="Keep handle types", default=False, options={'HIDDEN'})
|
||||
scale: bpy.props.FloatProperty(name="Scale Factor", description="Scale percentage of the average value", default=1.0, update = scale_value)
|
||||
randomness: bpy.props.FloatProperty(name="Randomness", description="Random Threshold of keyframes", default=0.1, min=0.0, max = 1.0, update = random_value)
|
||||
|
||||
#filters
|
||||
# filter_location: bpy.props.BoolVectorProperty(name="Location", description="Filter Location properties", default=(True, True, True), size = 3, options={'HIDDEN'})
|
||||
# filter_rotation: bpy.props.BoolVectorProperty(name="Rotation", description="Filter Rotation properties", default=(True, True, True, True), size = 4, options={'HIDDEN'})
|
||||
# filter_scale: bpy.props.BoolVectorProperty(name="Scale", description="Filter Scale properties", default=(True, True, True), size = 3, options={'HIDDEN'})
|
||||
|
||||
# class FilterProperties(bpy.types.Operator):
|
||||
# """Filter Location Rotation and Scale Properties"""
|
||||
# bl_idname = "fcurves.filter"
|
||||
# bl_label = "Filter Properties W X Y Z"
|
||||
# bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
# def invoke(self, context, event):
|
||||
# wm = context.window_manager
|
||||
# return wm.invoke_props_dialog(self, width = 200)
|
||||
|
||||
# def draw(self, context):
|
||||
# layout = self.layout
|
||||
# row = layout.row()
|
||||
# row.label(text = 'Location')
|
||||
# row.prop(context.scene.multikey, 'filter_location', text = '')
|
||||
# row = layout.row()
|
||||
# row.label(text = 'Rotation')
|
||||
# row.prop(context.scene.multikey, 'filter_rotation', text = '')
|
||||
# row = layout.row()
|
||||
# row.label(text = 'Scale')
|
||||
# row.prop(context.scene.multikey, 'filter_scale', text = '')
|
||||
|
||||
# def execute(self, context):
|
||||
# return {'CANCELLED'}
|
||||
|
||||
classes = (ScaleValuesOp, MULTIKEY_OT_Multikey)
|
||||
|
||||
#register, unregister = bpy.utils.register_classes_factory(classes)
|
||||
|
||||
def register():
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
# bpy.types.Scene.animtoolbox.multikey = bpy.props.PointerProperty(type = MultikeyProperties, options={'LIBRARY_EDITABLE'}, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
def unregister():
|
||||
from bpy.utils import unregister_class
|
||||
for cls in classes:
|
||||
unregister_class(cls)
|
||||
# del bpy.types.Scene.animtoolbox.multikey
|
||||
@@ -1,725 +0,0 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import bpy
|
||||
from . import Rigger_Toolbox
|
||||
from . import multikey
|
||||
from . import Rigger_Toolbox
|
||||
from pathlib import Path
|
||||
from bpy.utils import register_class
|
||||
from bpy.utils import unregister_class
|
||||
import os
|
||||
|
||||
######################################################## MENUS ########################################################
|
||||
|
||||
class ANIMTOOLBOX_MT_Copy_Paste_Matrix(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Copy_Paste_Matrix'
|
||||
bl_label = "Copy Paste Matrix"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator('anim.copy_matrix', text = 'Copy World Matrix', icon ='DUPLICATE')
|
||||
layout.operator('anim.paste_matrix', text = 'Paste World Matrix', icon ='PASTEDOWN')
|
||||
layout.separator()
|
||||
layout.operator('anim.copy_relative_matrix', text = 'Copy Relative Matrix', icon ='DUPLICATE')
|
||||
layout.operator('anim.paste_relative_matrix', text = 'Paste Relative Matrix', icon ='PASTEDOWN')
|
||||
layout.separator()
|
||||
layout.prop_menu_enum(context.scene.animtoolbox, 'range_type', text = 'Frame Range Type')
|
||||
if context.scene.animtoolbox.range_type == 'RANGE':
|
||||
# split = layout.split(factor = 0.3)
|
||||
# layout.prop(context.scene.animtoolbox, 'bake_frame_start', text = 'Start')
|
||||
# layout.prop(context.scene.animtoolbox, 'bake_frame_end', text = 'End')
|
||||
layout.operator("anim.markers_bakerange", icon = 'MARKER', text ='Frame Range Markers Widget', depress = context.scene.animtoolbox.bake_frame_range)
|
||||
|
||||
class ANIMTOOLBOX_MT_Temp_Ctrls(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Temp_Ctrls'
|
||||
bl_label = "Temp Ctrls"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
custom_icons = preview_collections["main"]
|
||||
layout.operator('anim.bake_to_ctrl', text="World Space Ctrls", icon = 'WORLD')
|
||||
# layout.operator('anim.worldspace_cursor', text="World Space Cursor Ctrls", icon ='ORIENTATION_CURSOR')
|
||||
layout.operator('anim.bake_to_temp_fk', text="Temp FK Ctrls", icon = 'BONE_DATA')
|
||||
layout.operator('anim.bake_to_temp_ik', text="Temp IK Ctrls", icon = 'CON_KINEMATIC')
|
||||
layout.separator()
|
||||
layout.operator('anim.link_temp_chains', text="Link Temp Chains", icon = 'DECORATE_LINKED')
|
||||
layout.operator('anim.unlink_temp_chains', text="UnLink Temp Chains", icon = 'DECORATE_LINKED')
|
||||
layout.separator()
|
||||
layout.operator('anim.bake_temp_ctrls', text="Bake Temp Ctrls", icon_value = custom_icons["oven"].icon_id)
|
||||
layout.operator('anim.remove_bones_constraints', text="Cleanup", icon_value = custom_icons["trash"].icon_id)
|
||||
layout.prop_menu_enum(context.scene.btc, 'target', text = 'Bake To', icon = 'MOD_ARMATURE')
|
||||
layout.separator()
|
||||
|
||||
ctrl = context.object.animtoolbox.controller if context.object.animtoolbox.controller else context.object
|
||||
if ctrl:
|
||||
layout.prop(ctrl.animtoolbox, 'ctrls_enabled', text ='Temp Ctrls On/Off')
|
||||
|
||||
# layout.operator('anim.enable_tempctrls', text="On" , icon = 'HIDE_OFF')#icon = 'CONSTRAINT_BONE'
|
||||
# layout.operator('anim.disable_tempctrls', text="Off", icon = 'HIDE_ON')
|
||||
layout.separator()
|
||||
layout.prop_menu_enum(context.scene.btc, 'shape_type', icon = 'MESH_DATA')
|
||||
layout.prop(context.scene.btc, 'shape_size', slider = False, icon ='CON_SIZELIKE')
|
||||
layout.prop(context.scene.btc, 'color_set', text = '')
|
||||
# layout.prop(context.scene.btc, 'shape_type', icon = 'MESH_DATA', text ='')
|
||||
|
||||
class ANIMTOOLBOX_MT_Keyframe_Offset(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Keyframe_Offset'
|
||||
bl_label = "Interactive Keyframe Offset"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(context.scene.animtoolbox, 'keyframes_offset', slider = False)
|
||||
layout.operator('anim.select_keyframes_offset', text="Select Offset Keyframes", icon ='RESTRICT_SELECT_OFF')
|
||||
layout.operator('anim.apply_keyframes_offset', text="Apply Offset", icon = 'ANIM')
|
||||
|
||||
class ANIMTOOLBOX_MT_Blendings(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Blendings'
|
||||
bl_label = "Blendings"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
ui = context.window_manager.atb_ui
|
||||
layout.prop(ui, 'inbetween_worldmatrix', slider = True)
|
||||
layout.prop(context.scene.animtoolbox, 'inbetweener', slider = True)
|
||||
layout.prop(ui, 'blend_mirror', slider = True)
|
||||
|
||||
class ANIMTOOLBOX_MT_Multikey(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Multikey'
|
||||
bl_label = "Multikey"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
ui = context.window_manager.atb_ui
|
||||
layout.operator("animtoolbox.multikey", icon = 'ACTION_TWEAK')
|
||||
layout.prop(ui.multikey, 'scale', slider = True)
|
||||
layout.prop(ui.multikey, 'randomness', slider = True)
|
||||
|
||||
class ANIMTOOLBOX_MT_Convert_Rotations(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_Convert_Rotations'
|
||||
bl_label = "Convert Rotations"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("anim.convert_rotation_mode", icon = 'DRIVER_ROTATIONAL_DIFFERENCE', text = 'Convert Rotation To')
|
||||
layout.operator("anim.find_rotation_mode", icon = 'VIEWZOOM', text = 'Recommend Euler Rotation')
|
||||
layout.prop_menu_enum(context.scene.animtoolbox, 'rotation_mode', text = 'Convert To')
|
||||
|
||||
class ANIMTOOLBOX_MT_operators(bpy.types.Menu):
|
||||
bl_idname = 'ANIMTOOLBOX_MT_menu_operators'
|
||||
bl_label = "AnimToolBox"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
ui = context.window_manager.atb_ui
|
||||
custom_icons = preview_collections["main"]
|
||||
|
||||
if context.area.type == 'VIEW_3D':
|
||||
layout.menu('ANIMTOOLBOX_MT_Temp_Ctrls', text = 'Temp Ctrls', icon_value = custom_icons["puppet"].icon_id)
|
||||
layout.separator()
|
||||
layout.operator('anim.share_keyframes', text = 'Share Keyframes', icon_value = custom_icons["sharekeys"].icon_id)
|
||||
layout.operator('anim.relative_cursor', text = 'Relative Cursor Pivot', icon_value = custom_icons["relative_cursor"].icon_id, depress = ui.relative_cursor)
|
||||
layout.operator("anim.markers_retimer", icon_value = custom_icons["retime"].icon_id, text ='Markers Retimer', depress = ui.markers_retimer)
|
||||
layout.menu('ANIMTOOLBOX_MT_Convert_Rotations', text = 'Convert Rotations', icon = 'DRIVER_ROTATIONAL_DIFFERENCE')
|
||||
|
||||
layout.separator()
|
||||
layout.menu('ANIMTOOLBOX_MT_Keyframe_Offset', text = 'Interactive Keyframe Offset', icon_value = custom_icons["keyframe_offset"].icon_id)
|
||||
layout.menu('ANIMTOOLBOX_MT_Blendings', text = 'Blendings and inbetweens', icon_value = custom_icons["sliders"].icon_id)
|
||||
layout.separator()
|
||||
layout.menu('ANIMTOOLBOX_MT_Copy_Paste_Matrix', text = 'Copy Paste Matrix', icon_value = custom_icons["copy_matrix"].icon_id)
|
||||
|
||||
if bpy.context.preferences.addons[__package__].preferences.multikey:
|
||||
layout.separator()
|
||||
layout.menu('ANIMTOOLBOX_MT_Multikey', text = 'Multikey', icon_value = custom_icons["multikey"].icon_id)
|
||||
|
||||
layout.separator(factor = 0.5)
|
||||
layout.operator('anim.switch_collections_visibility', icon = 'COLLECTION_COLOR_06', text = 'Animated Collections Visibilty')
|
||||
layout.operator('anim.isolate_pose_mode', icon_value = custom_icons["isolate"].icon_id, depress = scene.animtoolbox.isolate_pose_mode)
|
||||
layout.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
layout.separator()
|
||||
layout.prop(context.preferences.addons[__package__].preferences, 'quick_menu', text = 'Use Quick Icons Menu')
|
||||
# layout.prop(context.window_manager.atb_ui, 'quick_menu', text = 'Use Quick Icons Menu')
|
||||
# elif context.area.type == 'DOPESHEET_EDITOR':
|
||||
# layout.operator('wm.call_menu_pie', text="Pie AnimOffset").name = 'ANIMAIDE_MT_pie_anim_offset'
|
||||
# layout.menu('ANIMAIDE_MT_anim_offset')
|
||||
# layout.menu('ANIMAIDE_MT_anim_offset_mask')
|
||||
|
||||
# elif context.area.type == 'GRAPH_EDITOR':
|
||||
# layout.menu('ANIMAIDE_MT_curve_tools_pie')
|
||||
|
||||
######################################################## WorkSpaceTools ########################################################
|
||||
|
||||
class KeyframeOffsetTool(bpy.types.WorkSpaceTool):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_context_mode = 'POSE'
|
||||
bl_idname = 'animtoolbox.keyframe_offset'
|
||||
bl_label = 'Keyframe Offset Tool'
|
||||
bl_description = (
|
||||
'Offset the keyframes of the selected bone\n'
|
||||
'Shift + Click to select the bones with an offset\n'
|
||||
'Ctrl + Alt + Click to Apply the offset'
|
||||
)
|
||||
bl_icon = (Path(__file__).parent / "icons" / "ops.anim.keyframe_offset").as_posix()
|
||||
bl_keymap = (
|
||||
('anim.keyframe_offset', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG'}, None),
|
||||
# ('anim.select_keyframes_offset', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'shift': True}, None),
|
||||
('anim.apply_keyframes_offset', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'ctrl': True, 'alt': True}, None),
|
||||
|
||||
('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'shift': True}, {'properties': [('mode', 'ADD')]}),
|
||||
('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'ctrl': True}, {'properties': [('mode', 'SUB')]}),
|
||||
('view3d.select_box', {'type': 'LEFTMOUSE', 'value': 'CLICK_DRAG', 'shift': True, 'ctrl': True}, {'properties': [('mode', 'AND')]}),
|
||||
('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK'}, {'properties': [('deselect_all', True)]}),
|
||||
('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'shift': True}, {'properties': [('toggle', True)]}),
|
||||
('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'alt': True}, {'properties': [('enumerate', True)]}),
|
||||
('view3d.select', {'type': 'LEFTMOUSE', 'value': 'CLICK', 'shift': True, 'alt': True}, {'properties': [('toggle', True), ('enumerate', True)]})
|
||||
|
||||
)
|
||||
|
||||
######################################################## PANELS ########################################################
|
||||
class ANIMTOOLBOX_PT_Panel:
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "Animation"
|
||||
#bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.object is not None
|
||||
|
||||
class ANIMTOOLBOX_PT_MainPanel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
#bl_category = "Animation"
|
||||
bl_label = "AnimToolBox"
|
||||
bl_idname = "ANIMTOOLBOX_PT_MainPanel"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw_header(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
self.layout.label(text='', icon_value = custom_icons["animtoolbox"].icon_id)
|
||||
|
||||
def draw(self, context):
|
||||
obj = context.object
|
||||
if obj is None:
|
||||
return
|
||||
# layout = self.layout
|
||||
# row = layout.row(align = True)
|
||||
|
||||
# row.label(text = 'Support me on ')
|
||||
# row.operator("wm.url_open", text="Patreon", icon = 'FUND').url = "https://www.patreon.com/animtoolbox"
|
||||
|
||||
class TEMPCTRLS_PT_Panel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
#bl_category = "Animation"
|
||||
bl_label = "Temp Controls"
|
||||
bl_idname = "TEMPCTRLS_PT_Panel"
|
||||
bl_parent_id = 'ANIMTOOLBOX_PT_MainPanel'
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw_header(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
self.layout.label(text="", icon_value = custom_icons["puppet"].icon_id)
|
||||
|
||||
def draw(self, context):
|
||||
obj = context.object
|
||||
btc = context.scene.btc
|
||||
if obj is None:
|
||||
return
|
||||
custom_icons = preview_collections["main"]
|
||||
oven_icon = custom_icons["oven"]
|
||||
# row = layout.row()
|
||||
ui = context.window_manager.atb_ui
|
||||
layout = self.layout
|
||||
box = layout.box()
|
||||
col = box.column()
|
||||
row = col.row()
|
||||
row.operator('anim.bake_to_ctrl', text="WorldSpace Ctrls", icon ='WORLD') #
|
||||
row.operator('anim.add_empty_ctrl', text="", icon ='EMPTY_AXIS')
|
||||
# col.operator('anim.worldspace_cursor', text="WorldSpace Cursor Ctrls", icon ='ORIENTATION_CURSOR')
|
||||
col.operator('anim.bake_to_temp_fk', text="Temp FK Ctrls", icon = 'BONE_DATA')
|
||||
col.operator('anim.bake_to_temp_ik', text="Temp IK Ctrls", icon = 'CON_KINEMATIC')
|
||||
|
||||
# layout.separator(factor = 0.1)
|
||||
# box = layout.box()
|
||||
row = box.row()
|
||||
row.operator('anim.link_temp_chains', text="Link Temp Chains", icon = 'DECORATE_LINKED')
|
||||
row.prop(btc, 'linksettings', text = '', icon = 'SETTINGS')
|
||||
|
||||
if btc.linksettings:
|
||||
# insidebox = box.box()
|
||||
row = box.row()
|
||||
row.label(text = 'Link to Active Chain: ')
|
||||
row.prop(btc, 'link_to', text = '')
|
||||
row = box.row()
|
||||
row.operator('anim.unlink_temp_chains', text="UnLink Temp Chains", icon = 'UNLINKED')
|
||||
# row = insidebox.row()
|
||||
# row.label(text = 'Link from Chain: ')
|
||||
# row.prop(btc, 'link_from', text = '')
|
||||
# layout.separator(factor = 0.1)
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.operator('anim.bake_to_empties', text="WorldSpace Empties")
|
||||
row.operator('anim.empties_to_bones', text="", icon = 'EMPTY_AXIS')
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
# row.operator('anim.bake_constrained_bones', text="Quick Bake", icon = 'REC')
|
||||
row.operator('anim.bake_temp_ctrls', text="Bake Temp Ctrls", icon_value = oven_icon.icon_id)
|
||||
row.prop(btc, 'bakesettings', text = '', icon = 'SETTINGS')
|
||||
|
||||
if btc.bakesettings:
|
||||
insidebox = box.box()
|
||||
# split = insidebox.split(factor = 0.9)
|
||||
# split.prop(btc, 'smartbake', text = 'Smart Bake')
|
||||
# split.operator('fcurves.filter_ui', icon ='FILTER', text = '')
|
||||
# if btc.smartbake:
|
||||
# row.prop(btc, 'inbetween_keyframes')
|
||||
split = insidebox.split(factor = 0.3)
|
||||
split.label(text = 'Bake To:')
|
||||
# split.split(factor = 0.9)
|
||||
split_2 = split.split(factor = 0.9)
|
||||
split_2.prop(btc, 'target', text = '')
|
||||
split_2.operator('fcurves.filter_ui', icon ='FILTER', text = '')
|
||||
|
||||
split = insidebox.split(factor = 0.3)
|
||||
split.label(text = 'Bake Range:')
|
||||
split.prop(btc, 'bake_range_type', text = '')
|
||||
|
||||
if btc.bake_range_type == 'KEYFRAMES':
|
||||
row = insidebox.row()
|
||||
row.label(text = 'Keyframes: ')
|
||||
row.prop(btc, 'smartbake', text = 'Smart Bake')
|
||||
row.prop(btc, 'bake_layers', text = 'All Layers')
|
||||
row = insidebox.row()
|
||||
row.label(text = 'From:')
|
||||
row.prop(btc, 'from_origin', text = 'Origin')
|
||||
row.prop(btc, 'from_ctrl', text = 'Ctrls')
|
||||
|
||||
elif btc.bake_range_type == 'CUSTOM':
|
||||
row = insidebox.row()
|
||||
row.prop(btc, 'bake_range', text = '')
|
||||
|
||||
insidebox.separator(factor=0.1)
|
||||
row = insidebox.row()
|
||||
row.label(text = 'Clean: ')
|
||||
row.prop(btc, 'clean_constraints', text = 'Constraints')
|
||||
if btc.clean_constraints:
|
||||
row.prop(btc, 'clean_ctrls', text = 'Ctrls')
|
||||
|
||||
row = box.row()
|
||||
row.operator('anim.remove_bones_constraints', text="Cleanup", icon_value = custom_icons["trash"].icon_id)
|
||||
row.prop(btc, 'cleansettings', text = '', icon = 'SETTINGS')
|
||||
|
||||
if btc.cleansettings:
|
||||
insidebox = box.box()
|
||||
split = insidebox.split(factor = 0.4)
|
||||
split.label(text = 'Target: ')
|
||||
split.prop(btc, 'target', text = '')
|
||||
row = insidebox.row()
|
||||
row.label(text = 'Clean: ')
|
||||
row.prop(btc, 'clean_constraints', text = 'Constraints')
|
||||
if btc.clean_constraints:
|
||||
row.prop(btc, 'clean_ctrls', text = 'Ctrls')
|
||||
if btc.target == 'SELECTED':
|
||||
split = insidebox.split(factor = 0.68)
|
||||
split.label(text = 'ReBake Link Ctrls to Original: ')
|
||||
split.prop(btc, 'rebake_to_org', text = '')
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
# row = layout.row()
|
||||
|
||||
# row.prop(obj.animtoolbox, 'influence', text = 'Influence', slider = True)
|
||||
ctrl = obj.animtoolbox.controller if obj.animtoolbox.controller else obj
|
||||
if ctrl:
|
||||
enabled_icon = 'HIDE_OFF' if ctrl.animtoolbox.ctrls_enabled else 'HIDE_ON'
|
||||
row.prop(ctrl.animtoolbox, 'ctrls_enabled', text ='Temp Ctrls On/Off', icon = enabled_icon)
|
||||
# row = box.row()
|
||||
# row.prop(ui, 'temp_ctrls_switch', icon = 'RESTRICT_VIEW_OFF', text = '')
|
||||
# row.label(text = 'Temp Ctrls Switch: ')
|
||||
# row.prop(btc, 'target', text = '', icon = 'MOD_ARMATURE', icon_only = True)
|
||||
# if ui.temp_ctrls_switch:
|
||||
# # split = layout.split(factor = 0.225)
|
||||
# row = box.row()
|
||||
# row.operator('anim.enable_tempctrls', text="On" , icon = 'HIDE_OFF')#icon = 'CONSTRAINT_BONE'
|
||||
# row.operator('anim.disable_tempctrls', text="Off", icon = 'HIDE_ON')
|
||||
|
||||
box.separator(factor=0.1)
|
||||
row = box.row()
|
||||
row.prop(ui, 'temp_ctrls_shapes', icon = 'MESH_DATA', text = '')
|
||||
row.label(text = 'Temp Ctrls Shapes: ')
|
||||
row.prop(btc, 'target', text = '', icon = 'MOD_ARMATURE', icon_only = True)
|
||||
if ui.temp_ctrls_shapes:
|
||||
row = box.row()
|
||||
row.prop(btc, 'shape_size', slider = False)
|
||||
row.prop(btc, 'shape_type', text = '')
|
||||
row = layout.row()
|
||||
# split.label(text = 'Theme Color: ')
|
||||
row.prop(btc, 'color_set', text = '')
|
||||
|
||||
layout.separator()
|
||||
row = layout.row()
|
||||
row.operator('anim.btc_selections', text="Select", icon = 'CONSTRAINT_BONE')
|
||||
row.prop(btc, 'selection', text = '', icon = 'CON_ARMATURE')
|
||||
|
||||
class ANIMTOOLBOX_PT_Tools(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
bl_label = "Anim Tools"
|
||||
bl_idname = "ANIMTOOLBOX_PT_Tools"
|
||||
bl_parent_id = 'ANIMTOOLBOX_PT_MainPanel'
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw_header(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
layout = self.layout
|
||||
layout.label(text="", icon_value = custom_icons["toolbox"].icon_id)
|
||||
|
||||
|
||||
def draw(self, context):
|
||||
obj = context.object
|
||||
scene = context.scene
|
||||
atb = scene.animtoolbox
|
||||
if obj is None:
|
||||
return
|
||||
custom_icons = preview_collections["main"]
|
||||
layout = self.layout
|
||||
ui = context.window_manager.atb_ui
|
||||
row = layout.row()
|
||||
filter_text = 'Filter Tools Properties' if atb.filter_name == '' else 'Filters: ' + atb.filter_name
|
||||
filter_depress = False if atb.filter_name == '' else True
|
||||
row.operator('fcurves.filter_ui', icon ='FILTER', text = filter_text, depress = filter_depress)
|
||||
layout.separator()
|
||||
#layout.operator('anim.keyframes_offset', text="Offset Keyframes", icon = 'NEXT_KEYFRAME')
|
||||
split = layout.split(factor = 0.9)
|
||||
split.prop(context.scene.animtoolbox, 'keyframes_offset', slider = True)
|
||||
split.operator('anim.apply_keyframes_offset', text="", icon_value = custom_icons["apply"].icon_id)
|
||||
split.operator('anim.select_keyframes_offset', text="", icon_value = custom_icons["select"].icon_id)
|
||||
row = layout.row()
|
||||
row.operator('anim.share_keyframes', text = 'Share Keyframes', icon_value = custom_icons["sharekeys"].icon_id)
|
||||
row = layout.row()
|
||||
row.operator("anim.relative_cursor", text ='Relative Cursor Pivot', icon_value = custom_icons["relative_cursor"].icon_id, depress = ui.relative_cursor)
|
||||
row = layout.row()
|
||||
row.operator("anim.markers_retimer", icon_value = custom_icons["retime"].icon_id, text ='Markers Retimer', depress = ui.markers_retimer)
|
||||
layout.separator(factor = 0.5)
|
||||
|
||||
box = layout.box()
|
||||
# icon = 'DOWNARROW_HLT' if ui.copy_paste_matrix is True else 'RIGHTARROW_THIN'
|
||||
# split = box.split(factor = 0.9)
|
||||
# split.prop(ui, 'copy_paste_matrix', icon_value = custom_icons["copy_matrix"].icon_id, text = 'Copy Paste Matrices')
|
||||
# split.operator('fcurves.filter', icon ='FILTER', text = '')
|
||||
row = box.row()
|
||||
row.prop(ui, 'copy_paste_matrix', icon_value = custom_icons["copy_matrix"].icon_id, text = 'Copy Paste Matrices')
|
||||
if ui.copy_paste_matrix:
|
||||
row = box.row()
|
||||
row.label(text = 'Copy World Matrix :', icon = 'WORLD')
|
||||
row.operator('anim.copy_matrix', text = '', icon ='DUPLICATE')
|
||||
row.operator('anim.paste_matrix', text = '', icon ='PASTEDOWN')
|
||||
row = box.row()
|
||||
row.label(text = 'Copy Relative Matrix :', icon = 'LINKED')
|
||||
row.operator('anim.copy_relative_matrix', text = '', icon ='DUPLICATE')
|
||||
row.operator('anim.paste_relative_matrix', text = '', icon ='PASTEDOWN')
|
||||
split = box.split(factor = 0.32)
|
||||
split.label(text = 'Paste To')
|
||||
split.prop(context.scene.animtoolbox, 'range_type', text = '')
|
||||
if context.scene.animtoolbox.range_type == 'RANGE':
|
||||
row = box.row()
|
||||
row.prop(context.scene.animtoolbox, 'bake_frame_start', text = 'Start')
|
||||
row.prop(context.scene.animtoolbox, 'bake_frame_end', text = 'End')
|
||||
row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = context.scene.animtoolbox.bake_frame_range)
|
||||
layout.separator(factor = 0.5)
|
||||
|
||||
box = layout.box()
|
||||
# icon = 'DOWNARROW_HLT' if ui.Inbetweens is True else 'RIGHTARROW_THIN'
|
||||
# split = box.split(factor = 0.9)
|
||||
# split.prop(ui, 'Inbetweens', icon_value = custom_icons["sliders"].icon_id, text = 'Blendings / Inbetweens')
|
||||
# split.operator('fcurves.filter', icon ='FILTER', text = '')
|
||||
row = box.row()
|
||||
row.prop(ui, 'Inbetweens', icon_value = custom_icons["sliders"].icon_id, text = 'Blendings / Inbetweens')
|
||||
|
||||
if ui.Inbetweens:
|
||||
col = box.column()
|
||||
col.prop(ui, 'inbetween_worldmatrix', slider = True)
|
||||
col.prop(scene.animtoolbox, 'inbetweener', slider = True)
|
||||
col.prop(ui, 'blend_mirror', slider = True)
|
||||
|
||||
layout.separator(factor = 1)
|
||||
# my_icon = custom_icons["rotations"]
|
||||
split = layout.split(factor = 0.6)
|
||||
split.operator("anim.convert_rotation_mode", icon = 'DRIVER_ROTATIONAL_DIFFERENCE', text = 'Convert Rotation To')
|
||||
# split.operator("anim.convert_rotation_mode", text = 'Convert Rotation To', icon_value = my_icon.icon_id)
|
||||
split = split.split(factor = 0.3)
|
||||
split.operator("anim.find_rotation_mode", icon = 'VIEWZOOM', text = '')
|
||||
split.prop(context.scene.animtoolbox, 'rotation_mode', text = '')
|
||||
|
||||
class MULTIKEY_PT_Panel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
"""Add random value to selected keyframes"""
|
||||
bl_label = "Multikey"
|
||||
bl_idname = "MULTIKEY_PT_Panel"
|
||||
# bl_space_type = 'VIEW_3D'
|
||||
# bl_region_type = 'UI'
|
||||
# bl_category= 'Animation'
|
||||
bl_parent_id = 'ANIMTOOLBOX_PT_Tools'
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw_header(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
layout = self.layout
|
||||
layout.label(text="", icon_value = custom_icons["multikey"].icon_id)
|
||||
|
||||
def draw(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
layout = self.layout
|
||||
ui = context.window_manager.atb_ui
|
||||
# layout.separator()
|
||||
split = layout.split(factor=0.1, align = True)
|
||||
split.prop(ui.multikey, 'selectedbones', icon_value = custom_icons["selected_bones"].icon_id, text = '')
|
||||
# split = split.split(factor=0.1, align = True)
|
||||
#split.operator('fcurves.filter', icon ='FILTER', text = '')
|
||||
split.operator("animtoolbox.multikey", icon = 'ACTION_TWEAK')
|
||||
layout.separator()
|
||||
row = layout.row(align = True)
|
||||
row.prop(ui.multikey, 'scale')
|
||||
row.prop(ui.multikey, 'randomness', slider = True)
|
||||
|
||||
class ANIMTOOLBOX_PT_Display(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
bl_label = "Display"
|
||||
bl_idname = "ANIMTOOLBOX_PT_Display"
|
||||
bl_parent_id = 'ANIMTOOLBOX_PT_MainPanel'
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw_header(self, context):
|
||||
custom_icons = preview_collections["main"]
|
||||
self.layout.label(text="", icon_value = custom_icons["display"].icon_id)
|
||||
|
||||
def draw(self, context):
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
ui = context.window_manager.atb_ui
|
||||
custom_icons = preview_collections["main"]
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
icon = 'DOWNARROW_HLT' if ui.gizmo_size is True else 'RIGHTARROW_THIN'
|
||||
row.prop(ui, 'gizmo_size', icon = icon, text = 'Add to Gizmo Size:')
|
||||
if ui.gizmo_size:
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'gizmo_size', text = '')
|
||||
row.operator('view3d.gizmo_size_up', text="", icon ='ADD')
|
||||
row.operator('view3d.gizmo_size_down', text="", icon ='REMOVE')
|
||||
layout.separator(factor = 0.5)
|
||||
|
||||
row = layout.row()
|
||||
col_vis_icon = 'OUTLINER_COLLECTION' if scene.animtoolbox.col_vis else 'COLLECTION_COLOR_06'
|
||||
row.operator('anim.switch_collections_visibility', icon = col_vis_icon, text = 'Animated Collections Visibilty', depress = scene.animtoolbox.col_vis)
|
||||
layout.separator(factor = 0.5)
|
||||
row = layout.row()
|
||||
row.operator('anim.isolate_pose_mode', icon_value = custom_icons["isolate"].icon_id, depress = scene.animtoolbox.isolate_pose_mode)
|
||||
|
||||
layout.separator(factor = 0.5)
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
emp = scene.emp
|
||||
row.prop(scene.emp, 'settings', text = '', icon = 'SETTINGS')
|
||||
if scene.emp.settings:
|
||||
|
||||
split = box.split(factor = 0.4)
|
||||
split.label(text ='Frame Range')
|
||||
# row.prop(scene.animtoolbox, 'mp_frame_range', text = '')
|
||||
|
||||
split.prop(emp, 'frame_range', text = '')
|
||||
if emp.frame_range == 'MANUAL':
|
||||
row = box.row()
|
||||
row.prop(emp, 'frame_start', text = 'Start')
|
||||
row.prop(emp, 'frame_end', text = 'End')
|
||||
# row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
|
||||
elif emp.frame_range == 'AROUND':
|
||||
row = box.row()
|
||||
row.prop(emp, 'before', text = 'Before')
|
||||
row.prop(emp, 'after', text = 'After')
|
||||
|
||||
box.separator(factor = 0.1)
|
||||
col = box.column()
|
||||
col.prop(emp, 'display_size', icon = 'DOWNARROW_HLT')
|
||||
if emp.display_size:
|
||||
col.prop(emp, 'thickness', text = 'Line Thickness')
|
||||
col.prop(emp, 'keyframe_size', text = 'Keyframes Size')
|
||||
col.prop(emp, 'frame_size', text = 'Frames Size')
|
||||
|
||||
box.separator(factor = 0.1)
|
||||
row = box.row()
|
||||
row.label(text = 'Visualization Type')
|
||||
row.prop(emp, 'vis_type', text = '')
|
||||
if emp.vis_type == 'VELOCITY':
|
||||
row = box.row()
|
||||
row.prop(emp, 'velocity_factor', text = '')
|
||||
row.prop(emp, 'clamp_min', text = '')
|
||||
row.prop(emp, 'clamp_max', text = '')
|
||||
|
||||
row = box.row()
|
||||
row.prop(emp, 'color_before', text = '')
|
||||
row.prop(emp, 'color_after', text = '')
|
||||
|
||||
row = box.row()
|
||||
row.prop(emp, 'points', text = 'Points')
|
||||
row.prop(emp, 'lines', text = 'Lines')
|
||||
row = box.row()
|
||||
row.prop(emp, 'handles', text = 'Handles')
|
||||
row.prop(emp, 'infront', text = 'In Front')
|
||||
row = box.row()
|
||||
row.prop(emp, 'display_frames', text = 'Display Keyframe Numbers')
|
||||
row.separator()
|
||||
row = box.row()
|
||||
row.operator('anim.go_to_keyframe')
|
||||
# row = box.row()
|
||||
# row.prop(context.preferences.addons[__package__].preferences, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
# if context.object is None:
|
||||
# return
|
||||
# row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
|
||||
class RIGGERTOOLBOX_PT_Panel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
bl_label = "Rigger Toolbox"
|
||||
bl_idname = "RIGGERTOOLBOX_PT_Panel"
|
||||
bl_parent_id = 'ANIMTOOLBOX_PT_MainPanel'
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def draw(self, context):
|
||||
obj = context.object
|
||||
if obj is None:
|
||||
return
|
||||
layout = self.layout
|
||||
col = layout.column()
|
||||
|
||||
col.operator("armature.add_bbone_widgets", text = "Add Bbone Widgets", icon = 'IPO_BEZIER')
|
||||
col.separator()
|
||||
col.operator("armature.add_chain_ctrls", text = "Add Chain Controls", icon = 'OUTLINER_DATA_ARMATURE')
|
||||
col.separator()
|
||||
col.operator("armature.merge", text = "Merge Rigs", icon = 'MOD_ARMATURE')
|
||||
|
||||
# Add-ons Preferences Update Panel
|
||||
# Define Panel classes for updating
|
||||
panels = [ANIMTOOLBOX_PT_MainPanel, TEMPCTRLS_PT_Panel, ANIMTOOLBOX_PT_Tools, ANIMTOOLBOX_PT_Display]
|
||||
|
||||
def update_panel(self, context):
|
||||
message = "Animtoolbox: Updating Panel locations has failed"
|
||||
try:
|
||||
for panel in panels:
|
||||
if "bl_rna" in panel.__dict__:
|
||||
unregister_class(panel)
|
||||
|
||||
for panel in panels:
|
||||
panel.bl_category = context.preferences.addons[__package__].preferences.category
|
||||
register_class(panel)
|
||||
|
||||
except Exception as e:
|
||||
print("\n[{}]\n{}\n\nError:\n{}".format(__package__, message, e))
|
||||
pass
|
||||
|
||||
def add_multikey(self, context):
|
||||
if bpy.context.preferences.addons[__package__].preferences is None:
|
||||
return
|
||||
if bpy.context.preferences.addons[__package__].preferences.multikey:
|
||||
multikey.register()
|
||||
register_class(MULTIKEY_PT_Panel)
|
||||
register_class(ANIMTOOLBOX_MT_Multikey)
|
||||
panels.append(MULTIKEY_PT_Panel)
|
||||
#panels = panels + (MULTIKEY_PT_Panel)
|
||||
elif hasattr(bpy.types, 'MULTIKEY_PT_Panel'):
|
||||
multikey.unregister()
|
||||
panels.remove(MULTIKEY_PT_Panel)
|
||||
unregister_class(MULTIKEY_PT_Panel)
|
||||
unregister_class(ANIMTOOLBOX_MT_Multikey)
|
||||
|
||||
def add_riggertoolbox(self, context):
|
||||
if bpy.context.preferences.addons[__package__].preferences is None:
|
||||
return
|
||||
if bpy.context.preferences.addons[__package__].preferences.riggertoolbox:
|
||||
Rigger_Toolbox.register()
|
||||
register_class(RIGGERTOOLBOX_PT_Panel)
|
||||
panels.append(RIGGERTOOLBOX_PT_Panel)
|
||||
#panels = panels + (RIGGERTOOLBOX_PT_Panel)
|
||||
elif hasattr(bpy.types, 'RIGGERTOOLBOX_PT_Panel'):
|
||||
Rigger_Toolbox.unregister()
|
||||
panels.remove(RIGGERTOOLBOX_PT_Panel)
|
||||
unregister_class(RIGGERTOOLBOX_PT_Panel)
|
||||
|
||||
classes = (ANIMTOOLBOX_MT_Copy_Paste_Matrix, ANIMTOOLBOX_MT_Temp_Ctrls, ANIMTOOLBOX_MT_operators, ANIMTOOLBOX_MT_Keyframe_Offset,
|
||||
ANIMTOOLBOX_MT_Blendings, ANIMTOOLBOX_MT_Convert_Rotations) + tuple(panels)
|
||||
|
||||
preview_collections = {}
|
||||
#list of all the custom icons
|
||||
icons_list = {'relative_cursor' : 'relative_cursor.png', 'puppet' : 'puppet.png', 'animtoolbox' : 'animtoolbox.png',
|
||||
'sliders' : 'slider-navigation.png', 'world_space' : 'earth-rotation.png', 'isolate' : 'isolation.png',
|
||||
'mt' : 'curve.png', 'toolbox' : 'tools.png', 'oven' : 'oven.png', 'retime' : 'retime.png', 'copy_matrix' : 'copy_world.png',
|
||||
'sharekeys' : 'sharekeys.png', 'sliders' : 'sliders.png', 'keyframe_offset' : 'keyframes_offset.png', 'display' : 'display.png',
|
||||
'switch' : 'switch.png', 'trash' : 'trash.png', 'apply' : 'apply.png', 'select' : 'select.png', 'worldspace' : 'WorldSpace.png',
|
||||
'multikey' : 'multikey.png', 'selected_bones' : 'selected_bones.png'}
|
||||
|
||||
def register_custom_icon():
|
||||
# Note that preview collections returned by bpy.utils.previews
|
||||
# are regular py objects - you can use them to store custom data.
|
||||
import bpy.utils.previews
|
||||
custom_icons = bpy.utils.previews.new()
|
||||
# path to the folder where the icon is
|
||||
# the path is calculated relative to this py file inside the addon folder
|
||||
icons_dir = os.path.join(os.path.dirname(__file__), "icons")
|
||||
# load a preview thumbnail of a file and store in the previews collection
|
||||
for iconname, icon_file in icons_list.items():
|
||||
custom_icons.load(iconname, os.path.join(icons_dir, icon_file), 'IMAGE')
|
||||
preview_collections["main"] = custom_icons
|
||||
|
||||
def draw_menu(self, context):
|
||||
if context.mode == 'OBJECT' or context.mode == 'POSE':
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
ui = context.window_manager.atb_ui
|
||||
|
||||
custom_icons = preview_collections["main"]
|
||||
layout.menu('ANIMTOOLBOX_MT_menu_operators') #, icon_value = custom_icons["toolbox"].icon_id, text =''
|
||||
|
||||
if not context.preferences.addons[__package__].preferences.quick_menu:
|
||||
return
|
||||
#Only Icons Menu
|
||||
temp_ctrls = custom_icons["puppet"]
|
||||
layout.menu('ANIMTOOLBOX_MT_Temp_Ctrls' , icon_value = temp_ctrls.icon_id, text ='')
|
||||
# layout.separator()
|
||||
layout.menu('ANIMTOOLBOX_MT_Copy_Paste_Matrix' , icon_value = custom_icons["copy_matrix"].icon_id, text ='')
|
||||
|
||||
layout.separator()
|
||||
layout.operator('anim.relative_cursor', text = '', depress = ui.relative_cursor, icon_value = custom_icons["relative_cursor"].icon_id)
|
||||
|
||||
layout.separator()
|
||||
layout.operator('anim.markers_retimer', text = '', depress = ui.markers_retimer, icon_value = custom_icons["retime"].icon_id)
|
||||
|
||||
layout.separator()
|
||||
layout.operator('anim.isolate_pose_mode', text = '', depress = scene.animtoolbox.isolate_pose_mode, icon_value = custom_icons["isolate"].icon_id)
|
||||
|
||||
layout.separator()
|
||||
layout.operator('object.motion_path_operator', text = '', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -2007,7 +2007,7 @@ def remove_draw_handlers(self):
|
||||
# Operator with modal and draw handler
|
||||
class MotionPathOperator(bpy.types.Operator):
|
||||
|
||||
"""Creates an editable motion path, Ctrl click to refresh"""
|
||||
"""Creates a custom motion path"""
|
||||
bl_idname = "object.motion_path_operator"
|
||||
bl_label = "Motion Path Operator"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
@@ -2028,15 +2028,10 @@ class MotionPathOperator(bpy.types.Operator):
|
||||
scene = context.scene
|
||||
emp = scene.emp
|
||||
|
||||
emp.refresh = False
|
||||
if emp.motion_path:
|
||||
if event.ctrl:
|
||||
# Refresh the motion path
|
||||
emp.refresh = True
|
||||
else:
|
||||
emp.motion_path = False
|
||||
emp.motion_path = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
if context.selected_pose_bones is None and context.selected_objects is None:
|
||||
emp.motion_path = False
|
||||
return {'CANCELLED'}
|
||||
@@ -2242,6 +2237,9 @@ class MotionPathOperator(bpy.types.Operator):
|
||||
#return negative frame range to what it was
|
||||
if context.preferences.edit.use_negative_frames != nfr:
|
||||
context.preferences.edit.use_negative_frames = nfr
|
||||
|
||||
#assign the draw handler
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
#If overlays are turned off then skip drawing
|
||||
if self.mp_vis:
|
||||
@@ -2257,9 +2255,6 @@ class MotionPathOperator(bpy.types.Operator):
|
||||
self.area.tag_redraw()
|
||||
# Tools.redraw_areas(['VIEW_3D'])
|
||||
|
||||
#assign the draw handler
|
||||
context.window_manager.modal_handler_add(self)
|
||||
|
||||
bpy.ops.ed.undo_push(message = 'Initialize Motion Path')
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
@@ -2284,11 +2279,6 @@ class MotionPathOperator(bpy.types.Operator):
|
||||
if not emp.motion_path:
|
||||
quit_mp(self, context)
|
||||
return {'FINISHED'}
|
||||
|
||||
if emp.refresh:
|
||||
get_mp_points(self, context)
|
||||
emp.refresh = False
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
if not self.mp_vis:
|
||||
check_mp_vis_on(self, context)
|
||||
@@ -4874,8 +4864,6 @@ def disbale_non_smooth(self, context):
|
||||
class EditableMotionPathSettings(bpy.types.PropertyGroup):
|
||||
'''All the settings for Editable motion path'''
|
||||
motion_path: bpy.props.BoolProperty(name = "Motion Path", description = "Flag when Motion Path is on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
refresh: bpy.props.BoolProperty(name = "Refresh Motion Path", description = "Refresh the motion paths with hotkey ctrl", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
settings: bpy.props.BoolProperty(name = "Motion Path Settings", description = "Open the settings Menu", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
# mp_keyframe_scale: bpy.props.FloatProperty(name = "Scale Selecgted Keyframes Bounding Box", description = "Change the scale of the bounding box around the selected keyframes ", default = 0.1, step = 0.1, precision = 3)
|
||||
color_before: bpy.props.FloatVectorProperty(name="Motion Path Before Color", subtype='COLOR', default=(1.0, 0.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame", update=update_prop_callback)
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
bl_info = {
|
||||
"name": "Flamenco",
|
||||
"author": "Sybren A. Stüvel",
|
||||
"version": (3, 8, 5),
|
||||
"version": (3, 10),
|
||||
"blender": (3, 1, 0),
|
||||
"description": "Flamenco client for Blender.",
|
||||
"location": "Output Properties > Flamenco",
|
||||
"doc_url": "https://flamenco.blender.org/",
|
||||
"category": "System",
|
||||
"support": "COMMUNITY",
|
||||
"warning": "",
|
||||
"warning": "This is version 3.10-alpha0 of the add-on, which is not a stable release",
|
||||
}
|
||||
|
||||
from pathlib import Path
|
||||
@@ -20,14 +20,14 @@ from pathlib import Path
|
||||
__is_first_load = "operators" not in locals()
|
||||
if __is_first_load:
|
||||
from . import (
|
||||
operators,
|
||||
comms,
|
||||
gui,
|
||||
job_types,
|
||||
comms,
|
||||
manager_info,
|
||||
operators,
|
||||
preferences,
|
||||
projects,
|
||||
worker_tags,
|
||||
manager_info,
|
||||
)
|
||||
else:
|
||||
import importlib
|
||||
@@ -99,11 +99,18 @@ def register() -> None:
|
||||
bpy.app.handlers.save_pre.append(_unset_flamenco_job_name)
|
||||
bpy.app.handlers.save_post.append(_set_flamenco_job_name)
|
||||
|
||||
bpy.types.WindowManager.flamenco_can_abort = bpy.props.BoolProperty(
|
||||
name="Flamenco Can Abort",
|
||||
default=False,
|
||||
description="Whether the Flamenco submission can be aborted",
|
||||
)
|
||||
|
||||
bpy.types.WindowManager.flamenco_bat_status = bpy.props.EnumProperty(
|
||||
items=[
|
||||
("IDLE", "IDLE", "Not doing anything."),
|
||||
("SAVING", "SAVING", "Saving your file."),
|
||||
("INVESTIGATING", "INVESTIGATING", "Finding all dependencies."),
|
||||
("REWRITING", "REWRITING", "Rewriting blend files."),
|
||||
("TRANSFERRING", "TRANSFERRING", "Transferring all dependencies."),
|
||||
("COMMUNICATING", "COMMUNICATING", "Communicating with Flamenco Server."),
|
||||
("DONE", "DONE", "Not doing anything, but doing something earlier."),
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# This is the interface to BAT v1.x
|
||||
|
||||
|
||||
def bat_version() -> str:
|
||||
from .submodules import bat_toplevel
|
||||
|
||||
bat_version: str = bat_toplevel.__version__
|
||||
return bat_version
|
||||
|
||||
@@ -539,6 +539,13 @@ def _encode_original_filename_header(filename: str) -> str:
|
||||
"""
|
||||
|
||||
# This is a no-op when the filename is already in ASCII.
|
||||
fake_header = email.header.Header()
|
||||
fake_header = email.header.Header(maxlinelen=0)
|
||||
fake_header.append(filename, charset="utf-8")
|
||||
return fake_header.encode()
|
||||
encoded_header = fake_header.encode()
|
||||
|
||||
# Make sure that there are no newlines in the returned value.
|
||||
# HTTP Header line folding is obsolete, see RFC9112 section 5.2 in
|
||||
# https://www.rfc-editor.org/rfc/rfc9112#name-obsolete-line-folding
|
||||
assert "\n" not in encoded_header
|
||||
|
||||
return encoded_header
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user