Created
April 16, 2024 21:05
-
-
Save madjin/ef76cd93c7f9ea4290d173d3d2c98390 to your computer and use it in GitHub Desktop.
Blender script to bake each object then export as glTF + USDZ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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