"""Self-created cartoon scenery; run with Blender 5.2.2 --background --python.""" import bpy import math from pathlib import Path ROOT = Path(__file__).resolve().parents[2] SOURCE = ROOT / 'SourceAssets/Models' EXPORT = ROOT / 'Assets/MagnetismHeroes/UnityRuntime/Presentation/Models' SOURCE.mkdir(parents=True, exist_ok=True) EXPORT.mkdir(parents=True, exist_ok=True) bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False) def part(shape, location, scale): if shape == 'box': bpy.ops.mesh.primitive_cube_add(size=1, location=location) elif shape == 'sphere': bpy.ops.mesh.primitive_uv_sphere_add(segments=20, ring_count=12, radius=1, location=location) elif shape == 'cylinder': bpy.ops.mesh.primitive_cylinder_add(vertices=24, radius=1, depth=2, location=location) obj = bpy.context.object obj.scale = scale bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) if shape == 'box': bevel = obj.modifiers.new('SoftToyCorners', 'BEVEL'); bevel.width=.08; bevel.segments=3 bpy.ops.object.modifier_apply(modifier=bevel.name) for face in obj.data.polygons: face.use_smooth = shape != 'box' return obj def finish(name, parts): bpy.ops.object.select_all(action='DESELECT') for obj in parts: obj.select_set(True) bpy.context.view_layer.objects.active=parts[0] bpy.ops.object.join() obj=bpy.context.object; obj.name=name bpy.context.scene.cursor.location=(0,0,0) bpy.ops.object.origin_set(type='ORIGIN_CURSOR') bpy.ops.export_scene.fbx(filepath=str(EXPORT / (name+'.fbx')), use_selection=True, object_types={'MESH'}, axis_forward='-Z', axis_up='Y', apply_unit_scale=True, apply_scale_options='FBX_SCALE_ALL', use_mesh_modifiers=True, bake_anim=False, add_leaf_bones=False, path_mode='AUTO') obj.hide_set(True) return obj finish('Island', [part('cylinder',(0,0,-.18),(3,2.25,.18))]) finish('BlockArch', [part('box',(-.95,0,.85),(.45,.7,1.7)),part('box',(.95,0,.85),(.45,.7,1.7)),part('box',(0,0,1.85),(2.35,.7,.4))]) finish('ToySteps', [part('box',(-.35,0,.18),(.65,1,.36)),part('box',(.35,0,.4),(.65,1,.8))]) finish('Pebbles', [part('sphere',(-.32,0,.12),(.38,.3,.22)),part('sphere',(.32,.12,.16),(.35,.28,.26))]) finish('GardenFlower', [part('cylinder',(0,0,.65),(.1,.1,.65)),part('sphere',(0,0,1.32),(.23,.23,.23))]+[part('sphere',(.35*math.cos(i*math.pi/3),0,1.32+.35*math.sin(i*math.pi/3)),(.25,.15,.25)) for i in range(6)]) finish('GardenMushroom', [part('cylinder',(0,0,.38),(.22,.22,.38)),part('sphere',(0,0,.85),(.65,.65,.25))]) finish('GardenLeaf', [part('sphere',(0,0,.25),(.75,.22,.25)),part('cylinder',(.7,0,.18),(.08,.08,.18))]) finish('CloudPuff', [part('sphere',(x,0,z),(s,.55,s)) for x,z,s in [(-.65,.55,.5),(0,.65,.7),(.65,.5,.5)]]) finish('CloudRainbow', [part('sphere',(1.25*math.cos(i*math.pi/12),0,1.25*math.sin(i*math.pi/12)),(.2,.3,.2)) for i in range(13)]) finish('CloudMoon', [part('sphere',(.35*math.cos(i*math.pi/6),0,.65+.6*math.sin(i*math.pi/6)),(.22,.18,.22)) for i in range(1,12)]) # Closed extruded five-point star, with a base pivot. vertices=[] for depth in (-.2,.2): for i in range(10): angle=math.pi/2+i*math.pi/5; radius=.8 if i%2==0 else .36 vertices.append((radius*math.cos(angle),depth,.8+radius*math.sin(angle))) faces=[tuple(range(9,-1,-1)),tuple(range(10,20))]+[(i,(i+1)%10,(i+1)%10+10,i+10) for i in range(10)] mesh=bpy.data.meshes.new('StarMesh'); mesh.from_pydata(vertices,[],faces); mesh.update() obj=bpy.data.objects.new('Star',mesh); bpy.context.collection.objects.link(obj) finish('WorkshopStar',[obj]) finish('WorkshopGear',[part('cylinder',(0,0,.18),(.6,.6,.18))]+[part('box',(.6*math.cos(i*math.pi/4),.6*math.sin(i*math.pi/4),.18),(.35,.35,.3)) for i in range(8)]) finish('WorkshopCrystals',[part('box',(-.3,0,.6),(.38,.38,1.2)),part('box',(.25,.12,.4),(.35,.35,.8))]) for index, obj in enumerate(bpy.context.scene.objects): obj.hide_set(False) obj.location=(index%5*5, index//5*5, 0) bpy.ops.wm.save_as_mainfile(filepath=str(SOURCE/'PlaygroundProps.blend')) print('Saved self-created source and 13 FBX exports with base pivots, meter units, Y-up Unity export.')