Resolve merge conflict in NewProject.bat - take most recent changes
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
|||||||
|
<!-- Generated by SpecStory -->
|
||||||
|
|
||||||
|
# Remap non-working material names (2025-09-05 21:38Z)
|
||||||
|
|
||||||
|
_**User (2025-09-09 19:45Z)**_
|
||||||
|
|
||||||
|
remapped mats that are currently not working:
|
||||||
|
bag BLACK (squid ink) => BSDF_black_SQUID-INK
|
||||||
|
bag WHITE => BSDF_WHITE
|
||||||
|
orange (smile) => BSDF_orange-3_SMILE
|
||||||
|
orange (blaze) => BSDF_orange-1_BLAZE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Assistant**_
|
||||||
|
|
||||||
|
<think><details><summary>Thought Process</summary>**Debugging material mapping issues**
|
||||||
|
|
||||||
|
There's a warning saying "Target material not found," so I need to dig into this and figure out why the mappings aren't functioning. First, I should confirm the actual material names in the scene and the linked library, but I can't query Blender data here. I also want to adjust the code to be more flexible, like tolerating name variants and case differences. If the library path isn't right, it should print an error but might be okay. I'll address potential issues with suffixes and name matching too.
|
||||||
|
**Fixing material mapping issues**
|
||||||
|
|
||||||
|
I need to address the fact that names like "bag BLACK (squid ink).001" and "bag WHITE.001" won't match due to their numeric suffixes. So, I should implement case-insensitive matching for custom mappings.
|
||||||
|
|
||||||
|
Also, when linking materials through link_bsdf_materials, they need to be in bpy.data.materials first. I noticed potential spelling differences between different naming conventions, like hyphens versus underscores. Moreover, "orange (blaze)" needs a mapping added for "BSDF_orange-1_BLAZE." Finally, the user mentioned four remapped materials that aren't currently working, so that's an additional concern.
|
||||||
|
**Improving custom mapping functionality**
|
||||||
|
|
||||||
|
It looks like the script attempted to remap materials, but the results didn't change, which indicates they might be flagged as missing targets. The issue could stem from source names having suffixes we didn't account for, or they not being prefixed with "CER_". Since these are custom names like "bag WHITE," it's crucial to ensure their suffixes are properly matched. I plan to modify replace_cel_with_bsdf.py to enhance custom mappings by normalizing material names, stripping numeric suffixes like ".###," and matching them in a case-insensitive manner.
|
||||||
|
**Enhancing material mapping logic**
|
||||||
|
|
||||||
|
I need to allow for cases where the source name is "bag WHITE" and actual material names could be "bag WHITE.001." To implement this, I plan to build a map from normalized names to materials by defining a function that lowercases and strips trailing numeric suffixes, while also ensuring ".blend" isn’t included. I'll use a regex pattern to achieve this, and consider collapsing whitespace and unifying hyphens and underscores.
|
||||||
|
|
||||||
|
For matching target names, I should ignore suffixes when using the bsdf_base_map, allowing for more accurate mapping when the linked material has variations like "BSDF_WHITE.001."
|
||||||
|
**Implementing material mapping changes**
|
||||||
|
|
||||||
|
I need to adjust the script to ensure the mapping works correctly for materials with suffixes, such as "bag WHITE" matching "bag WHITE.001." My plan includes constructing a mapping for normalized base names to actual materials, which requires creating a helper function to normalize names by stripping suffixes and standardizing case.
|
||||||
|
|
||||||
|
I will modify the custom mapping loop to handle multiple materials that match the base name. I’ll also add the new mapping for "orange (blaze)." A note on formatting: I must keep my indentation consistent while making these changes. I'll check for any lint issues before applying the patch to ensure everything is in order.
|
||||||
|
**Preparing to apply file changes**
|
||||||
|
|
||||||
|
I need to apply some context-sensitive changes to the file. Even though we have the content already attached, I'll err on the side of caution and use the read_file tool to ensure I have the exact file content in the workspace. I will add the new mapping for "orange (blaze)" to the existing custom_mappings dict.
|
||||||
|
|
||||||
|
Additionally, I’ll insert helper functions and update the custom mapping logic to make it case- and suffix-insensitive, while ensuring my imports are intact. Then, I’ll assemble the patch and add a brief status update before execution, keeping the changes concise and directly addressing the user's query.</details></think>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I'll update your Blender script to make custom name remapping robust to numeric suffixes and case differences, add the missing "orange (blaze)" mapping, and resolve targets by base BSDF names. Applying the edits now.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<think><details><summary>Thought Process</summary>**Updating project status**
|
||||||
|
|
||||||
|
I want to provide a brief status update after fixing some lints, along with a concise response confirming the changes and instructions for running them in Blender. Since we only modified an existing script using the apply_patch tool, we can avoid generating new scripts. I'll keep the code concise as per our guidelines, and while we don't need to show the code, I might include a snippet if necessary. I'll also remember to manage any todos, but we may skip creating a list for smaller tasks since tool calls were used.
|
||||||
|
**Clarifying tool use**
|
||||||
|
|
||||||
|
I need to remember that I should call todo_write to update the todo list after completing tasks, but since we didn't create one, that's okay. I should also add a status update before any new batch, specifically before calling read_lints. Since there's only read_lints to run, I’m considering using multi_tool_use.parallel, but it might not be necessary to read a file for confirmation. Let's just move ahead and run read_lints.</details></think>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
I updated the script to make custom remapping case/suffix-insensitive and added the missing "orange (blaze)" mapping. Let me check for any linter issues in the modified file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- I updated `replace_cel_with_bsdf.py` to resolve your four problematic mappings by:
|
||||||
|
- Adding the missing custom mapping: `orange (blaze) => BSDF_orange-1_BLAZE`.
|
||||||
|
- Making custom mappings robust to case differences and numeric suffixes (e.g., `.001`) for both sources and targets.
|
||||||
|
- Resolving targets by base BSDF names when exact names aren’t present.
|
||||||
|
|
||||||
|
- No linter issues detected.
|
||||||
|
|
||||||
|
Run the script again in Blender; those four should now remap correctly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,11 @@ set projectRoot=%yyyy%-%mm%-%dd%_%projectName%
|
|||||||
mkdir "%projectRoot%"
|
mkdir "%projectRoot%"
|
||||||
|
|
||||||
mkdir "%projectRoot%\Assets\VO"
|
mkdir "%projectRoot%\Assets\VO"
|
||||||
if exist "%~dp0NewDaily.bat" copy /Y "%~dp0NewDaily.bat" "%projectRoot%\Assets\VO\NewDaily.bat" >nul
|
if exist "A:\1 Amazon_Active_Projects\3 ProjectStructure\NewDaily.bat" copy /Y "A:\1 Amazon_Active_Projects\3 ProjectStructure\NewDaily.bat" "%projectRoot%\Assets\VO\NewDaily.bat" >nul
|
||||||
|
|
||||||
|
:: Create Blends structure
|
||||||
|
mkdir "%projectRoot%\Blends\animations\"
|
||||||
|
mkdir "%projectRoot%\Blends\stills\img-BG"
|
||||||
|
|
||||||
:: Create Deliverable structure
|
:: Create Deliverable structure
|
||||||
mkdir "%projectRoot%\Deliverable\"
|
mkdir "%projectRoot%\Deliverable\"
|
||||||
@@ -40,7 +44,6 @@ if exist "%~dp0components\gitattributes" copy /Y "%~dp0components\gitattributes"
|
|||||||
:: Initialize git and install Git LFS
|
:: Initialize git and install Git LFS
|
||||||
pushd "%projectRoot%" >nul
|
pushd "%projectRoot%" >nul
|
||||||
git init
|
git init
|
||||||
git config --global --add safe.directory "%projectRoot%"
|
|
||||||
git lfs install
|
git lfs install
|
||||||
git add . -v
|
git add . -v
|
||||||
git commit -m "init"
|
git commit -m "init"
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
*.fbx filter=lfs diff=lfs merge=lfs -text
|
*.fbx filter=lfs diff=lfs merge=lfs -text
|
||||||
*.fbxkey filter=lfs diff=lfs merge=lfs -text
|
*.fbxkey filter=lfs diff=lfs merge=lfs -text
|
||||||
*.blend2 filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.mb filter=lfs diff=lfs merge=lfs -text
|
*.mb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ma filter=lfs diff=lfs merge=lfs -text
|
||||||
*.tiff filter=lfs diff=lfs merge=lfs -text
|
*.tiff filter=lfs diff=lfs merge=lfs -text
|
||||||
*.ai filter=lfs diff=lfs merge=lfs -text
|
*.ai filter=lfs diff=lfs merge=lfs -text
|
||||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||||
@@ -40,6 +40,7 @@
|
|||||||
*.dae filter=lfs diff=lfs merge=lfs -text
|
*.dae filter=lfs diff=lfs merge=lfs -text
|
||||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||||
*.vdb filter=lfs diff=lfs merge=lfs -text
|
*.vdb filter=lfs diff=lfs merge=lfs -text
|
||||||
*.aep filter=lfs diff=lfs merge=lfs -text
|
*.aep filter=lfs diff=lfs merge=lfs -text
|
||||||
*.prproj filter=gzipped
|
*.prproj filter=gzipped
|
||||||
@@ -125,4 +125,7 @@ Renders/
|
|||||||
|
|
||||||
# Premiere
|
# Premiere
|
||||||
*.prlock
|
*.prlock
|
||||||
Adobe Premiere Pro Video Previews/
|
Adobe Premiere Pro Video Previews/
|
||||||
|
Adobe Premiere Pro Audio Previews/
|
||||||
|
Adobe Premiere Pro (Beta) Video Previews/
|
||||||
|
Adobe Premiere Pro (Beta) Audio Previews/
|
||||||
@@ -20,6 +20,8 @@ REM Initialize counters and tracking
|
|||||||
set "processed=0"
|
set "processed=0"
|
||||||
set "crashed=0"
|
set "crashed=0"
|
||||||
set "skipped=0"
|
set "skipped=0"
|
||||||
|
set "deleted_similar=0"
|
||||||
|
set "threshold_percent=10"
|
||||||
|
|
||||||
REM Create a temporary Python script for compression
|
REM Create a temporary Python script for compression
|
||||||
set "TEMP_SCRIPT=compress_blend_temp.py"
|
set "TEMP_SCRIPT=compress_blend_temp.py"
|
||||||
@@ -80,7 +82,7 @@ if exist "!TEMP_SCRIPT!" (
|
|||||||
REM Run Blender to process the dragged files
|
REM Run Blender to process the dragged files
|
||||||
echo Processing dragged .blend files...
|
echo Processing dragged .blend files...
|
||||||
echo Using script: !TEMP_SCRIPT!
|
echo Using script: !TEMP_SCRIPT!
|
||||||
blender --background --factory-startup --python "!TEMP_SCRIPT!" -- %* > blender_output.txt 2^>^&1
|
blender --background --factory-startup --python "!TEMP_SCRIPT!" -- %* 2^>^&1 | powershell -NoProfile -Command "$input | Tee-Object -FilePath 'blender_output.txt'"
|
||||||
|
|
||||||
REM Clean up temporary script
|
REM Clean up temporary script
|
||||||
echo Cleaning up temporary script...
|
echo Cleaning up temporary script...
|
||||||
@@ -108,7 +110,14 @@ for /f "tokens=1,2,3 delims=:" %%a in (blender_output.txt) do (
|
|||||||
echo Original: !original_size! bytes
|
echo Original: !original_size! bytes
|
||||||
echo Compressed: !compressed_size! bytes
|
echo Compressed: !compressed_size! bytes
|
||||||
set /a "savings=!original_size! - !compressed_size!"
|
set /a "savings=!original_size! - !compressed_size!"
|
||||||
|
if !original_size! gtr 0 (set /a percent=(savings*100)/original_size) else (set percent=0)
|
||||||
echo Savings: !savings! bytes
|
echo Savings: !savings! bytes
|
||||||
|
echo Reduction: !percent!%%
|
||||||
|
if !percent! lss !threshold_percent! (
|
||||||
|
del "!compressed_file!" 2>nul
|
||||||
|
set /a deleted_similar+=1
|
||||||
|
echo Deleted: too similar to original
|
||||||
|
)
|
||||||
echo.
|
echo.
|
||||||
) else if "%%a"=="CRASH" (
|
) else if "%%a"=="CRASH" (
|
||||||
set /a crashed+=1
|
set /a crashed+=1
|
||||||
@@ -127,7 +136,7 @@ for /f "tokens=1,2,3 delims=:" %%a in (blender_output.txt) do (
|
|||||||
)
|
)
|
||||||
|
|
||||||
REM Clean up output file
|
REM Clean up output file
|
||||||
del "blender_output.txt" 2>nul
|
del /f /q "blender_output.txt" 2>nul
|
||||||
|
|
||||||
echo ========================================
|
echo ========================================
|
||||||
echo SUMMARY
|
echo SUMMARY
|
||||||
@@ -135,6 +144,7 @@ echo ========================================
|
|||||||
echo Processed: !processed! files
|
echo Processed: !processed! files
|
||||||
echo Crashed: !crashed! files
|
echo Crashed: !crashed! files
|
||||||
echo Skipped: !skipped! files
|
echo Skipped: !skipped! files
|
||||||
|
echo Deleted ^(too similar^): !deleted_similar! files
|
||||||
echo Total: %* files
|
echo Total: %* files
|
||||||
echo ========================================
|
echo ========================================
|
||||||
echo.
|
echo.
|
||||||
|
|||||||
153
find_missing_files.bat
Normal file
153
find_missing_files.bat
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
echo Starting missing file search...
|
||||||
|
|
||||||
|
REM Check if files were dragged onto the batch file
|
||||||
|
if "%~1"=="" (
|
||||||
|
echo.
|
||||||
|
echo Usage: Drag .blend files onto this batch file to find missing files.
|
||||||
|
echo Output will be saved to the \output folder.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Create output directory if it doesn't exist
|
||||||
|
if not exist "output" mkdir "output"
|
||||||
|
|
||||||
|
REM Initialize counters and tracking
|
||||||
|
set "processed=0"
|
||||||
|
set "crashed=0"
|
||||||
|
set "skipped=0"
|
||||||
|
set "found_missing=0"
|
||||||
|
set "search_path=A:/1 Amazon_Active_Projects/1 BlenderAssets/Amazon/"
|
||||||
|
|
||||||
|
REM Create a temporary Python script for processing
|
||||||
|
set "TEMP_SCRIPT=find_missing_files_temp.py"
|
||||||
|
echo Creating Python script: !TEMP_SCRIPT!
|
||||||
|
|
||||||
|
(
|
||||||
|
echo import bpy
|
||||||
|
echo import os
|
||||||
|
echo import sys
|
||||||
|
echo.
|
||||||
|
echo # Enable compression globally
|
||||||
|
echo bpy.context.preferences.filepaths.save_version = 0
|
||||||
|
echo bpy.context.preferences.filepaths.use_file_compression = True
|
||||||
|
echo.
|
||||||
|
echo # Create output directory if it doesn't exist
|
||||||
|
echo if not os.path.exists^("output"^):
|
||||||
|
echo os.makedirs^("output"^)
|
||||||
|
echo.
|
||||||
|
echo # Get command line arguments ^(the dragged files^)
|
||||||
|
echo blend_files = sys.argv[sys.argv.index^("--"^) + 1:] if "--" in sys.argv else []
|
||||||
|
echo.
|
||||||
|
echo print^("Found " + str^(len^(blend_files^)^) + " .blend files to process"^)
|
||||||
|
echo.
|
||||||
|
echo for blend_file in blend_files:
|
||||||
|
echo ^ if blend_file.lower^(^).endswith^(".blend"^):
|
||||||
|
echo ^ try:
|
||||||
|
echo ^ # Create output path in output folder
|
||||||
|
echo ^ filename = os.path.basename^(blend_file^)
|
||||||
|
echo ^ output_file = os.path.join^("output", filename^)
|
||||||
|
echo ^ # Check if output file already exists
|
||||||
|
echo ^ if os.path.exists^(output_file^):
|
||||||
|
echo ^ print^("SKIP_EXISTING:" + blend_file^)
|
||||||
|
echo ^ continue
|
||||||
|
echo ^ print^("PROCESSING:" + blend_file^)
|
||||||
|
echo ^ # Load the blend file
|
||||||
|
echo ^ bpy.ops.wm.open_mainfile^(filepath=blend_file^)
|
||||||
|
echo ^ # Count missing files before search
|
||||||
|
echo ^ missing_before = len^([f for f in bpy.data.images if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ missing_before += len^([f for f in bpy.data.movieclips if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ missing_before += len^([f for f in bpy.data.sounds if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ # Run find missing files operator
|
||||||
|
echo ^ bpy.ops.file.find_missing_files^(directory="!search_path!", find_all=True^)
|
||||||
|
echo ^ # Count missing files after search
|
||||||
|
echo ^ missing_after = len^([f for f in bpy.data.images if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ missing_after += len^([f for f in bpy.data.movieclips if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ missing_after += len^([f for f in bpy.data.sounds if not f.filepath or not os.path.exists^(bpy.path.abspath^(f.filepath^)^)^]^)
|
||||||
|
echo ^ found_count = missing_before - missing_after
|
||||||
|
echo ^ print^("FOUND_MISSING:" + blend_file + ":" + str^(found_count^)^)
|
||||||
|
echo ^ # Save to output folder
|
||||||
|
echo ^ bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)
|
||||||
|
echo ^ print^("SUCCESS:" + blend_file + ":" + output_file^)
|
||||||
|
echo ^ except Exception as e:
|
||||||
|
echo ^ print^("CRASH:" + blend_file + ":" + str^(e^)^)
|
||||||
|
echo ^ else:
|
||||||
|
echo ^ print^("SKIP_NOT_BLEND:" + blend_file^)
|
||||||
|
echo.
|
||||||
|
echo print^("MISSING_FILE_SEARCH_COMPLETE"^)
|
||||||
|
echo bpy.ops.wm.quit_blender^(^)
|
||||||
|
) > "!TEMP_SCRIPT!"
|
||||||
|
|
||||||
|
REM Check if script was created successfully
|
||||||
|
if exist "!TEMP_SCRIPT!" (
|
||||||
|
echo Script created successfully: !TEMP_SCRIPT!
|
||||||
|
) else (
|
||||||
|
echo ERROR: Failed to create script file!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Run Blender to process the dragged files
|
||||||
|
echo Processing dragged .blend files...
|
||||||
|
echo Using script: !TEMP_SCRIPT!
|
||||||
|
echo Search path: !search_path!
|
||||||
|
blender --background --factory-startup --python "!TEMP_SCRIPT!" -- %* 2^>^&1 | powershell -NoProfile -Command "$input | Tee-Object -FilePath 'blender_output.txt'"
|
||||||
|
|
||||||
|
REM Clean up temporary script
|
||||||
|
echo Cleaning up temporary script...
|
||||||
|
del "!TEMP_SCRIPT!" 2>nul
|
||||||
|
|
||||||
|
REM Parse output and generate report
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo MISSING FILE SEARCH REPORT
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Track found missing files during parse
|
||||||
|
for /f "tokens=1,2,3 delims=:" %%a in (blender_output.txt) do (
|
||||||
|
if "%%a"=="SUCCESS" (
|
||||||
|
set /a processed+=1
|
||||||
|
echo [!processed!] SUCCESS: %%b
|
||||||
|
echo Saved to: %%c
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="CRASH" (
|
||||||
|
set /a crashed+=1
|
||||||
|
echo [!crashed!] CRASHED: %%b
|
||||||
|
echo Error: %%c
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="SKIP_EXISTING" (
|
||||||
|
set /a skipped+=1
|
||||||
|
echo [!skipped!] SKIPPED ^(already exists^): %%b
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="SKIP_NOT_BLEND" (
|
||||||
|
set /a skipped+=1
|
||||||
|
echo [!skipped!] SKIPPED ^(not .blend^): %%b
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="FOUND_MISSING" (
|
||||||
|
for /f "delims= tokens=1" %%x in ("%%c") do set "found_in_file=%%x"
|
||||||
|
set /a found_missing+=found_in_file
|
||||||
|
echo Found missing files: !found_in_file!
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Clean up output file
|
||||||
|
del /f /q "blender_output.txt" 2>nul
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo SUMMARY
|
||||||
|
echo ========================================
|
||||||
|
echo Processed: !processed! files
|
||||||
|
echo Crashed: !crashed! files
|
||||||
|
echo Skipped: !skipped! files
|
||||||
|
echo Total missing files found: !found_missing!
|
||||||
|
echo Search path: !search_path!
|
||||||
|
echo Total: %* files
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo Done!
|
||||||
|
pause
|
||||||
160
remove_action_fake_users.bat
Normal file
160
remove_action_fake_users.bat
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
echo Starting fake user removal for actions...
|
||||||
|
|
||||||
|
REM Check if files were dragged onto the batch file
|
||||||
|
if "%~1"=="" (
|
||||||
|
echo.
|
||||||
|
echo Usage: Drag .blend files onto this batch file to remove fake users from actions.
|
||||||
|
echo Output will be saved to the \output folder.
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Create output directory if it doesn't exist
|
||||||
|
if not exist "output" mkdir "output"
|
||||||
|
|
||||||
|
REM Initialize counters and tracking
|
||||||
|
set "processed=0"
|
||||||
|
set "crashed=0"
|
||||||
|
set "skipped=0"
|
||||||
|
set "deleted_similar=0"
|
||||||
|
set "threshold_percent=10"
|
||||||
|
set "updated_total=0"
|
||||||
|
|
||||||
|
REM Create a temporary Python script for processing
|
||||||
|
set "TEMP_SCRIPT=remove_action_fake_users_temp.py"
|
||||||
|
echo Creating Python script: !TEMP_SCRIPT!
|
||||||
|
|
||||||
|
(
|
||||||
|
echo import bpy
|
||||||
|
echo import os
|
||||||
|
echo import sys
|
||||||
|
echo.
|
||||||
|
echo # Create output directory if it doesn't exist
|
||||||
|
echo if not os.path.exists^("output"^):
|
||||||
|
echo os.makedirs^("output"^)
|
||||||
|
echo.
|
||||||
|
echo # Get command line arguments ^(the dragged files^)
|
||||||
|
echo blend_files = sys.argv[sys.argv.index^("--"^) + 1:] if "--" in sys.argv else []
|
||||||
|
echo.
|
||||||
|
echo print^("Found " + str^(len^(blend_files^)^) + " .blend files to process"^)
|
||||||
|
echo.
|
||||||
|
echo for blend_file in blend_files:
|
||||||
|
echo ^ if blend_file.lower^(^).endswith^(".blend"^):
|
||||||
|
echo ^ try:
|
||||||
|
echo ^ # Create output path in output folder
|
||||||
|
echo ^ filename = os.path.basename^(blend_file^)
|
||||||
|
echo ^ output_file = os.path.join^("output", filename^)
|
||||||
|
echo ^ # Check if output file already exists
|
||||||
|
echo ^ if os.path.exists^(output_file^):
|
||||||
|
echo ^ print^("SKIP_EXISTING:" + blend_file^)
|
||||||
|
echo ^ continue
|
||||||
|
echo ^ print^("PROCESSING:" + blend_file^)
|
||||||
|
echo ^ # Load the blend file
|
||||||
|
echo ^ bpy.ops.wm.open_mainfile^(filepath=blend_file^)
|
||||||
|
echo ^ # Remove fake users from all actions
|
||||||
|
echo ^ changed = 0
|
||||||
|
echo ^ for action in bpy.data.actions:
|
||||||
|
echo ^ if getattr^(action, "use_fake_user", False^):
|
||||||
|
echo ^ action.use_fake_user = False
|
||||||
|
echo ^ changed += 1
|
||||||
|
echo ^ print^("UPDATED:" + blend_file + ":" + str^(changed^)^)
|
||||||
|
echo ^ # Save to output folder
|
||||||
|
echo ^ bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)
|
||||||
|
echo ^ print^("SUCCESS:" + blend_file + ":" + output_file^)
|
||||||
|
echo ^ except Exception as e:
|
||||||
|
echo ^ print^("CRASH:" + blend_file + ":" + str^(e^)^)
|
||||||
|
echo ^ else:
|
||||||
|
echo ^ print^("SKIP_NOT_BLEND:" + blend_file^)
|
||||||
|
echo.
|
||||||
|
echo print^("FAKE_USER_REMOVAL_COMPLETE"^)
|
||||||
|
echo bpy.ops.wm.quit_blender^(^)
|
||||||
|
) > "!TEMP_SCRIPT!"
|
||||||
|
|
||||||
|
REM Check if script was created successfully
|
||||||
|
if exist "!TEMP_SCRIPT!" (
|
||||||
|
echo Script created successfully: !TEMP_SCRIPT!
|
||||||
|
) else (
|
||||||
|
echo ERROR: Failed to create script file!
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Run Blender to process the dragged files
|
||||||
|
echo Processing dragged .blend files...
|
||||||
|
echo Using script: !TEMP_SCRIPT!
|
||||||
|
blender --background --factory-startup --python "!TEMP_SCRIPT!" -- %* 2^>^&1 | powershell -NoProfile -Command "$input | Tee-Object -FilePath 'blender_output.txt'"
|
||||||
|
|
||||||
|
REM Clean up temporary script
|
||||||
|
echo Cleaning up temporary script...
|
||||||
|
del "!TEMP_SCRIPT!" 2>nul
|
||||||
|
|
||||||
|
REM Parse output and generate report
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo ACTION FAKE USER REMOVAL REPORT
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Track updated counts per file during parse
|
||||||
|
for /f "tokens=1,2,3 delims=:" %%a in (blender_output.txt) do (
|
||||||
|
if "%%a"=="SUCCESS" (
|
||||||
|
set /a processed+=1
|
||||||
|
echo [!processed!] SUCCESS: %%b
|
||||||
|
echo Saved to: %%c
|
||||||
|
REM Compare sizes and delete if reduction < threshold
|
||||||
|
for %%f in ("%%b") do set "original_size=%%~zf"
|
||||||
|
for %%f in ("%%c") do set "compressed_size=%%~zf"
|
||||||
|
set /a savings=original_size-compressed_size
|
||||||
|
if !original_size! gtr 0 (set /a percent=(savings*100)/original_size) else (set percent=0)
|
||||||
|
echo Original: !original_size! bytes
|
||||||
|
echo Output: !compressed_size! bytes
|
||||||
|
echo Reduction: !percent!%%
|
||||||
|
if !percent! lss !threshold_percent! (
|
||||||
|
del "%%c" 2>nul
|
||||||
|
set /a deleted_similar+=1
|
||||||
|
echo Deleted: too similar to original
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="CRASH" (
|
||||||
|
set /a crashed+=1
|
||||||
|
echo [!crashed!] CRASHED: %%b
|
||||||
|
echo Error: %%c
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="SKIP_EXISTING" (
|
||||||
|
set /a skipped+=1
|
||||||
|
echo [!skipped!] SKIPPED ^(already exists^): %%b
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="SKIP_NOT_BLEND" (
|
||||||
|
set /a skipped+=1
|
||||||
|
echo [!skipped!] SKIPPED ^(not .blend^): %%b
|
||||||
|
echo.
|
||||||
|
) else if "%%a"=="UPDATED" (
|
||||||
|
REM Accumulate total updated actions
|
||||||
|
for /f "delims= tokens=1" %%x in ("%%c") do set "updated_in_file=%%x"
|
||||||
|
set /a updated_total+=updated_in_file
|
||||||
|
echo Updated actions: !updated_in_file!
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Clean up output file
|
||||||
|
del /f /q "blender_output.txt" 2>nul
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo SUMMARY
|
||||||
|
echo ========================================
|
||||||
|
echo Processed: !processed! files
|
||||||
|
echo Crashed: !crashed! files
|
||||||
|
echo Skipped: !skipped! files
|
||||||
|
echo Deleted ^(too similar^): !deleted_similar! files
|
||||||
|
echo Total actions updated: !updated_total!
|
||||||
|
echo Total: %* files
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo Done!
|
||||||
|
pause
|
||||||
|
|
||||||
|
|
||||||
375
replace_cel_with_bsdf.py
Normal file
375
replace_cel_with_bsdf.py
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
import bpy
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
def link_bsdf_materials():
|
||||||
|
"""Link all materials from the BSDF library file"""
|
||||||
|
|
||||||
|
library_path = r"A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\MATERIALS_BSDF_pallette_v1.0.blend"
|
||||||
|
|
||||||
|
if not os.path.exists(library_path):
|
||||||
|
print(f"Warning: Library file not found at {library_path}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
print(f"Linking materials from: {library_path}")
|
||||||
|
|
||||||
|
# Get list of materials before linking
|
||||||
|
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
|
||||||
|
|
||||||
|
# Get list of newly linked materials
|
||||||
|
materials_after = set(bpy.data.materials.keys())
|
||||||
|
newly_linked = materials_after - materials_before
|
||||||
|
|
||||||
|
print(f"Linked {len(newly_linked)} materials from library")
|
||||||
|
for mat_name in sorted(newly_linked):
|
||||||
|
print(f" - {mat_name}")
|
||||||
|
|
||||||
|
return list(newly_linked)
|
||||||
|
|
||||||
|
def remap_appended_to_linked():
|
||||||
|
"""Remap any appended BSDF materials to their linked counterparts"""
|
||||||
|
|
||||||
|
print("\nChecking for appended BSDF materials to remap to linked versions...")
|
||||||
|
|
||||||
|
materials = bpy.data.materials
|
||||||
|
remapping_count = 0
|
||||||
|
|
||||||
|
# Group materials by base name (without library suffix)
|
||||||
|
material_groups = {}
|
||||||
|
|
||||||
|
for mat in materials:
|
||||||
|
# Check if it's a BSDF material (from any source)
|
||||||
|
if mat.name.startswith("BSDF_") or "BSDF_" in mat.name:
|
||||||
|
# Extract base name (remove library reference if present)
|
||||||
|
base_name = mat.name.split(".blend")[0] if ".blend" in mat.name else mat.name
|
||||||
|
base_name = base_name.split(".")[0] if "." in base_name else base_name
|
||||||
|
|
||||||
|
if base_name not in material_groups:
|
||||||
|
material_groups[base_name] = []
|
||||||
|
material_groups[base_name].append(mat)
|
||||||
|
|
||||||
|
# For each group, prefer linked materials over appended ones
|
||||||
|
for base_name, mats in material_groups.items():
|
||||||
|
if len(mats) > 1:
|
||||||
|
# Sort to prefer linked materials (they have library references)
|
||||||
|
linked_mats = [m for m in mats if m.library is not None]
|
||||||
|
appended_mats = [m for m in mats if m.library is None]
|
||||||
|
|
||||||
|
if linked_mats and appended_mats:
|
||||||
|
# Use the first linked material as target
|
||||||
|
target_material = linked_mats[0]
|
||||||
|
|
||||||
|
# Remap all appended materials to the linked one
|
||||||
|
for appended_mat in appended_mats:
|
||||||
|
if appended_mat.users > 0:
|
||||||
|
print(f"Remapping appended {appended_mat.name} ({appended_mat.users} users) to linked {target_material.name}")
|
||||||
|
appended_mat.user_remap(target_material)
|
||||||
|
remapping_count += 1
|
||||||
|
|
||||||
|
# Remove the unused appended material
|
||||||
|
if appended_mat.users == 0:
|
||||||
|
print(f"Removing unused appended material: {appended_mat.name}")
|
||||||
|
bpy.data.materials.remove(appended_mat)
|
||||||
|
|
||||||
|
# Also check for any BSDF materials that might be from old paths or different files
|
||||||
|
# and try to find matching linked materials
|
||||||
|
for mat in materials:
|
||||||
|
if mat.library is None and (mat.name.startswith("BSDF_") or "BSDF_" in mat.name):
|
||||||
|
# This is an appended BSDF material - look for a linked version
|
||||||
|
base_name = mat.name.split(".blend")[0] if ".blend" in mat.name else mat.name
|
||||||
|
base_name = base_name.split(".")[0] if "." in base_name else base_name
|
||||||
|
|
||||||
|
# Look for any linked material with the same base name
|
||||||
|
for linked_mat in materials:
|
||||||
|
if (linked_mat.library is not None and
|
||||||
|
linked_mat.name.startswith("BSDF_") and
|
||||||
|
(linked_mat.name == base_name or
|
||||||
|
linked_mat.name.startswith(base_name + ".") or
|
||||||
|
linked_mat.name == mat.name)):
|
||||||
|
|
||||||
|
if mat.users > 0:
|
||||||
|
print(f"Remapping old BSDF {mat.name} ({mat.users} users) to linked {linked_mat.name}")
|
||||||
|
mat.user_remap(linked_mat)
|
||||||
|
remapping_count += 1
|
||||||
|
|
||||||
|
# Remove the unused material
|
||||||
|
if mat.users == 0:
|
||||||
|
print(f"Removing unused old BSDF material: {mat.name}")
|
||||||
|
bpy.data.materials.remove(mat)
|
||||||
|
break
|
||||||
|
|
||||||
|
print(f"Remapped {remapping_count} appended/old BSDF materials to linked versions")
|
||||||
|
return remapping_count
|
||||||
|
|
||||||
|
def remap_missing_datablocks():
|
||||||
|
"""Remap materials that have missing/broken library links"""
|
||||||
|
|
||||||
|
print("\nChecking for missing datablocks to remap...")
|
||||||
|
|
||||||
|
materials = bpy.data.materials
|
||||||
|
remapping_count = 0
|
||||||
|
|
||||||
|
# Find materials with missing library links
|
||||||
|
missing_materials = []
|
||||||
|
for mat in materials:
|
||||||
|
if mat.library is not None and mat.library.filepath and not os.path.exists(bpy.path.abspath(mat.library.filepath)):
|
||||||
|
missing_materials.append(mat)
|
||||||
|
print(f"Found missing datablock: {mat.name} (from {mat.library.filepath})")
|
||||||
|
|
||||||
|
if not missing_materials:
|
||||||
|
print("No missing datablocks found.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# For each missing material, try to find a replacement
|
||||||
|
for missing_mat in missing_materials:
|
||||||
|
base_name = missing_mat.name.split(".blend")[0] if ".blend" in missing_mat.name else missing_mat.name
|
||||||
|
base_name = base_name.split(".")[0] if "." in base_name else base_name
|
||||||
|
|
||||||
|
# Look for a replacement material
|
||||||
|
replacement_found = False
|
||||||
|
|
||||||
|
# First, try to find a linked material with the same name from the current library
|
||||||
|
for mat in materials:
|
||||||
|
if (mat.library is not None and
|
||||||
|
mat.library.filepath and
|
||||||
|
os.path.exists(bpy.path.abspath(mat.library.filepath)) and
|
||||||
|
mat.name == missing_mat.name):
|
||||||
|
|
||||||
|
if missing_mat.users > 0:
|
||||||
|
print(f"Remapping missing {missing_mat.name} ({missing_mat.users} users) to valid linked {mat.name}")
|
||||||
|
missing_mat.user_remap(mat)
|
||||||
|
remapping_count += 1
|
||||||
|
replacement_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# If no exact match, try to find a BSDF material with similar name
|
||||||
|
if not replacement_found and (missing_mat.name.startswith("BSDF_") or "BSDF_" in missing_mat.name):
|
||||||
|
for mat in materials:
|
||||||
|
if (mat.library is not None and
|
||||||
|
mat.library.filepath and
|
||||||
|
os.path.exists(bpy.path.abspath(mat.library.filepath)) and
|
||||||
|
mat.name.startswith("BSDF_") and
|
||||||
|
(mat.name == base_name or
|
||||||
|
mat.name.startswith(base_name + ".") or
|
||||||
|
base_name in mat.name)):
|
||||||
|
|
||||||
|
if missing_mat.users > 0:
|
||||||
|
print(f"Remapping missing BSDF {missing_mat.name} ({missing_mat.users} users) to valid linked {mat.name}")
|
||||||
|
missing_mat.user_remap(mat)
|
||||||
|
remapping_count += 1
|
||||||
|
replacement_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# If still no replacement, try to find any valid linked material with the same base name
|
||||||
|
if not replacement_found:
|
||||||
|
for mat in materials:
|
||||||
|
if (mat.library is not None and
|
||||||
|
mat.library.filepath and
|
||||||
|
os.path.exists(bpy.path.abspath(mat.library.filepath)) and
|
||||||
|
mat.name == base_name):
|
||||||
|
|
||||||
|
if missing_mat.users > 0:
|
||||||
|
print(f"Remapping missing {missing_mat.name} ({missing_mat.users} users) to valid linked {mat.name}")
|
||||||
|
missing_mat.user_remap(mat)
|
||||||
|
remapping_count += 1
|
||||||
|
replacement_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not replacement_found:
|
||||||
|
print(f"Warning: No replacement found for missing material {missing_mat.name}")
|
||||||
|
|
||||||
|
print(f"Remapped {remapping_count} missing datablocks to valid linked materials")
|
||||||
|
return remapping_count
|
||||||
|
|
||||||
|
def replace_cel_materials():
|
||||||
|
"""Replace all CEL materials with their BSDF counterparts using Blender's user remapping"""
|
||||||
|
|
||||||
|
# First, link BSDF materials from library
|
||||||
|
linked_materials = link_bsdf_materials()
|
||||||
|
|
||||||
|
# Then, remap any missing datablocks
|
||||||
|
missing_remaps = remap_missing_datablocks()
|
||||||
|
|
||||||
|
# Then, remap any appended BSDF materials to linked versions
|
||||||
|
appended_remaps = remap_appended_to_linked()
|
||||||
|
|
||||||
|
print(f"\n=== STARTING MATERIAL REPLACEMENT ===")
|
||||||
|
|
||||||
|
# Custom material mappings (source -> target)
|
||||||
|
custom_mappings = {
|
||||||
|
"bag BLACK (squid ink)": "BSDF_black_SQUID-INK",
|
||||||
|
"bag WHITE": "BSDF_WHITE",
|
||||||
|
"Wheel-White": "BSDF_WHITE",
|
||||||
|
"Bag Colors": "BSDF_Bag Colors",
|
||||||
|
"cardboard": "Package_Cardboard",
|
||||||
|
"blue (triton)": "BSDF_blue-2_TRITON",
|
||||||
|
"gray (snow)": "BSDF_gray-6_SNOW",
|
||||||
|
"gray (storm)": "BSDF_gray-2_STORM",
|
||||||
|
"gray (summit)": "BSDF_gray-5_SUMMIT",
|
||||||
|
"light blue (prime)": "BSDF_blue-4_PRIME",
|
||||||
|
"yellow (summer)": "BSDF_orange-5_SUMMER",
|
||||||
|
"Accessory_CEL_gray-6_SNOW": "BSDF_gray-6_SNOW",
|
||||||
|
"Accessory_CEL_SquidInk": "BSDF_black_SQUID-INK",
|
||||||
|
"FingerScanner": "BSDF_black_SQUID-INK",
|
||||||
|
"cel BLACK (squid ink)": "BSDF_black_SQUID-INK",
|
||||||
|
"cel WHITE": "BSDF_WHITE",
|
||||||
|
"gray (stone)": "BSDF_gray-3_STONE",
|
||||||
|
"green (oxygen)": "BSDF_green-3_OXYGEN",
|
||||||
|
"orange (smile)": "BSDF_orange-3_SMILE",
|
||||||
|
"orange (blaze)": "BSDF_orange-1_BLAZE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get all materials in the scene
|
||||||
|
materials = bpy.data.materials
|
||||||
|
|
||||||
|
# Dictionary to store source -> target material mapping
|
||||||
|
material_mapping = {}
|
||||||
|
|
||||||
|
# Replace all CEL materials with their BSDF counterparts, ignoring numeric suffixes
|
||||||
|
cel_pattern = re.compile(r"^(CEL_.+?)(\.\d{3})?$")
|
||||||
|
bsdf_pattern = re.compile(r"^(BSDF_.+?)(\.\d{3})?$")
|
||||||
|
|
||||||
|
# Build a mapping from base BSDF name to BSDF material (without suffix)
|
||||||
|
bsdf_base_map = {bsdf_pattern.match(mat.name).group(1): mat for mat in materials if bsdf_pattern.match(mat.name)}
|
||||||
|
|
||||||
|
# Build a mapping from exact material names to materials
|
||||||
|
exact_material_map = {mat.name: mat for mat in materials}
|
||||||
|
|
||||||
|
# Helpers to normalize names (case-insensitive, ignore numeric suffixes and library suffix)
|
||||||
|
def normalize_base(name):
|
||||||
|
base_name = name.split(".blend")[0] if ".blend" in name else name
|
||||||
|
match = re.match(r"^(.*?)(\.\d{3})?$", base_name)
|
||||||
|
base_name = match.group(1) if match else base_name
|
||||||
|
return base_name.strip().casefold()
|
||||||
|
|
||||||
|
# Map normalized base name -> list of materials
|
||||||
|
materials_by_base = {}
|
||||||
|
for mat in materials:
|
||||||
|
base = normalize_base(mat.name)
|
||||||
|
materials_by_base.setdefault(base, []).append(mat)
|
||||||
|
|
||||||
|
# Normalize BSDF base name map for robust target lookups
|
||||||
|
bsdf_base_map_normalized = {normalize_base(base): mat for base, mat in bsdf_base_map.items()}
|
||||||
|
|
||||||
|
replacements_made = 0
|
||||||
|
missing_targets = []
|
||||||
|
|
||||||
|
# Process custom mappings first (case/suffix-insensitive)
|
||||||
|
for source_name, target_name in custom_mappings.items():
|
||||||
|
# Gather source candidates by exact name or base name (handles .001 etc.)
|
||||||
|
if source_name in exact_material_map:
|
||||||
|
source_candidates = [exact_material_map[source_name]]
|
||||||
|
else:
|
||||||
|
source_candidates = materials_by_base.get(normalize_base(source_name), [])
|
||||||
|
|
||||||
|
if not source_candidates:
|
||||||
|
print(f"Warning: Source material '{source_name}' not found")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Resolve target BSDF by exact or base name
|
||||||
|
target_material = exact_material_map.get(target_name)
|
||||||
|
if target_material is None:
|
||||||
|
target_material = bsdf_base_map_normalized.get(normalize_base(target_name))
|
||||||
|
if target_material is None:
|
||||||
|
# Final fallback: any BSDF whose base equals target base
|
||||||
|
target_base_norm = normalize_base(target_name)
|
||||||
|
for mat in materials:
|
||||||
|
m = bsdf_pattern.match(mat.name)
|
||||||
|
if m and normalize_base(m.group(1)) == target_base_norm:
|
||||||
|
target_material = mat
|
||||||
|
break
|
||||||
|
|
||||||
|
if target_material is None:
|
||||||
|
missing_targets.append(f"{source_name} -> {target_name}")
|
||||||
|
print(f"Warning: Target material '{target_name}' not found for custom mapping '{source_name}'")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for src_mat in source_candidates:
|
||||||
|
material_mapping[src_mat] = target_material
|
||||||
|
print(f"Found custom mapping: {src_mat.name} -> {target_material.name}")
|
||||||
|
|
||||||
|
# Find all CEL materials and their BSDF counterparts
|
||||||
|
for mat in materials:
|
||||||
|
cel_match = cel_pattern.match(mat.name)
|
||||||
|
if cel_match:
|
||||||
|
base_cel = cel_match.group(1)
|
||||||
|
base_bsdf = base_cel.replace("CEL_", "BSDF_", 1)
|
||||||
|
if base_bsdf in bsdf_base_map:
|
||||||
|
material_mapping[mat] = bsdf_base_map[base_bsdf]
|
||||||
|
print(f"Found CEL mapping: {mat.name} -> {bsdf_base_map[base_bsdf].name}")
|
||||||
|
else:
|
||||||
|
missing_targets.append(f"{mat.name} -> {base_bsdf}")
|
||||||
|
print(f"Warning: No BSDF counterpart found for {mat.name}")
|
||||||
|
|
||||||
|
# Use Blender's built-in user remapping to replace ALL users
|
||||||
|
for source_material, target_material in material_mapping.items():
|
||||||
|
print(f"Remapping all users of {source_material.name} to {target_material.name}")
|
||||||
|
|
||||||
|
# Get user count before remapping
|
||||||
|
users_before = source_material.users
|
||||||
|
|
||||||
|
# Remap all users of the source material to the target material
|
||||||
|
# This catches ALL users including geometry node instances, drivers, etc.
|
||||||
|
source_material.user_remap(target_material)
|
||||||
|
|
||||||
|
# Get user count after remapping
|
||||||
|
users_after = source_material.users
|
||||||
|
|
||||||
|
replacements_this_material = users_before - users_after
|
||||||
|
replacements_made += replacements_this_material
|
||||||
|
|
||||||
|
print(f" Users before: {users_before}, after: {users_after}")
|
||||||
|
print(f" Remapped {replacements_this_material} users")
|
||||||
|
|
||||||
|
# Optional: Remove unused source materials after remapping
|
||||||
|
print(f"\nCleaning up unused source materials...")
|
||||||
|
removed_materials = 0
|
||||||
|
|
||||||
|
for source_material in material_mapping.keys():
|
||||||
|
if source_material.users == 0:
|
||||||
|
print(f"Removing unused material: {source_material.name}")
|
||||||
|
bpy.data.materials.remove(source_material)
|
||||||
|
removed_materials += 1
|
||||||
|
else:
|
||||||
|
print(f"Warning: {source_material.name} still has {source_material.users} users after remapping")
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
print(f"\n=== REPLACEMENT SUMMARY ===")
|
||||||
|
print(f"Materials linked from library: {len(linked_materials)}")
|
||||||
|
print(f"Missing datablocks remapped: {missing_remaps}")
|
||||||
|
print(f"Appended->Linked remappings: {appended_remaps}")
|
||||||
|
print(f"Total materials mapped: {len(material_mapping)}")
|
||||||
|
print(f"Successful mappings: {len(material_mapping)}")
|
||||||
|
print(f"Total user remappings: {replacements_made}")
|
||||||
|
print(f"Source materials removed: {removed_materials}")
|
||||||
|
|
||||||
|
if missing_targets:
|
||||||
|
print(f"\nMissing target materials for:")
|
||||||
|
for mapping in missing_targets:
|
||||||
|
print(f" - {mapping}")
|
||||||
|
|
||||||
|
return len(material_mapping), replacements_made
|
||||||
|
|
||||||
|
# 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)")
|
||||||
Reference in New Issue
Block a user