Materials Introduction
In this tutorial you will learn how materials are processed in SkyRenderer. We will walk through the process
of defining Material instance and applying this Material to the mesh.
Agenda:
- Material Definition
- Setting Material to an Object
- HDR Textures
Material Definition
MaterialDefinition is an object that stores properties describing how the material behaves.
Each Material consists of following parameters:
- Texture Provider - asset and data source for material (e.g. texture loading interface),
- Shader (Procedure) - procedures responsible for shading,
- Parameter Provider - procedure's parameters required by procedure to work,
- Strategy and Randomization Group - rules for randomization.
Texture Provider
It should be considered as an interface that loads textures from files. Texture Providers look for textures in
connected assets repository. SkyRenderer contains two main interfaces to load textures from available assets:
- FileTextureProvider - texture file maps (.png, .jpg, .tiff) from directory "textures"
- SubstanceTextureProvider - materials from substance maps (.sbsar) from directory "substances"
Shader
A procedure responsible for shading process describing how particular surface will physically behave under
the rays. In SkyRenderer we have many types of shaders implemented like:
- PBRShader (Physically Based Rendering Shader)
- SkinShader
- PhongShader
- TranslucentShader
- GlassShader
- many more
Most effects are covered by PBRShader since it is the most universal shader, however for some materials it is
worth to use specialized shaders for a higher quality of the output renders.
Parameter Provider
Each shader has their own Parameter Provider class, that passes values of shader-specific parameters to the
shader procedure. To create a Parameter Provider we call shader's .create_parameter_provider() method.
In case we do not specify parameter values, default one are used. Available parameters and their default values
can be checked in shader's documentation.
Strategy and Randomization Group
We can define Material's Randomization Strategy and Group to enable randomization and synchronization of
materials.
Detailed usage of Texture Providers, Shaders and Randomization can be found in detailed cases for each of these
topics.
Setting Material to an Object
Let's render a scene with a shaderball with a default texture applied and see how we can set a Material Definition
to an Object.
from skyrenderer.cases.utils import MaterialsSceneComposer
scene_composer = MaterialsSceneComposer(antialiasing_level=256)
scene_composer.setup_scene(render_width=1600, render_height=1000)
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:03:38,952 | 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-06 14:03:39,388 | skyrenderer.utils.time_measurement | INFO: Setup time: 402 ms 2025-02-06 14:03:42,134 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.74 seconds 2025-02-06 14:03:54,681 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:03:54,682 | skyrenderer.utils.time_measurement | INFO: Render time: 12.55 seconds
Let's create a glass Material Definition using GlassShader and assign this material to the shaderball
To assign the material we will use RendererContext's .set_material_definition() method.
from skyrenderer.scene.scene_layout.layout_elements_definitions import MaterialDefinition
from skyrenderer.basic_types.procedure.shader.basic_shaders.glass_shader import GlassShader
glass_shader = GlassShader(scene_composer.renderer_context)
glass_material_definition = MaterialDefinition(shader=glass_shader)
scene_composer.renderer_context.set_material_definition(
node_name="shaderball_GEO", material_definition=glass_material_definition
)
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:03:55,309 | skyrenderer.utils.time_measurement | INFO: Setup time: 70 ms 2025-02-06 14:03:58,166 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.86 seconds 2025-02-06 14:04:04,476 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:04:04,477 | skyrenderer.utils.time_measurement | INFO: Render time: 6.31 seconds
We can also assign a texture from files. Let's use black and white test grid texture available in assets
repository and PBRShader.
from skyrenderer.basic_types.procedure import PBRShader
from skyrenderer.basic_types.provider import FileTextureProvider
grid_bw_file_texture_provider = FileTextureProvider(scene_composer.renderer_context, "test_grid_bw")
pbr_shader = PBRShader(scene_composer.renderer_context)
grid_bw_material_definition = MaterialDefinition(
texture_provider=grid_bw_file_texture_provider,
shader=pbr_shader,
)
scene_composer.renderer_context.set_material_definition(
node_name="shaderball_GEO", material_definition=grid_bw_material_definition
)
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:04:05,055 | skyrenderer.utils.time_measurement | INFO: Setup time: 62 ms 2025-02-06 14:04:07,925 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.87 seconds 2025-02-06 14:04:20,413 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:04:20,414 | skyrenderer.utils.time_measurement | INFO: Render time: 12.49 seconds
Each shader has a vast range of parameters that are available to manipulate. To check parameters' values can be
changed check shader's documentation.
We will change texture scale for our shader via PBRShader's Parameter Provider:
pbr_shader_parameter_provider = PBRShader.create_parameter_provider(scene_composer.renderer_context, tex_scale=5)
grid_bw_material_definition = MaterialDefinition(
texture_provider=grid_bw_file_texture_provider,
shader=pbr_shader,
parameter_set=pbr_shader_parameter_provider,
)
scene_composer.renderer_context.set_material_definition(
node_name="shaderball_GEO", material_definition=grid_bw_material_definition
)
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:04:20,988 | skyrenderer.utils.time_measurement | INFO: Setup time: 61 ms 2025-02-06 14:04:23,732 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.74 seconds 2025-02-06 14:04:36,961 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:04:36,962 | skyrenderer.utils.time_measurement | INFO: Render time: 13.23 seconds
Textures can also origin from Substance Archive:
from skyrenderer.basic_types.provider import SubstanceTextureProvider
granite_substance_texture_provider = SubstanceTextureProvider(scene_composer.renderer_context, "granite")
granite_material_definition = MaterialDefinition(
texture_provider=granite_substance_texture_provider,
shader=pbr_shader,
parameter_set=pbr_shader_parameter_provider,
)
scene_composer.renderer_context.set_material_definition(
node_name="shaderball_GEO", material_definition=granite_material_definition
)
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:04:37,498 | skyrenderer.basic_types.provider.unit_providers.substance_texture_provider | WARNING: Unable to map purpose diffuse. Map will be parsed with legacy system. Purpose not present in ['ambientocclusion', 'basecolor', 'coatweight', 'coatroughness', 'emissive', 'height', 'metallic', 'normal', 'opacity', 'refractioncolor', 'roughness', 'specular', 'scattering', 'scatteringcolor', 'visibility', 'texturesemanticmap', 'any', 'mask'] See: Texture and substance convention for more details. Remember, purpose mapping is case insensitive. Parsed purpose : diffuse_map 2025-02-06 14:04:37,499 | skyrenderer.basic_types.provider.unit_providers.substance_texture_provider | WARNING: Unable to map purpose glossiness. Map will be parsed with legacy system. Purpose not present in ['ambientocclusion', 'basecolor', 'coatweight', 'coatroughness', 'emissive', 'height', 'metallic', 'normal', 'opacity', 'refractioncolor', 'roughness', 'specular', 'scattering', 'scatteringcolor', 'visibility', 'texturesemanticmap', 'any', 'mask'] See: Texture and substance convention for more details. Remember, purpose mapping is case insensitive. Parsed purpose : glossiness_map 2025-02-06 14:04:37,566 | skyrenderer.utils.time_measurement | INFO: Setup time: 66 ms 2025-02-06 14:04:40,493 | skyrenderer.utils.time_measurement | INFO: Context update time: 2.93 seconds 2025-02-06 14:04:53,055 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:04:53,056 | skyrenderer.utils.time_measurement | INFO: Render time: 12.56 seconds
HDR Textures
HDR Textures are a different type of textures since they are not defined by Material Definition because we do not
assign them to the mesh object. We define a whole environment in Renderer Context, and it is done via a Background
object.
Background object similarly to Material Definition requires:
- Texture Provider - asset and data source for material (e.g. texture loading interface),
- Shader (Procedure) - procedures responsible for shading,
- Parameter Provider - procedure's parameters required by procedure to work.
Texture Provider
There is only one Texture Provider that works on HDRs - HDRTextureProvider. This interface loads HDR textures
from a "background_hdrs" directory in assets repository.
Shader
We distinguish two miss shader procedures that describe behavior for rays that do not hit any target and their
way and environment maps is sampled (hence "miss").
- EnvMapMiss - returning color value from the sampled HDR map
- ConstantColorMiss - returning constant color value regardless of the HDR map
Parameter Provider
Analogically to regular shaders each of miss programs have their Parameter Providers enabling to pass values for
procedures' parameters.
from skyrenderer.basic_types.item_component import Background
from skyrenderer.basic_types.provider import HdrTextureProvider
from skyrenderer.basic_types.procedure import EnvMapMiss
scene_composer.renderer_context.define_env(
Background(
renderer_context=scene_composer.renderer_context,
texture_provider=HdrTextureProvider(scene_composer.renderer_context, "flower_road_4k", gamma_light=3),
shader=EnvMapMiss(scene_composer.renderer_context),
)
)
scene_composer.renderer_context.remove_subtree("plane_GEO")
scene_composer.visualize(scene_composer.get_render())
2025-02-06 14:04:53,639 | skyrenderer.scene.renderer_context | WARNING: Setting background definition after setup. 2025-02-06 14:04:53,639 | skyrenderer.scene.renderer_context | WARNING: Setting light after setup. Origin refers to last scene tree set up. Lights are stored in dict - change is visible immediately; Wrong parameter provider possible 2025-02-06 14:04:53,640 | skyrenderer.scene.renderer_context | WARNING: You are removing subtree after context setup. No changes would be done in current scene. 2025-02-06 14:04:53,702 | skyrenderer.utils.time_measurement | INFO: Setup time: 62 ms 2025-02-06 14:04:56,893 | skyrenderer.utils.time_measurement | INFO: Context update time: 3.19 seconds 2025-02-06 14:05:07,086 | skyrenderer.utils.time_measurement | INFO: Key points calculation time: 0 ms 2025-02-06 14:05:07,087 | skyrenderer.utils.time_measurement | INFO: Render time: 10.19 seconds
Summary
In this section you have learnt:
- Material Definition is an object that describes materials behavior.
- Texture Providers, Shaders, Parameter Providers can be used to create Material Definition object.
- Material Definition can be assigned to the Object via set_material_definition() method.
- We can assign an environment texture via Background object via HDRTextureProvider.