Files
unity/Tools/Blender/CreatePrototypeMech.py
RCiBot 92623a1bc8 feat: establish mech extraction prototype with bilingual UI
Track Unity source, scenes, editable assets, licenses, tools and QA evidence. Exclude generated caches, Windows builds and raw runtime logs.
2026-11-12 12:28:40 +08:00

86 lines
4.0 KiB
Python

"""Create a reusable blockout mech, preserve other scenes, export selected asset."""
import bpy
from pathlib import Path
root_path = Path('D:/vibeCoding/unityRouge')
source_path = root_path / 'SourceAssets/Blender/Mechs'
export_path = root_path / 'Assets/Game/Art/Models/Mechs'
source_path.mkdir(parents=True, exist_ok=True)
export_path.mkdir(parents=True, exist_ok=True)
scene = bpy.data.scenes.get('UnityRouge_Assets') or bpy.data.scenes.new('UnityRouge_Assets')
bpy.context.window.scene = scene
collection = bpy.data.collections.get('Mech_Scout_A')
if collection is None:
collection = bpy.data.collections.new('Mech_Scout_A')
scene.collection.children.link(collection)
else:
for obj in list(collection.objects):
bpy.data.objects.remove(obj, do_unlink=True)
def material(name, color, metal=0.0):
mat = bpy.data.materials.get(name) or bpy.data.materials.new(name)
mat.use_nodes = True
node = next(n for n in mat.node_tree.nodes if n.type == 'BSDF_PRINCIPLED')
node.inputs['Base Color'].default_value = (*color, 1)
node.inputs['Metallic'].default_value = metal
node.inputs['Roughness'].default_value = 0.4
mat.diffuse_color = (*color, 1)
return mat
armor = material('Armor', (0.18, 0.28, 0.30), 0.65)
dark = material('Mechanism', (0.035, 0.055, 0.065), 0.7)
light = material('Trim', (0.55, 0.63, 0.62), 0.5)
glow = material('Reactor', (0.05, 0.9, 0.78), 0.3)
root = bpy.data.objects.new('Mech_Root', None)
collection.objects.link(root)
def box(name, pos, size, mat, parent=root):
bpy.ops.mesh.primitive_cube_add(size=1, location=pos)
obj = bpy.context.object
obj.name = name
for old in list(obj.users_collection):
old.objects.unlink(obj)
collection.objects.link(obj)
obj.dimensions = size
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
obj.data.materials.append(mat)
bevel = obj.modifiers.new('ManufacturedEdges', 'BEVEL')
bevel.width = 0.055
bevel.segments = 2
obj.parent = parent
return obj
for side, x in [('L', -0.48), ('R', 0.48)]:
box('Foot_' + side, (x, -0.16, 0.18), (0.64, 1.05, 0.36), dark)
box('Shin_' + side, (x, 0.04, 0.66), (0.5, 0.54, 0.7), armor)
box('Knee_' + side, (x, -0.28, 1.02), (0.52, 0.2, 0.3), light)
box('Thigh_' + side, (x, 0.02, 1.32), (0.43, 0.48, 0.6), dark)
box('Shoulder_' + side, (x * 1.9, 0, 2.5), (0.65, 0.72, 0.65), armor)
box('Arm_' + side, (x * 1.95, -0.05, 2.0), (0.42, 0.48, 0.65), dark)
box('Gauntlet_' + side, (x * 1.95, -0.25, 1.78), (0.52, 0.65, 0.45), armor)
box('Thruster_' + side, (x * 0.9, 0.58, 2.18), (0.32, 0.38, 0.8), dark)
box('ThrusterGlow_' + side, (x * 0.9, 0.6, 1.75), (0.24, 0.27, 0.14), glow)
box('Pelvis', (0, 0, 1.65), (1.1, 0.58, 0.34), armor)
box('Core', (0, 0.0, 2.32), (1.28, 0.7, 0.94), armor)
box('BreastPlate', (0, -0.4, 2.4), (0.8, 0.2, 0.5), light)
box('CoreGlow', (0, -0.52, 2.4), (0.45, 0.07, 0.09), glow)
box('Head', (0, -0.04, 2.98), (0.62, 0.58, 0.45), dark)
box('Visor', (0, -0.35, 3.0), (0.49, 0.08, 0.14), glow)
box('Weapon_Main', (1.0, -0.7, 1.95), (0.35, 1.5, 0.35), dark)
box('Weapon_Trim', (1.0, -0.8, 2.15), (0.2, 1.0, 0.08), light)
for name, pos in [('Mount_Primary',(1.0,-1.48,1.95)), ('Mount_Secondary',(-0.92,-0.5,2.5)), ('View_Cockpit',(0,-0.22,2.85))]:
marker = bpy.data.objects.new(name, None)
collection.objects.link(marker)
marker.location = pos
marker.parent = root
scene.unit_settings.system = 'METRIC'
scene.unit_settings.scale_length = 1.0
bpy.ops.object.select_all(action='DESELECT')
for obj in collection.objects:
obj.select_set(True)
bpy.context.view_layer.objects.active = root
bpy.ops.wm.save_as_mainfile(filepath=str(source_path / 'Mech_Scout_A.blend'))
bpy.ops.export_scene.fbx(filepath=str(export_path / 'Mech_Scout_A.fbx'), use_selection=True, add_leaf_bones=False, axis_forward='-Z', axis_up='Y', apply_unit_scale=True, bake_anim=False)
print({'source': str(source_path / 'Mech_Scout_A.blend'), 'export': str(export_path / 'Mech_Scout_A.fbx'), 'objects':len(collection.objects)})