Commands
[V8 API]
Description
A V8 command is simply a module whose exports contains a property called command that in turn has a String property called name and a Function property called execute. The command will be registered with RealityServer as name and the execute function will be called to execute the command. As with C++, V8 commands can be self documenting and provide argument types and defaults. This is not required but recommended as best practice. Additionally an Object property called user_types can be provided to register User Types with RealityServer.
As commands do not have direct access to Iray they use the RS global object to call other C++ or V8 commands to implement functionality. Alternatively, many convenience modules are provided that wrap scene elements with JavaScript classes to allow more natural access and editing. Once processing is complete, a command can simply return it's calculated value, or on error throw an instance of RS.Error to return error messages to the user. Alternatively commands can return a Promise that should resolve with the command result or reject with an RS.Error. When using asynchronous functionality commands must return Promises to ensure that all asynchronous tasks are completed. See mi_v8_command_async for details.
To illustrate complete command implemenations we present the following paired commands. These allow a scene camera to have it's focal value driven from a horizontal field of view angle and also retrieved as a field of view. The first examples call RealityServer directly using the RS global, the second use the element wrappers to abstract out the RealityServer usage.
// v8_set_fov command, a V8 implementation of the sample set_fov C++ command // found in src/commands/set_fov.cpp module.exports.command = { name: 'v8_set_fov', description: 'Sets camera focal length from a full horizontal field of view.', groups: ['javascript', 'camera'], arguments: { scene_name: { description: 'Scene who\'s camera will have it\'s field of view set.', type: 'String' }, angle: { description: 'FOV angle in degrees', type: 'Float32' } }, returns: { type: 'Void' }, // The execute function. This takes a single argument, which is an Object whose properties // are the arguments passed to the command. Any arguments that are documented above will have // already been converted to the documented type. Undocumented arguments will be passed directly // through without conversion. execute: function(args) { // Look up the scene we are setting the camera on. This will throw an error if scene_name does // not exist which will be returned to the user. const scene_data = RS.get_scene({scene_name: args.scene_name}); // look up the camera name from the scene camera instance. Again this will throw an // error on failure however we do not expect this to fail. const camera = RS.instance_get_item({instance_name: scene_data.camera_instance}); // Check if camera is orthographic since we cannot set FOV on an orthographic camera. // If camera is not a camera (which again, we do not expect) then this call will // throw an error back to the user. if (RS.camera_get_orthographic({camera_name: camera})) { // It's orthographic, throw an error to be returned to the user throw new RS.Error(RS.Error.FAILED,'Cannot set FOV on an orthographic camera.'); } // check range of FOV. Note that since we set the argument type as 'Float32' we are guaranteed // that arg.angle will be a number as RealityServer would have already returned an error if it // was not. if (args.angle <= 0 || args.angle >= 180) { throw new RS.Error(RS.Error.COMMAND_INVALID_PARAMS, '\'angle\' is invalid. Must be greater than 0 and less than 180.'); } // fetch camera aperture so we can calulate the focal value to use. const aperture = RS.camera_get_aperture({camera_name: camera}); // Trigonometry const focal = aperture / (2.0 * Math.tan(RS.Math.radians(args.angle) / 2)); // finally set the focal attribute on the camera RS.camera_set_focal({camera_name: camera, focal: focal}); // NB: we don't return anything as we return Void. } };
The matching v8_get_fov command.
// v8_get_fov command, mirrored implemention of v8_set_fov to return a scene's camera's // field of view. module.exports.command = { name: 'v8_get_fov', description: 'Gets the full horizontal field of view of a scene\'s camera.', groups: ['javascript', 'camera'], arguments: { scene_name: { description: 'Scene who\'s camera will have it\'s field of view returned.', type: 'String' } }, returns: { type: 'Float64', description: 'The full horizontal field of view of the camera in degrees.' }, execute: function(args) { // Look up the scene we are getting the camera from. const scene_data = RS.get_scene({scene_name: args.scene_name}); // look up the camera name from the scene camera instance. const camera = RS.instance_get_item({instance_name: scene_data.camera_instance}); // Check if camera is orthographic since we cannot get FOV on an orthographic camera. if (RS.camera_get_orthographic({camera_name: camera})) { // It's orthographic, throw an error to be returned to the user throw new RS.Error(RS.Error.FAILED,'Cannot get FOV from an orthographic camera.'); } // fetch camera aperture and focal so we can calulate the FOV const aperture = RS.camera_get_aperture({camera_name: camera}); const focal = RS.camera_get_focal({camera_name: camera}); // return the full field of view return 2 * RS.Math.degrees(Math.atan2(aperture / 2.0,focal)); } };
Both these commands can also be implemented using element wrappers rather than calling RealityServer command directly. These provide a more natual and object oriented interface into RealityServer. Additionally we use the ECMAScript 6 'destructuring assignment' syntax to access command arguments more easily.
// v8_set_fov command, a V8 implementation of the sample set_fov C++ command // found in src/commands/set_fov.cpp using element classes // pull in the Scene class const Scene = require('Scene'); module.exports.command = { name: 'v8_set_fov', description: 'Sets camera focal length from a full horizontal field of view.', groups: ['javascript', 'camera'], arguments: { scene_name: { description: 'Scene who\'s camera will have it\'s field of view set.', type: 'String' }, angle: { description: 'FOV angle in degrees', type: 'Float32' } }, execute: function({scene_name,angle}) { // Look up the scene who's camera we are modifying. This will throw an error if scene_name does // not exist which will automatically be returned to the user. const scene = new Scene(scene_name); // if any of the property accesses fail then an error will be thrown and returned // to the user. We use Element.as here to convert the Element_scene_graph instance // returned by Instance.item to the Camera class that we require. const camera = scene.camera_instance.item.as('Camera'); if (camera.orthographic == true) { // It's orthographic, throw an error to be returned to the user throw new RS.Error(RS.Error.FAILED,'Cannot set FOV on an orthographic camera.'); } // check range of FOV. Note that since we set the argument type as 'Float32' we are guaranteed // that arg.angle will be a number as RealityServer would have already returned an error if it // was not. if (angle <= 0 || angle >= 180) { throw new RS.Error(RS.Error.COMMAND_INVALID_PARAMS,'\'angle\' is invalid. Must be greater than 0 and less than 180.'); } // Trigonometry camera.focal = camera.aperture / (2.0 * Math.tan(RS.Math.radians(angle) / 2)); // NB: we don't return anything } };
v8_get_fov with element wrappers.
// v8_get_fov command, mirrored implemention of v8_set_fov to return a scene's camera's // field of view. // pull in the Scene class const Scene = require('Scene'); module.exports.command = { name: 'v8_get_fov', description: 'Gets the full horizontal field of view of a scene\'s camera.', groups: ['javascript', 'camera'], arguments: { scene_name: { description: 'Scene who\'s camera will have it\'s field of view returned.', type: 'String' } }, returns: { type: 'Float64', description: 'The full horizontal field of view of the camera in degrees.' }, execute: function({scene_name}) { // Look up the scene who's camera we are getting. const scene = new Scene(scene_name); // if any of the property accesses fail then an error will be thrown and returned // to the user. const camera = scene.camera_instance.item.as('Camera'); if (camera.orthographic == true) { // It's orthographic, throw an error to be returned to the user throw new RS.Error(RS.Error.FAILED,'Cannot get FOV from an orthographic camera.'); } // return the full field of view return 2 * RS.Math.degrees(Math.atan2(camera.aperture / 2.0,camera.focal)); } };
Modules
- Commands can make use of all the asynchronous functionality that JavaScript and RealityServer modules provide. More...
- RealityServer supports the V8 Inspector Protocol for remotely debugging V8 command execution. More...
- V8 commands support most native JavaScript types as arguments and return values in addtion to some custom RealityServer types to allow binary data to be returned and manipulated. More...
- Command modules can also register user types with RealityServer by exporting a user_types Object. More...
Classes
- class
- Interface for a command implementation. More...