def main(): # Parse the command line. param = parseCommandLine() # Helper class to start/stop Azrael stack and other processes. az = azrael.startup.AzraelStack(param.loglevel) # Start Azrael services. with azutils.Timeit('Startup Time', True): az.start() if not param.noinit: # Add the specified number of cubes in a grid layout. demo_default.spawnCubes(*param.cubes, center=(0, 0, -10)) # Launch a dedicated process to periodically reset the simulation. time.sleep(2) az.startProcess(demo_default.ResetSim(period=param.reset)) print('Azrael now live') # Start the process that periodically changes the force field. Add the # process handle to the list of processes. az.startProcess( UpdateGrid(period_circ=param.circular, period_lin=param.linear)) # Either wait forever or start the Qt Viewer and wait for it to return. if param.noviewer: demolib.waitForever() else: viewer = demolib.launchQtViewer() viewer.wait() # Stop Azrael stack. az.stop() print('Clean shutdown')
def main(): # Parse the command line. param = parseCommandLine() assert vectorgrid.resetGrid('force').ok # Helper class to start/stop Azrael stack and other processes. az = azrael.startup.AzraelStack(param.loglevel) # Start Azrael services. with azutils.Timeit('Startup Time', True): az.start() if not param.noinit: # Spawn four cubes in a row. spawnCubes(4, 1, 1, center=(0, 0, 10)) # Launch a dedicated process to periodically reset the simulation. time.sleep(2) print('Azrael now live') # Either wait forever or start the Qt Viewer and wait for it to return. if param.noviewer: demolib.waitForever() else: viewer = demolib.launchQtViewer() viewer.wait() # Stop Azrael stack. az.stop() print('Clean shutdown')
def main(): # Parse the command line. param = parseCommandLine() # Helper class to start/stop Azrael stack and other processes. az = azrael.startup.AzraelStack(param.loglevel) # Start Azrael services. with azutils.Timeit('Startup Time', True): az.start() if not param.noinit: # Add a model to the otherwise empty simulation. The sphere is # in the repo whereas the Vatican model is available here: # http://artist-3d.com/free_3d_models/dnm/model_disp.php?\ # uid=3290&count=count # p = os.path.dirname(os.path.abspath(__file__)) # fname = os.path.join(p, 'models', 'sphere', 'sphere.obj') # fname = os.path.join(p, 'house', 'house.obj') # fname = os.path.join(p, 'test.obj') # scale, model_name = (1.25, fname) # scale, model_name = ( # 50, 'viewer/models/vatican/vatican-cathedral.3ds') # scale, model_name = ( # 1.25, 'viewer/models/house/house.3ds') # vert, uv, rgb = demolib.loadModel(model_name) # Load the Booster Cube Model created in Blender. scale, (vert, uv, rgb) = 1, demolib.loadBoosterCubeBlender() # Wrap the UV data into a BoosterCube template and add it to # Azrael. addBoosterCubeTemplate(scale, vert, uv, rgb) # Define additional templates, in this case the wall of cubes. # Spawn them a bit to the right and back. spawnCubes(*param.cubes, center=(5, 0, -5)) # del p, fname, model_name # Launch a dedicated process to periodically reset the simulation. time.sleep(2) az.startProcess(ResetSim(period=param.reset)) print('Azrael now live') # Either wait forever or start the Qt Viewer and wait for it to return. if param.noviewer: demolib.waitForever() else: viewer = demolib.launchQtViewer() viewer.wait() # Stop Azrael stack. az.stop() print('Clean shutdown')
def paintGL(self): try: with util.Timeit('viewer.paintGL') as timeit: self._paintGL() except Exception as err: print('Error in paintGL:') print('\n' + '-' * 79) print(err) import traceback traceback.print_exc(file=sys.stdout) print('-' * 79 + '\n') sys.exit(1)
def sendToClerk(self, cmd: str, data: dict): """ Send data to Clerk and return the response. This method blocks until a response arrives. Upon a reply it inspects the response to determine whether the request succeeded or not. This is returned as the first argument in the 'ok' flag. .. note:: JSON must be able to serialise the content of ``data``. :param str cmd: command word :param dict data: payload (must be JSON encodeable) :return: Payload data in whatever form it arrives. :rtype: any """ with azutils.Timeit('client.sendToClerk:{}:1'.format(cmd)): try: payload = json.dumps({'cmd': cmd, 'data': data}) except (ValueError, TypeError): msg = 'JSON encoding error for Client command <{}>'.format(cmd) self.logit.warning(msg) return RetVal(False, msg, None) # Send data and wait for response. with azutils.Timeit('client.sendToClerk:{}:2'.format(cmd)): self.send(payload) payload = self.recv() azutils.logMetricQty('client.recv:{}'.format(cmd), len(payload)) # Decode the response and wrap it into a RetVal tuple. with azutils.Timeit('client.sendToClerk:{}:3'.format(cmd)): try: ret = json.loads(payload) ret = RetVal(**ret) except (ValueError, TypeError): return RetVal(False, 'JSON decoding error in Client', None) return ret
def ToClerk_AddTemplates_Decode(payload: dict): """ Undo the Base64 encoding from all files. Otherwise the templates remain unchanged. .. raw:: html <script src="http://localhost:9000/docson/widget.js" data-schema="/json_schemas/template.json"> </script> """ # Convenience. T = aztypes.Template dec = base64.b64decode with azutils.Timeit('clerk.decode'): decoded = [] # Iterate over all templates. for template in payload['templates']: # Validate the template against the schema. jsonschema.validate(template, azrael.azschemas.Template) # Iterate over all fragments in current template. for fragname in template['fragments']: # Undo the Base64 encoding for each fragment geometry file. files = template['fragments'][fragname]['files'] files = {k: dec(v.encode('utf8')) for k, v in files.items()} # Overwrite the original 'file' dictionary. template['fragments'][fragname]['files'] = files # Turn the input data into a Template type. decoded.append(T(**template)) # Overwrite the original template with the updated version. payload['templates'] = decoded return payload
def main(): # Parse the command line. param = demo_default.parseCommandLine() # Helper class to start/stop Azrael stack and other processes. az = azrael.startup.AzraelStack(param.loglevel) # Start Azrael services. with azutils.Timeit('Startup Time', True): az.start() if not param.noinit: # Define a sphere with boosters and spawn an instance thereof. p = os.path.dirname(os.path.abspath(__file__)) fname = os.path.join(p, 'models', 'sphere', 'sphere.obj') spawnSpaceship(scale=1.0, fname=fname) # Add the specified number of cubes in a grid layout. demo_default.addTexturedCubeTemplates(2, 2, 1) del p, fname # Launch a dedicated process to periodically reset the simulation. time.sleep(2) az.startProcess(demo_default.ResetSim(period=param.reset)) print('Azrael now live') # Either wait forever or start the Qt Viewer and wait for it to return. if param.noviewer: demolib.waitForever() else: viewer = demolib.launchQtViewer() viewer.wait() # Stop Azrael stack. az.stop() print('Clean shutdown')
def _paintGL(self): """ Paint the OpenGL scene. Qt calls this method whenever it needs re-painting (eg. window movement), or when the updateGL() method was called somewhere explicitly. In this script we use a timer to periodically trigger the updateGL() method for a smooth viewing experience. """ # Update the position/rotation of the camera depending on the # currently pressed keys and mouse position. self.updateCamera() # Load the geometry of newly added objects. self.loadGeometry() # -------------------------------------------------------------------- # Draw the scene. # -------------------------------------------------------------------- # Clear the scene. gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) # Compute the combined camera- and projection matrix. cameraMat = self.camera.cameraMatrix() matPerspCam = np.array(np.dot(self.matPerspective, cameraMat)) # Convert it to the flat 32Bit format the GPU expects. matPerspCam = matPerspCam.astype(np.float32) matPerspCam = matPerspCam.flatten(order='F') with util.Timeit('viewer.loop') as timeit: for objID in self.newSVs: # Do not add anything if it is the player object itself. if objID == self.player_id: continue # Compute the model matrix for the overall object. body = self.newSVs[objID]['rbs'] tmp = { 'scale': body['scale'], 'position': body['position'], 'rotation': body['rotation'] } matModelObj = self.buildModelMatrix(tmp) del body, tmp # Update each fragment in the scene based on the position, # rotation, and scale of the overall object. self._drawFragments(objID, matModelObj, matPerspCam) # -------------------------------------------------------------------- # Display HUD for this frame. # -------------------------------------------------------------------- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0) gl.glUseProgram(0) gl.glColor3f(0.5, 0.5, 0.5) hud = 'Frame {}'.format(self.frameCnt) if self.recording: hud += ', Recording On' self.renderText(0, 15, hud) # -------------------------------------------------------------------- # Optional: save the frame buffer content to disk to record a video. # -------------------------------------------------------------------- if self.recording: # Time how long it takes to grab the framebuffer. t0 = time.time() img = self.grabFrameBuffer() elapsed = float(1E3 * (time.time() - t0)) # Send the image to a dedicated writer thread to avoid blocking # this thread more than necessary. self.imgWriter.sigUpdate.emit(elapsed, img) del t0, img, elapsed self.frameCnt += 1
def loadGeometry(self): # Backup the latest state variables because we will download new ones # from Azrael shortly. self.oldSVs = self.newSVs # Get latest SV values. with util.Timeit('viewer.getV') as timeit: ret = self.client.getObjectStates(None) if not ret.ok: print('Could not retrieve the state variables -- Abort') self.close() # Remove all *None* entries (means Azrael does not know about them; # should be impossible but just to be sure). self.newSVs = {} for objID in ret.data: if ret.data[objID] is None: self._removeObjectData(objID) self.newSVs[objID] = ret.data[objID] # Remove all objects from the local scene for which Azrael did not # provid SV data. for objID in self.oldSVs: # Ignore the player object. if (objID in self.newSVs) or (objID == self.player_id): continue # Delete all fragment textures. for frag in self.textureBuffer[objID].values(): gl.glDeleteTextures(frag) # Delete the corresponding entries in our meta variables. # gl.glDeleteBuffers(2, [1, 2]) self._removeObjectData(objID) # The previous loop removed objects that do not exist anymore in # Azrael. This loop adds objects that now exist in Azrael but not yet # in our scene. for objID in list(self.newSVs.keys()): # Do not add anything if it is the player object itself. if objID == self.player_id: continue # Skip the object if we already have its model, unless the model # changed. if (objID in self.oldSVs) and not self.hasGeometryChanged(objID): continue # Download the latest geometry for this object; skip it if the # object does not exist (anymore). ret = self.client.getFragments([objID]) if not ret.ok or ret.data is None or ret.data[objID] is None: self._removeObjectData(objID) continue # Fetch fragment model from Azrael and pass it to the GPU. base_url = 'http://{}:{}'.format(self.addr_clerk, self.port_webapi) for fragID, frag_data in ret.data[objID].items(): if frag_data['fragtype'] == 'RAW': url = base_url + frag_data['url_frag'] + '/model.json' frag = requests.get(url).content if len(frag) == 0: self._removeObjectData(objID) break frag = json.loads(frag.decode('utf8')) frag = getFragMetaRaw(frag['vert'], frag['uv'], frag['rgb'], frag['width'], frag['height']) elif frag_data['fragtype'] == 'DAE': url = base_url + frag_data['url_frag'] + '/' + fragID frag = requests.get(url).content if len(frag) == 0: self._removeObjectData(objID) break with tempfile.TemporaryDirectory() as tmpdir: open('model.dae', 'wb').write(frag) mesh = model_import.loadModelAll('model.dae') # The model may contain several sub-models. Each one has a # set of vertices, UV- and texture maps. The following code # simply flattens the three list-of-lists into three plain # lists. vert = np.array(mesh['vertices']).flatten() uv = np.array(mesh['UV']).flatten() rgb = np.array(mesh['RGB']).flatten() width = height = None # Ensure the data has the correct format. vert = np.array(vert) uv = np.array(uv, np.float32) rgb = np.array(rgb, np.uint8) frag = getFragMetaRaw(vert, uv, rgb, width, height) elif frag_data['fragtype'] == '3JS_V3': # Model files in 3JS format. These are stored in a main # JSON file plus (optional) texture files. Find the JSON # file and log an error if there is not exactly one. fnames = [ _ for _ in frag_data['files'] if _.lower().endswith('.json') ] if len(fnames) != 1: print('{} possible 3JS model candidates'.format( len(fnames))) break # Download the model. url = base_url + frag_data['url_frag'] + '/' + fnames[0] frag = requests.get(url).content if len(frag) == 0: self._removeObjectData(objID) break frag = json.loads(frag.decode('utf8')) vert, uv, rgb = demolib.load3JSModel(frag) # Download a texture file (if the model has one). fnames = [ _ for _ in frag_data['files'] if _.lower().endswith('.jpg') ] if len(fnames) > 0: print('found texture') url = base_url + frag_data['url_frag'] + '/' + fnames[0] texture = requests.get(url).content assert len(texture) > 0 with tempfile.TemporaryDirectory() as tmpdir: open('texture.jpg', 'wb').write(texture) img = PIL.Image.open(fnames[0]) width, height = img.size img = np.array(img) rgb = np.rollaxis(np.flipud(img), 1).flatten() print('imported texture {}'.format(url)) del img del url, texture del fnames frag = getFragMetaRaw(vert, uv, rgb, width, height) else: continue self.upload2GPU(objID, fragID, frag) # Only draw visible triangles for this fragment. gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthFunc(gl.GL_LESS)