Nomad 3D Viewer
Development notes concerning the work realised during summer 2020.
Communication between server and client
The Nomad 3D Viewer web application uses a node.js server and clients are web pages. The communication between the server and the clients is based on streams through a websocket.
An explanation page for websocket streams is given here.
The figure shows the main objects of the communication between the server and client. The clients requests:
- 3D model with different LODs (level of details)
- Positions of the axis
- Get the list of simulated servers
- Pause/restart the animation
The 3D model data are binary data and can be very big for finest LODs and common websocket messages cannot hold such data.
That is why using the streams was a solution and allowed to transfer big data with the chunks. However only using the stream for all requests/responses forced to implement a special "protocol".
here is how the communication works. When a client opens a connection on the server, a stream is opened between the server and the client, meaning that there is as many streams as the number of clients. For each type of request, there is a handler that is why the data collected must be dispatched to the correct handler e.g. there is a handler for the positions request, another one for pause/restart requests, etc. To implement the dispatch, the messages (or chunks) are sent in the following sequence:
- start message: the name the request hashed into a fixed length word with START.
- content messages: sequence of binary or ascii messages depending on the type of request.
- end message: the name the request hashed into a fixed length word with END.
The messages or chunks are sent through the stream. After the message reading, the read handler name allows to dispatch it to the correct handler. The StreamDispatcher object is responsible for collecting and forwarding the message to the correct handler. There is one StreamDispatcher on the client side and as many as clients on the server side.
The main functions of StreamDispatcher are:
- stringCollector: Returns a stream and calls the callback with the resulting string.
- stringCollectorGenerator: Generates generic writable streams, transforming the received data in a string which is forwarded to a callback when completely received.
- setHandler: Fills a writable stream when data is received at the corresponding handler.
- sendString: Sends a string to a specific handler.
- sendStream: Sends a stream.
The function setHandler is used with stringCollector or stringCollectorGenerator and there are two ways to use:
- The handler is set once for many streams or requests. That is the case on the server side. In that case the handler generator is recalled after each end of stream. Here a function returning a stream is called.
- The handler is set once for one single stream or request. That is the case on the client side because it is necessary to synchronize the end of the handler execution. Here stringCollectorGenerator is called.
Limitations and improvements
For big data, we do not know the number of chunks that will be sent to the client (the chunks are read from another file stream). Then the current protocol searches in each chunk the presence of the end sequence by comparing the bytes. When it is found, the response is considered finished. However in case of a binary response, there is a small probability that a message contains the end sequence whereas it is not the end sequence. One solution:
- start message: the handler's name (can be hashed)
- content messages interleaved with status messages: the status message tells if there is more data or not.
Thus the end message is a status message and the receiver can check only the status messages.
AssetGetter: The object is getting the 3D model data on the browser side. It registers handlers on the StreamDispatcher and when data are fetched they are stored in the IndexedDB browser database using the AssetStorage object.
Nomad3DPositions: The object is getting the current positions of the axis on the browser side. It registers handlers on the StreamDispatcher and updates the positions read by the model.
AssetResponder: The object is getting the model assets on the server side. It registers handlers on the StreamDispatcher and reads the model data from disk.
AddonsResponder: The object is responding to the positions requests on the server side. It registers handlers on the StreamDispatcher and forwards its calls to the NomadPositions object that calls the addon. The addon communicates with the intermediate nomad-3d-positions application that checks the nomad server execution and registers the Cameo subscriber. Notice that there is a single instance of the NomadPositions object whereas there is one instance of AddonsResponder per client.
The environment files are generated from an environment image. The file used is img/environment.jpg. The Blender script img/environment.blend is used to generate the 6 texture files from it. To do it:
- Open the Blender script and click on Animation. The 6 files are generated.
- Run rename.sh to obtain the good names.
- Move the files into img/Env.
The script comes from the site aerotwist.com.
The ideas are welcome. Here are some:
- Automatic zoom on interesting parts.
- Draw the neutron beam.