# Batch Export from Character Studio ## 10-16-23 - https://github.com/M3-org/character-assets/issues?q=is%3Aissue+is%3Aclosed+archived%3Afalse+reason%3Acompleted Generated all the manifest.json and named them $id_manifest.json in this zip: https://cdn.discordapp.com/attachments/1041270464271622234/1163308582591275079/female_manifest_json.zip?ex=653f1a8b&is=652ca58b&hm=6284e176678f846b1649b5a73d4267c842e975bba669491c9145c354d222c2a1& I also generated 800x1356 thumbnails for each, and put into folders in this zip: https://cdn.discordapp.com/attachments/1041270464271622234/1163309952610357338/thumbnails_female.zip?ex=653f1bd1&is=652ca6d1&hm=a8af77c485562349baa00e99bf31ceac30dbb84ad269bd12753b69cf28e148fa& the scripts I used are being uploaded here: https://github.com/M3-org/anata/tree/main/vrm/scripts --- ## 10-24-23 Need to debug some vertices being glued together in female clothing blend files ![](https://i.imgur.com/XOEJPe1.png) ### New export script > I modified the code a bit so it export each glass model with the same armature for each, maybe this scripts is also helpful in your side 🙂 - memelotsqui ```python=! import bpy import os import sys # REMEMBER TO SET THE EXPORT PATH export_path = "/home/$USER/Desktop/Exports" view_layer_name = 'ViewLayer' view_layer = bpy.context.scene.view_layers.get(view_layer_name) if view_layer is None: print(f"View Layer '{view_layer_name}' not found.") sys.exit(1) bpy.context.window.view_layer = view_layer # Get a list of all visible objects in the scene visible_objects = [obj for obj in bpy.context.scene.objects if obj.parent is None] # Iterate over each visible object and export it as a separate VRM file for obj in visible_objects: # Skip objects not in the specified view layer if obj.name not in view_layer.objects: print(f"Object '{obj.name}' is not in view layer '{view_layer_name}'. Skipping.") continue # Search for a mesh in the hierarchy of children mesh = None for child in obj.children_recursive: if child.type == 'MESH': mesh = child # If a mesh is found and it's in the view layer, select it for export if mesh and mesh.name in view_layer.objects: # Set the filename for the exported VRM file armature = mesh.parent armature.data.vrm_addon_extension.spec_version = "0.0" filename = mesh.name + ".vrm" filepath = os.path.join(export_path, filename) # Select the mesh for export bpy.context.view_layer.objects.active = mesh mesh.select_set(True) # Export the mesh (VRM) bpy.ops.export_scene.vrm( filepath=filepath, export_invisibles=False, enable_advanced_preferences=True, export_fb_ngon_encoding=False, export_only_selections=True, armature_object_name=obj.name ) ``` --- ## Prepping VRM Folder First go into `vrm/male` or `vrm/female` and get all the JSON metadata from NFTs into current dir `find ./ -iname "*.json" -exec cp '{}' . \;` Now we need to convert the NFT metadata to a more simpler form. Copy convert_json.py from `vrm/scripts` and either the male or female renamed_traits.csv from `metadata/csv` in the Anata repo to current dir. It is a CSV that contains two columns, "Original","Rename". Running convert_json.py will then copy new files to converted_json folder with the metadata matching the project directory / filename structure. I go into this folder then select / rename everything to be *_renamed.json for organization. Then bring attributes2.sh from `vrm/scripts` and run in current directory to get simplified JSON per Anata, like below: ```json!= { "name": "1", "attributes": [ { "trait_type": "BODY", "value": "Masculine" }, { "trait_type": "CLOTHING", "value": "Ragnarok_777_T_Shirt" }, { "trait_type": "HAIR", "value": "Mid_Red-Black" }, { "trait_type": "TYPE", "value": "Ragnarok" }, { "trait_type": "GLASSES", "value": "Modern_Shades" }, { "trait_type": "NECK", "value": "Silver_Links_Chain" }, { "trait_type": "BRACE", "value": "Strobe_Light_Brace" }, { "trait_type": "SET", "value": "Ragnarok" } ] } ``` I want to get all the preview images into the VRM folders now for male, I'll fetch them from another place in Anata project repo this way (saved as `vrm/scripts/copy_previews.sh`): ```bash! source_directory1="../../img/0-999" source_directory2="../../img/1000-2000" # Loop through the JSON files in the current directory for json_file in *.json; do # Extract the filename without the .json extension filename=$(basename "$json_file" .json) # Debug: Show the filenames being checked echo "Checking for $filename.jpg in $source_directory1" # Check if a corresponding JPEG file exists in the source directory if [ -e "$source_directory1/$filename.jpg" ]; then echo "Copying $filename.jpg" cp "$source_directory1/$filename.jpg" "$filename.jpg" else echo "No matching JPEG file found for $filename.json" fi echo "Checking for $filename.jpg in $source_directory2" if [ -e "$source_directory2/$filename.jpg" ]; then echo "Copying $filename.jpg" cp "$source_directory2/$filename.jpg" "$filename.jpg" else echo "No matching JPEG file found for $filename.json" fi done ``` I need to crop them a bit for the UI, using this command to make them the same portrait resolution across the app: ```bash! mkdir -p output # Create an "output" directory if it doesn't exist for file in *.jpg; do output_file="output/t_$file" convert "$file" -resize 800x1356^ -gravity center -extent 800x1356 "$output_file" done ``` I want to move all the *_attribute.json files to each folder in `vrm/male`, I mv them from converted_json over to current dir and run this: ```bash! for file in *_attributes.json; do folder_name="${file%%_*}" # Extract the numerical value mv "$file" "$folder_name/" done ``` ## Combine Skin + Eyes I'm starting with priority Anata first, and all these share the same skin texture so I want to copy the skintone texture to each folder. ```bash! source_file="/path/to/repo/anata/files/BODY/male_skintone/male_body_6.png" # Define an array of destination folders destination_folders=(1161 1183 1192 1297 1505 1524 1558 1562 1645 1736 195 32 338 412 718 867) # Loop through the destination folders and copy the source file to each one for folder in "${destination_folders[@]}"; do cp "$source_file" "$folder" done ``` Now to combine with eyes, this will 2x eyes resolution to match skin then composite. Just have to run against the folder, it will output skin-eyes_$dirname.png in that folder. Just need tattoos next and it's ready to be used. ```bash! #!/bin/bash # Check if an input directory argument is provided if [ "$#" -ne 1 ]; then echo "Usage: $0 <input_directory>" exit 1 fi input_directory="$1" # Check if the directory exists if [ ! -d "$input_directory" ]; then echo "Error: Directory $input_directory does not exist." exit 1 fi # Define the desired resolution resolution="4096x4096" # Loop through all images starting with "eyes_" in the input directory for eyes_image in "$input_directory"/eyes_*.png; do # Get the basename of the "eyes_" image (e.g., eyes_image.png) base_eyes_image=$(basename "$eyes_image") # Extract the filename without the extension (e.g., eyes_image) eyes_filename="${base_eyes_image%.png}" # Compose the output filename output_filename="$input_directory/skin-$eyes_filename.png" # Use a wildcard to find the male body image (e.g., male_body_*.png) male_body_image=$(find "$input_directory" -name "male_body_*.png" -print -quit) # Check if a male body image was found if [ -n "$male_body_image" ]; then # Upscale the "eyes_" image to 4096x4096 convert "$eyes_image" -resize "$resolution" temp_eyes.png # Perform the image operations using the 'composite' command composite -gravity center temp_eyes.png "$male_body_image" "$output_filename" # Remove the temporary upscaled "eyes_" image rm temp_eyes.png echo "Processed $base_eyes_image" else echo "Error: Male body image not found for '$base_eyes_image'. Skipping." fi done ``` Can batch convert with this snippet: ```bash! destination_folders=(1161 1183 1192 1297 1505 1524 1558 1562 1645 1736 195 32 338 412 718 867) # Loop through the destination folders and copy the source file to each one for folder in "${destination_folders[@]}"; do bash combine_skin-eyes.sh "$folder" done ``` ![](https://hackmd.io/_uploads/Sk4-BEsfa.png) ![](https://hackmd.io/_uploads/HJgDSVszp.png) ![](https://hackmd.io/_uploads/ByETHNif6.png) ![](https://hackmd.io/_uploads/BJdUDNsM6.png) Score