def addLineOfCubes(client, objName: str, numCubes: int):
    """
    Spawn a single body with ``numCubes`` fragments.

    The body will also be tagged with `objName`.
    """
    # Get the mesh and collision shape for a single cube.
    vert, csmetabox = demolib.cubeGeometry(0.5, 0.5, 0.5)

    # Create a fragment template (convenience only for the loop below).
    ref_frag = demolib.getFragMetaRaw(vert=vert, uv=[], rgb=[])

    # Create the fragments and line them up in a line along the x-axis.
    frags = {}
    centre = (numCubes - 1) / 2
    for idx in range(numCubes):
        frag_name = str(idx)
        frag_pos = [(idx - centre) * 2, 0, 0]
        frags[frag_name] = ref_frag._replace(position=frag_pos)

    # Rigid body description (defines its physics, not its appearance).
    body = demolib.getRigidBody(cshapes={'cs': csmetabox})

    # Define the object template (physics and appearance) and upload to Azrael.
    template = Template('PlotObject', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn one instance.
    templates = [{'templateID': 'PlotObject', 'rbs': {'position': [0, 0, 0]}}]
    ret = client.spawn(templates)
    assert ret.ok
    objID = ret.data[0]

    # Tag the object.
    assert client.setObjectTags({objID: objName})
Exemple #2
0
        def _buildTemplate(name, imass, hlen, lf, rf):
            """
            Return a complete template for a cube object.
            This is a helper function only.
            """
            # Geometry and collision shape for platform.
            vert, cshapes = demolib.cubeGeometry(hlen, hlen, hlen)

            # Rigid body data for platforms (defines their physics, not appearance).
            body = demolib.getRigidBody(
                cshapes={'cs': cshapes},
                linFactor=lf,
                rotFactor=rf,
                imass=imass,
            )

            # Geometry for the platforms (defines their appearance, not physics).
            fm = demolib.getFragMetaRaw(
                vert=vert,
                uv=[],
                rgb=[],
                scale=1,
                pos=(0, 0, 0),
                rot=(0, 0, 0, 1)
            )
            frags = {'frag_1': fm}

            # Define the platform template and upload it to Azrael.
            return Template(name, body, frags, {}, {})
Exemple #3
0
        def _buildTemplate(name, imass, hlen, lf, rf):
            """
            Return a complete template for a cube object.
            This is a helper function only.
            """
            # Geometry and collision shape for platform.
            vert, cshapes = demolib.cubeGeometry(hlen, hlen, hlen)

            # Rigid body data for platforms (defines their physics, not appearance).
            body = demolib.getRigidBody(
                cshapes={'cs': cshapes},
                linFactor=lf,
                rotFactor=rf,
                imass=imass,
            )

            # Geometry for the platforms (defines their appearance, not physics).
            fm = demolib.getFragMetaRaw(vert=vert,
                                        uv=[],
                                        rgb=[],
                                        scale=1,
                                        pos=(0, 0, 0),
                                        rot=(0, 0, 0, 1))
            frags = {'frag_1': fm}

            # Define the platform template and upload it to Azrael.
            return Template(name, body, frags, {}, {})
def getSmallAsteroidTemplate(hlen):
    """
    Return the template for a small asteroid.

    A small asteroid is merely a cube with half length ``hlen``.
    """
    vert, cshapes = demolib.cubeGeometry(hlen, hlen, hlen)

    # Define the geometry of the Asteroids.
    fm = demolib.getFragMetaRaw(
        vert=vert,
        uv=[],
        rgb=[],
        scale=1,
        pos=(0, 0, 0),
        rot=(0, 0, 0, 1)
    )
    frags = {'frag_1': fm}

    # Define the physics parameters for the Asteroids.
    body = demolib.getRigidBody(
        imass=80,
        inertia=[1, 1, 1],
        cshapes={'cs': cshapes},
    )

    return Template('Asteroid_small', body, frags, {}, {})
Exemple #5
0
def addLineOfCubes(client, objName: str, numCubes: int):
    """
    Spawn a single body with ``numCubes`` fragments.

    The body will also be tagged with `objName`.
    """
    # Get the mesh and collision shape for a single cube.
    vert, csmetabox = demolib.cubeGeometry(0.5, 0.5, 0.5)

    # Create a fragment template (convenience only for the loop below).
    ref_frag = demolib.getFragMetaRaw(vert=vert, uv=[], rgb=[])

    # Create the fragments and line them up in a line along the x-axis.
    frags = {}
    centre = (numCubes - 1) / 2
    for idx in range(numCubes):
        frag_name = str(idx)
        frag_pos = [(idx - centre) * 2, 0, 0]
        frags[frag_name] = ref_frag._replace(position=frag_pos)

    # Rigid body description (defines its physics, not its appearance).
    body = demolib.getRigidBody(cshapes={'cs': csmetabox})

    # Define the object template (physics and appearance) and upload to Azrael.
    template = Template('PlotObject', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn one instance.
    templates = [{'templateID': 'PlotObject', 'rbs': {'position': [0, 0, 0]}}]
    ret = client.spawn(templates)
    assert ret.ok
    objID = ret.data[0]

    # Tag the object.
    assert client.setObjectTags({objID: objName})
def getLargeAsteroidTemplate(hlen):
    """
    Return the template for a large asteroid.

    A large asteroids consists of multiple 6 patched together cubes. Each cube
    has a half length of ``hlen``.
    """
    def _randomise(scale, pos):
        pos = scale * np.random.uniform(-1, 1, 3) + pos
        return pos.tolist()

    # Geometry and collision shape for a single cube.
    vert, csmetabox = demolib.cubeGeometry(hlen, hlen, hlen)

    # Define the positions of the individual cubes/fragments in that will
    # constitute the Asteroid. The positions are slightly randomised to make the
    # Asteroids somewhat irregular.
    ofs = 1.5 * hlen
    noise = 0.6
    frag_src = {
        'up': _randomise(noise, [0, ofs, 0]),
        'down': _randomise(noise, [0, -ofs, 0]),
        'left': _randomise(noise, [ofs, 0, 0]),
        'right': _randomise(noise, [-ofs, 0, 0]),
        'front': _randomise(noise, [0, 0, ofs]),
        'back': _randomise(noise, [0, 0, -ofs]),
    }
    del ofs

    # Patch together the fragments that will constitute the geometry of a
    # single large Asteroid. While at it, also create the individual collision
    # shapes for each fragment (not part of the geometry but needed
    # afterwards).
    frags, cshapes = {}, {}
    for name, pos in frag_src.items():
        frags[name] = demolib.getFragMetaRaw(
            vert=vert,
            uv=[],
            rgb=[],
            scale=1,
            pos=pos,
            rot=[0, 0, 0, 1],
        )

        # Collision shape for this fragment.
        cshapes[name] = csmetabox._replace(position=pos)
        del name, pos
    del frag_src

    # Specify the physics of the overall bodies.
    body = demolib.getRigidBody(
        imass=0.01,
        inertia=[3, 3, 3],
        cshapes=cshapes,
    )

    # Return the completed Template.
    return Template('Asteroid_large', body, frags, {}, {})
def addMolecule():
    # Connect to Azrael.
    client = azrael.clerk.Clerk()

    # The molecule will consist of several cubes.
    vert, csmetabox = demolib.cubeGeometry(0.5, 0.5, 0.5)

    # The molecule object.
    ofs = 2
    frag_src = {
        'up': [0, ofs, 0],
        'down': [0, -ofs, 0],
        'left': [ofs, 0, 0],
        'right': [-ofs, 0, 0],
        'front': [0, 0, ofs],
        'back': [0, 0, -ofs],
        'center': [0, 0, 0],
    }
    del ofs
#    frag_src = {'down': frag_src['down']}
#    frag_src = {'center': frag_src['center']}

    frags, cshapes = {}, {}
    for name, pos in frag_src.items():
        frags[name] = demolib.getFragMetaRaw(
            vert=vert,
            uv=[],
            rgb=[],
            scale=1,
            pos=pos,
            rot=[0, 0, 0, 1],
        )

        cshapes[name] = csmetabox._replace(position=pos)
        del name, pos
    del frag_src

    # Rigid body data parameters (defines its physics, not appearance). Specify
    # the centre of mass (com) and principal axis rotation (paxis) for the
    # inertia values.
    body = demolib.getRigidBody(
        imass=0.1,
        com=[0, -1, 0],
        inertia=[1, 2, 3],
        paxis=[0, 0, 0, 1],
        cshapes=cshapes,
    )

    # Define the object template and upload it to Azrael.
    template = Template('molecule', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn one molecule.
    templates = [{'templateID': 'molecule', 'rbs': {'position': [0, 0.5, 0]}}]
    objID = client.spawn(templates)
def addMolecule():
    # Connect to Azrael.
    client = azrael.clerk.Clerk()

    # The molecule will consist of several cubes.
    vert, csmetabox = demolib.cubeGeometry(0.5, 0.5, 0.5)

    # The molecule object.
    ofs = 2
    frag_src = {
        'up': [0, ofs, 0],
        'down': [0, -ofs, 0],
        'left': [ofs, 0, 0],
        'right': [-ofs, 0, 0],
        'front': [0, 0, ofs],
        'back': [0, 0, -ofs],
        'center': [0, 0, 0],
    }
    del ofs
    #    frag_src = {'down': frag_src['down']}
    #    frag_src = {'center': frag_src['center']}

    frags, cshapes = {}, {}
    for name, pos in frag_src.items():
        frags[name] = demolib.getFragMetaRaw(
            vert=vert,
            uv=[],
            rgb=[],
            scale=1,
            pos=pos,
            rot=[0, 0, 0, 1],
        )

        cshapes[name] = csmetabox._replace(position=pos)
        del name, pos
    del frag_src

    # Rigid body data parameters (defines its physics, not appearance). Specify
    # the centre of mass (com) and principal axis rotation (paxis) for the
    # inertia values.
    body = demolib.getRigidBody(
        imass=0.1,
        com=[0, -1, 0],
        inertia=[1, 2, 3],
        paxis=[0, 0, 0, 1],
        cshapes=cshapes,
    )

    # Define the object template and upload it to Azrael.
    template = Template('molecule', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn one molecule.
    templates = [{'templateID': 'molecule', 'rbs': {'position': [0, 0.5, 0]}}]
    objID = client.spawn(templates)
Exemple #9
0
def addPlatforms():
    # Connect to Azrael.
    client = azrael.clerk.Clerk()

    # Geometry and collision shape for platform.
    vert, cshapes = demolib.cubeGeometry(2, 0.1, 2)

    # Rigid body data for platforms (defines their physics, not appearance).
    body = demolib.getRigidBody(
        cshapes={'cs': cshapes},
        linFactor=[0, 0, 0],
        rotFactor=[0, 0, 0]
    )

    # Geometry for the platforms (defines their appearance, not physics).
    fm = demolib.getFragMetaRaw(
        vert=vert,
        uv=[],
        rgb=[],
        scale=1,
        pos=(0, 0, 0),
        rot=(0, 0, 0, 1)
    )
    frags = {'frag_1': fm}

    # Define the platform template and upload it to Azrael.
    template = Template('platform', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn several platforms at different positions. Their positions are
    # supposed to create the impression of a stairway. The values assume the
    # camera is at [0, 0, 10] and points in -z direction.
    platforms = []
    for ii in range(5):
        pos = (-10 + ii * 5, -ii * 2, -20)
        platforms.append(
            {
                'templateID': 'platform',
                'rbs': {
                    'position': pos,
                    'velocityLin': (0, 0, 0),
                    'scale': 1,
                    'imass': 20
                }
            }
        )
    platformIDs = client.spawn(platforms)

    # Tag all platforms with a custom string.
    cmd = {platformID: 'Platform' for platformID in platformIDs.data}
    assert client.setObjectTags(cmd)
def addPlatforms():
    # Connect to Azrael.
    client = azrael.clerk.Clerk()

    # Geometry and collision shape for platform.
    vert, cshapes = demolib.cubeGeometry(2, 0.1, 2)

    # Rigid body data for platforms (defines their physics, not appearance).
    body = demolib.getRigidBody(cshapes={'cs': cshapes},
                                linFactor=[0, 0, 0],
                                rotFactor=[0, 0, 0])

    # Geometry for the platforms (defines their appearance, not physics).
    fm = demolib.getFragMetaRaw(vert=vert,
                                uv=[],
                                rgb=[],
                                scale=1,
                                pos=(0, 0, 0),
                                rot=(0, 0, 0, 1))
    frags = {'frag_1': fm}

    # Define the platform template and upload it to Azrael.
    template = Template('platform', body, frags, {}, {})
    ret = client.addTemplates([template])

    # Spawn several platforms at different positions. Their positions are
    # supposed to create the impression of a stairway. The values assume the
    # camera is at [0, 0, 10] and points in -z direction.
    platforms = []
    for ii in range(5):
        pos = (-10 + ii * 5, -ii * 2, -20)
        platforms.append({
            'templateID': 'platform',
            'rbs': {
                'position': pos,
                'velocityLin': (0, 0, 0),
                'scale': 1,
                'imass': 20
            }
        })
    platformIDs = client.spawn(platforms)

    # Tag all platforms with a custom string.
    cmd = {platformID: 'Platform' for platformID in platformIDs.data}
    assert client.setObjectTags(cmd)
Exemple #11
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))
Exemple #12
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
Exemple #13
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))