\nmodule.exports.command = {\n name: 'tutorial_add_hdri',\n description: 'Adds a HDRI lighting environment to an existing scene.',\n groups: ['tutorial', 'javascript'],\n arguments: {\n scene_name: {\n description: 'The name of the existing scene to add the HDRI lighting to.',\n type: 'String'\n },\n hdri_filename: {\n description: 'The filename of the HDRI image to use for the environment.',\n type: 'String'\n },\n hdri_intensity: {\n description: 'Multiplier for the values within the HDRI image.',\n type: 'Float32',\n default: 1.0\n }\n }\n}\n<\/pre><\/div>\n\n\nThis is the same structure scene in the empty scene example. Here though we’ll take three parameters. Firstly, we’ll get the name of the existing scene we want to add the HDRI environment to. We also want a filename for the HDRI image and a value for the intensity so we can brighten our environment if required. Note that this command doesn’t return anything so the definition has no returns<\/em> property.<\/p>\n\n\n\nThe observant among you will notice something not shown in the previous example, a default value. Parameters in V8 commands can specify a default value (in this case we give one for hdri_intensity<\/em>). If a default is specified the command can be called without specifying that value and the default will be used. This is useful for making optional parameters.<\/p>\n\n\n\nExecution<\/h4>\n\n\n\n To start building up the execute function we will fetch the existing scene data so we can modify it.<\/p>\n\n\n
\nmodule.exports.command = {\n ...\n execute: function({scene_name, hdri_filename, hdri_intensity}) {\n \/\/ Fetch the existing scene data to work with\n const scene = new Scene(scene_name);\n const options = scene.options;\n ...\n }\n};\n<\/pre><\/div>\n\n\nHere, rather than create a new scene as we did in the previous example, we initialise our scene<\/em> object by retrieving an existing scene from the RealityServer database (for example one made with the command for creating empty scenes, though it could also be one imported using Scene.import<\/em>). This is done by omitting the second parameter of the Scene<\/em> constructor (this pattern holds for all helpers derived from Element<\/em>).<\/p>\n\n\n\nOnce we have the scene we can grab its Options element which will give us a pre-populated Options object, saving us having to retrieve it from the database by name. We need the options later to tell RealityServer what to use for the environment. Now we’ll continue adding functionality to our execute<\/em> function.<\/p>\n\n\n\nlet hdri_image = new Image(`${scene.name}_environment_image`, true);\n<\/pre><\/div>\n\n\nThis makes an image element in the database, for now with no actual image data. Note the second parameter which forces the element to be created. An image without any data isn’t much good so let’s load our HDRI.<\/p>\n\n\n
\nhdri_image.filename = hdri_filename;\n<\/pre><\/div>\n\n\nSetting the filename property of the Image<\/em> object causes the file to be loaded. The file will be searched for in any texture paths you have configured for RealityServer and also within content_root<\/em>. Image elements are not used directly in RealityServer so we need to wrap it in a Texture<\/em> element.<\/p>\n\n\n\nlet hdri_texture = new Texture(`${scene.name}_environment_texture`, true);\nhdri_texture.image = hdri_image;\n<\/pre><\/div>\n\n\nThis creates a new Texture<\/em> element in the database and then sets its image<\/em> property which associates the image data with the texture. Now we can finally use the texture as an environment.<\/p>\n\n\n\nScene.import_elements('${shader}\/base.mdl');\n\nlet environment = Mdl_function_call.create(`${scene.name}_environment_function`,\n 'mdl::base::environment_spherical', {\n texture: hdri_texture\n }\n);\n<\/pre><\/div>\n\n\nTo setup the environment we’ll need to use an MDL function called environment_spherical<\/em>. This is contained in the built in base<\/em> module. Even though this file doesn’t exist on disk we have to load it to make the functions within the module available. We can import things using the static import_elements<\/em> method on the Scene<\/em> object.<\/p>\n\n\n\nWe then call the static method create<\/em> on Mdl_function_call<\/em> to create a new MDL function call (an instance of an MDL function definition). The function we need is environment_spherical<\/em>. This takes one argument texture<\/em> which references the texture to use as the environment. So we pass in the texture element we have just made. It’s ready to use but isn’t hooked up yet, for that we need to set some attributes on our Options<\/em> element for the scene.<\/p>\n\n\n\noptions.attributes.set('environment_function', environment.name, 'Ref');\noptions.attributes.set('environment_function_intensity', hdri_intensity, 'Float32');\n<\/pre><\/div>\n\n\nThe environment_function<\/em> attribute tells the renderer which MDL function to use when looking up the environment, while the environment_function_intensity<\/em> sets a multiplier for the brightness of the environment. Here we pass in our hdri_intensity<\/em> argument to set that. For the environment_function<\/em> we need to get the name<\/em> property of the environment texture since this attribute is of type Ref<\/em>, which is a reference to another element in the database, which is made by name.<\/p>\n\n\n\nThe command should now actually do something if you call it. Here is a quick test JSON-RPC command set you can HTTP POST to RealityServer to verify.<\/p>\n\n\n
\n[\n {"jsonrpc": "2.0", "method": "create_scope", "params": {\n "scope_name": "tutorial_scope"\n }, "id": 1},\n {"jsonrpc": "2.0", "method": "use_scope", "params": {\n "scope_name": "tutorial_scope"\n }, "id": 2},\n {"jsonrpc": "2.0", "method": "tutorial_create_empty_scene", "params": {\n "scene_name": "tutorial_scene"\n }, "id": 3},\n {"jsonrpc": "2.0", "method": "tutorial_add_hdri", "params": {\n "scene_name": "tutorial_scene",\n "hdri_filename": "studio_grid.exr",\n "hdri_intensity": 1.0\n }, "id": 4},\n {"jsonrpc": "2.0", "method": "render", "params": {\n "scene_name": "tutorial_scene"\n }, "id": 5},\n {"jsonrpc": "2.0", "method": "delete_scope", "params": {\n "scope_name": "tutorial_scope"\n }, "id": 6}\n]\n\n<\/pre><\/div>\n\n\n\n
\n
If you run this command sequence you should get an image similar to the one on the right. What you are seeing is the background using the HDRI. We can’t see the effect of lighting yet as we don’t have any objects in our scene.<\/p>\n\n\n\n
There is no tone-mapping or other camera modifications done and no objects in the scene, we’ll cover those in a future article. However if you continue to add objects to this scene they will be illuminated by the new environment. <\/p>\n\n\n\n
This completes the first command of this article and allows you to add a simple HDRI environment to your scenes. There are many options available in RealityServer to control the shape of the environment dome, add ground planes, and re-orient it. You can find more details in the Iray Programmers Guide in the RealityServer Document Center.<\/p>\n<\/div>\n\n\n\n
\n
Image with HDRI Environment<\/figcaption><\/figure>\n\n\n\n<\/p>\n<\/div>\n<\/div>\n\n\n\n
Physically Based Daylight Environment<\/h2>\n\n\n\n In addition to texture or MDL function based environments, RealityServer also has the ability use a built in physically based daylight system. Rather than work from a texture, this dynamically evaluates the sun and sky and can be changed interactively. Using this is just a matter of attaching a different MDL function to the environment_function<\/em> attribute.<\/p>\n\n\n\nCommand Definition<\/h4>\n\n\n\n We’ll define a slightly different interface for this command. Like the previous one we’ll also take in the name of an existing scene but instead of the hdri parameters there is a parameter to control the sun direction and one to control the intensity of the daylight system. Here is the command definition.<\/p>\n\n\n