Open In Colab

image tooltip here

In this tutorial, we’ll walk through a pipeline to fetch a diverse set of 3D avatar models from a GitHub repository, convert them into Blender-compatible .blend files, and generate randomized renders of full models and faces. This workflow is designed for technical users comfortable with Python, Blender, and command-line operations.


1. Cloning the Standard GitHub Avatar Repository

We start by cloning the Validated Avatar Library which contains FBX assets for inclusion and diversity research:

#Clone the Standard Github Avatar Repo
!git clone https://github.com/xrtlab/Validated-Avatar-Library-for-Inclusion-and-Diversity---VALID.git
!cd Validated-Avatar-Library-for-Inclusion-and-Diversity---VALID/Avatars

2. Collecting All FBX Files

We traverse the repository to collect all .fbx files into a list of raw GitHub URLs:

import os

base_raw_url = 'https://github.com/xrtlab/Validated-Avatar-Library-for-Inclusion-and-Diversity---VALID/raw/refs/heads/main/Avatars'
raws = []

for root, dirs, files in os.walk('.'):
    for file in files:
        if file.endswith('.fbx'):
            # Get last directory name from root
            last_subdir = os.path.basename(root)
            # Combine last subdir and filename
            partial_path = f"{last_subdir}/{file}"
            raws.append(f"{base_raw_url}/{partial_path}")

3. Downloading FBX Files Locally

We create a folder and download all FBX assets:

!mkdir fbxs

for raw_url in raws:
    file_name = os.path.basename(raw_url)
    !wget -q -O fbxs/{file_name} {raw_url}

import shutil
!zip -r fbxs.zip fbxs

zip_file_path = 'fbxs.zip'

4. Installing and Preparing Blender

Blender is required for importing FBX files and rendering them:

# Blender
import os
import inspect
from IPython.display import Image

# Download and Extract Blender
!wget https://download.blender.org/release/Blender4.4/blender-4.4.3-linux-x64.tar.xz  -O /content/BlenderDownload.tar.xz
!tar -xf /content/BlenderDownload.tar.xz -C /content/

blender_path = 'blender-4.4.3-linux-x64/blender'

5. Converting FBX to Blender .blend Files

We define a Blender Python script to import an FBX file and save it as a .blend file:

%%writefile /content/fbx_to_blend.py
import bpy

# Clear existing scene
bpy.ops.wm.read_factory_settings(use_empty=True)

# Path to your FBX file
fbx_path = "/content/model.fbx"

# Import FBX
bpy.ops.import_scene.fbx(filepath=fbx_path)

# (Optional) Save the result
bpy.ops.wm.save_as_mainfile(filepath="/content/model.blend")

# Run Blender in background mode with the import script
#!./{blender_path} -b --python /content/fbx_to_blend.py

def fbx_to_blend():
  function_name = inspect.currentframe().f_code.co_name
  blender_cmd = f"./{blender_path} -b --python /content/{function_name}.py"
  os.system(blender_cmd)

Next, we batch process all FBX files:

!mkdir blends

import os
import shutil

fbx_folder = '/content/fbxs'
temp_fbx_path = '/content/model.fbx'
blend_folder = '/content/blends'

# Loop through files in the 'fbxs' folder
for filename in os.listdir(fbx_folder):
    if filename.endswith(".fbx"):
        source_path = os.path.join(fbx_folder, filename)
        # Copy the FBX file to '/content/model.fbx'
        shutil.copyfile(source_path, temp_fbx_path)
        print(f"Copied {filename} to {temp_fbx_path}")
        fbx_to_blend()
        print(f"Processed {filename}")
        base, _ = os.path.splitext(filename)   # split name and extension
        new_filename = base + ".blend"   
        shutil.copyfile('/content/model.blend', os.path.join(blend_folder,new_filename))

6. Rendering Full Model Images

We create a Blender script to render full models with Cycles:

%%writefile blend_to_png_model.py
import bpy
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.render.filepath = '/content/model.png'
scene.render.image_settings.file_format = 'PNG'

scene.cycles.samples = 8
scene.cycles.use_adaptive_sampling = True
scene.cycles.use_denoising = True
scene.render.resolution_x = 800
scene.render.resolution_y = 600
scene.render.resolution_percentage = 100

# Create a camera if one doesn't exist
cam_data = bpy.data.cameras.new(name="Camera")
cam = bpy.data.objects.new("Camera", cam_data)
bpy.context.collection.objects.link(cam)
scene.camera = cam

cam.rotation_euler = (0, 0, 0)
cam.location = (0, -5, 1.6)
cam.rotation_euler = (1.5708, 0, 0)

sun_data = bpy.data.lights.new(name="Sun", type='SUN')
sun_data.energy = 3.0
sun = bpy.data.objects.new(name="Sun", object_data=sun_data)
bpy.context.collection.objects.link(sun)
sun.location = (0, -2, 5)
sun.rotation_euler = (1.2, 0, 0)

# Optional: frame the mesh (if camera is new)
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_by_type(type='MESH')
bpy.ops.view3d.camera_to_view_selected()

# Render the image
bpy.ops.render.render(write_still=True)

We define a helper function to execute Blender in background mode:

def blend_to_png_model():
  function_name = inspect.currentframe().f_code.co_name
  blender_cmd = f"./{blender_path} -b /content/model.blend --python /content/{function_name}.py"
  os.system(blender_cmd)
  with open("model.png", "rb") as f:
    image_bytes = f.read()
  return image_bytes

bytes = blend_to_png_model()
Image(data=bytes)

7. Randomizing Model Selection

We can randomly select a .blend file and render it:

import os
import random
import shutil

def model_random_choice():
  blends_folder = '/content/blends'
  destination_blend_path = '/content/model.blend'

  blend_files = [f for f in os.listdir(blends_folder) if f.endswith('.blend')]

  if blend_files:
      chosen_file = random.choice(blend_files)
      source_path = os.path.join(blends_folder, chosen_file)
      shutil.copyfile(source_path, destination_blend_path)
      print(f"Randomly selected and copied '{chosen_file}' to '{destination_blend_path}'")
  else:
      print(f"No .blend files found in '{blends_folder}'")

model_random_choice()
bytes = blend_to_png_model()
Image(data=bytes)

8. Rendering Randomized Close-Up Poses

To generate face-focused images with random angles and distances, we use:

%%writefile /content/blend_to_png_face.py
import bpy
import mathutils
import random
import math

scene = bpy.context.scene
# (Camera, lighting, and render setup omitted for brevity—full code included in original snippet)
bpy.ops.render.render(write_still=True)

Finally, we define a function to generate a grid of random face images:

import math
import io
from PIL import Image as PILImage
import matplotlib.pyplot as plt

def generate_random_images(num_images):
    images = []
    for _ in range(num_images):
        img_bytes = blend_to_png_face()
        pil_img = PILImage.open(io.BytesIO(img_bytes))
        images.append(pil_img)

    cols = math.ceil(math.sqrt(num_images))
    rows = math.ceil(num_images / cols)

    fig, axs = plt.subplots(rows, cols, figsize=(3*cols, 3*rows))
    axs = axs.flatten() if hasattr(axs, 'flatten') else [axs]

    for ax, img in zip(axs, images):
        ax.imshow(img)
        ax.axis("off")
    for ax in axs[len(images):]:
        ax.axis("off")
    plt.tight_layout()
    plt.show()

generate_random_images(6)
model_random_choice()
generate_random_images(3)

Conclusion

This workflow demonstrates a fully automated pipeline for:

  • Downloading FBX avatars from GitHub
  • Converting them to .blend files
  • Randomly rendering full-body and face-focused images

It’s ideal for research in diversity, gaming, VR, or AI dataset creation. With this setup, you can generate hundreds of avatar renders programmatically with Blender’s powerful rendering engine.