Skip to content

Latest commit

 

History

History
 
 

src

Source code

Each module used in BlenderProc is defined in here. The folders structure the modules according to their use-case.

Contents

Overview

As mentioned before, all of the source code relevant to the key features (i.e. modules) of BlenderProc is presented here. The main folder contains the Module base class and the Pipeline class, which gets executed by the run.py & debug.py

Existing modules are placed in use-case-dependent folders:

  • camera: camera loading and camera pose sampling.
  • composite: complex (composite, duh) modules that are using other existing modules.
  • constructor: constructing scenery and adding objects.
  • lighting: light source loading, light source pose sampling, dataset-specific light loaders.
  • loader: .obj, .ply, etc. object loading, dataset-specific object loading.
  • manipulators: manipulating of the World and different entities present in the scene.
  • materials: manipulating materials.
  • object: object pose manipulation, physics between-object interaction, sampling and geometry manipulation.
  • postprocessing: changing the pipeline output inside of a .hdf5 container.
  • provider: samplers and getters used for sampling various values, selecting objects, etc.
  • renderer: RGB, distance, etc. rendering.
  • utility: an assortment of variuos utility functions and classes for any taste.
  • writer: world-to-.hdf5-container state writers.

Writing your own modules

If our modules lack some specific functionality, you always can modify it, or create your own module. When deciding, where to place your module, think about it's use-case. If you are working on something, that isn't really fitting anywhere, use your best judgement and create a new folder with a clear and short name.

A module is a class executing one step in the pipeline. Here is the basic structure of such a module:

from src.main.Module import Module

class CameraLoader(Module):

    def __init__(self, config):
        Module.__init__(self, config)
        [...]

    def run(self):
        [...]

The constructor of all modules is called before running any module, also in the order specified in the config file. Nevertheless it should only be used for small preparation work, while most of the module`s work should be done inside run()

Access configuration

The module`s configuration can be accessed via self.config. This configuration object has the methods get_int, get_float, get_bool, get_string, get_list, get_raw_dict, etc. each working in the same way.

  • The first parameter specifies the key/name of the parameter to get. By using / it is also possible access values nested inside additional dicts (see example below).
  • The second parameter specifies the default value which is returned, if the requested parameter has not been specified inside the config file. If None is given, an error is thrown instead.

Example:

Config file:

{
  "modules": [
    {
      "module": "main.Initializer",
      "config": {
        "global": {
          "output_dir": "/tmp/",
          "auto_tile_size": False,
          "pixel_aspect_x": 1.333333333
        }
      }
    },
    {
      "module": "renderer.NewRenderer",
      "config": {
        "auto_tile_size": True,
        "cycles": {
          "samples": 255
        }
      }
    }
  ]
}

Inside the renderer.NewRenderer module:

self.get_int("cycles/samples", 42)  
# -> 255

self.get_float("pixel_aspect_x") 
# -> 1.333333333 this value is drawn from the GlobalStorage

self.get_string("output_dir", "output/") 
# -> /tmp/ this value is drawn from the GlobalStorage

self.get_bool("auto_tile_size") 
# -> True 

self.config.get_int("resolution_x", 512)
# ->  512

self.config.get_int("tile_x") 
# -> throws an error

Undo changes

In some modules it makes sense to revert changes made inside the module to not disturb modules coming afterwards (For example renderer modules should not change the state of the scene).

This often required functionality can be easily done via the Utility.UndoAfterExecution() with-statement:

Example:

def run(self):
    bpy.context.scene.cycles.samples = 50
    
    with Utility.UndoAfterExecution():
        bpy.context.scene.cycles.samples = 320
        
        print(bpy.context.scene.cycles.samples)
        # Outputs: 320

    print(bpy.context.scene.cycles.samples)
    # Outputs: 50

All changes inside the with-block are undone which could also be undone via CTRL+Z inside Blender.

Between-module communication

To exchange information between modules the blender's custom properties are used (Blender allows to assign arbitrary information to scenes and objects). So modules can read out custom properties set by earlier modules and change their behaviour accordingly.

Example

  • The module loader.SuncgLoader adds the custom property category_id to every object
  • The module renderer.SegMapRenderer reads out this property and sets the segmentation color of every object correspondingly

In this way the renderer.SegMapRenderer can also be used without using the loader.SuncgLoader. The loader used instead just has to also set the category_id.