Skip to content

Instantly share code, notes, and snippets.

@madjin
Created April 16, 2024 21:05
Show Gist options
  • Save madjin/ef76cd93c7f9ea4290d173d3d2c98390 to your computer and use it in GitHub Desktop.
Save madjin/ef76cd93c7f9ea4290d173d3d2c98390 to your computer and use it in GitHub Desktop.
Blender script to bake each object then export as glTF + USDZ
import bpy
import sys
import os
def unwrap_and_bake_texture(obj, bake_resolution):
# Select the object
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
# Check if the object is a mesh
if obj.type == 'MESH':
# Switch to Edit mode
bpy.ops.object.mode_set(mode='EDIT')
# Unwrap the mesh
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.smart_project(island_margin=0.01)
bpy.ops.object.mode_set(mode='OBJECT')
else:
print(f"Skipping non-mesh object: {obj.name}")
return
# Switch to Cycles rendering mode
bpy.context.scene.render.engine = 'CYCLES'
# Set baking settings
bpy.context.scene.cycles.bake_type = 'DIFFUSE'
bpy.context.scene.render.bake.use_pass_color = True
bpy.context.scene.render.bake.use_pass_direct = False
bpy.context.scene.render.bake.use_pass_indirect = False
bpy.context.scene.render.bake.target = 'IMAGE_TEXTURES'
bpy.context.scene.render.bake.margin_type = 'ADJACENT_FACES'
# Extract the base name from the object name
base_name = obj.name.split('.')[0]
# Create a new image texture for each material or reuse existing ones
for mat in obj.data.materials:
texture_name = f"{base_name}_{mat.name}"
texture = bpy.data.images.new(texture_name, bake_resolution, bake_resolution)
# Assign the image texture to the material
mat.use_nodes = True
nodes = mat.node_tree.nodes
principled_bsdf = next(n for n in nodes if n.type == 'BSDF_PRINCIPLED')
# Create the image texture node and select it
texture_node = nodes.new('ShaderNodeTexImage')
texture_node.image = texture
texture_node.select = True
nodes.active = texture_node
# Bake the texture
bpy.ops.object.bake(type='DIFFUSE', pass_filter={'COLOR'})
# Connect the image texture to the base color input
links = mat.node_tree.links
links.new(texture_node.outputs['Color'], principled_bsdf.inputs['Base Color'])
def process_glb_file(filepath, bake_resolution):
if "Cube" in bpy.data.objects:
bpy.data.objects.remove(bpy.data.objects["Cube"], do_unlink=True)
# Import the glb file
bpy.ops.import_scene.gltf(filepath=filepath)
# Get the imported object
obj = bpy.context.selected_objects[0]
# Unwrap and bake the texture
unwrap_and_bake_texture(obj, bake_resolution)
# Export the new glb file
glb_filepath = os.path.join(os.path.dirname(filepath), f"{os.path.basename(filepath)}")
new_glb_filepath = os.path.join(os.path.dirname(filepath), f"new_{os.path.basename(filepath)}")
bpy.ops.export_scene.gltf(filepath=new_glb_filepath, export_format='GLB')
# Export the USDC file with packed textures
usdc_filepath = os.path.splitext(glb_filepath)[0] + ".usdz"
bpy.ops.wm.usd_export(filepath=usdc_filepath, selected_objects_only=True, export_textures=True)
## Export the USD file
#usd_filepath = os.path.splitext(new_glb_filepath)[0] + ".usd"
#bpy.ops.wm.usd_export(filepath=usd_filepath)
# Clean up the scene
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
if __name__ == "__main__":
if len(sys.argv) != 6 or sys.argv[4] != "--":
print("Usage: blender --background --python script.py -- <input_glb_file>")
sys.exit(1)
input_filepath = sys.argv[5]
bake_resolution = 512
process_glb_file(input_filepath, bake_resolution)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment