Material Slot Filler
In this section you will learn how material slots can be filled automatically via MaterialSlotFiller tool.
Agenda:
- Material Slot Filler basics
- Material Slot Filler usage
Scene setup
Let's use custom scene composer to set up the scene.
Scene consists of:
- Room (MocapRoomAll_GEO) node in the scene split using nine material slots
- Bottle (Bottle_GEO) node with one material slot "Glass" covering the whole node, instanced three times
from skyrenderer.cases.utils import MaterialSlotFillerSceneComposer
scene_composer = MaterialSlotFillerSceneComposer(antialiasing_level=2048)
scene_composer.setup_scene()
scene_composer.log_info(scene_composer.renderer_context.layout())
scene_composer.visualize()
2025-02-03 15:47:24,434 | skyrenderer.scene.renderer_context | INFO: Root paths:
- root path: /dli/skyenvironment/skyrenderer/skyrenderer
- assets path: /dli/mount/assets
- config path: /dli/skyenvironment/skyrenderer/skyrenderer/config
- gpu sources path: /dli/skyenvironment/skyrenderer/skyrenderer/optix_sources/sources
- cache path: /dli/mount/cache
- ptx cache path: compiled_ptx/ptx
- ocio path: ocio_configs/aces_1.2/config.ocio
2025-02-03 15:47:24,796 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:47:24,797 | skyrenderer | INFO:
top_node
|-- light_LIGHT_NUL
|-- bottle_GEO_NUL_000
| +-- Bottle_GEO_Glass_000
|-- Camera_CAM_NUL
| +-- camera_CAM
|-- camera_target_NUL
|-- bottle_GEO_NUL_001
| +-- Bottle_GEO_Glass_001
|-- bottle_GEO_NUL_002
| +-- Bottle_GEO_Glass_002
|-- MocapRoomAll_GEO_NUL
| |-- MocapRoomAll_GEO_BlackGlossyTiles
| |-- MocapRoomAll_GEO_DarkWood
| |-- MocapRoomAll_GEO_EmissionWindows
| |-- MocapRoomAll_GEO_Floor
| |-- MocapRoomAll_GEO_Marble
| |-- MocapRoomAll_GEO_Metal
| |-- MocapRoomAll_GEO_Mirror
| |-- MocapRoomAll_GEO_WhiteGlossy
| +-- MocapRoomAll_GEO_WhiteWalls
+-- light_LIGHT1_NUL
2025-02-03 15:47:24,910 | skyrenderer.utils.time_measurement | INFO: Setup time: 112 ms
/dli/skyenvironment/skyrenderer/skyrenderer/basic_types/provider/unit_providers/geometry.py:25: RuntimeWarning: invalid value encountered in true_divide
n0 = n0 / np.linalg.norm(n0, axis=1, keepdims=True)
/dli/skyenvironment/skyrenderer/skyrenderer/basic_types/provider/unit_providers/geometry.py:26: RuntimeWarning: invalid value encountered in true_divide
n1 = n1 / np.linalg.norm(n1, axis=1, keepdims=True)
/dli/skyenvironment/skyrenderer/skyrenderer/basic_types/provider/unit_providers/geometry.py:27: RuntimeWarning: invalid value encountered in true_divide
n2 = n2 / np.linalg.norm(n2, axis=1, keepdims=True)
/dli/skyenvironment/skyrenderer/skyrenderer/basic_types/provider/unit_providers/geometry.py:36: RuntimeWarning: invalid value encountered in true_divide
dpdu = dpdu / np.linalg.norm(dpdu, axis=1, keepdims=True)
2025-02-03 15:47:25,655 | skyrenderer.utils.time_measurement | INFO: Context update time: 743 ms
2025-02-03 15:47:26,425 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:47:26,426 | skyrenderer.utils.time_measurement | INFO: Render time: 770 ms
Material Slot Filler basics
MaterialSlotFiller is a tool allowing for automatic load of materials to the material slots
(check ASSETS_MaterialSlots). Automatic load may be done based on .json file with predefined parameters,
texture files (.png, .jpg, .tiff, etc.) and substance archives (.sbsar).
Predefined materials .json file
You could have noticed that the names for the material slots are self-explanatory. For example, it's obvious
that White Walls is what a CG engineer had in mind with the "WhiteWalls" name. Therefore, some common
self-explanatory material slot names are supported automatically without the need for additional specification.
These automatically supported material slots are saved in a .json file in the main asset directory. Let's print
first 5 materials present in the aforementioned file to see which slots you can expect to be filled
"out of the box":
import json
from skyrenderer.core.asset_manager.asset_manager import AssetsTypes
predefined_parameters_path = scene_composer.renderer_context.get_abs_path(
file_path=scene_composer.renderer_context.material_slot_filler.PREDEFINED_MATERIAL_PARAMETERS_PATH,
asset_type=AssetsTypes.NONE,
)
scene_composer.logger.info(predefined_parameters_path)
with predefined_parameters_path.open() as f:
predefined_materials = json.load(f)
head_predefined_materials = predefined_materials[:5]
scene_composer.logger.info(f"\n{json.dumps(head_predefined_materials, indent=4)}")
2025-02-03 15:47:26,750 | skyrenderer | INFO: /dli/mount/assets/renderer/predefined_material_parameters.json
2025-02-03 15:47:26,751 | skyrenderer | INFO:
[
{
"name": "default",
"type (PBR, emissive, glass)": "PBR",
"base_color (RGB 0-1 / hex)": "(0.5, 0.5, 0.5)",
"alpha (0-1)": 1,
"roughness (0-1)": 1,
"metallic (0-1)": 0,
"reflectivity (0-1)": 0,
"tex_scale (any number)": 1
},
{
"name": "MetallicVeryRough",
"type (PBR, emissive, glass)": "",
"base_color (RGB 0-1 / hex)": "(0.7, 0.7, 0.7)",
"alpha (0-1)": "",
"roughness (0-1)": "",
"metallic (0-1)": 1,
"reflectivity (0-1)": 1,
"tex_scale (any number)": ""
},
{
"name": "BlackMetalRough",
"type (PBR, emissive, glass)": "",
"base_color (RGB 0-1 / hex)": "(0.1, 0.1, 0.1)",
"alpha (0-1)": "",
"roughness (0-1)": "",
"metallic (0-1)": 1,
"reflectivity (0-1)": 1,
"tex_scale (any number)": ""
},
{
"name": "EmissionGreen",
"type (PBR, emissive, glass)": "emissive",
"base_color (RGB 0-1 / hex)": "(0, 1, 0)",
"alpha (0-1)": "",
"roughness (0-1)": "",
"metallic (0-1)": "",
"reflectivity (0-1)": "",
"tex_scale (any number)": ""
},
{
"name": "MetallicRough",
"type (PBR, emissive, glass)": "",
"base_color (RGB 0-1 / hex)": "(0.7, 0.7, 0.7)",
"alpha (0-1)": "",
"roughness (0-1)": 0.3,
"metallic (0-1)": 0.7,
"reflectivity (0-1)": 0.2,
"tex_scale (any number)": ""
}
]
Texture files and substance archives
Material slot filler has an additional feature: it also loads texture providers from assets
(both from files and Substance) that match the material slot name (e.g. assets from directory "Bricks"
are assigned automatically to the "Bricks" material slot).
NOTE: The material slot and directory name matching is case-sensitive.
Material Slot Filler usage
The MaterialSlotFiller is disabled by default - it needs to be manually enabled.
We can see that the most popular material slots names like "Glass", "WhiteWalls" and others are filled
automatically:
scene_composer.renderer_context.material_slot_filler.enable()
scene_composer.visualize()
2025-02-03 15:47:29,964 | skyrenderer.utils.time_measurement | INFO: Setup time: 3.21 seconds
2025-02-03 15:47:31,818 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:47:31,819 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:47:32,256 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.29 seconds
2025-02-03 15:47:33,788 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:47:33,788 | skyrenderer.utils.time_measurement | INFO: Render time: 1.53 seconds
Recursive material search
By default, the MaterialSlotFiller looks for the texture provider matches only in the main assets directory
for the given provider type. To look into all the nested folders too, we can enable recursive material search.
NOTE: This option should be used with caution, if the same texture provider is defined in separate
subdirectories, the one found first is used.
scene_composer.renderer_context.material_slot_filler.enable_recursive_material_search()
scene_composer.visualize()
2025-02-03 15:47:37,286 | skyrenderer.utils.time_measurement | INFO: Setup time: 3.05 seconds
2025-02-03 15:47:39,092 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:47:39,093 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:47:39,520 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.23 seconds
2025-02-03 15:47:40,349 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:47:40,350 | skyrenderer.utils.time_measurement | INFO: Render time: 830 ms
Loading priority
As noted before, it is possible that one material slot matches texture providers in different directories.
It can also have a match both in substance archives and file textures.
The priority between texture provider types can be controlled by the user. It can be set using ordered
iterable of the provider classes (e.g. [SubstanceTextureProvider, FileTextureProvider]
or [FileTextureProvider]
) or MaterialSlotLoadingPriority enum
(e.g. MaterialSlotLoadingPriority.SUBSTANCE_FIRST_FILE_TEXTURES_SECOND
or MaterialSlotLoadingPriority.ONLY_FILE_TEXTURES
).
The default priority is [FileTextureProvider, SubstanceTextureProvider]
.
Since previously loaded parameters and texture providers still persist in the context registers, we'll reload
the scene with scene_composer's method that clears context, reloads the scene and enables MaterialSlotFiller.
from skyrenderer.basic_types.provider import FileTextureProvider, SubstanceTextureProvider
scene_composer.reload_the_scene_with_filler_enabled()
scene_composer.renderer_context.material_slot_filler.enable_recursive_material_search()
scene_composer.renderer_context.material_slot_filler.set_loading_priority(
[SubstanceTextureProvider, FileTextureProvider]
)
scene_composer.visualize()
2025-02-03 15:47:40,796 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:47:44,015 | skyrenderer.utils.time_measurement | INFO: Setup time: 3.22 seconds
2025-02-03 15:47:44,587 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:47:44,587 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:47:44,612 | skyrenderer.basic_types.provider.unit_providers.substance_texture_provider | INFO: SkySubstance: rendering Floor...
2025-02-03 15:47:44,778 | skysubstance.skysubstance_renderer | INFO: OpenGL verification successful.
2025-02-03 15:50:14,836 | skyrenderer.utils.time_measurement | INFO: SubstanceRender time: 150.22 seconds
2025-02-03 15:50:15,653 | skyrenderer.basic_types.provider.unit_providers.substance_texture_provider | INFO: SkySubstance: rendering WhiteGlossy...
2025-02-03 15:50:18,882 | skyrenderer.utils.time_measurement | INFO: SubstanceRender time: 3.23 seconds
2025-02-03 15:50:19,203 | skyrenderer.utils.time_measurement | INFO: Context update time: 155.19 seconds
2025-02-03 15:50:22,957 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:22,958 | skyrenderer.utils.time_measurement | INFO: Render time: 3.75 seconds
When only one provider type is given, the other is disabled.
from skyrenderer.scene.material_slot_filler.material_slot_filler import MaterialSlotLoadingPriority
scene_composer.reload_the_scene_with_filler_enabled()
scene_composer.renderer_context.material_slot_filler.enable_recursive_material_search()
scene_composer.renderer_context.material_slot_filler.set_loading_priority(
MaterialSlotLoadingPriority.ONLY_FILE_TEXTURES
)
scene_composer.visualize()
2025-02-03 15:50:23,405 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:50:26,381 | skyrenderer.utils.time_measurement | INFO: Setup time: 2.97 seconds
2025-02-03 15:50:28,158 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:28,158 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:28,576 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.19 seconds
2025-02-03 15:50:32,255 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:32,256 | skyrenderer.utils.time_measurement | INFO: Render time: 3.68 seconds
The recursive asset search combined with the loading priority is very useful for prototyping.
It allows to quickly fill the most common material slots with the providers from previous projects or use cases.
However, as it largely depends on the asset structure, it is not recommended to rely on it for the final versions
of your projects.
You can always disable the recursive search and switch back to the default loading priority, but previously
loaded parameters and texture providers still persist in the context registers, so we'll reload the scene.
scene_composer.renderer_context.material_slot_filler.disable_recursive_material_search()
scene_composer.renderer_context.material_slot_filler.set_loading_priority(
[FileTextureProvider, SubstanceTextureProvider]
)
scene_composer.reload_the_scene_with_filler_enabled()
2025-02-03 15:50:32,634 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
Defined subdirectories
Often, the assets for a given project are prepared in subdirectories of the assets folder. Instead of enabling the
recursive global search, we can limit the search to these subfolders (one or more).
For even more control, we can disable the search in the main directory. This way the user can limit the search
to the defined subfolders and be sure that only the dedicated materials have been loaded. We can assign subfolders
specifically per asset type using AssetsTypes.TEXTURES or AssetsTypes.SUBSTANCES enum.
scene_composer.renderer_context.material_slot_filler.set_subfolders("room_materialslot_demo", AssetsTypes.TEXTURES)
scene_composer.renderer_context.material_slot_filler.disable_loading_from_main_folder()
scene_composer.visualize()
2025-02-03 15:50:32,823 | skyrenderer.utils.time_measurement | INFO: Setup time: 184 ms
2025-02-03 15:50:33,393 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:33,394 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:33,645 | skyrenderer.utils.time_measurement | INFO: Context update time: 821 ms
2025-02-03 15:50:37,214 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:37,215 | skyrenderer.utils.time_measurement | INFO: Render time: 3.57 seconds
Custom predefined material parameters
At the beginning of this tutorial, we printed out the contents of the json file with the default predefined
material parameters.
It is possible to expand this predefined list or to overwrite parameters of some of the material slots -
later definition of the parameters with the same name overwrites previous ones.
Custom parameters must match the predefined_material_parameters.json content format.
The parameters that are default can be omitted.
custom_predefined_material_parameters = [
{"name": "DarkWood", "tex_scale": 11},
{"name": "WhiteWalls", "tex_scale": 8},
{"name": "Floor", "tex_scale": 7},
{"name": "Marble", "tex_scale": 12},
{"name": "BlackGlossyTiles", "base_color": (0.1, 0.1, 0.1)},
]
scene_composer.reload_the_scene_with_filler_enabled()
scene_composer.renderer_context.material_slot_filler.update_predefined_material_parameters(
custom_predefined_material_parameters
)
scene_composer.renderer_context.material_slot_filler.set_subfolders("room_materialslot_demo", AssetsTypes.TEXTURES)
scene_composer.renderer_context.material_slot_filler.disable_loading_from_main_folder()
scene_composer.visualize()
2025-02-03 15:50:37,540 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:50:37,629 | skyrenderer.utils.time_measurement | INFO: Setup time: 88 ms
2025-02-03 15:50:38,197 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:38,198 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:38,446 | skyrenderer.utils.time_measurement | INFO: Context update time: 816 ms
2025-02-03 15:50:39,930 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:39,931 | skyrenderer.utils.time_measurement | INFO: Render time: 1.48 seconds
Randomized predefined material parameters
It is possible to define randomized parameters using this feature. Since randomization is deterministic in
SkyRenderer, we will render two frames and see how base color values change for the bottles. To learn more about
randomization, see the INTRO_Randomization tutorial.
from skyrenderer.basic_types.provider.provider_inputs import FloatInput
random_glass_color_parameters = [
{"name": "Glass", "type": "glass", "base_color": FloatInput(dims=3)},
]
scene_composer.reload_the_scene_with_filler_enabled()
scene_composer.renderer_context.material_slot_filler.update_predefined_material_parameters(
custom_predefined_material_parameters
)
scene_composer.renderer_context.material_slot_filler.update_predefined_material_parameters(
random_glass_color_parameters
)
scene_composer.renderer_context.material_slot_filler.set_subfolders("room_materialslot_demo", AssetsTypes.TEXTURES)
scene_composer.renderer_context.material_slot_filler.disable_loading_from_main_folder()
scene_composer.visualize(frame=0)
scene_composer.visualize(frame=1)
2025-02-03 15:50:40,253 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:50:40,336 | skyrenderer.utils.time_measurement | INFO: Setup time: 82 ms
2025-02-03 15:50:40,906 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:40,906 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:41,153 | skyrenderer.utils.time_measurement | INFO: Context update time: 817 ms
2025-02-03 15:50:42,708 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:42,709 | skyrenderer.utils.time_measurement | INFO: Render time: 1.55 seconds
2025-02-03 15:50:43,076 | skyrenderer.utils.time_measurement | INFO: Setup time: 81 ms
2025-02-03 15:50:43,648 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:43,648 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:43,894 | skyrenderer.utils.time_measurement | INFO: Context update time: 817 ms
2025-02-03 15:50:44,687 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:44,688 | skyrenderer.utils.time_measurement | INFO: Render time: 793 ms
Material Slot Filler usage recap
Part of material slot filler configuration was done with a helper, so now we'll clear the renderer context and
perform the whole configuration explicitly to make it clear what options were used for the image rendered above.
scene_composer.renderer_context.clear()
scene_composer.setup_scene()
scene_composer.renderer_context.material_slot_filler.enable()
scene_composer.renderer_context.material_slot_filler.set_subfolders("room_materialslot_demo", AssetsTypes.TEXTURES)
scene_composer.renderer_context.material_slot_filler.disable_loading_from_main_folder()
scene_composer.renderer_context.material_slot_filler.update_predefined_material_parameters(
custom_predefined_material_parameters
)
scene_composer.visualize()
2025-02-03 15:50:44,995 | skyrenderer.scene.renderer_context | WARNING: Light with light_id=light_LIGHT_NUL already exists in the scene and will be replace with a new one.There can only be a single light for a single node.
2025-02-03 15:50:45,079 | skyrenderer.utils.time_measurement | INFO: Setup time: 84 ms
2025-02-03 15:50:45,662 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Calculating 'position_map' and 'pdf_map' for MocapRoomAll_GEO_EmissionWindows, this may take a while...
2025-02-03 15:50:45,662 | skyrenderer.basic_types.provider.unit_providers.alembic_buffer_provider | INFO: Consider adding mesh cacher if you want to avoid waiting in the future.
2025-02-03 15:50:45,912 | skyrenderer.utils.time_measurement | INFO: Context update time: 832 ms
2025-02-03 15:50:46,706 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms
2025-02-03 15:50:46,707 | skyrenderer.utils.time_measurement | INFO: Render time: 794 ms
Summary
In this section you have learnt:
- MaterialSlotFiller can be used to load automatically materials from predefined .json file, file textures and
substance archives. - MaterialSlotFiller is disabled by default, hence has to be enabled explicitly.
- MaterialSlotFiller can perform recursive search and can use only provided subfolders.
- Loading priority of providers can be changed accordingly from the default FileTexture and Substance order.
- We can customize and randomize predefined material parameters used by MaterialSlotFiller.