def spawnSpaceship(scale, fname):
    """
    Define a sphere with three boosters and four fragments.

    The first fragment comprises the hull (ie. the sphere itself), whereas
    remaining three fragments reprsent the "flames" that come out of the
    boosters.
    """
    # Get a Client instance.
    client = pyazrael.AzraelClient()

    # Load the model.
    vert, uv, rgb = demolib.loadBoosterCubeBlender()
    frag_cube = demolib.compileRawFragment(vert, uv, rgb)
    del vert, uv, rgb

    # Attach six boosters, two for every axis.
    dir_x = np.array([1, 0, 0])
    dir_y = np.array([0, 1, 0])
    dir_z = np.array([0, 0, 1])
    pos = (0, 0, 0)
    B = aztypes.Booster
    boosters = {
        'b_x': B(pos, direction=(1, 0, 0), force=0),
        'b_y': B(pos, direction=(0, 1, 0), force=0),
        'b_z': B(pos, direction=(0, 0, 1), force=0)
    }
    del dir_x, dir_y, dir_z, pos, B

    # Load sphere and color it blue(ish). This is going to be the (super
    # simple) "flame" that comes out of the (still invisible) boosters.
    p = os.path.dirname(os.path.abspath(__file__))
    fname = os.path.join(p, 'models', 'sphere', 'sphere.obj')
    vert, uv, rgb = demolib.loadModel(fname)
    rgb = np.tile([0, 0, 0.8], len(vert) // 3)
    rgb += 0.2 * np.random.rand(len(rgb))
    rgb = np.array(255 * rgb.clip(0, 1), np.uint8)
    frag_flame = demolib.compileRawFragment(vert, np.array([]), rgb)
    del p, fname, vert, uv, rgb

    # Add the template to Azrael.
    print('  Adding template to Azrael... ', end='', flush=True)
    tID = 'spaceship'
    cs = aztypes.CollShapeBox(scale, scale, scale)
    cs = aztypes.CollShapeMeta('box', (0, 0, 0), (0, 0, 0, 1), cs)
    body = demolib.getRigidBody(cshapes={'0': cs})
    pos, rot = (0, 0, 0), (0, 0, 0, 1)
    frags = {
        'frag_1': FragMeta('raw', scale, pos, rot, frag_cube),
        'b_x': FragMeta('raw', 0, pos, rot, frag_flame),
        'b_y': FragMeta('raw', 0, pos, rot, frag_flame),
        'b_z': FragMeta('raw', 0, pos, rot, frag_flame),
    }
    temp = Template(tID, body, frags, boosters, {})
    assert client.addTemplates([temp]).ok
    del cs, frags, temp, frag_cube, frag_flame, scale, pos, rot
    print('done')
Example #2
0
    def _initializeGL(self):
        """
        Create the graphic buffers and compile the shaders.
        """
        # Connect to Azrael.
        self.client = pyazrael.AzraelClient(self.addr_clerk, self.port_clerk)

        print('Client connected')

        # Define a template for projectiles.
        self.defineProjectileTemplate()

        # Create the camera and place it (in the z-direction) between the
        # Cubes and Sphere generated  by the 'start' script, but out of their
        # way to the side.
        initPos = [0, 0, 10]
        self.camera = Camera(initPos, np.pi, 0)

        # Spawn the player object (it has the same shape as a projectile).
        if self.show_player:
            ret = self.client.spawn([{
                'templateID': 'player',
                'rbs': {
                    'position': initPos
                }
            }])
            if ret.ok:
                self.player_id = ret.data[0]
                print('Spawned player object <{}>'.format(self.player_id))
            else:
                print('Could not spawn player object (<{}>)'.format(ret.data))
                self.close()
        else:
            self.player_id = None

        # Initialise instance variables.
        self.numVertices = {}
        self.vertex_array_object = {}
        self.textureBuffer = {}
        self.shaderDict = {}

        # Background color.
        gl.glClearColor(0, 0, 0, 0)

        # Put the two possible shaders into dictionaries.
        fdir = os.path.dirname(os.path.abspath(__file__))
        vs = os.path.join(fdir, 'shaders/passthrough.vs')
        fs = os.path.join(fdir, 'shaders/passthrough.fs')
        self.shaderDict['passthrough'] = self.linkShaders(vs, fs)

        vs = os.path.join(fdir, 'shaders/uv.vs')
        fs = os.path.join(fdir, 'shaders/uv.fs')
        self.shaderDict['uv'] = self.linkShaders(vs, fs)

        # Load and compile all objects.
        self.loadGeometry()
Example #3
0
    def __init__(self, host, port=5555):
        # Connect to Azrael.
        self.client = pyazrael.AzraelClient(host, port)

        # Ping Azrael. This call will block if it cannot connect.
        ret = self.client.ping()
        if not ret.ok:
            print('Could not connect to Azrael')
            assert False
        print('Connected to Azrael')

        # Initialise the ID of the target object (for now we have none). The
        # controller will attempt to match the position of that target when
        # this script was started with the 'ship' option (see main function).
        self.targetID = None
    def __init__(self, host, port=5555):
        self.shipID = None

        # Connect to Azrael.
        self.client = pyazrael.AzraelClient(addr_clerk=host, port_clerk=port)

        # Ping Azrael. This call will block if it cannot connect.
        ret = self.client.ping()
        if not ret.ok:
            print('Could not connect to Azrael')
            assert False
        print('Connected to Azrael')

        print('Adding template for this ship...', flush=True, end='')
        template = BoostercubeTemplate(scale=1.0)
        self.client.addTemplates([template])
        print('done')
Example #5
0
    def run(self):
        # Return immediately if no resets are required.
        if self.period == -1:
            return

        # Establish connection to Azrael.
        client = pyazrael.AzraelClient()

        # Query all objects in the scene. These are the only objects that will
        # survive the reset.
        ret = client.getAllObjectIDs()
        assert ret.ok
        ret = client.getRigidBodyData(ret.data)
        assert ret.ok
        allowed_objIDs = {k: v['rbs'] for k, v in ret.data.items()
                          if v is not None}
        print('Took simulation snapshot for reset: ({} objects)'
              .format(len(allowed_objIDs)))

        # Periodically reset the SV values. Set them several times because it
        # is well possible that not all State Variables reach Leonard in the
        # same frame, which means some objects will be reset while other are
        # not. This in turn may cause strange artefacts in the next physics
        # update step, especially when the objects now partially overlap.
        while True:
            # Wait until the timeout expires.
            time.sleep(self.period)

            # Remove all newly added objects.
            ret = client.getAllObjectIDs()
            for objID in ret.data:
                if objID not in allowed_objIDs:
                    client.removeObjects([objID])

            # Forcefully reset the position and velocity of every object. Do
            # this several times since network latency may result in some
            # objects being reset sooner than others.
            for ii in range(5):
                for objID, SV in allowed_objIDs.items():
                    tmp = {
                        'position': SV.position,
                        'velocityLin': SV.velocityLin,
                        'velocityRot': SV.velocityRot,
                        'rotation': SV.rotation}
                    assert client.setRigidBodyData({objID: tmp}).ok
                time.sleep(0.1)
Example #6
0
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 = pyazrael.AzraelClient()

    # ----------------------------------------------------------------------
    # Spawn the differently textured cubes in a regular grid.
    # ----------------------------------------------------------------------
    # The cubes currently have a size of 2. The grid spacing must thus be
    # larger than 2 if the cubes are not to touch each other.
    cube_size = 2 + 0.1

    # Compute the grid position. The grid is centered at `center`.
    positions = np.array(list(np.ndindex(numCols, numRows, numLayers)))
    positions = positions - np.mean(positions, axis=0)
    positions = positions * cube_size + center

    # Specify the initial state for each cube and spawn them.
    t0 = time.time()
    allObjs = [
        {'templateID': tID_cube[idx], 'rbs': {'position': pos.tolist()}}
        for idx, pos in enumerate(positions)
    ]
    print('Spawning {} objects: '.format(len(allObjs)), end='', flush=True)
    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:
        cmd = {objID: {'frag_2': {'op': 'mod', 'scale': 0}}}
        assert client.setFragments(cmd).ok
        assert client.setObjectTags({objID: 'asteroid'}).ok
Example #7
0
def resetSimulation(host, port=5555):
    """
    Delete all objects in the scene.

    Azrael does not have a command to do that (yet), which is why this function
    queries all objects and the deletes them one-by-one.

    The `host` and `port` parameters specify the location of the Azrael API.
    """
    # Connect to Azrael.
    client = pyazrael.AzraelClient(host, port=port)

    # Query IDs of all objects in the simulation.
    ret = client.getAllObjectIDs()
    assert ret.ok
    allIDs = ret.data

    # Delete all objects.
    for objID in allIDs:
        assert client.removeObjects([objID]).ok
Example #8
0
def main():
    # Parse the command line.
    param = parseCommandLine()

    # Guess Azrael's IP address on the local computer.
    host = demolib.azService['clerk'].ip
    print('Assuming Azrael services on <{}>'.format(host))

    # Helper class to start/stop Azrael stack and other processes.
    az = azrael.startup.AzraelStack(param.loglevel)
    az.start()
    print('Azrael now live')

    # Connect to Azrael.
    client = pyazrael.AzraelClient(host)

    # Create the template for the asteroid and spawn one instance.
    asteroidID = spawnAsteroid(client)

    # Create the template for our ship and spawn one instance thereof.
    rosetta = Rosetta(host)
    rosetta.spawn((0, 50, -100))

    # Start the Qt viewer unless the user specified '--noviewer'.
    if param.noviewer:
        viewer = None
    else:
        viewer = demolib.launchQtViewer()

    # Conduct the Rosetta mission.
    conductMission(client, viewer, asteroidID, rosetta)

    # Stop Azrael stack and exit.
    rosetta.removeShip()
    az.stop()
    print('Clean shutdown')
def BoostercubeTemplate(scale=1.0):
    """
    Return template for BoosterCube.
    """
    # Get a Client instance.
    client = pyazrael.AzraelClient()

    # Load the model.
    vert, uv, rgb = demolib.loadBoosterCubeBlender()
    frag_cube = {
        'vert': vert,
        'uv': uv,
        'rgb': rgb,
        'scale': scale,
        'pos': (0, 0, 0),
        'rot': (0, 0, 0, 1)
    }
    del vert, uv, rgb

    # Attach six boosters, two for every axis.
    dir_x = np.array([1, 0, 0])
    dir_y = np.array([0, 1, 0])
    dir_z = np.array([0, 0, 1])
    pos = (0, 0, 0)
    B = aztypes.Booster
    boosters = {
        'b_x': B(pos, direction=(1, 0, 0), force=0),
        'b_y': B(pos, direction=(0, 1, 0), force=0),
        'b_z': B(pos, direction=(0, 0, 1), force=0)
    }
    del dir_x, dir_y, dir_z, pos, B

    # Load sphere and colour it blue(ish). This is going to be the (super
    # simple) "flame" that comes out of the (still invisible) boosters.
    p = os.path.dirname(os.path.abspath(__file__))
    fname = os.path.join(p, 'models', 'sphere', 'sphere.obj')
    vert, uv, rgb = demolib.loadModel(fname)
    rgb = np.tile([0, 0, 0.8], len(vert) // 3)
    rgb += 0.2 * np.random.rand(len(rgb))
    rgb = np.array(255 * rgb.clip(0, 1), np.uint8)
    frag_flame = {
        'vert': vert,
        'uv': [],
        'rgb': rgb,
        'pos': (0, 0, 0),
        'rot': (0, 0, 0, 1)
    }
    del p, fname, vert, uv, rgb

    # Add the template to Azrael.
    tID = 'spaceship'
    cs = aztypes.CollShapeBox(scale, scale, scale)
    cs = aztypes.CollShapeMeta('box', (0, 0, 0), (0, 0, 0, 1), cs)
    body = demolib.getRigidBody(cshapes={'0': cs})
    frags = {
        'frag_1': demolib.getFragMetaRaw(**frag_cube),
        'b_x': demolib.getFragMetaRaw(**frag_flame),
        'b_y': demolib.getFragMetaRaw(**frag_flame),
        'b_z': demolib.getFragMetaRaw(**frag_flame),
    }
    template = Template(tID, body, frags, boosters, {})
    return template
Example #10
0
def addBoosterCubeTemplate(scale, vert, uv, rgb):
    # Get a Client instance.
    client = pyazrael.AzraelClient()

    # 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': aztypes.Booster(position=pos_left, direction=-dir_up, force=0),
        '1': aztypes.Booster(position=pos_center, direction=dir_forward, force=0),
        '2': aztypes.Booster(position=-pos_left, direction=dir_up, force=0),
        '3': aztypes.Booster(position=pos_center, direction=-dir_forward, 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': demolib.getFragMetaRaw(vert, uv, rgb),
        'b_left': demolib.getFragMetaRaw(vert_b, z, z),
        'b_right': demolib.getFragMetaRaw(vert_b, z, z),
    }

    body = demolib.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,
            'linFactor': [1, 1, 1],
            'rotFactor': [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': {'op': 'mod', 'scale': 0},
        'b_right': {'op': 'mod', 'scale': 0},
    }}
    assert client.setFragments(newStates).ok
Example #11
0
def addTexturedCubeTemplates(numCols, numRows, numLayers):
    # Get a Client instance.
    client = pyazrael.AzraelClient()

    # Geometry and collision shape for cube.
    vert, cs = demolib.cubeGeometry()

    # Assign the UV coordinates. Each vertex needs a coordinate pair. That
    # means each triangle needs 6 coordinates. And the cube has 12 triangles.
    uv = np.zeros(12 * 6, np.float64)
    uv[0:6] = [0, 0, 1, 0, 1, 1]
    uv[6:12] = [0, 0, 1, 1, 0, 1]
    uv[12:18] = [1, 0, 0, 1, 0, 0]
    uv[18:24] = [1, 0, 1, 1, 0, 1]
    uv[24:30] = [0, 0, 1, 1, 0, 1]
    uv[30:36] = [0, 0, 1, 0, 1, 1]
    uv[36:42] = [1, 1, 1, 0, 0, 0]
    uv[42:48] = [1, 1, 0, 0, 0, 1]
    uv[48:54] = [0, 1, 1, 0, 1, 1]
    uv[54:60] = [0, 1, 0, 0, 1, 0]
    uv[60:66] = [0, 1, 0, 0, 1, 0]
    uv[66:72] = [1, 1, 0, 1, 1, 0]

    uv = np.array(uv, np.float64)

    # Compile the path to the texture file.
    path_base = os.path.dirname(os.path.abspath(__file__))
    path_base = os.path.join(path_base, '..', 'azrael', 'static', 'img')
    fname = os.path.join(path_base, 'texture_5.jpg')

    # Load the texture and convert it to a flat vector because this is how
    # OpenGL will want it.
    img = PIL.Image.open(fname)
    img = np.array(img)
    rgb = np.rollaxis(np.flipud(img), 1)

    # ----------------------------------------------------------------------
    # Create templates for the factory output.
    # ----------------------------------------------------------------------
    tID_1 = 'Product1'
    tID_2 = 'Product2'
    frags_1 = {'frag_1': demolib.getFragMetaRaw(0.75 * vert, uv, rgb)}
    frags_2 = {'frag_1': demolib.getFragMetaRaw(0.24 * vert, uv, rgb)}
    body = demolib.getRigidBody(cshapes={'0': cs})
    t1 = Template(tID_1, body, frags_1, {}, {})
    t2 = Template(tID_2, body, frags_2, {}, {})
    assert client.addTemplates([t1, t2]).ok
    del frags_1, frags_2, t1, t2

    # ----------------------------------------------------------------------
    # Define a cube with boosters and factories.
    # ----------------------------------------------------------------------
    # Two boosters, one left, one right. Both point in the same direction.
    boosters = {
        '0': aztypes.Booster(position=[+0.05, 0, 0], direction=[0, 0, 1], force=0),
        '1': aztypes.Booster(position=[-0.05, 0, 0], direction=[0, 0, 1], force=0)
    }

    # Two factories, one left one right. They will eject the new objects
    # forwards and backwards, respectively.
    factories = {
        '0': aztypes.Factory(position=[+1.5, 0, 0], direction=[+1, 0, 0],
                             templateID=tID_1, exit_speed=[0.1, 1]),
        '1': aztypes.Factory(position=[-1.5, 0, 0], direction=[-1, 0, 0],
                             templateID=tID_2, exit_speed=[0.1, 1])
    }

    # Add the template.
    tID_3 = 'BoosterCube'
    frags = {'frag_1': demolib.getFragMetaRaw(vert, uv, rgb)}
    body = demolib.getRigidBody(cshapes={'0': cs})
    t3 = Template(tID_3, body, frags, boosters, factories)
    assert client.addTemplates([t3]).ok
    del frags, t3

    # ----------------------------------------------------------------------
    # Define more booster cubes, each with a different texture.
    # ----------------------------------------------------------------------
    tID_cube = {}
    templates = []
    texture_errors = 0
    for ii in range(numRows * numCols * numLayers):
        # File name of texture.
        fname = os.path.join(path_base, 'texture_{}.jpg'.format(ii + 1))

        # Load the texture image. If the image is unavailable do not endow the
        # cube with a texture.
        try:
            img = PIL.Image.open(fname)
            img = np.array(img)
            rgb = np.rollaxis(np.flipud(img), 1)
            curUV = uv
        except FileNotFoundError:
            texture_errors += 1
            rgb = curUV = np.array([])

        # Create the template.
        tID = ('BoosterCube_{}'.format(ii))
        frags = {'frag_1': demolib.getFragMetaRaw(vert, curUV, rgb),
                 'frag_2': demolib.getFragMetaRaw(vert, curUV, rgb)}
        body = demolib.getRigidBody(cshapes={'0': cs})
        tmp = Template(tID, body, frags, boosters, {})
        templates.append(tmp)

        # Add the templateID to a dictionary because we will need it in the
        # next step to spawn the templates.
        tID_cube[ii] = tID
        del frags, tmp, tID, fname

    if texture_errors > 0:
        print('Could not load texture for {} of the {} objects'
              .format(texture_errors, ii + 1))

    # Define all templates.
    print('Adding {} templates: '.format(ii + 1), end='', flush=True)
    t0 = time.time()
    assert client.addTemplates(templates).ok
    print('{:.1f}s'.format(time.time() - t0))
    return tID_cube
Example #12
0
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.
    """
    # Get a Client instance.
    client = pyazrael.AzraelClient()

    # Geometry and collision shape for cube.
    vert, cs = demolib.cubeGeometry()

    # Assign the UV coordinates. Each vertex needs a coordinate pair. That
    # means each triangle needs 6 coordinates. And the cube has 12 triangles.
    uv = np.zeros(12 * 6, np.float64)
    uv[0:6] = [0, 0, 1, 0, 1, 1]
    uv[6:12] = [0, 0, 1, 1, 0, 1]
    uv[12:18] = [1, 0, 0, 1, 0, 0]
    uv[18:24] = [1, 0, 1, 1, 0, 1]
    uv[24:30] = [0, 0, 1, 1, 0, 1]
    uv[30:36] = [0, 0, 1, 0, 1, 1]
    uv[36:42] = [1, 1, 1, 0, 0, 0]
    uv[42:48] = [1, 1, 0, 0, 0, 1]
    uv[48:54] = [0, 1, 1, 0, 1, 1]
    uv[54:60] = [0, 1, 0, 0, 1, 0]
    uv[60:66] = [0, 1, 0, 0, 1, 0]
    uv[66:72] = [1, 1, 0, 1, 1, 0]

    uv = np.array(uv, np.float64)

    # Compile the path to the texture file.
    path_base = os.path.dirname(os.path.abspath(__file__))
    path_base = os.path.join(path_base, '..', 'azrael', 'static', 'img')
    fname = os.path.join(path_base, 'texture_5.jpg')

    # Load the texture and convert it to flat vector because this is how OpenGL
    # will want it.
    img = PIL.Image.open(fname)
    img = np.array(img)
    rgb = np.rollaxis(np.flipud(img), 1).flatten()

    # ----------------------------------------------------------------------
    # Define a cube with boosters and factories.
    # ----------------------------------------------------------------------
    # Two boosters, one left, one right. Both point in the same direction.
    boosters = {
        '0': aztypes.Booster(position=[+0.05, 0, 0],
                             direction=[0, 0, 1],
                             force=0),
        '1': aztypes.Booster(position=[-0.05, 0, 0],
                             direction=[0, 0, 1],
                             force=0)
    }

    # ----------------------------------------------------------------------
    # Define more booster cubes, each with a different texture.
    # ----------------------------------------------------------------------
    tID_cube = {}
    templates = []
    texture_errors = 0
    for ii in range(numRows * numCols * numLayers):
        # File name of texture.
        fname = os.path.join(path_base, 'texture_{}.jpg'.format(ii + 1))

        # Load the texture image. If the image is unavailable do not endow the
        # cube with a texture.
        try:
            img = PIL.Image.open(fname)
            img = np.array(img)
            rgb = np.rollaxis(np.flipud(img), 1)
            curUV = uv
        except FileNotFoundError:
            texture_errors += 1
            rgb = curUV = np.array([])

        # Create the template.
        tID = ('BoosterCube_{}'.format(ii))
        frags = {
            'frag_1': demolib.getFragMetaRaw(vert, curUV, rgb),
            'frag_2': demolib.getFragMetaRaw(vert, curUV, rgb)
        }
        body = demolib.getRigidBody(cshapes={'0': cs})
        tmp = Template(tID, body, frags, boosters, {})
        templates.append(tmp)

        # Add the templateID to a dictionary because we will need it in the
        # next step to spawn the templates.
        tID_cube[ii] = tID
        del frags, tmp, tID, fname

    if texture_errors > 0:
        print('Could not load texture for {} of the {} objects'.format(
            texture_errors, ii + 1))

    # Define all templates.
    print('Adding {} templates: '.format(ii + 1), end='', flush=True)
    t0 = time.time()
    assert client.addTemplates(templates).ok
    print('{:.1f}s'.format(time.time() - t0))

    # ----------------------------------------------------------------------
    # Spawn the differently textured cubes in a regular grid.
    # ----------------------------------------------------------------------
    allObjs = []
    cube_idx = 0
    cube_spacing = 0.0

    # 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 *= -(4 + 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({
                    'template': tID_cube[cube_idx],
                    'position': pos
                })
                cube_idx += 1
                del pos

    # Since the first four cubes will be chained together we need at least four
    # of them!
    assert len(allObjs) >= 4

    allObjs = []
    pos_0 = [2, 0, -10]
    pos_1 = [-2, 0, -10]
    pos_2 = [-6, 0, -10]
    pos_3 = [-10, 0, -10]
    allObjs.append({'templateID': tID_cube[0], 'rbs': {'position': pos_0}})
    allObjs.append({'templateID': tID_cube[1], 'rbs': {'position': pos_1}})
    allObjs.append({'templateID': tID_cube[2], 'rbs': {'position': pos_2}})
    allObjs.append({'templateID': tID_cube[3], 'rbs': {'position': pos_3}})

    # The first object cannot move (only rotate). It serves as an anchor for
    # the connected bodies.
    allObjs[0]['rbs']['linFactor'] = [0, 0, 0]
    allObjs[0]['rbs']['rotFactor'] = [1, 1, 1]

    # Add a small damping factor to all bodies to avoid them moving around
    # perpetually.
    for oo in allObjs[1:]:
        oo['rbs']['linFactor'] = [0.9, 0.9, 0.9]
        oo['rbs']['rotFactor'] = [0.9, 0.9, 0.9]

    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)
    assert ret.ok
    objIDs = ret.data
    print('{:.1f}s'.format(time.time() - t0))

    # Define the constraints.
    p2p_0 = ConstraintP2P(pivot_a=[-2, 0, 0], pivot_b=[2, 0, 0])
    p2p_1 = ConstraintP2P(pivot_a=[-2, 0, 0], pivot_b=[2, 0, 0])
    p2p_2 = ConstraintP2P(pivot_a=[-2, 0, 0], pivot_b=[2, 0, 0])
    dof = Constraint6DofSpring2(
        frameInA=[0, 0, 0, 0, 0, 0, 1],
        frameInB=[0, 0, 0, 0, 0, 0, 1],
        stiffness=[2, 2, 2, 1, 1, 1],
        damping=[1, 1, 1, 1, 1, 1],
        equilibrium=[-2, -2, -2, 0, 0, 0],
        linLimitLo=[-4.5, -4.5, -4.5],
        linLimitHi=[4.5, 4.5, 4.5],
        rotLimitLo=[-0.1, -0.2, -0.3],
        rotLimitHi=[0.1, 0.2, 0.3],
        bounce=[1, 1.5, 2],
        enableSpring=[True, False, False, False, False, False])
    constraints = [
        ConstraintMeta('', 'p2p', objIDs[0], objIDs[1], p2p_0),
        ConstraintMeta('', 'p2p', objIDs[1], objIDs[2], p2p_1),
        ConstraintMeta('', '6DOFSPRING2', objIDs[2], objIDs[3], dof),
    ]
    assert client.addConstraints(constraints) == (True, None,
                                                  [True] * len(constraints))
Example #13
0
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 = pyazrael.AzraelClient(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 = aztypes.CollShapeEmpty()
    cs = aztypes.CollShapeMeta('empty', (0, 0, 0), (0, 0, 0, 1), cs)
    cmd = {targetID: {'cshapes': {'cssphere': cs}} for targetID in targetIDs}
    assert client.setRigidBodyData(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.setObjectTags(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.setRigidBodyData(cmd).ok
        cnt += 1