{"id":2226,"date":"2018-11-20T08:48:02","date_gmt":"2018-11-20T08:48:02","guid":{"rendered":"https:\/\/www.migenius.com\/?p=2226"},"modified":"2019-08-27T03:05:11","modified_gmt":"2019-08-27T03:05:11","slug":"creating-an-empty-scene-with-server-side-v8","status":"publish","type":"post","link":"https:\/\/www.migenius.com\/articles\/creating-an-empty-scene-with-server-side-v8","title":{"rendered":"Creating an Empty Scene with Server-side V8"},"content":{"rendered":"
We’ve covered server-side V8 commands before but in this post we will go into a little more detail and use some of the helper classes that are provided with RealityServer to make common tasks easier. Quite often you want to kick off an application by creating a valid, empty scene ready for adding your content. Actually, it’s something we we need to do in a lot of our posts here so to avoid repeating it each time, lets make a V8 command to do it for us.<\/p>\n
<\/p>\n
If you haven’t already used it, the server-side V8 JavaScript API<\/em> in RealityServer is an easy way to add commands to the RealityServer JSON-RPC API<\/a> with a little JavaScript. We covered some of the essentials in our Basic Canvas Operations in V8<\/a>. The command in this post will be very simple but is a good example of something repetitive than can be frustrating to keep implementing on the client-side.<\/p>\n We’re going to make a command called create_empty_scene<\/em>, can you guess what it will do? If you’re following along you can place it in your v8\/commands<\/em> directory and call the file create_empty_scene.js<\/em>.<\/p>\n The V8 JavaScript API ships with many helpful classes for wrapping common manipulations and operations. You can read the full documentation in the RealityServer Document Center<\/em> under Server APIs<\/em> \u2192 V8 JavaScript API<\/em> \u2192 V8 API<\/em> \u2192 Core Modules<\/em>. If you’re interested in how they are implemented the full source is provided in v8\/includes<\/em>.<\/p>\n For our command we will need five of the helper classes so let’s require<\/em> them, Node.js style.<\/p>\n The require()<\/em> method searches any configured include paths, by default just v8\/includes<\/em> but you can add more. By convention we put these require lines together at the start of the command file. As an interesting side note, you can also require<\/em> JSON files which can be useful for configuration information.<\/p>\n All V8 commands need to define their parameters and other information. This also provides the documentation for the command. The code is pretty self explanatory.<\/p>\n By this point the command will already be showing up in your list of RealityServer commands at http:\/\/host:port\/?doc<\/a>. However the command won’t do anything just yet as there is no execute<\/em> function being exported.<\/p>\n To get the command to do anything useful we need to provide an execute<\/em> function. This will look something like this.<\/p>\n This boilerplate shows a nice convenience you may want to use in your commands, destructuring arguments<\/em>. The execute function when called receives a single argument, let’s call it args<\/em> for now. Normally to access the individual arguments you need to use standard dot notation, e.g., args.scene_name<\/em>. Using JavaScript destructuring in the argument list we can pull out the arguments directly into their own variables. So in the above there is no need to have lots of args dot this and args dot that, we can just use scene_name<\/em>. You can of course also use the standard JavaScript arguments<\/em> array.<\/p>\n Everything is now setup to do the work. Here is the code, with comments to explain what is happening.<\/p>\n If you look through the first sections of the Creating a Simple Scene Programmatically<\/a> article you can get a feeling for how this sequence of operations would be implemented using the JSON-RPC API. Needless to say it is a lot more verbose and a lot less readable than the above code. Even so, a few parts warrant further explanation.<\/p>\n Looking at the constructors for the elements you may notice something:<\/p>\n The second parameter controls whether the constructor will try to locate an existing element to use or whether to create a new element. If set to true<\/em> a new element will be created, otherwise the constructor will try and look up the named element in the database. This is useful for pulling existing elements into the helper objects so you can access them conveniently. Of course in this command we are creating everything from scratch.<\/p>\n All of the helpers in our example are for Elements<\/em> and derive from the Element<\/em> class. This furnishes them with a property attributes<\/em> which contains a special set<\/em> and get<\/em> function. You can see them used in these lines.<\/p>\n Because attributes in RealityServer are typed we do not make use of the setter\/getter system in JavaScript but rather need to set them through a function where we provide the name, value and type respectively.<\/p>\n So, what does our fancy new command actually do. Well if you run the command and then call the render<\/em> command on the scene it outputs, you’ll be treated to a rendering of the cover art from Smell the Glove<\/a> by Sp\u0131n\u0308al Tap. Not too shabby. Yes, I did actually render the image to the right using Iray rendering.<\/p>\n If you call the export_scene<\/em> command and output the scene to a .mi<\/em> file you can see the structure that has been created. Obviously there are no lights, environment or objects in the scene so there is nothing to render yet. While you can see from the code what the names of the elements created by the command will be, it also returns them in case you need to automate processing. In our next post we will turn on the light by adding a HDRI environment.<\/p>\n<\/div><\/div> <\/p>\n<\/div><\/div><\/div>\n This post has given you another quick introduction to some key concepts for using the server-side V8 JavaScript API. You can download the full code for the command below and it serves as a useful starting point for writing your own (it uses most of the useful boiler plate). For example, you could add parameters to allowing passing in initial options to be set as attributes on the options object or camera. As always, get in touch<\/a> if you want to know more or have any questions.<\/p>\nV8 Helper Classes<\/h3>\n
\nconst Scene = require('Scene');\nconst Options = require('Options');\nconst Camera = require('Camera');\nconst Instance = require('Instance');\nconst Group = require('Group');\n<\/pre>\n
Command Definition<\/h3>\n
\nmodule.exports.command = {\n name: 'create_empty_scene',\n description: 'Creates a valid but empty scene ready for adding objects and lighting.',\n groups: ['scene', 'javascript'],\n arguments: {\n scene_name: {\n description: 'The name to use when storing the created scene in the database. '\n + 'Other element names will be derived from this name as well.',\n type: 'String'\n }\n },\n returns: {\n type: 'Map',\n description: 'Map containing the database names of the options, camera, camera instance and rootgroup.'\n }\n};\n<\/pre>\n
Command Execution<\/h3>\n
\nmodule.exports.command = {\n ...\n execute: function({scene_name}) {\n ...\n }\n};\n<\/pre>\n
Making Things Happen<\/h3>\n
\nfunction({scene_name}) {\n \/\/ Create all of the needed database elements\n const scene = new Scene(scene_name, true);\n const options = new Options(`${scene_name}_opt`, true);\n const camera = new Camera(`${scene_name}_cam`, true);\n const camera_instance = new Instance(`${scene_name}_cam_inst`, true);\n const rootgroup = new Group(`${scene_name}_root`, true);\n\n \/\/ Attach the camera to its instance\n camera_instance.item = camera;\n\n \/\/ Attach the camera instance to the rootgroup\n rootgroup.attach(camera_instance);\n\n \/\/ Set default filtering to Gauss with a radius of 1.5 pixels\n options.attributes.set('filter', 2, 'Sint32');\n options.attributes.set('radius', 1.5, 'Float32');\n\n \/\/ Set the needed elements onto the scene\n scene.options = options;\n scene.camera_instance = camera_instance;\n scene.root_group = rootgroup;\n\n \/\/ Return the details of our configured scene\n return {\n rootgroup: rootgroup.name,\n options: options.name,\n camera: camera.name,\n camera_instance: camera_instance.name\n };\n}\n<\/pre>\n
Element Constructors<\/h3>\n
\nconst scene = new Scene(scene_name, true);\n<\/pre>\n
Element Attributes<\/h3>\n
\n\/\/ Set default filtering to Gauss with a radius of 1.5 pixels\noptions.attributes.set('filter', 2, 'Sint32');\noptions.attributes.set('radius', 1.5, 'Float32');\n<\/pre>\n
Results<\/h3>\n
Write Your Own\u2013Start With Ours<\/h3>\n