def test_setFragments_dae(self, client_type): """ Spawn a new object and modify its geometry at runtime. """ # Get the client for this test. client = self.clients[client_type] # Get a Collada fragment. f_dae = {'f_dae': getFragDae()} # Add a new template and spawn it. temp = getTemplate('t1', fragments=f_dae) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) objID = ret.data[0] assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the body states to obtain the 'version' value. ret = client.getRigidBodies(objID) assert ret.ok version = ret.data[objID]['rbs'].version # Fetch-, modify-, update- and verify the geometry. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'DAE' # Change the geometry for fragment 'f_dae' to a RAW type. assert client.setFragments({objID: {'f_dae': getFragRaw()._asdict()}}).ok # Ensure the fragment is now indeed of type 'RAW'. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'RAW' # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version) # Change the fragment geometry once more. version = ret.data[objID]['rbs'].version assert client.setFragments({objID: {'f_dae': getFragDae()._asdict()}}).ok # Ensure it now has type 'DAE' again. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'DAE' # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version)
def test_remove_fragments(self, client_type): """ Remove a fragment. This test is basically the integration test for 'test_dibbler.test_updateFragments_partial'. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # The original template has the following three fragments: frags_orig = { 'fname_1': getFragRaw(), 'fname_2': getFragDae(), 'fname_3': getFragRaw(), } t1 = getTemplate('t1', fragments=frags_orig) # Add a new template and spawn it. assert client.addTemplates([t1]).ok new_obj = {'templateID': t1.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} assert client.spawn([new_obj]) == (True, None, [objID]) # Query the fragment geometries and Body State to verify that both # report three fragments. ret = client.getFragments([objID]) assert ret.ok and len(ret.data[objID]) == 3 ret = client.getObjectStates(objID) assert ret.ok and len(ret.data[objID]['frag']) == 3 # Update the fragments as follows: keep the first intact, remove the # second, and modify the third one. frags_new = { 'fname_2': getFragNone()._asdict(), 'fname_3': getFragDae()._asdict() } assert client.setFragments({objID: frags_new}).ok # After the last update there must now only be two fragments. ret = client.getFragments([objID]) assert ret.ok and len(ret.data[objID]) == 2 ret = client.getObjectStates(objID) assert ret.ok and len(ret.data[objID]['frag']) == 2
def test_update_FragmentStates(self, client_type): """ Query and modify fragment states. Note that fragment states are updated via 'setFragments'. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # Add a new template and spawn it. temp = getTemplate('t1', fragments={'bar': getFragRaw()}) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the Body State to get the Fragment States. Then verify the # Fragment State named 'bar'. ret = client.getObjectStates(objID) ref = {'bar': {'scale': 1, 'position': [0, 0, 0], 'rotation': [0, 0, 0, 1]}} assert ret.ok assert ret.data[objID]['frag'] == ref # Modify and update the fragment states in Azrael, then query and # verify it worked. newStates = {objID: {'bar': {'scale': 2.2, 'position': [1, 2, 3], 'rotation': [1, 0, 0, 0]}}} assert client.setFragments(newStates).ok ret = client.getObjectStates(objID) assert ret.ok ret = ret.data[objID]['frag']['bar'] assert ret == newStates[objID]['bar']
def placeTarget(host, numTargets=1): """ Spawn ``numTargets`` in the scene. The targets visually oscillate in size. They also have no collision shapes and are thus unaffected by physics (ie they cannot collide with anything). """ # Connect to Azrael. client = azrael.client.Client(ip=host) # Spawn the target object from the 'BoosterCube_1' template (defined in # 'demo_boostercube' that must already be running at this point). init = [] for ii in range(numTargets): tmp = { 'templateID': 'BoosterCube_1', 'rbs': {'imass': 0, 'position': (0, 0, 3 * ii)} } init.append(tmp) ret = client.spawn(init) # Check for errors and abort if there are any. if not ret.ok: print(ret) sys.exit(1) # Extract the IDs of the spawned target objects. targetIDs = ret.data print('Spawned {} targets'.format(len(targetIDs))) del init, ret # Replace the collision shape with an empty one to disable the physics for # those targets. cs = types.CollShapeEmpty() cs = types.CollShapeMeta('empty', (0, 0, 0), (0, 0, 0, 1), cs) cmd = {targetID: {'cshapes': {'cssphere': cs}} for targetID in targetIDs} assert client.setRigidBodies(cmd).ok del cs # Tag the object with target. This is necessary because the # `PyConBrisbaneClient.selectNewTarget` method will use to distinguish # targets from other objects. cmd = {targetID: 'Target' for targetID in targetIDs} assert client.setCustomData(cmd) # Create a random phase offset in the oscillation pattern (pure eye candy # to avoid all targets scale synchronously). phi = 2 * np.pi * np.random.rand(len(targetIDs)) # Modify the scale of the target every 100ms. cnt = 0 while True: time.sleep(0.1) # Compile the payload for the update command, then send it to Azrael. # The fragment names (eg 'frag_1') are hard coded in the Template # (don't worry about them, just accept that they exist). cmd = {} for idx, targetID in enumerate(targetIDs): # Compute the new scale value. scale = 1 + np.sin(2 * np.pi * 0.1 * cnt + phi[idx]) scale *= 0.1 tmp = { 'frag_1': {'scale': scale}, 'frag_2': {'scale': scale}, } cmd[targetID] = tmp assert client.setFragments(cmd).ok # Randomly update the target's position every 10s. if (cnt % 100) == 0: cmd = {} for targetID in targetIDs: pos = 15 * np.random.rand(3) - 10 cmd[targetID] = {'position': pos.tolist()} assert client.setRigidBodies(cmd).ok cnt += 1
def test_setFragments_raw(self, client_type): """ Spawn a new object and modify its geometry at runtime. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # Add a new template and spawn it. frag = {'bar': getFragRaw()} temp = getTemplate('t1', fragments=frag) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the SV to obtain the 'version' value. ret = client.getRigidBodies(objID) assert ret.ok version = ret.data[objID]['rbs'].version # Fetch-, modify-, update- and verify the geometry. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['bar']['fragtype'] == 'RAW' # Download the fragment. base_url = 'http://{ip}:{port}'.format( ip=config.addr_webserver, port=config.port_webserver) url = base_url + ret.data[objID]['bar']['url_frag'] + '/model.json' for ii in range(10): assert ii < 8 try: tmp = urllib.request.urlopen(url).readall() break except urllib.request.URLError: time.sleep(0.2) tmp = json.loads(tmp.decode('utf8')) assert FragRaw(**tmp) == frag['bar'].fragdata # Change the fragment geometries. cmd = {objID: {k: v._asdict() for (k, v) in frag.items()}} assert client.setFragments(cmd).ok ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['bar']['fragtype'] == 'RAW' # Download the fragment. url = base_url + ret.data[objID]['bar']['url_frag'] + '/model.json' tmp = urllib.request.urlopen(url).readall() tmp = json.loads(tmp.decode('utf8')) assert FragRaw(**tmp) == frag['bar'].fragdata # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version)
def spawnCubes(numCols, numRows, numLayers, center=(0, 0, 0)): """ Spawn multiple cubes in a regular grid. The number of cubes equals ``numCols`` * ``numRows`` * ``numLayers``. The center of this "prism" is at ``center``. Every cube has two boosters and two factories. The factories can themselves spawn more (purely passive) cubes. """ tID_cube = addTexturedCubeTemplates(numCols, numRows, numLayers) # Get a Client instance. client = azrael.client.Client() # ---------------------------------------------------------------------- # Spawn the differently textured cubes in a regular grid. # ---------------------------------------------------------------------- allObjs = [] cube_idx = 0 cube_spacing = 0.1 # Determine the template and position for every cube. The cubes are *not* # spawned in this loop, but afterwards. print("Compiling scene: ", end="", flush=True) t0 = time.time() for row in range(numRows): for col in range(numCols): for lay in range(numLayers): # Base position of cube. pos = np.array([col, row, lay], np.float64) # Add space in between cubes. pos *= -(2 + cube_spacing) # Correct the cube's position to ensure the center of the # grid coincides with the origin. pos[0] += (numCols // 2) * (1 + cube_spacing) pos[1] += (numRows // 2) * (1 + cube_spacing) pos[2] += (numLayers // 2) * (1 + cube_spacing) # Move the grid to position ``center``. pos += np.array(center) # Store the position and template for this cube. allObjs.append({"templateID": tID_cube[cube_idx], "rbs": {"position": pos.tolist()}}) cube_idx += 1 del pos print("{:,} objects ({:.1f}s)".format(len(allObjs), time.time() - t0)) del cube_idx, cube_spacing, row, col, lay # Spawn the cubes from the templates at the just determined positions. print("Spawning {} objects: ".format(len(allObjs)), end="", flush=True) t0 = time.time() ret = client.spawn(allObjs) if not ret.ok: print("** Error:") print(ret) assert False print(" {:.1f}s".format(time.time() - t0)) # Make 'frag_2' invisible by setting its scale to zero. for objID in ret.data: assert client.setFragments({objID: {"frag_2": {"scale": 0}}}).ok assert client.setCustomData({objID: "asteroid"}).ok
def addBoosterCubeTemplate(scale, vert, uv, rgb): # Get a Client instance. client = azrael.client.Client() # Ensure the data has the correct format. vert = scale * np.array(vert) uv = np.array(uv, np.float32) rgb = np.array(rgb, np.uint8) print("done") # Attach four boosters: left (points down), front (points back), right # (points up), and back (point forward). dir_up = np.array([0, +1, 0]) dir_forward = np.array([0, 0, -1]) pos_left = np.array([-1.5, 0, 0]) pos_center = np.zeros(3) boosters = { "0": types.Booster(pos=pos_left, direction=-dir_up, minval=0, maxval=10.0, force=0), "1": types.Booster(pos=pos_center, direction=dir_forward, minval=0, maxval=1000.0, force=0), "2": types.Booster(pos=-pos_left, direction=dir_up, minval=0, maxval=10.0, force=0), "3": types.Booster(pos=pos_center, direction=-dir_forward, minval=0, maxval=1000.0, force=0), } del dir_up, dir_forward, pos_left, pos_center # Construct a Tetrahedron (triangular Pyramid). This is going to be the # (super simple) "flame" that comes out of the (still invisible) boosters. y = 0.5 * np.arctan(np.pi / 6) a = (-0.5, -y, 1) b = (0.5, -y, 1) c = (0, 3 / 4 - y, 1) d = (0, 0, 0) vert_b = [(a + b + c) + (a + b + d) + (a + c + d) + (b + c + d)] vert_b = np.array(vert_b[0], np.float64) del a, b, c, d, y # Add the template to Azrael. print(" Adding template to Azrael... ", end="", flush=True) tID = "ground" cs = CollShapeBox(1, 1, 1) cs = CollShapeMeta("box", (0, 0, 0), (0, 0, 0, 1), cs) z = np.array([]) frags = { "frag_1": getFragMeta("raw", FragRaw(vert, uv, rgb)), "b_left": getFragMeta("raw", FragRaw(vert_b, z, z)), "b_right": getFragMeta("raw", FragRaw(vert_b, z, z)), } body = getRigidBody() temp = Template(tID, body, frags, boosters, {}) assert client.addTemplates([temp]).ok del cs, frags, temp, z print("done") # Spawn the template near the center. print(" Spawning object... ", end="", flush=True) pos, orient = [0, 0, -10], [0, 1, 0, 0] new_obj = { "templateID": tID, "rbs": { "scale": scale, "imass": 0.1, "position": pos, "rotation": orient, "axesLockLin": [1, 1, 1], "axesLockRot": [1, 1, 1], }, } ret = client.spawn([new_obj]) objID = ret.data[0] print("done (ID=<{}>)".format(objID)) # Disable the booster fragments by settings their scale to Zero. newStates = {objID: {"b_left": {"scale": 0}, "b_right": {"scale": 0}}} assert client.setFragments(newStates).ok