work
update amznchartools
This commit is contained in:
@@ -10,13 +10,13 @@ D:\Work\9 iClone\Amazon\
|
||||
D:\Amazon\00_external-files\
|
||||
N:\1. CHARACTERS\remapping\
|
||||
[Recent]
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Scenes\textures\AMZ-warehouse_BSDF\SLAM_0\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\
|
||||
C:\Users\Nathan\AppData\Local\Temp\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\
|
||||
T:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\blendcache_Visual_new_final\drinkfluid\
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\stills\Waterspider A\
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Deliverable\WSA\
|
||||
A:\1 Amazon_Active_Projects\0 AssetArchive\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\
|
||||
E:\SteamLibrary\steamapps\common\Blender\5.0\scripts\startup\
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Deliverable\
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\
|
||||
C:\Users\Nathan\Desktop\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Mat\
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\Char\
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\
|
||||
|
||||
+40
-5
@@ -1,4 +1,44 @@
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 1a_part1.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 1a_part2.blend
|
||||
T:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final.blend
|
||||
P:\250827_FestivalTurf\Blends\animations\07 Final Touches And Maintenance\Visual_new_final.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\animations\Waterspider A\WS_A_move go-cart from trailer A.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\stills\Waterspider A\WS_A_go-cart loading_e_red.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\stills\Waterspider A\WS_A_go-cart loading_f_red.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\stills\Waterspider A\WS_A_go-cart loading_f.blend
|
||||
A:\1 Amazon_Active_Projects\260206_Dock_Unified\Blends\stills\Waterspider A\WS_A_go-cart loading_e.blend
|
||||
C:\Users\Nathan\Desktop\Untitled.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Regina_v4.3.blend
|
||||
T:\1 BlenderAssets\Amazon\Char\Cartoon2\AS\Paul_v3.4.blend
|
||||
T:\1 BlenderAssets\Amazon\Char\Cartoon2\AS\Kennedy_v3.3.blend
|
||||
T:\1 BlenderAssets\Amazon\Char\Cartoon1\Regina_v4.3.blend
|
||||
T:\1 BlenderAssets\Amazon\Char\Cartoon1\Hailey_v4.3.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10a.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Chan_v4.3.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Manny_v4.3.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Dennis_v4.3.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Joe_v4.3.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\Kirk_v4.4.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Mat\MAT_Char.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8c_part2.blend
|
||||
A:\1 Amazon_Active_Projects\260206_PAE_2026\Blends\animations\PAE_Animation 4B.blend
|
||||
A:\1 Amazon_Active_Projects\260206_PAE_2026\Blends\animations\PAE_Animation 3C.blend
|
||||
A:\1 Amazon_Active_Projects\260206_PAE_2026\Blends\animations\PAE_Animation 3B.blend
|
||||
A:\1 Amazon_Active_Projects\260225_Problem-Solve_2026\Blends\animations\PS_2026_animation 5G.blend
|
||||
A:\1 Amazon_Active_Projects\260225_Problem-Solve_2026\Blends\animations\PS_2026_animation 5E.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 2f.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Mat\MATERIALS_BSDF_pallette_v1.0.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Scenes\AMZ-warehouse_v6.1_small.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Scenes\AMZ-warehouse_v5.1.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Scenes\AMZ-warehouse_BSDF_v4.0.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\3075 Decade Dr.blend
|
||||
P:\260217_Jarvis-Defense\Blends\animations\Shot_Q.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\Char\Priest_v3.0.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 2e.blend
|
||||
C:\Users\Nathan\Downloads\noncon_OOG_short_animation 2d.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 2d.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 2a.blend
|
||||
T:\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 9a.blend
|
||||
A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Props\Dog-Food-Bag.blend
|
||||
A:\1 Amazon_Active_Projects\260317_NONCON_2026\Blends\animations\noncon_OOG_short_animation 3d.blend
|
||||
@@ -30,7 +70,6 @@ C:\Users\Nathan\Downloads\PnS_BD2_animation 6d\UNC_NEXUS_amazon\1 Amazon_Active_
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6a.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6c.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 6b.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 8c_part2.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 11a.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 9b.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 7c.blend
|
||||
@@ -56,7 +95,6 @@ A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_an
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 11b.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part3.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part2.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10a.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 10b_part1.blend
|
||||
P:\260217_Jarvis-Defense\Blends\animations\Shot_4.blend
|
||||
P:\260217_Jarvis-Defense\Blends\animations\Shot_3_retimed.blend
|
||||
@@ -71,8 +109,6 @@ P:\260217_Jarvis-Defense\Blends\animations\closeup.blend
|
||||
F:\jobs\Shot5c\Shot_Q.flamenco.blend
|
||||
F:\jobs\Shot5b\Shot_Q.flamenco.blend
|
||||
F:\jobs\Shot5a\Shot_Q.flamenco.blend
|
||||
P:\260217_Jarvis-Defense\Blends\animations\Shot_Q.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\3075 Decade Dr.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\stills\iP&S_BD2_11b.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 3a_part1.blend
|
||||
A:\1 Amazon_Active_Projects\260311_PnS-Beyond-Day-2\Blends\animations\P&S_BD2_animation 3a.blend
|
||||
@@ -94,7 +130,6 @@ P:\260217_Jarvis-Defense\Assets\Blends\Char\Chase_v3.0.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\Char\Russell_v4.0.blend
|
||||
P:\260217_Jarvis-Defense\Blends\animations\Shot_3.blend
|
||||
T:\260217_Jarvis-Defense\Assets\Blends\Char\Chase_v2.0.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\Char\Priest_v3.0.blend
|
||||
P:\260217_Jarvis-Defense\Assets\Blends\Char\Priest_v2.0.blend
|
||||
D:\Work\9 iClone\Jarvis Defense\Blender\Dec_v5.blend
|
||||
C:\Users\Nathan\Desktop\Shot5c.blend
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
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
@@ -3,7 +3,7 @@ schema_version = "1.0.0"
|
||||
id = "amzncharactertools"
|
||||
name = "AMZNCharacterTools"
|
||||
tagline = "AMZNCharacterTools"
|
||||
version = "0.10.2"
|
||||
version = "0.11.0"
|
||||
type = "add-on"
|
||||
|
||||
maintainer = "Nathan Lindsay"
|
||||
|
||||
@@ -5,7 +5,7 @@ def add_body_masks():
|
||||
body_obj = bpy.data.objects.get('CC_Base_Body')
|
||||
if not body_obj:
|
||||
print("Error: CC_Base_Body object not found")
|
||||
return
|
||||
return {"success": False, "reason": "NO_BODY"}
|
||||
|
||||
print(f"Found body object: {body_obj.name}")
|
||||
|
||||
@@ -124,6 +124,8 @@ def add_body_masks():
|
||||
print("\nBody masking completed!")
|
||||
print("Main_Mask: Shows head, arms, and chest")
|
||||
print("Hand_Mask: Shows head, arms, chest, and hands")
|
||||
return {"success": True}
|
||||
|
||||
# Execute the operation
|
||||
add_body_masks()
|
||||
if __name__ == "__main__":
|
||||
# When run as a script, execute for side-effects and keep existing prints.
|
||||
add_body_masks()
|
||||
@@ -0,0 +1,10 @@
|
||||
import bpy
|
||||
|
||||
# Simple operator script that removes the 'Devices' custom property from the active pose bone.
|
||||
# Usage: enter Pose Mode, select the Settings pose bone, then click the button in the Devices panel.
|
||||
try:
|
||||
bpy.ops.wm.properties_remove(data_path="active_pose_bone", property_name="Devices")
|
||||
except Exception as e:
|
||||
# This will fail if the context isn't correct; keep it minimal and print for debugging.
|
||||
print(f"Failed to remove 'Devices' property via wm.properties_remove: {e}")
|
||||
|
||||
@@ -8,14 +8,17 @@ print(f"Auto-execution enabled: {bpy.context.preferences.filepaths.use_scripts_a
|
||||
if not bpy.context.preferences.filepaths.use_scripts_auto_execute:
|
||||
print("WARNING: Auto-execution is disabled - drivers may not work properly")
|
||||
|
||||
# Get the active object
|
||||
# Get the active object and selected objects
|
||||
active_obj = bpy.context.active_object
|
||||
selected_objects = bpy.context.selected_objects
|
||||
|
||||
if not active_obj:
|
||||
print("✗ ERROR: No active object selected")
|
||||
print("Please select an object and run the script again")
|
||||
raise Exception("No active object - script aborted")
|
||||
|
||||
print(f"Found active object: {active_obj.name}")
|
||||
print(f"Found {len(selected_objects)} selected object(s): {[obj.name for obj in selected_objects]}")
|
||||
|
||||
# Find the armature object in the scene
|
||||
armature_obj = None
|
||||
@@ -92,61 +95,65 @@ print(f"✓ Created '{property_name}' custom property with library override supp
|
||||
print(f"Setting up drivers for {active_obj.name} object...")
|
||||
|
||||
try:
|
||||
# Clear any existing drivers
|
||||
try:
|
||||
active_obj.driver_remove('hide_render')
|
||||
print(" Removed existing hide_render driver")
|
||||
except:
|
||||
print(" No existing hide_render driver to remove")
|
||||
|
||||
try:
|
||||
active_obj.driver_remove('hide_viewport')
|
||||
print(" Removed existing hide_viewport driver")
|
||||
except:
|
||||
print(" No existing hide_viewport driver to remove")
|
||||
|
||||
# Create hide_render driver (hide when property = False, show when property = True)
|
||||
driver_fcurve = active_obj.driver_add('hide_render')
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'SUM'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = 'vis_val'
|
||||
var.type = 'SINGLE_PROP'
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = armature_obj
|
||||
var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]'
|
||||
|
||||
# Use polynomial modifier to invert: hide_render = 1 - vis_val
|
||||
mod = driver_fcurve.modifiers.new('GENERATOR')
|
||||
mod.mode = 'POLYNOMIAL'
|
||||
mod.poly_order = 1
|
||||
mod.coefficients = (1.0, -1.0) # 1 - x
|
||||
|
||||
print(f" ✓ Created hide_render driver for {active_obj.name}")
|
||||
|
||||
# Create hide_viewport driver (same logic)
|
||||
driver_fcurve = active_obj.driver_add('hide_viewport')
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'SUM'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = 'vis_val'
|
||||
var.type = 'SINGLE_PROP'
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = armature_obj
|
||||
var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]'
|
||||
|
||||
# Use polynomial modifier to invert: hide_viewport = 1 - vis_val
|
||||
mod = driver_fcurve.modifiers.new('GENERATOR')
|
||||
mod.mode = 'POLYNOMIAL'
|
||||
mod.poly_order = 1
|
||||
mod.coefficients = (1.0, -1.0) # 1 - x
|
||||
|
||||
print(f" ✓ Created hide_viewport driver for {active_obj.name}")
|
||||
|
||||
# Set up drivers for all selected objects
|
||||
for obj in selected_objects:
|
||||
print(f" Setting up drivers for {obj.name}...")
|
||||
|
||||
# Clear any existing drivers
|
||||
try:
|
||||
obj.driver_remove('hide_render')
|
||||
print(f" Removed existing hide_render driver")
|
||||
except:
|
||||
print(" No existing hide_render driver to remove")
|
||||
|
||||
try:
|
||||
obj.driver_remove('hide_viewport')
|
||||
print(" Removed existing hide_viewport driver")
|
||||
except:
|
||||
print(" No existing hide_viewport driver to remove")
|
||||
|
||||
# Create hide_render driver (hide when property = False, show when property = True)
|
||||
driver_fcurve = obj.driver_add('hide_render')
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'SUM'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = 'vis_val'
|
||||
var.type = 'SINGLE_PROP'
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = armature_obj
|
||||
var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]'
|
||||
|
||||
# Use polynomial modifier to invert: hide_render = 1 - vis_val
|
||||
mod = driver_fcurve.modifiers.new('GENERATOR')
|
||||
mod.mode = 'POLYNOMIAL'
|
||||
mod.poly_order = 1
|
||||
mod.coefficients = (1.0, -1.0) # 1 - x
|
||||
|
||||
print(f" ✓ Created hide_render driver for {obj.name}")
|
||||
|
||||
# Create hide_viewport driver (same logic)
|
||||
driver_fcurve = obj.driver_add('hide_viewport')
|
||||
driver = driver_fcurve.driver
|
||||
driver.type = 'SUM'
|
||||
|
||||
var = driver.variables.new()
|
||||
var.name = 'vis_val'
|
||||
var.type = 'SINGLE_PROP'
|
||||
var.targets[0].id_type = 'OBJECT'
|
||||
var.targets[0].id = armature_obj
|
||||
var.targets[0].data_path = f'pose.bones["Settings"]["{property_name}"]'
|
||||
|
||||
# Use polynomial modifier to invert: hide_viewport = 1 - vis_val
|
||||
mod = driver_fcurve.modifiers.new('GENERATOR')
|
||||
mod.mode = 'POLYNOMIAL'
|
||||
mod.poly_order = 1
|
||||
mod.coefficients = (1.0, -1.0) # 1 - x
|
||||
|
||||
print(f" ✓ Created hide_viewport driver for {obj.name}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" Error creating {active_obj.name} drivers: {e}")
|
||||
print(f" Error creating drivers: {e}")
|
||||
|
||||
print("✓ Driver setup complete")
|
||||
|
||||
@@ -159,28 +166,31 @@ bpy.context.evaluated_depsgraph_get().update()
|
||||
|
||||
# Initial state (should be visible)
|
||||
print(f"Current state: {property_name} = {pose_bone[property_name]} (True=visible, False=hidden)")
|
||||
print(f" {active_obj.name}: hide_render={active_obj.hide_render}, hide_viewport={active_obj.hide_viewport}")
|
||||
for obj in selected_objects:
|
||||
print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
||||
|
||||
# Test toggle to False (object hidden)
|
||||
print(f"\nToggling to False ({active_obj.name} hidden)...")
|
||||
# Test toggle to False (objects hidden)
|
||||
print(f"\nToggling to False (objects hidden)...")
|
||||
pose_bone[property_name] = False
|
||||
bpy.context.view_layer.update()
|
||||
bpy.context.evaluated_depsgraph_get().update()
|
||||
|
||||
print(f"New state: {property_name} = {pose_bone[property_name]}")
|
||||
print(f" {active_obj.name}: hide_render={active_obj.hide_render}, hide_viewport={active_obj.hide_viewport}")
|
||||
for obj in selected_objects:
|
||||
print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
||||
|
||||
# Test toggle back to True (object visible)
|
||||
print(f"\nToggling to True ({active_obj.name} visible)...")
|
||||
# Test toggle back to True (objects visible)
|
||||
print(f"\nToggling to True (objects visible)...")
|
||||
pose_bone[property_name] = True
|
||||
bpy.context.view_layer.update()
|
||||
bpy.context.evaluated_depsgraph_get().update()
|
||||
|
||||
print(f"Final state: {property_name} = {pose_bone[property_name]}")
|
||||
print(f" {active_obj.name}: hide_render={active_obj.hide_render}, hide_viewport={active_obj.hide_viewport}")
|
||||
for obj in selected_objects:
|
||||
print(f" {obj.name}: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
|
||||
|
||||
print("\n✓ Custom Visibility script completed successfully!")
|
||||
print(f"The '{property_name}' property is now available on the Settings bone as a checkbox")
|
||||
print(f"Use checkbox to toggle {active_obj.name} visibility")
|
||||
print(f" - {property_name} ON (checked): Shows {active_obj.name}")
|
||||
print(f" - {property_name} OFF (unchecked): Hides {active_obj.name}")
|
||||
print(f"Use checkbox to toggle visibility of {len(selected_objects)} selected object(s): {[obj.name for obj in selected_objects]}")
|
||||
print(f" - {property_name} ON (checked): Shows all selected objects")
|
||||
print(f" - {property_name} OFF (unchecked): Hides all selected objects")
|
||||
@@ -53,9 +53,16 @@ def link_bsdf_materials():
|
||||
materials_before = set(bpy.data.materials.keys())
|
||||
|
||||
# Link all materials from the library file
|
||||
with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):
|
||||
# Link all materials
|
||||
data_to.materials = data_from.materials
|
||||
try:
|
||||
with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):
|
||||
# Link all materials
|
||||
data_to.materials = data_from.materials
|
||||
print(f" Library loaded successfully, materials in file: {len(data_from.materials)}")
|
||||
except Exception as e:
|
||||
print(f"Error loading library: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
# Get list of newly linked materials
|
||||
materials_after = set(bpy.data.materials.keys())
|
||||
@@ -368,6 +375,8 @@ def replace_cel_materials():
|
||||
"wood": "Pallet_Wood",
|
||||
"Package_Cardboard": "Package_Cardboard",
|
||||
"Pallet_Wood": "Pallet_Wood",
|
||||
"Shuttle_Cardboard_1": "Shuttle_Cardboard_1",
|
||||
"Shuttle_Cardboard_2": "Shuttle_Cardboard_2",
|
||||
"blue (triton)": "BSDF_blue-2_TRITON",
|
||||
"gray (snow)": "BSDF_gray-6_SNOW",
|
||||
"gray (storm)": "BSDF_gray-2_STORM",
|
||||
@@ -608,6 +617,13 @@ def replace_cel_materials():
|
||||
print(f"Total user remappings: {replacements_made}")
|
||||
print(f"Source materials removed: {removed_materials}")
|
||||
|
||||
# Print a highly visible summary message
|
||||
print(f"\n{'='*60}")
|
||||
print(f" CEL REPLACEMENT COMPLETE")
|
||||
print(f" {len(material_mapping)} materials replaced")
|
||||
print(f" {replacements_made} total users remapped")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
if missing_targets:
|
||||
print(f"\nMissing target materials for:")
|
||||
for mapping in missing_targets:
|
||||
@@ -618,19 +634,19 @@ def replace_cel_materials():
|
||||
# Run the replacement
|
||||
if __name__ == "__main__":
|
||||
replace_cel_materials()
|
||||
|
||||
print("\nRemaining CEL materials in file:")
|
||||
cel_count = 0
|
||||
for mat in bpy.data.materials:
|
||||
if mat.name.startswith("CEL_"):
|
||||
print(f" {mat.name} ({mat.users} users)")
|
||||
cel_count += 1
|
||||
|
||||
if cel_count == 0:
|
||||
print(" None - all CEL materials have been replaced!")
|
||||
|
||||
print("\nBSDF materials in file:")
|
||||
for mat in bpy.data.materials:
|
||||
if mat.name.startswith("BSDF_"):
|
||||
print(f" {mat.name} ({mat.users} users)")
|
||||
|
||||
print("\nRemaining CEL materials in file:")
|
||||
cel_count = 0
|
||||
for mat in bpy.data.materials:
|
||||
if mat.name.startswith("CEL_"):
|
||||
print(f" {mat.name} ({mat.users} users)")
|
||||
cel_count += 1
|
||||
|
||||
if cel_count == 0:
|
||||
print(" None - all CEL materials have been replaced!")
|
||||
|
||||
print("\nBSDF materials in file:")
|
||||
for mat in bpy.data.materials:
|
||||
if mat.name.startswith("BSDF_"):
|
||||
print(f" {mat.name} ({mat.users} users)")
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
"""Add Ambassador Vest Color to the active object's vest color node group."""
|
||||
import bpy
|
||||
import os
|
||||
|
||||
try:
|
||||
from ..utils import get_addon_preferences
|
||||
except (ImportError, ValueError):
|
||||
# Fallback if import fails
|
||||
def get_addon_preferences():
|
||||
test_names = [
|
||||
"bl_ext.vscode_development.AmazonCharacterTools",
|
||||
"amzncharactertools",
|
||||
"AmazonCharacterTools",
|
||||
]
|
||||
for addon_name in test_names:
|
||||
addon_prefs = bpy.context.preferences.addons.get(addon_name)
|
||||
if addon_prefs and hasattr(addon_prefs, 'preferences'):
|
||||
if hasattr(addon_prefs.preferences, 'amzn_bsdf_materials_path'):
|
||||
return addon_prefs.preferences
|
||||
return None
|
||||
|
||||
|
||||
def add_vest_ambassador_color():
|
||||
"""Add blue (ambassador) vest color option to the active object's vest color node group."""
|
||||
|
||||
# Get active object
|
||||
obj = bpy.context.active_object
|
||||
if not obj:
|
||||
print("Error: No active object selected")
|
||||
return {"success": False, "reason": "NO_ACTIVE_OBJECT"}
|
||||
|
||||
print(f"Working on object: {obj.name}")
|
||||
|
||||
# Find the amazon-vest-color node group on the object
|
||||
vest_node_group = None
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'NODES' and mod.node_group:
|
||||
if 'amazon-vest-color' in mod.node_group.name.lower():
|
||||
vest_node_group = mod.node_group
|
||||
print(f"Found vest color node group: {vest_node_group.name}")
|
||||
break
|
||||
|
||||
if not vest_node_group:
|
||||
print("Error: No amazon-vest-color node group found on active object")
|
||||
print("Available geometry node groups:")
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'NODES' and mod.node_group:
|
||||
print(f" - {mod.node_group.name}")
|
||||
return {"success": False, "reason": "NO_NODE_GROUP"}
|
||||
|
||||
# Link the Vest-blue material from MAT_Char.blend
|
||||
library_path = r"A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Mat\MAT_Char.blend"
|
||||
|
||||
if not os.path.exists(library_path):
|
||||
print(f"Error: Library file not found at {library_path}")
|
||||
return {"success": False, "reason": "LIBRARY_NOT_FOUND"}
|
||||
|
||||
print(f"Linking Vest-blue material from: {library_path}")
|
||||
|
||||
# Check if material already exists
|
||||
materials_before = set(bpy.data.materials.keys())
|
||||
|
||||
try:
|
||||
with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):
|
||||
if 'Vest-blue' in data_from.materials:
|
||||
data_to.materials = ['Vest-blue']
|
||||
print(" Vest-blue material linked successfully")
|
||||
else:
|
||||
print(" Warning: Vest-blue not found in library, trying alternate names...")
|
||||
# Try to find any vest-related material
|
||||
for mat_name in data_from.materials:
|
||||
if 'vest' in mat_name.lower() and 'blue' in mat_name.lower():
|
||||
data_to.materials = [mat_name]
|
||||
print(f" Found and linked alternate: {mat_name}")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"Error loading library: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return {"success": False, "reason": "LIBRARY_LOAD_FAILED"}
|
||||
|
||||
# Get the linked material
|
||||
materials_after = set(bpy.data.materials.keys())
|
||||
newly_linked = materials_after - materials_before
|
||||
|
||||
if not newly_linked:
|
||||
# Check if Vest-blue already exists
|
||||
if 'Vest-blue' in bpy.data.materials:
|
||||
vest_material = bpy.data.materials['Vest-blue']
|
||||
print(f"Vest-blue already exists: {vest_material.name}")
|
||||
else:
|
||||
print("Error: Could not link Vest-blue material")
|
||||
return {"success": False, "reason": "MATERIAL_NOT_FOUND"}
|
||||
else:
|
||||
vest_material = bpy.data.materials[list(newly_linked)[0]]
|
||||
print(f"Linked material: {vest_material.name}")
|
||||
|
||||
# Find the menu switch node in the node group
|
||||
# This is typically a node with an enum property or index-based switch
|
||||
menu_switch_node = None
|
||||
for node in vest_node_group.nodes:
|
||||
# Look for common menu/switch node types
|
||||
if node.type in ('MENU_SWITCH', 'MENU_SWITCH_ITEM', 'SWITCH', 'INDEX_SWITCH'):
|
||||
menu_switch_node = node
|
||||
print(f"Found menu switch node: {node.name} (type: {node.type})")
|
||||
break
|
||||
# Also check for nodes with "color" or "menu" in the name
|
||||
if 'color' in node.name.lower() or 'menu' in node.name.lower():
|
||||
print(f"Potential menu node: {node.name} (type: {node.type})")
|
||||
if not menu_switch_node:
|
||||
menu_switch_node = node
|
||||
|
||||
if not menu_switch_node:
|
||||
print("Error: Could not find menu/switch node in vest color node group")
|
||||
print("Available nodes:")
|
||||
for node in vest_node_group.nodes:
|
||||
print(f" - {node.name} (type: {node.type})")
|
||||
return {"success": False, "reason": "NO_MENU_SWITCH"}
|
||||
|
||||
node_type = menu_switch_node.type
|
||||
print(f"Adding 'blue (ambassador)' option to {menu_switch_node.name} (type: {node_type})...")
|
||||
added = False
|
||||
item_name = "blue (ambassador)"
|
||||
|
||||
if node_type == "MENU_SWITCH" and hasattr(menu_switch_node, "enum_items"):
|
||||
existing_names = [item.name for item in menu_switch_node.enum_items]
|
||||
if item_name in existing_names:
|
||||
print(" Option 'blue (ambassador)' already exists")
|
||||
added = True
|
||||
else:
|
||||
try:
|
||||
# Blender API for GeometryNodeMenuSwitch: enum_items.new(name)
|
||||
menu_switch_node.enum_items.new(item_name)
|
||||
print(" Added enum item to menu switch")
|
||||
added = True
|
||||
except Exception as e:
|
||||
print(f" Failed to add enum item: {e}")
|
||||
elif node_type in {"SWITCH", "INDEX_SWITCH"}:
|
||||
print(f" Switch node type '{node_type}' is not a geometry menu switch; cannot add named menu item")
|
||||
else:
|
||||
print(f" Node type '{node_type}' does not support enum menu items")
|
||||
|
||||
# For MATERIAL menu switches, assign the linked material to the corresponding input socket default.
|
||||
if added:
|
||||
for socket in menu_switch_node.inputs:
|
||||
if socket.name == item_name and hasattr(socket, "default_value"):
|
||||
try:
|
||||
socket.default_value = vest_material
|
||||
print(f" Assigned material '{vest_material.name}' to input '{socket.name}'")
|
||||
except Exception as e:
|
||||
print(f" Warning: could not assign material to '{socket.name}': {e}")
|
||||
break
|
||||
|
||||
if added:
|
||||
print("\n" + "="*60)
|
||||
print(" VEST AMBASSADOR COLOR ADDED")
|
||||
print(f" Material: {vest_material.name}")
|
||||
print(f" Target: {obj.name}")
|
||||
print("="*60 + "\n")
|
||||
else:
|
||||
print("\n" + "="*60)
|
||||
print(" WARNING: Could not add menu item")
|
||||
print(f" Material: {vest_material.name} was linked but not assigned")
|
||||
print(" The menu API may need manual configuration")
|
||||
print("="*60 + "\n")
|
||||
|
||||
if added:
|
||||
return {"success": True, "reason": "OK"}
|
||||
return {"success": False, "reason": "MENU_ITEM_ADD_FAILED"}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
add_vest_ambassador_color()
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Operator definitions for AMZN Character Tools."""
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
import runpy
|
||||
import traceback
|
||||
@@ -8,6 +9,7 @@ from bpy.types import Operator
|
||||
|
||||
|
||||
OPS_DIR = Path(__file__).parent.parent / "ops"
|
||||
BASE_PACKAGE = (__package__ or "").rsplit(".", 1)[0]
|
||||
|
||||
|
||||
def run_script(script_name: str) -> None:
|
||||
@@ -25,6 +27,15 @@ def run_script(script_name: str) -> None:
|
||||
runpy.run_path(str(script_path), run_name="__main__")
|
||||
|
||||
|
||||
def _import_ops_module(module_name: str):
|
||||
"""Import and reload an ops module from this addon package."""
|
||||
if not BASE_PACKAGE:
|
||||
raise RuntimeError("Cannot resolve addon base package for module imports")
|
||||
full_name = f"{BASE_PACKAGE}.ops.{module_name}"
|
||||
module = importlib.import_module(full_name)
|
||||
return importlib.reload(module)
|
||||
|
||||
|
||||
# Icon mapping from old indices to icon names
|
||||
ICON_MAP = {
|
||||
144: "PREFERENCES", # Settings/configuration operations
|
||||
@@ -86,6 +97,15 @@ OP_SPECS = [
|
||||
"icon": "FILE_REFRESH",
|
||||
"panel": "devices",
|
||||
},
|
||||
{
|
||||
"name": "RemoveDevicesSettings",
|
||||
"id": "remove_devices_settings",
|
||||
"desc": "Removes the 'Devices' custom property from SettingsBone",
|
||||
"script": "RemoveDevicesSettings.py",
|
||||
"button": "Remove Devices Settings",
|
||||
"icon": "CANCEL",
|
||||
"panel": "devices",
|
||||
},
|
||||
{
|
||||
"name": "GeoSeparator",
|
||||
"id": "geo_separator",
|
||||
@@ -122,6 +142,15 @@ OP_SPECS = [
|
||||
"icon": "PREFERENCES",
|
||||
"panel": "geo",
|
||||
},
|
||||
{
|
||||
"name": "AddVestAmbassadorColor",
|
||||
"id": "add_vest_ambassador_color",
|
||||
"desc": "Adds blue (ambassador) vest color option to active object's vest color node group",
|
||||
"script": "vest_ambassador_color.py",
|
||||
"button": "Add Vest Ambassador Color",
|
||||
"icon": "MATERIAL",
|
||||
"panel": "vest",
|
||||
},
|
||||
{
|
||||
"name": "HHSpawn",
|
||||
"id": "hh_spawn",
|
||||
@@ -192,7 +221,65 @@ def _make_operator(spec: dict) -> type[Operator]:
|
||||
"""Create an operator class from a specification dictionary."""
|
||||
def _execute(self, context):
|
||||
try:
|
||||
run_script(spec["script"])
|
||||
# Special handling for operators that need result capture
|
||||
if spec["script"] == "replace_cel_with_bsdf.py":
|
||||
script_path = OPS_DIR / spec["script"]
|
||||
if script_path.exists():
|
||||
module = _import_ops_module("replace_cel_with_bsdf")
|
||||
materials_mapped, users_remapped = module.replace_cel_materials()
|
||||
self.report({"INFO"}, f"Replaced CEL: {materials_mapped} materials, {users_remapped} users remapped")
|
||||
else:
|
||||
run_script(spec["script"])
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
elif spec["script"] == "vest_ambassador_color.py":
|
||||
script_path = OPS_DIR / spec["script"]
|
||||
if script_path.exists():
|
||||
module = _import_ops_module("vest_ambassador_color")
|
||||
result = module.add_vest_ambassador_color()
|
||||
success = bool(result.get("success")) if isinstance(result, dict) else bool(result)
|
||||
reason = result.get("reason") if isinstance(result, dict) else ""
|
||||
if success:
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
else:
|
||||
if reason == "NO_NODE_GROUP":
|
||||
self.report({"INFO"}, "No vest color node group found on active object")
|
||||
elif reason == "NO_ACTIVE_OBJECT":
|
||||
self.report({"INFO"}, "No active object selected")
|
||||
elif reason == "NO_MENU_SWITCH":
|
||||
self.report({"INFO"}, "No vest menu switch node found in vest color node group")
|
||||
else:
|
||||
self.report({"WARNING"}, "Vest-blue material linked but menu item was not added")
|
||||
else:
|
||||
run_script(spec["script"])
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
elif spec["script"] == "BodyMasker.py":
|
||||
script_path = OPS_DIR / spec["script"]
|
||||
if script_path.exists():
|
||||
module = _import_ops_module("BodyMasker")
|
||||
result = module.add_body_masks()
|
||||
if isinstance(result, dict):
|
||||
if result.get("success"):
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
else:
|
||||
reason = result.get("reason")
|
||||
if reason == "NO_BODY":
|
||||
self.report({"ERROR"}, "CC_Base_Body not found in scene")
|
||||
else:
|
||||
self.report({"WARNING"}, f"{spec['button']} incomplete: {reason}")
|
||||
else:
|
||||
# Unexpected return type; fall back to running the script for side-effects
|
||||
run_script(spec["script"])
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
elif spec.get("id") == "remove_devices_settings":
|
||||
# Pre-check: ensure CC_Base_Body exists in the scene. If not, inform the user.
|
||||
if "CC_Base_Body" not in bpy.data.objects:
|
||||
self.report({"ERROR"}, "CC_Base_Body not found in scene")
|
||||
return {"CANCELLED"}
|
||||
run_script(spec["script"])
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
else:
|
||||
run_script(spec["script"])
|
||||
self.report({"INFO"}, f"{spec['button']} complete")
|
||||
except Exception as exc: # pragma: no cover - best effort logging
|
||||
traceback.print_exc()
|
||||
self.report({"ERROR"}, f"{spec['button']} failed: {exc}")
|
||||
|
||||
@@ -5,7 +5,7 @@ from bpy.types import Panel
|
||||
from .operators import OP_SPECS
|
||||
|
||||
|
||||
PANEL_KEYS = ("scene", "general", "core", "devices", "geo", "helmet")
|
||||
PANEL_KEYS = ("scene", "general", "core", "devices", "geo", "helmet", "vest")
|
||||
PANEL_BUTTONS = {key: [spec for spec in OP_SPECS if spec["panel"] == key] for key in PANEL_KEYS}
|
||||
|
||||
|
||||
@@ -87,5 +87,13 @@ class AMZN_PT_Helmet(_AMZN_BasePanel):
|
||||
panel_key = "helmet"
|
||||
|
||||
|
||||
PANEL_CLASSES = (AMZN_PT_Main, AMZN_PT_Scene, AMZN_PT_General, AMZN_PT_Devices, AMZN_PT_Geo, AMZN_PT_Helmet)
|
||||
class AMZN_PT_Vest(_AMZN_BasePanel):
|
||||
"""Vest panel."""
|
||||
bl_idname = "AMZN_PT_VEST"
|
||||
bl_label = "Vest"
|
||||
bl_parent_id = "AMZN_PT_MAIN"
|
||||
panel_key = "vest"
|
||||
|
||||
|
||||
PANEL_CLASSES = (AMZN_PT_Main, AMZN_PT_Scene, AMZN_PT_General, AMZN_PT_Devices, AMZN_PT_Geo, AMZN_PT_Helmet, AMZN_PT_Vest)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class AMZN_AddonPreferences(AddonPreferences):
|
||||
name="BSDF Materials Library",
|
||||
description="Path to MATERIALS_BSDF_pallette_v1.0.blend",
|
||||
subtype='FILE_PATH',
|
||||
default=r"A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\MATERIALS_BSDF_pallette_v1.0.blend",
|
||||
default=r"A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Mat\MATERIALS_BSDF_pallette_v1.0.blend",
|
||||
)
|
||||
|
||||
amzn_device_path: StringProperty(
|
||||
|
||||
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
Reference in New Issue
Block a user