RealityServer Features

Lightmap

The lightmap renderer utilises the irradiance probe functionality of Iray to compute lightmap textures for the selected objects in the scene. It uses OpenGL to calculate the positions of the irradiance probes based on the texture cooridinates of the geometry and then calls the chosen renderer to perform the lighting calculations. The images below show a conventional rendering along with an image where pre-computed lightmaps are used as emission textures to show the contents of the lightmaps.

Conventional Image with Iray Photoreal Rendered Image.
Lightmapped Irradiance Rendering Lightmap Textures.

Lightmap images computed with this renderer represent the irradiance or the amount and color of light arriving at a given point. These textures would normally be used in a real-time renderer such as a game engine or WebGL based renderer where the precomputed lightmap is used instead of calculating the lighting at runtime.

Implementation

Lightmapping is implemented as an additional rendering mode called lightmap, making it available to the standard rendering commands as well as scripting through server-side V8 commands. It is controlled through render context settings which allow you to communicate to the renderer which objects in the scene to lightmap and which texture coordiante set you wish to use. Using the lightmap renderer you can produce output such as that shown below.

Lightmap of Walls Walls Lightmap.
Lightmap of Objects Objects Lightmap.

Render Context Options

The lightmap render mode is controlled through a set of specific render context options. Additionally any options not recognised by the lightmap renderer are passed on to the underlying renderer. The following options are recognised by the lightmap renderer.

Lightmap Render Context Options
Name Type Default Description
lightmap_targets Array None List of items to be processed by the lightmap renderer. The elements of this array can either be and Array with Map elements or just a Map. The Maps must contain a path property, which is an Array of Strings which provide the full path through the scene graph to the instance element to undergo lightmap rendering and a texture_space property which defines which set of texture coordinates to use for the lightmap rendering. If no value is given for this option the renderer will attempt to lightmap the entire scene into a single lightmap. See below for a description of how the scene graph paths work.
lightmap_renderer String iray The renderer to be used for performing the actual irradiance calculations. This renderer must support the irradiance probe functionality of Iray and at present only iray and irt modes support this. This option is provided in case other rendering modes later support irradiance probes.
lightmap_max_triangles Sint32 No limit Limits the number of triangles that are processed by the OpenGL system which produces the irradiance probe locations from the texture coordinates in the model. This can be useful in situations where the model is extremely large and must be processed in stages in order to fit into GPU memory.
lightmap_point_offset Float32 0 Offsets each irradiance probe from it's face by this amount in the direction of it's normal. This is useful if you are encountering self shadowing issues.
lightmap_padding_passes Uint32 5 To avoid boundary artifacts when using lightmaps the computed lightmaps will expand the boundary of each area of the image with lightmap contents using the edge pixels. This uses a 3x3 average filter that is applied only to the blank regions of the image. This setting controls the number of times this filter is run and so how much the boundary of the lightmap regions is expanded.
lightmap_median_filter Boolean false If enabled runs a median filter over the computed lightmap images. This can be useful to help smooth noisy lightmaps.
lightmap_canvas_types Array None Specifies the canvas result type to be rendered for each canvas in the render target. If an entry is specified as anything other than 'result' then instead of rendering a lightmap, the lightmap renderer will output the content as defined by lightmap_canvas_types. Valid lightmap_canvas_types values are: result (the irradiance result), positions (positional coordinates), normals (normals in the range of -1 to 1), unormals (normals in the range of 0 to 1), derivatives_u (derivatives in the u direction in the range of -1 to 1), uderivatives_u (derivatives in the u direction in the range of 0 to 1), derivatives_v (derivatives in the v direction in the range of -1 to 1), uderivatives_v (derivatives in the v direction in the range of 0 to 1).

Scene Graph Paths

The path property used above in the lightmap_targets render context option is more complex than simply specifying the name of an element of the scene to lightmap. The primary reason for this is that RealityServer scenes support multiple instancing, grouping and other structures which mean that you cannot uniquely identify something in a scene purely by its name. Take the following example of a simple scene graph.

Example Scene Graph Scene Graph.

There are three main types of elements in this scene graph: groups, instances and objects (geometry). Groups can contain instances or other groups, instances can reference groups or objects. This mechanism allows you to connect elements together and re-use complex elements and structures.

Looking at the above example, if you were to take Objects_obj, this alone does not identify a single object as there are four instances of it in our scene. So how do we identify a particular item? We use paths. Here is an example.

Scene_root → Scene_root_grp_inst → Scene_root_grp → Objects_A_grp_inst → Objects_A_grp → Objects_01_inst

Starting with the scene root group on the left we traverse all of the elements required to reach the leaf element we want to target for rendering a lightmap. For lightmap rendering the leaf should be an instance element. This is provided in the path property as an ordered array of strings. If we stop before the leaf, all of the elements below the last element we specify will be selected.

Progress Information

The lightmap renderer will output progress information as with other render modes which can be picked up by commands such as get_render_progress. The following progress areas are supported by the lightmap renderer.

  • iteration
  • lightmap_progress
  • lightmap_canvas_render_start
  • lightmap_canvas_render_finish

The iteration area reports the number of iterations processed by the currently rendering lightmap and is passed from the underlying render. All other progress information from that renderer is also passed through and made available. The lightmap_progress area gives a percentage completion in the [0.0-1.0] range indicating how many of the requested lightmaps have been processed. The remaining two areas indicate the canvas numbers which have started rendering and finished rendering.

Convenience Command

To facilitate common lightmap rendering tasks the render_lightmap_to_file command is provided. This is implemented as a V8 server-side JavaScript command enabling you to review the source code and adapt to your own needs if required. The command has quite a few options and we recommend referring to the command documentation in full before using. Most of the parameters are the same as a regular render command, however here are some extended explanations for some of the more critical options.

render_lightmap_to_file Parameters
Name Type Default Description
path String "" This is the path relative to content_root into which the lightmap files will be saved.
base_name String None The base name of the filename for saving. The canvas index and format extension will be appended to the base name.
lightmaps Array None An array of arrays of the user type Lightmap_object which contain the path and texture_space properties to be passed to the renderer.
resolution_x Sint32 None Width of each of the lightmap images to be rendered.
resolution_y Sint32 None Height of each of the lightmap images to be rendered.

Using the Lightmap Renderer

We strongly recommend using the convenience command to perform lightmap rendering tasks unless you have a specific reason not to. Before lightmapping a scene there are also some important considerations.

  • Valid Texture Coordinates - The texture coordinates (UVs) on your model are extremely important when using creating a lightmap. Since these are used to determine where to take measurements your texture coordinates should not overlap and should be in the [0-1] range for all geometry. If you are computing a single lightmap for multiple objects you must ensure their texture coordiantes do not overlap. The renderer cannot detect such cases so you will get invalid results.
  • Texture Space Selection - You have the ability to choose which set of texture coordinates to use on your model. It is very typical when using lightmapping to have a second set of texture coordinates just for lightmapping and another for conventional texturing. You need to ensure you select the correct texture space to use for lightmapping.
  • Tone-mapping - As mentioned above, if you wish to use the lightmap results in a PBR and linear color workflow then you should disable the tone-mapper prior to performing the lightmap render. You can do this by setting the tm_enable_tonemapper attribute on the camera to false. This is better than removing the tone-mapper since it allows Iray to use the luminance estimate from the tone-mapper to drive the firefly filtering algorithm. You should ensure that even though it is disabled, your tone-mapping settings are sensible for your scene.
  • Output Formats - When rendering you will need to choose a pixel format as well as an output file format. We generally recommend at least using Rgbe for the pixel format and either hdr or exr as file formats to store your lightmaps. You can of course also output low dynamic range images in standard formats such as jpg or png however this will result in a loss of information. This may be acceptable if you are not doing tone-mapping again in your real-time application.
  • Render Context Options - In addition to any options needed for the lightmap renderer itself, you will almost certainly want to set the scheduler_mode option for the Iray renderer to batch so that the lightmap is computed in a single render call, otherwise you will only get a single iteration back.
  • Multiple Lightmap Canvases - If you are not using the render_lightmap_to_file command and wish to render multiple lightmaps you cannot use the normal render command and will need to use render_to_canvases instead and provide an array of canvases to the command matching the number of lightmap images to be rendered. Named canvases can then later be retrieved with the get_canvas or the get_canvase_base64 command. Generally however it makes more sense to do this in a server-side V8 command where canvases can be more easily handled. If in doubt, just use the provided render_lightmap_to_file command.

All conventional scene options and attributes should be setup prior to calling the renderer. Typically you will load or create a scene, make changes to the attributes and then call the render_lightmap_to_file command. If you want to obtain rendering progress during rendering then the scene must have been committed to the database first. The easiest way to do this is to put the commands that create or load your scene into a separate request from the rendering. Once rendering has completed your lightmap files will be written to disk for use in whichever environment you need them.

Example

The following is an example JSON-RPC command sequence that will take a scene and render out two lightmap images for different parts of the scene using the convenience command.

[
    {
        "method": "create_scope", "params": {
            "scope_name": "ex_scope"
        },
        "jsonrpc": "2.0", "id": 1
    },
    {
        "method": "use_scope", "params": {
            "scope_name": "ex_scope"
        },
        "jsonrpc": "2.0", "id": 2
    },
    {
        "method": "import_scene", "params": {
            "filename": "scenes/lightmap_example.mi",
            "scene_name": "ex_scene"
        },
        "jsonrpc": "2.0", "id": 3
    },
    {
        "method": "element_set_attributes", "params": {
            "element_name": "Camera_cam",
            "create": true,
            "attributes": {
                "tm_enable_tonemapper": {
                        "type": "Boolean",
                        "value": false
                }
            }
        },
        "jsonrpc": "2.0", "id": 4
    },
    {
        "method": "element_set_attributes", "params": {
            "element_name": "opt",
            "create": true,
            "attributes": {
                "progressive_rendering_max_samples": {
                        "type": "Sint32",
                        "value": 350
                },
                "progressive_rendering_quality_enabled": {
                        "type": "Boolean",
                        "value": false
                }
            }
        },
        "jsonrpc": "2.0", "id": 5
    },
    {
        "method": "render_lightmap_to_file", "params": {
            "scene_name": "ex_scene",
            "base_name": "lm_example_",
            "format": "hdr",
            "renderer": "iray",
            "pixel_type": "Rgbe",
            "render_context_name": "ex_rc",
            "render_context_timeout": 10,
            "render_context_options": {
                "scheduler_mode": {
                        "type": "String",
                        "value": "batch"
                }
            },
            "resolution_x": 4096,
            "resolution_y": 4096,
            "quality": "100",
            "lightmaps": [
                {
                        "path": ["Scene_Root", "Scene_Root_grp_inst", "Scene_Root_grp", "Room_inst"],
                        "texture_space": 1
                },
                {
                        "path": ["Scene_Root", "Scene_Root_grp_inst", "Scene_Root_grp", "Objects_inst"],
                        "texture_space": 1
                }
            ]
        },
        "jsonrpc": "2.0", "id": 6
    },
    {
        "method": "delete_scope", "params": {
            "scope_name": "ex_scope"
        },
        "jsonrpc": "2.0", "id": 7
    }
]