Welcome to XRFeitoria’s documentation!
XRFeitoria is a rendering toolbox for generating synthetic data photorealistic with ground-truth annotations. It is a part of the OpenXRLab project.
Major Features
Support rendering photorealistic images with ground-truth annotations.
Support multiple engine backends, including Unreal Engine and Blender.
Support assets/camera management, including import, export, and delete.
Support a CLI tool to render images from a mesh file.
Installation
pip install xrfeitoria
# to use visualization tools
pip install xrfeitoria[vis]
Requirements
Python >= 3.8
- (optional)
Unreal Engine >= 5.1
Windows
Linux
- (optional)
- (optional)
Blender >= 3.0
Windows
Linux
MacOS
- (optional)
CLI
A CLI tool to render images from a mesh file.
xf-render --help
# render a mesh file
xf-render {mesh_file}
# for example
wget https://graphics.stanford.edu/~mdfisher/Data/Meshes/bunny.obj
xf-render bunny.obj
Tutorials
A quick start guide to using the XRFeitoria
package.
The following tutorials cover the basic operations needed to render with XRFeitoria
.
Note
Download notebook and run it offline.
Tutorial01 - Getting Started
Overview
🚀 This tutorial demonstrates a minimal application of XRFeitoria. By the end of this tutorial, you will be able to:
Open Blender/Unreal Engine by XRFeitoria
Import a mesh
Add a camera
Render images and get annotations of the mesh
1. Import XRFeitoria
After installing pip install xrfeitoria[vis]
, you can import it as follows:
[ ]:
import xrfeitoria as xf
2. Choose engine
XRFeitoria
supports both Blender
and Unreal Engine
. Choose your engine and replace the following engine_exec_path
with your own engine path.
Then, initialize XRFeitoria and open the engine by xf.init_blender
or by xf.init_unreal
.
[ ]:
# Replace with your executable path
engine_exec_path = 'C:/Program Files/Blender Foundation/Blender 3.3/blender.exe'
# engine_exec_path = 'C:/Program Files/Epic Games/UE_5.2/Engine/Binaries/Win64/UnrealEditor-Cmd.exe'
[ ]:
from pathlib import Path
exec_path_stem = Path(engine_exec_path).stem.lower()
if 'blender' in exec_path_stem:
# Open Blender
render_engine = 'blender'
xf_runner = xf.init_blender(exec_path=engine_exec_path, background=False, new_process=True)
elif 'unreal' in exec_path_stem:
# Unreal Engine requires a project to be opened
# Here we use a sample project, which is downloaded from the following link
# You can also use your own project
import shutil
from xrfeitoria.utils.downloader import download
unreal_project_zip = download(url='https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/unreal_project/UE_Sample.zip',
dst_dir="./tutorial01/assets/")
shutil.unpack_archive(filename=unreal_project_zip, extract_dir='./tutorial01/assets/')
# Open Unreal Engine
render_engine = 'unreal'
xf_runner = xf.init_unreal(exec_path=engine_exec_path,
background=False,
new_process=True,
project_path='./tutorial01/assets/UE_sample/UE_sample.uproject')
✨ Now you can see a new Blender/Unreal Engine process has been started.
Blender
Unreal Engine
3. Import a mesh
Download the scanned Koupen Chan model by the following cell.
[ ]:
from xrfeitoria.utils.downloader import download
# Download the Koupen-chan model
kc_path = download(url='https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/assets/koupen_chan.fbx',
dst_dir="./tutorial01/assets/")
Import the .fbx file to create an Actor
instance.
Actor
is the container of a mesh. By using Actor
, you can place a mesh in the space and set its transform data (location, rotation and scale).
[ ]:
# Import the Koupen-chan
actor_kc = xf_runner.Actor.import_from_file(file_path=kc_path, stencil_value=255)
Switch to the engine window, and you can see the Koupen chan has been imported. The space to place Actor
is called Level
, and you can add, remove, or modify Actor
in the Level
.
Blender
Unreal Engine
If you use Unreal Engine
, the Level
should be saved after been modified.
[ ]:
# save the level
if render_engine == 'unreal':
xf_runner.utils.save_current_level()
4. Add a sequence
Sequence
is a multifunctional class in XRFeitoria. It can be used for:
rendering
adding transform keys
grouping different objects
Here, we use it for rendering. Firstly we will add a Camera
in the Sequence
by using the function spawn_camera
and set its location, rotation, and focal length. Then, we will add a render job to the renderer and set the render settings by using the function add_to_renderer
.
[ ]:
from xrfeitoria.data_structure.models import RenderPass
# Use `with` statement to create a sequence, and it will be automatically close the sequence after the code block is executed.
sequence_name = 'MySequence'
with xf_runner.Sequence.new(seq_name=sequence_name, replace=True) as seq:
# Add a camera and make it look at the koupen-chan
camera_location = (0.0, -0.8, 0.0)
camera_rotation = xf_runner.utils.get_rotation_to_look_at(location=camera_location, target=actor_kc.location)
camera = seq.spawn_camera(location=camera_location, rotation=camera_rotation, fov=90)
# Add a render job to renderer
# In render job, you can specify the output path, resolution, render passes, etc.
# The ``output_path`` is the path to save the rendered data.
# The ``resolution`` is the resolution of the rendered image.
# The ``render_passes`` define what kind of data you want to render, such as img, mask, normal, etc.
# and what kind of format you want to save, such as png, exr, etc.
seq.add_to_renderer(
output_path=f'./tutorial01/outputs/{render_engine}/',
resolution=(1280, 720),
render_passes=[RenderPass('img', 'png'),
RenderPass('mask', 'exr'),
RenderPass('normal', 'exr'),
RenderPass('diffuse', 'exr')]
)
5. Render
Use the following cell to render and save the images to the output_path
you set in seq.add_to_renderer
above.
[ ]:
xf_runner.render()
Check the output_path
, and you can see the rendered images and various annotations. The following code shows the rendered image and the corresponding annotations.
[ ]:
import matplotlib.pyplot as plt
from xrfeitoria.utils.viewer import Viewer
xf_viewer = Viewer(sequence_dir=f'./tutorial01/outputs/{render_engine}/{sequence_name}/')
img = xf_viewer.get_img(camera_name=camera.name, frame=0)
diffuse = xf_viewer.get_diffuse(camera_name=camera.name, frame=0)
mask = xf_viewer.get_mask(camera_name=camera.name, frame=0)
normal = xf_viewer.get_normal(camera_name=camera.name, frame=0)
plt.figure(figsize=(20, 20))
plt.subplot(1, 4, 1)
plt.imshow(img)
plt.axis('off')
plt.title('img')
plt.subplot(1, 4, 2)
plt.imshow(diffuse)
plt.axis('off')
plt.title('diffuse')
plt.subplot(1, 4, 3)
plt.imshow(mask)
plt.axis('off')
plt.title('mask')
plt.subplot(1, 4, 4)
plt.imshow(normal)
plt.axis('off')
plt.title('normal')
Hint: When using Unreal Engine, if the image of the mask looks weird, try running the notebook again.
6. Final step
🥳 This is a good start! Finally, Do remember to close the engine.
[ ]:
xf_runner.close()
Ref to api docs, you can always use with
statement to ensure the engine is closed when the codes are finished.
7. Conclusion
In this tutorial, we imported a mesh and rendered images for it. To accomplish this procedure, essential steps should be taken:
Initialization
Import an
Actor
Add a
Sequence
Add a
Camera
Render
It is worth mention that while Sequence
does not directly perform rendering, the creation of Sequence
is necessary for adding cameras and submitting rendering jobs. And the detailed definitions of the classes Actor, Camera, and Sequence can be referred to the documentation.
Note
Download notebook and run it offline.
Tutorial02 - Randomization
Overview
🚀 By the last tutorial, you have learned the concept of Actor
, Level
and Sequence
. In this tutorial, you will learn how to add random transform keys to an Actor
in order to render multiple poses of it. By the end of this tutorial, you will be able to:
Initialize XRFeitoria
Import
Actor
and label it bystencil value
Set the scale of
Actor
in theLevel
Create a
Sequence
for rendering and adding transform keys toActor
Add a camera in the
Sequence
Render images and annotations
1. Initialization
Install the following packages that will be used in this tutorial:
[ ]:
%pip install objaverse
%pip install scipy
Then, similar to Tutorial01, specify your engine path and initialize XRFeitoria.
[ ]:
import xrfeitoria as xf
[ ]:
# Replace with your executable path
engine_exec_path = 'C:/Program Files/Blender Foundation/Blender 3.3/blender.exe'
# engine_exec_path = 'C:/Program Files/Epic Games/UE_5.2/Engine/Binaries/Win64/UnrealEditor-Cmd.exe'
[ ]:
from pathlib import Path
exec_path_stem = Path(engine_exec_path).stem.lower()
if 'blender' in exec_path_stem:
# Open Blender
render_engine = 'blender'
xf_runner = xf.init_blender(exec_path=engine_exec_path, background=False, new_process=True)
elif 'unreal' in exec_path_stem:
# Unreal Engine requires a project to be opened
# Here we use a sample project, which is downloaded from the following link
# You can also use your own project
import shutil
from xrfeitoria.utils.downloader import download
unreal_project_zip = download(url='https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/unreal_project/UE_Sample.zip',
dst_dir="./tutorial02/assets/")
shutil.unpack_archive(filename=unreal_project_zip, extract_dir='./tutorial02/assets/')
# Open Unreal Engine
render_engine = 'unreal'
xf_runner = xf.init_unreal(exec_path=engine_exec_path,
background=False,
new_process=True,
project_path='./tutorial02/assets/UE_sample/UE_sample.uproject')
✨ Now you can see a new Blender/Unreal Engine process has started.
2. Import meshes
Download some meshes from Objaverse.
[ ]:
import objaverse
objects = objaverse.load_objects(
uids=['eb0807309530496aaab9dcff67bf5c31',
'b4065dd5ce9d46be90db3e1f3e4b9cc1',
'0176be079c2449e7aaebfb652910a854',
'f130ebeb60f24ed8bd3714a7ed3ba280',
'289a2221178843a78ad433705555e16a',
'b7f7ab9bf7244c3a8851bae3fb0bf741',
],
download_processes=1
)
Import the meshes to create Actor
instances in the Level
.
Here we set different stencil_value
for each Actor
. The stencil value is used to distinguish different Actors when rendering segmentation masks.
[ ]:
actors = []
for idx, file_path in enumerate(objects.values()):
actor = xf_runner.Actor.import_from_file(
file_path=file_path,
stencil_value=(idx+1)*10
)
actors.append(actor)
Switch to the engine window, and you can see the meshes has been imported.
Then, we adjust the scale of the Actors to make their sizes equal to 0.3m.
[ ]:
actor_size = 0.3
for actor in actors:
_scale = actor_size / max(actor.dimensions)
actor.scale = (_scale, _scale, _scale)
Now they look like:
Blender
Unreal Engine
If you use Unreal Engine
, the Level
should be saved after been modified.
[ ]:
# save the level
if render_engine == 'unreal':
xf_runner.utils.save_current_level()
3. Add a sequence for rendering and adding transform keys
Sequence
is a multifunctional class in XRFeitoria. It can be used for: - rendering - adding transform keys - grouping different objects.
Here, we use it for rendering
and adding transform keys
.
Transform keys
record the transformation (location, rotation and scale) of anActor
or aCamera
at specific frames, and the transformation between two adjacent keys will be interpolated by the specified interpolation method. By adding transform keys, you can render multiple poses of anActor
.In
XRFeitoria
, transform keys are always stored in a list, and the members of the list are SequenceTransformKey object.
Firstly, we randomly generate some transform keys for each actors.
[ ]:
import random
from loguru import logger
from scipy.stats import qmc
from xrfeitoria.data_structure.models import SequenceTransformKey as SeqTransKey
# Set the number of frames
frame_num = 10
# Use a dictionary to store the transform keys of all actors
all_actors_transform_keys = {actor: [] for actor in actors}
# Iterate over all frames
for i in range(frame_num):
# Generate random locations by Poisson Disk Sampling
# The minimum distance between two actors is set to be `actor_size` we defined before
posson_engine = qmc.PoissonDisk(d=2, radius=actor_size)
sample_location = posson_engine.random(len(actors))
# Set the transform keys for each actor
for actor_idx, actor in enumerate(actors):
actor_scale = actor.scale
# Get the location from the samples generated by Poisson Disk Sampling
random_location = (sample_location[actor_idx][0],
0.0,
sample_location[actor_idx][1])
# Generate random rotations
random_rotation = (random.random() * 360.0,
random.random() * 360.0,
random.random() * 360.0)
# Generate random scales
scale = random.uniform(0.5, 1.0)
random_scale = (scale * actor_scale[0],
scale * actor_scale[1],
scale * actor_scale[2])
# Save the transform keys
all_actors_transform_keys[actor].append(
SeqTransKey(
frame=i,
location=random_location,
rotation=random_rotation,
scale=random_scale,
interpolation='AUTO',
)
)
logger.info(f'Generated transform keys of frame {i}.')
Then we create a Sequence
to apply the transform keys to the actors and render the images.
[ ]:
from xrfeitoria.data_structure.models import RenderPass
# Use the `with` statement to create a sequence, and it will be automatically close the sequence after the code block is executed.
# The argument `seq_length` controls the number of frames to be rendered.
sequence_name = 'MySequence'
with xf_runner.Sequence.new(seq_name=sequence_name, seq_length=frame_num, replace=True) as seq:
##############################
##### Add transform keys #####
##############################
# The function `use_actor_with_keys` sets transform keys for the actor in the sequence.
# The transform keys are only stored in the sequence.
# When the sequence is closed, the actor will be restored to its original state(without transform keys).
for actor, keys in all_actors_transform_keys.items():
seq.use_actor_with_keys(actor=actor, transform_keys=keys)
#####################
##### Rendering #####
#####################
# Add a camera and make it look at the specified location
camera_location = (0.5, -3.0, 0.5)
camera_rotation = xf_runner.utils.get_rotation_to_look_at(location=camera_location, target=(0.5, 0.0, 0.5))
camera = seq.spawn_camera(location=camera_location, rotation=camera_rotation, fov=45)
# Add a render job to renderer
# In render job, you can specify the output path, resolution, render passes, etc.
# The ``output_path`` is the path to save the rendered data.
# The ``resolution`` is the resolution of the rendered image.
# The ``render_passes`` define what kind of data you want to render, such as img, depth, normal, etc.
# and what kind of format you want to save, such as png, jpg, exr, etc.
seq.add_to_renderer(
output_path=f'./tutorial02/outputs/{render_engine}/',
resolution=(1280, 720),
render_passes=[RenderPass('img', 'png'),
RenderPass('mask', 'exr'),
RenderPass('normal', 'exr'),
RenderPass('diffuse', 'exr')],
)
4. Render
The following code renders all the render jobs and save the images to the output_path
set in seq.add_to_renderer
above.
[ ]:
# Render
xf_runner.render()
Check the output_path
, and you can see the rendered images and their annotations. Visualize the images and annotations by the following code.
[ ]:
import matplotlib.pyplot as plt
from xrfeitoria.utils.viewer import Viewer
xf_viewer = Viewer(sequence_dir=f'./tutorial02/outputs/{render_engine}/{sequence_name}/')
for i in range(frame_num):
img = xf_viewer.get_img(camera_name=camera.name, frame=i)
mask = xf_viewer.get_mask(camera_name=camera.name, frame=i)
normal = xf_viewer.get_normal(camera_name=camera.name, frame=i)
diffuse = xf_viewer.get_diffuse(camera_name=camera.name, frame=i)
plt.figure(figsize=(20, 20))
plt.subplot(1, 4, 1)
plt.imshow(img)
plt.axis('off')
plt.title('img')
plt.subplot(1, 4, 2)
plt.imshow(mask)
plt.axis('off')
plt.title('mask')
plt.subplot(1, 4, 3)
plt.imshow(normal)
plt.axis('off')
plt.title('normal')
plt.subplot(1, 4, 4)
plt.imshow(diffuse)
plt.axis('off')
plt.title('diffuse')
Hint: When using Unreal Engine, if the images of the mask look weird, try running the notebook again.
Finally, close the engine by:
[ ]:
# Close the engine
xf_runner.close()
Ref to api docs, you can always use with
statement to ensure the engine is closed when the codes are finished.
Note
Download notebook and run it offline.
Tutorial03 - Human NeRF
Overview
🚀 This tutorial provides an example of rendering animated skeletal meshes from different points of view. The rendered images can support various research topics, including human pose and shape estimation (HPS) and novel view synthesis for human (Human NeRF). By the end of this tutorial, you will be able to:
Initialize XRFeitoria
Import a skeletal mesh with animation
Import another skeletal mesh without animation and setup animation for it
Set
Actor
’s location in theLevel
Create a
Sequence
for renderingAdd multiple static cameras in the
Sequence
Add a moving camera with transform keys in the
Sequence
Render images and annotations
1. Initialization
Then, similar to Tutorial01, specify your engine path and initialize XRFeitoria.
[ ]:
import xrfeitoria as xf
[ ]:
# Replace with your executable path
engine_exec_path = 'C:/Program Files/Blender Foundation/Blender 3.3/blender.exe'
# engine_exec_path = 'C:/Program Files/Epic Games/UE_5.2/Engine/Binaries/Win64/UnrealEditor-Cmd.exe'
[ ]:
from pathlib import Path
exec_path_stem = Path(engine_exec_path).stem.lower()
if 'blender' in exec_path_stem:
# Open Blender
render_engine = 'blender'
xf_runner = xf.init_blender(exec_path=engine_exec_path, background=False, new_process=True)
elif 'unreal' in exec_path_stem:
# Unreal Engine requires a project to be opened
# Here we use a sample project, which is downloaded from the following link
# You can also use your own project
import shutil
from xrfeitoria.utils.downloader import download
unreal_project_zip = download(url='https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/unreal_project/UE_Sample.zip',
dst_dir="./tutorial03/assets/")
shutil.unpack_archive(filename=unreal_project_zip, extract_dir='./tutorial03/assets/')
# Open Unreal Engine
render_engine = 'unreal'
xf_runner = xf.init_unreal(exec_path=engine_exec_path,
background=False,
new_process=True,
project_path='./tutorial03/assets/UE_sample/UE_sample.uproject')
✨ Now you can see a new Blender/Unreal Engine process has started.
2. Import skeletal meshes to Level
Download the skeletal meshes in SynBody to local folder and import them to Level
.
[ ]:
from xrfeitoria.utils.downloader import download
# Download the skeletal meshes
actor1_path = download('https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/assets/SMPL-XL/SMPL-XL-00439__Subject_75_F_12.fbx', dst_dir="./tutorial03/assets/")
actor2_path = download('https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/assets/SMPL-XL/SMPL-XL-00045.fbx', dst_dir="./tutorial03/assets/")
actor2_motion_path = download('https://openxrlab-share.oss-cn-hongkong.aliyuncs.com/xrfeitoria/tutorials/assets/SMPL-XL/walking__15_01.fbx', dst_dir="./tutorial03/assets/")
Here we import two actors. The actor1
has animation and the actor2
has no animation.
And we set different stencil value for each Actor
to distinguish different Actors when rendering segmentation masks.
[ ]:
# Import the skeletal mesh
actor1 = xf_runner.Actor.import_from_file(file_path=actor1_path, stencil_value=100)
actor2 = xf_runner.Actor.import_from_file(file_path=actor2_path, stencil_value=200)
Then, we load an animation from another file and set it to the actor2
[ ]:
actor2.setup_animation(animation_path=actor2_motion_path)
We can also modify the properties of the actors, such as the location, rotation, and scale.
[ ]:
# Set the location of the two actors to make their distance to be 1.0 meter
actor1_location = actor1.location
actor2_location = actor2.location
actor2.location = (actor1_location[0] + 1.0, actor1_location[1], actor1_location[2])
Now they look like:
Blender
Unreal Engine
If you use Unreal Engine
, the Level
should be saved after been modified.
[ ]:
# save the level
if render_engine == 'unreal':
xf_runner.utils.save_current_level()
3. Add a sequence for rendering
Sequence
is a multifunctional class in XRFeitoria. It can be used for: - rendering - adding transform keys - grouping different objects.
Here, we use it for rendering.
[ ]:
import math
from xrfeitoria.data_structure.models import RenderPass
from xrfeitoria.data_structure.models import SequenceTransformKey as SeqTransKey
# Use `with` statement to create a sequence, and it will be automatically close the sequence after the code block is executed.
# The argument `seq_length` controls the number of frames to be rendered.
sequence_name = 'MySequence'
frame_num = 6
with xf_runner.Sequence.new(seq_name=sequence_name, seq_length=frame_num, replace=True) as seq:
# Get the bounding boxes of the actors
actor1_bbox = actor1.bound_box
actor2_bbox = actor2.bound_box
# Get the center location of the actors
actor1_center = ((actor1_bbox[0][0] + actor1_bbox[1][0]) / 2, (actor1_bbox[0][1] + actor1_bbox[1][1]) / 2, (actor1_bbox[0][2] + actor1_bbox[1][2]) / 2)
actor2_center = ((actor2_bbox[0][0] + actor2_bbox[1][0]) / 2, (actor2_bbox[0][1] + actor2_bbox[1][1]) / 2, (actor2_bbox[0][2] + actor2_bbox[1][2]) / 2)
actors_center = ((actor1_center[0] + actor2_center[0]) / 2, (actor1_center[1] + actor2_center[1]) / 2, (actor1_center[2] + actor2_center[2]) / 2)
##########################################################################
# Add 6 static cameras and a moving camera around the actors for rendering
##########################################################################
# Set cameras' field of view to 90°
camera_fov = 90
# Set cameras' distance to 3.0m
distance_to_actor = 3.0
# Prepare the transform keys for moving camera
transform_keys = []
# calculate the location and rotation of the cameras
for i in range(6):
azimuth = 360 / 6 * i
azimuth_radians = math.radians(azimuth)
x = distance_to_actor * math.cos(azimuth_radians) + actors_center[0]
y = distance_to_actor * math.sin(azimuth_radians) + actors_center[1]
z = 0.0 + actors_center[2]
location = (x, y, z)
# Set camera's rotation to look at the actor's center
rotation = xf_runner.utils.get_rotation_to_look_at(location=location, target=actors_center)
# Add a static camera
static_camera = seq.spawn_camera(
camera_name=f'static_camera_{i}',
location=location,
rotation=rotation,
fov=camera_fov,
)
# Add a transform key to the moving camera
transform_keys.append(
SeqTransKey(
frame=i,
location=location,
rotation=rotation,
interpolation='AUTO',
)
)
# Add a moving camera rotating around the actors
moving_camera = seq.spawn_camera_with_keys(
camera_name=f'moving_camera',
transform_keys=transform_keys,
fov=camera_fov,
)
# Add a render job to renderer
# In render job, you can specify the output path, resolution, render passes, etc.
# The output path is the path to save the rendered data.
# The resolution is the resolution of the rendered image.
# The render passes define what kind of data you want to render, such as img, depth, normal, etc.
# and what kind of format you want to save, such as png, exr, etc.
seq.add_to_renderer(
output_path=f'./tutorial03/outputs/{render_engine}/',
resolution=(1280, 720),
render_passes=[RenderPass('img', 'png'),
RenderPass('mask', 'exr'),
RenderPass('normal', 'exr'),
RenderPass('diffuse', 'exr')]
)
4. Render
The following code renders all the render jobs and save the images to the output_path
set in seq.add_to_renderer
above.
[ ]:
# Render
xf_runner.render()
Check the output_path
, and you can see that for the frame i, the image rendered by the moving camera is the same as the image rendered by the ith static camera. For example, the moving_camera/0002.png
is the same as the static_camera_2/0002.png
.
[ ]:
import matplotlib.pyplot as plt
from xrfeitoria.utils.viewer import Viewer
xf_viewer = Viewer(sequence_dir=f'./tutorial03/outputs/{render_engine}/{sequence_name}/')
moving_camera_img = xf_viewer.get_img(camera_name='moving_camera', frame=2)
static_camera_img = xf_viewer.get_img(camera_name='static_camera_2', frame=2)
plt.figure(figsize=(20, 20))
plt.subplot(1, 2, 1)
plt.imshow(moving_camera_img)
plt.axis('off')
plt.title('moving_camera/0002.png')
plt.subplot(1, 2, 2)
plt.imshow(static_camera_img)
plt.axis('off')
plt.title('static_camera_2/0002.png')
View the rendered images and annotations of the camera static_camera_2
by:
[ ]:
import matplotlib.pyplot as plt
from xrfeitoria.utils.viewer import Viewer
xf_viewer = Viewer(sequence_dir=f'./tutorial03/outputs/{render_engine}/{sequence_name}/')
camera_name = 'static_camera_2'
for i in range(frame_num):
img = xf_viewer.get_img(camera_name=camera_name, frame=i)
mask = xf_viewer.get_mask(camera_name=camera_name, frame=i)
normal = xf_viewer.get_normal(camera_name=camera_name, frame=i)
diffuse = xf_viewer.get_diffuse(camera_name=camera_name, frame=i)
plt.figure(figsize=(20, 20))
plt.subplot(1, 4, 1)
plt.imshow(img)
plt.axis('off')
plt.title('img')
plt.subplot(1, 4, 2)
plt.imshow(mask)
plt.axis('off')
plt.title('mask')
plt.subplot(1, 4, 3)
plt.imshow(normal)
plt.axis('off')
plt.title('normal')
plt.subplot(1, 4, 4)
plt.imshow(diffuse)
plt.axis('off')
plt.title('diffuse')
Hint: When using Unreal Engine, if the images of the mask look weird, try running the notebook again.
Finally, close the engine by:
[ ]:
xf_runner.close()
Ref to api docs, you can always use with
statement to ensure the engine is closed when the codes are finished.
Extra Samples
For more advanced examples, see the samples section.
xrfeitoria
Initialize firstly and run xrfeitoria.
1import xrfeitoria as xf
2with xf.init_blender() as xf_runner:
3 ...
xf_runner
is an instance of XRFeitoriaBlender
,
where contains all the classes and methods to run xrfeitoria.
1import xrfeitoria as xf
2with xf.init_unreal() as xf_runner:
3 ...
xf_runner
is an instance of XRFeitoriaUnreal
,
where contains all the classes and methods to run xrfeitoria.
After initialized, use members of xf_runner
.
Ref to members of XRFeitoriaBlender
and
XRFeitoriaUnreal
.
xrfeitoria.factory
Inheritance diagram
Initialize Blender with |
|
|
Initialize Unreal with |
Factory class contains all the classes and functions for Blender. |
|
Factory class contains all the classes and functions for Unreal. |
xrfeitoria.object
Inheritance diagram
Base class for all objects in the world. |
|
Base class for object utils. |
|
Object utils class for Blender. |
|
Object utils class for Unreal. |
xrfeitoria.actor
Inheritance diagram
Base class for all actors in the world. |
|
Actor class for Blender. |
|
Actor class for Unreal Engine. |
|
Wrapper class for shapes in Blender. |
|
Wrapper class for shapes in Unreal Engine. |
xrfeitoria.camera
Inheritance diagram
Base camera class. |
|
Camera class for Blender. |
|
Camera class for Unreal. |
|
Camera parameter class for pinhole camera model. |
xrfeitoria.sequence
Inheritance diagram
Base sequence class. |
|
Sequence class for Blender. |
|
Sequence class for Unreal. |
Sequence wrapper functions. |
xrfeitoria.renderer
Inheritance diagram
Base renderer class. |
|
Renderer class for Blender. |
|
Renderer class for Unreal. |
xrfeitoria.utils
Remote Functions
Remote functions for blender. |
|
Remote functions for unreal. |
Animation utils
Motion data structure and related functions. |
|
Utilities for animation data loading and dumping. |
RPC runner
Runner for starting blender or unreal as a rpc server. |
Tools
Utils tools for logging and progress bar. |
|
Utils for loading images and annotations. |
|
Project 3D points to 2D points, and draw 3D points on image, using XRPrimer camera. |
|
Validations for the arguments. |
xrfeitoria.data_structure
Models
Render pass model contains render layer and image format. |
|
Render job model for Blender. |
|
Render job model for Unreal. |
|
Transform key model for object (actor/camera) in sequence. |
Enumerations
Render engine enum. |
|
|
Import file format enum. |
|
Image file format enum. |
|
Render layer enum of Blender. |
|
Render layer enum of Unreal. |
|
Keyframe interpolation enum of Unreal. |
|
Keyframe interpolation enum of Blender. |
|
Render engine enum of Blender. |
|
Shape type enum of Blender. |
|
Shape type enum of Unreal. |
XRFeitoria Blender Addon
By running xf.init_blender
, a XRFeitoria addon will be installed in your Blender.
The source code of the addon is in src/XRFeitoriaBpy
.
It enables you to start RPC server and manage your sequences.
The addon panel is in the top-right corner of the 3D Viewport.
Click the button Start RPC Server
to start the RPC server. The server will listen on port 9997 to receive commands from XRFeitoria and execute them in Blender.
Click the drop down box Active
in the Manage sequences
section to open a sequence belonging to the current level. The objects in the sequence will be loaded to the window, and the properties of the sequence such as fps
, frame_start
, frame_end
and frame_current
will be set.
Click the ‘x’ button beside the drop down box to close the sequence.
XRFeitoria Unreal Plugin
TBD
Frequently Asked Questions
We list some common troubles faced by many users and their corresponding solutions here. Feel free to enrich the list if you find any frequent issues and have ways to help others to solve them. If the contents here do not cover your issue, do not hesitate to create an issue!
API
How to use the plugin of Blender/Unreal under development
First you should clone the repo of XRFeitoria, and maybe modify the code of the plugin under src/XRFeitoriaBlender
or src/XRFeitoriaUnreal
.
Then you can use the plugin under development by setting dev_plugin=True
in init_blender
or init_unreal
.
You can install the plugin by:
1git clone https://github.com/openxrlab/xrfeitoria.git
2cd xrfeitoria
3pip install -e .
4python -c "import xrfeitoria as xf; xf.init_blender(replace_plugin=True, dev_plugin=True)"
5
6# or through the code in tests
7python -m tests.blender.init --dev [-b]
1git clone https://github.com/openxrlab/xrfeitoria.git
2cd xrfeitoria
3pip install -e .
4python -c "import xrfeitoria as xf; xf.init_unreal(replace_plugin=True, dev_plugin=True)"
5
6# or through the code in tests
7python -m tests.unreal.init --dev [-b]
Build plugins
If you want to publish plugins of your own, you can use the following command:
1# install xrfeitoria first
2cd xrfeitoria
3pip install .
4
5# for instance, build plugins for Blender, UE 5.1, UE 5.2, and UE 5.3 on Windows.
6# using powershell where backtick(`) is the line continuation character.
7python -m xrfeitoria.utils.publish_plugins `
8 -u "C:/Program Files/Epic Games/UE_5.1/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" `
9 -u "C:/Program Files/Epic Games/UE_5.2/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" `
10 -u "C:/Program Files/Epic Games/UE_5.3/Engine/Binaries/Win64/UnrealEditor-Cmd.exe"
Please check the path ./src/dist
for the generated plugins.
XRFeitoriaBlender
will be archived by default, and XRFeitoriaUnreal
will only be built when you specify the Unreal editor path.
Make sure you have installed the corresponding Unreal Engine and Visual Studio before building the unreal plugin.
Find out the plugin version in ./xrfeitoria/version.py
. Or by:
>>> python -c "import xrfeitoria; print(xrfeitoria.__version__)"
0.6.1.dev10+gd12997e.d20240122
You can set the environment variable XRFEITORIA__DIST_ROOT
and XRFEITORIA__VERSION
to change the plugins used by XRFeitoria.
Run your code xxx.py
like:
XRFEITORIA__VERSION=$(python -c "import xrfeitoria; print(xrfeitoria.__version__)") \
XRFEITORIA__DIST_ROOT=src/dist \
python xxx.py
$env:XRFEITORIA__VERSION=$(python -c "import xrfeitoria; print(xrfeitoria.__version__)")
$env:XRFEITORIA__DIST_ROOT="src/dist"; `
python xxx.py
What is stencil_value
stencil_value
is to distinguish different actors in the sequence when rendering segmentation masks.
The RGB mask color of actors will be saved in the {output_path}/actor_infos.json
of the render job.
What is console_variables
console_variables
is a dictionary of console variables for configure detailed rendering settings.
Please refer to the official documentation for more details: Unreal-MRQ-Doc.
example:
>>> console_variables = {'r.MotionBlurQuality': 0} # disable motion blur
RPC Port
The RPC port is used for communication between python and engine (blender/unreal).
If the default port is occupied, or you want to use multiple engines at the same time,
you can set the environment variable BLENDER_PORT
or UNREAL_PORT
to change it.
BLENDER_PORT=50051 python xxx.py
$env:BLENDER_PORT=50051; python xxx.py