| --- |
| datasets: |
| - lamm-mit/Bioinspired3D |
| language: |
| - en |
| base_model: |
| - meta-llama/Llama-3.2-3B-Instruct |
| --- |
| |
| # Bioinspired3D |
|
|
| Fine-tuned version of meta-llama/Llama-3.2-3B-Instruct using LoRA adapters for Blender code generation for bioinspired 3D models. |
|
|
| ## Abstract |
|
|
| Generative AI has made rapid progress in text, image, and video synthesis, yet text-to-3D modeling for |
| scientific design remains particularly challenging due to limited controllability and high computational |
| cost. Most existing 3D generative methods rely on meshes, voxels, or point clouds which can be costly |
| to train and difficult to control. We introduce Bioinspired123D, a lightweight and modular code- |
| as-geometry pipeline that generates fabricable 3D structures directly through parametric programs |
| rather than dense visual representations. At the core of Bioinspired123D is Bioinspired3D, a compact |
| language model finetuned to translate natural language design cues into Blender Python scripts |
| encoding smooth, biologically inspired geometries. We curate a domain-specific dataset of over |
| 4,000 bioinspired and geometric design scripts spanning helical, cellular, and tubular motifs with |
| parametric variability. The dataset is expanded and validated through an automated LLM-driven, |
| Blender-based quality control pipeline. Bioinspired3D is then embedded in a graph-based agentic |
| framework that integrates multimodal retrieval-augmented generation and a vision–language model |
| critic to iteratively evaluate, critique, and repair generated scripts. We evaluate performance on a new |
| benchmark for 3D geometry script generation and show that Bioinspired123D demonstrates a near |
| fourfold improvement over its unfinetuned base model, while also outperforming substantially larger |
| state-of-the-art language models despite using far fewer parameters and compute. By prioritizing |
| code-as-geometry representations, Bioinspired123D enables compute-efficient, controllable, and |
| interpretable text-to-3D generation, lowering barriers to AI driven scientific discovery in materials |
| and structural design. |
|
|
| ## What’s in this repo (Hugging Face) |
|
|
| This Hugging Face release contains **Bioinspired3D only**: a LoRA adapter that you load on top of the base model to generate **Blender Python scripts from natural-language prompts**. |
|
|
| For the full **Bioinspired123D** agentic framework (retrieval + VLM critic + iterative repair), see the GitHub repo: |
| https://github.com/lamm-mit/Bioinspired123D . For training and evaluation scripts, see also the project GitHub. |
|
|
|
|
| ## Usage |
|
|
| ### Install |
|
|
| ```bash |
| pip install -U transformers accelerate peft torch |
| ``` |
|
|
| ### Load the base model + LoRA adapter |
| ```bash |
| from transformers import AutoTokenizer, AutoModelForCausalLM |
| from peft import PeftModel |
| import torch |
| |
| BASE_MODEL = "meta-llama/Llama-3.2-3B-Instruct" |
| LORA_ADAPTER = "rachelkluu/bioinspired3D" |
| |
| # Set this to your preferred device, e.g. "cuda:0" or "cpu" |
| DEVICE_3D = "cuda:0" |
| |
| bio3d_tok = AutoTokenizer.from_pretrained(BASE_MODEL) |
| |
| base_model = AutoModelForCausalLM.from_pretrained( |
| BASE_MODEL, |
| torch_dtype=torch.float16, |
| device_map={"": DEVICE_3D}, |
| ) |
| |
| bio3d_model = PeftModel.from_pretrained(base_model, LORA_ADAPTER) |
| bio3d_model.eval() |
| |
| def format_input(prompt: str) -> str: |
| return ( |
| "<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n" |
| "You are a helpful assistant<|eot_id|>" |
| "<|start_header_id|>user<|end_header_id|>\n\n" |
| f"{prompt}<|eot_id|>" |
| "<|start_header_id|>assistant<|end_header_id|>\n\n" |
| ) |
| ``` |
| ### Load utility functions |
| ```bash |
| def extract_blender_code(model_out: str) -> str: |
| matches = list(re.finditer(r"```python\s*(.*?)```", model_out, flags=re.DOTALL)) |
| if matches: |
| return matches[-1].group(1).strip() |
| pos = model_out.rfind("import bpy") |
| return model_out[pos:].strip() if pos != -1 else model_out.strip() |
| |
| |
| def clean_blender_code(text: str) -> str: |
| if not text: |
| return "import bpy" |
| code = text.strip() |
| code = code.replace("```python", "").replace("```", "") |
| code = re.sub(r"[\x00-\x08\x0b-\x1f]", "", code) |
| if not code.lstrip().startswith("import bpy"): |
| code = "import bpy\n" + code |
| return code |
| ``` |
| ### Generate Blender code from a natural-language prompt |
| ```bash |
| prompt = """Write Blender code to make a cellular structure.""" |
| |
| formatted = format_input(prompt) |
| inputs = bio3d_tok(formatted, return_tensors="pt").to(bio3d_model.device) |
| |
| with torch.no_grad(): |
| outputs = bio3d_model.generate( |
| **inputs, |
| max_new_tokens=2048, |
| do_sample=True, |
| temperature=0.1, |
| top_p=0.9, |
| ) |
| |
| raw = bio3d_tok.decode(outputs[0], skip_special_tokens=True) |
| raw_code = extract_blender_code(raw) |
| blender_code = clean_blender_code(raw_code) |
| |
| print(blender_code) |
| ``` |
| ### Prompting tips |
|
|
| Input: Natural language design intent (for example: “tubular structure with noisy placement”, “helical material with cylindrical fibers”, “smoothed cellular structure”). |
|
|
| Output: A Blender Python script (intended to be executed in Blender) that constructs the requested geometry. |
|
|
| To encourage explicit reasoning, append a variant of: “Think step by step.” to the end of your prompt. For example: "Write Blender code to make a tubular structure with z-aligned tubules. Think step by step." |
|
|
| ## Sample output #1 |
|
|
| ### Example prompt |
| ```text |
| Write Blender code to make a cellular structure with smooth curves and layers on top and bottom |
| ``` |
| ### Example model output (Blender Python) |
| ```python |
| import bpy |
| import addon_utils |
| |
| # Clear the scene |
| bpy.ops.object.select_all(action='SELECT') |
| bpy.ops.object.delete(use_global=False) |
| |
| # Parameters for the sandwich structure |
| strut_thickness = 0.2 # Thickness of the struts |
| smoothness_level = 3 # Level of smoothness |
| slab_thickness = 0.1 # Thickness of the top and bottom slabs |
| |
| def create_cellular_sandwich(): |
| # Function to create a smooth cellular sandwich structure. |
| # Steps: |
| # 1. Create a cube. |
| # 2. Fracture the cube into pieces. |
| # 3. Apply wireframe modifier for cellular effect. |
| # 4. Apply subsurface modifier for smoothing. |
| # 5. Create top and bottom slabs. |
| |
| # Enable the Fracture Cell add-on |
| addon_utils.enable('object_fracture_cell') |
| |
| # Create a cube |
| bpy.ops.mesh.primitive_cube_add() |
| cube = bpy.context.active_object |
| |
| # Scale the cube |
| cube.scale = (1, 1, 0.75) |
| bpy.ops.object.transform_apply(scale=True) |
| |
| # Fracture the cube |
| bpy.ops.object.add_fracture_cell_objects( |
| source={'PARTICLE_OWN'}, |
| source_limit=100, |
| source_noise=0.5, |
| cell_scale=(1, 1, 1), |
| recursion=0, |
| recursion_source_limit=8, |
| recursion_clamp=250, |
| recursion_chance=0.25, |
| recursion_chance_select='SIZE_MIN', |
| use_smooth_faces=False, |
| use_sharp_edges=True, |
| use_sharp_edges_apply=True, |
| use_data_match=True, |
| use_island_split=True, |
| margin=0.001, |
| material_index=0, |
| use_interior_vgroup=False, |
| mass_mode='VOLUME', |
| mass=1, |
| use_recenter=True, |
| use_remove_original=True, |
| collection_name='', |
| use_debug_points=False, |
| use_debug_redraw=True, |
| use_debug_bool=False |
| ) |
| |
| # Remove the original cube |
| if cube and cube.name in bpy.data.objects: |
| bpy.data.objects.remove(cube, do_unlink=True) |
| |
| # Join fractured pieces |
| bpy.ops.object.select_all(action='DESELECT') |
| for obj in bpy.context.scene.objects: |
| if obj.type == 'MESH': |
| obj.select_set(True) |
| bpy.context.view_layer.objects.active = obj |
| bpy.ops.object.join() |
| |
| # Clean up geometry |
| active_mesh = bpy.context.view_layer.objects.active |
| bpy.ops.object.mode_set(mode='EDIT') |
| bpy.ops.mesh.select_all(action='SELECT') |
| bpy.ops.mesh.remove_doubles(threshold=0.2) |
| bpy.ops.mesh.dissolve_limited() |
| bpy.ops.object.mode_set(mode='OBJECT') |
| |
| # Wireframe Modifier |
| wireframe_mod = active_mesh.modifiers.new(name='Wireframe', type='WIREFRAME') |
| wireframe_mod.thickness = strut_thickness |
| wireframe_mod.offset = -1 |
| wireframe_mod.use_even_offset = False |
| wireframe_mod.use_relative_offset = True |
| wireframe_mod.use_replace = True |
| bpy.ops.object.convert(target='MESH') |
| |
| # Subsurface Modifier |
| subsurf_mod = active_mesh.modifiers.new(name='Subdivision', type='SUBSURF') |
| subsurf_mod.levels = smoothness_level |
| subsurf_mod.render_levels = smoothness_level |
| |
| # Create slabs |
| slab_height = 1.5 |
| bottom_slab_z = -slab_height / 2 - slab_thickness / 2 |
| top_slab_z = slab_height / 2 + slab_thickness / 2 |
| |
| # Bottom slab |
| bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, bottom_slab_z)) |
| bottom_slab = bpy.context.active_object |
| bottom_slab.scale = (1, 1, slab_thickness / 2) |
| bpy.ops.object.transform_apply(scale=True) |
| |
| # Top slab |
| bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, top_slab_z)) |
| top_slab = bpy.context.active_object |
| top_slab.scale = (1, 1, slab_thickness / 2) |
| bpy.ops.object.transform_apply(scale=True) |
| |
| # Create the sandwich structure |
| create_cellular_sandwich() |
| ``` |
| ### Rendered example (image) |
|  |
|
|
|
|
| ## Sample output #2 |
| ### Example prompt |
| ```text |
| Write Blender code to make a helical bioinspired structure with flat rectangular struts in each layer |
| ``` |
| ### Example model output (Blender Python) |
| ```python |
| import bpy |
| import math |
| |
| bpy.ops.object.select_all(action='SELECT') |
| bpy.ops.object.delete(use_global=False) |
| |
| # Parameters for the helical fiber structure |
| ply_count = 7 # Number of plies in the structure |
| angle_increment = 10 # Rotation angle for each ply |
| fiber_form ='rect' # Shape of the fibers |
| |
| # Dimensions of the structure |
| structure_height = 2 # Total height of the structure |
| plate_dimension = 2 # Width and length of each plate |
| thickness_per_ply = structure_height / ply_count # Thickness of each ply |
| fiber_gap = 0.01 # Gap between fibers |
| |
| def create_fiber(form, diameter, x, y, z, thickness): |
| if form =='rect': |
| bpy.ops.mesh.primitive_cube_add(size=1.0, location=(x, y, z), rotation=(0, math.radians(90), 0)) |
| fiber = bpy.context.object |
| fiber.dimensions = (thickness, diameter, plate_dimension) |
| return fiber |
| |
| def generate_ply(index): |
| # Generate a ply of fibers in a helical arrangement. |
| z_position = index * thickness_per_ply |
| rotation_angle = index * angle_increment |
| |
| bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0, 0, z_position)) |
| empty_object = bpy.context.object |
| |
| fiber_diameter = thickness_per_ply |
| fiber_distance = fiber_diameter + fiber_gap |
| fiber_count = max(1, int(plate_dimension / fiber_distance)) |
| |
| total_fiber_space = fiber_count * fiber_distance |
| start_y_position = -plate_dimension / 2 + fiber_distance / 2 + (plate_dimension - total_fiber_space) / 2 |
| |
| for i in range(fiber_count): |
| fiber_y_center = start_y_position + i * fiber_distance |
| fiber_instance = create_fiber(fiber_form, fiber_diameter, 0, fiber_y_center, z_position, thickness_per_ply) |
| fiber_instance.parent = empty_object |
| fiber_instance.matrix_parent_inverse = empty_object.matrix_world.inverted() |
| |
| empty_object.rotation_euler[2] = math.radians(rotation_angle) |
| return empty_object |
| |
| # Create the helical structure |
| for i in range(ply_count): |
| generate_ply(i) |
| ``` |
|
|
| ### Rendered example (image) |
|  |
|
|
|
|
| ## Notes: |
| This adapter is meant to be used with the specified base model. Generated scripts should be treated like code: run in a sandboxed environment and validate geometry as needed. |
|
|
| ## Citation |
|
|
| If you use Bioinspired3D or the broader Bioinspired123D framework in your work, please cite: |
|
|
| ```bibtex |
| @article{luu2026bioinspired123d, |
| title={Bioinspired123D: Generative 3D Modeling System for Bioinspired Structures}, |
| author={Luu, Rachel K. and Buehler, Markus J.}, |
| year={2026} |
| } |
| |