Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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, {}, {})
Ejemplo n.º 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, {}, {})
Ejemplo n.º 4
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, {}, {})
Ejemplo n.º 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})
Ejemplo n.º 6
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})
Ejemplo n.º 7
0
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)
Ejemplo n.º 10
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)
Ejemplo n.º 11
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)
Ejemplo n.º 12
0
def spawnAsteroid(client):
    """Spawn the asteroid 67P and return its Azrael ID (AID).
    """
    # This is a convenience function that returns geometry and collision shape
    # for a sphere.
    vert, cshapes = demolib.loadSphere(10)

    # This is a convenience function that compiles the rigid body parameters to
    # compute the Newtonian physics.
    body = demolib.getRigidBody(cshapes={'cs': cshapes})

    # Define the visual geometry of the Asteroid.
    frags = {'foo': demolib.getFragMetaRaw(vert=vert, uv=[], rgb=[])}

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

    # Specify the parameters for the asteroid and spawn it.
    spawn_param = {
        'templateID': 'asteroid',
        'rbs': {
            'position': (0, 0, -100),
            'velocityLin': (0, 0, 0),
            'imass': 0.0001,
        }
    }
    ret = client.spawn([spawn_param])
    assert ret.ok

    # The return value contains the Azrael IDs (AIDs) of all spawned objects.
    # In this case we have only spawned one, namely the asteroid.
    asteroidID = ret.data[0]

    # Tag the asteroid with a custom string (optional).
    assert client.setObjectTags({asteroidID: '67P'}).ok
    return asteroidID
Ejemplo n.º 13
0
def spawnAsteroid(client):
    """Spawn the asteroid 67P and return its Azrael ID (AID).
    """
    # This is a convenience function that returns geometry and collision shape
    # for a sphere.
    vert, cshapes = demolib.loadSphere(10)

    # This is a convenience function that compiles the rigid body parameters to
    # compute the Newtonian physics.
    body = demolib.getRigidBody(cshapes={'cs': cshapes})

    # Define the visual geometry of the Asteroid.
    frags = {'foo': demolib.getFragMetaRaw(vert=vert, uv=[], rgb=[])}

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

    # Specify the parameters for the asteroid and spawn it.
    spawn_param = {
        'templateID': 'asteroid',
        'rbs': {
            'position': (0, 0, -100),
            'velocityLin': (0, 0, 0),
            'imass': 0.0001,
        }
    }
    ret = client.spawn([spawn_param])
    assert ret.ok

    # The return value contains the Azrael IDs (AIDs) of all spawned objects.
    # In this case we have only spawned one, namely the asteroid.
    asteroidID = ret.data[0]

    # Tag the asteroid with a custom string (optional).
    assert client.setObjectTags({asteroidID: '67P'}).ok
    return asteroidID
Ejemplo n.º 14
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))
Ejemplo n.º 15
0
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
Ejemplo n.º 16
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
Ejemplo n.º 17
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
Ejemplo n.º 18
0
def loadBlender(fname_blender: str):
    """
    Compile and return the fragments and collision shapes from ``fname``.

    The ``fname`` file must specify a Blender file.

    :param str fname: Blender file name
    :return: (frags dict, cshapes dict)
    """
    # Use Blender itself to load the Blender file. This will trigger a script
    # inside Blender that creates a JSON file with custom scene data. The name
    # of that file is returned in 'fname_az'.
    fname_az = processBlenderFile(fname_blender)

    # Load the collision shape data and geometry.
    pp = pyassimp.postprocess
    azFile = json.loads(open(fname_az, 'rb').read().decode('utf8'))
    scene = pyassimp.load(fname_blender, pp.aiProcess_Triangulate)
    del fname_az, pp

    # Sanity check: both must contain information about the exact same objects.
    assert set(azFile.keys()) == {_.name for _ in scene.meshes}

    # Load all the materials.
    materials = loadMaterials(scene, fname_blender)

    # Compile fragments and collision shapes for Azrael.
    frags, cshapes = {}, {}
    for mesh in scene.meshes:
        # Get the material for this mesh.
        material = materials[mesh.materialindex]

        # Iterate over the faces and rebuild the vertices.
        azData = azFile[mesh.name]
        vert = np.zeros(len(mesh.faces) * 9)
        for idx, face in enumerate(mesh.faces):
            tmp = [mesh.vertices[_] for _ in face]
            start, stop = idx * 9, (idx + 1) * 9
            vert[start:stop] = np.hstack(tmp)
            del start, stop, tmp, idx, face

        # Copy the UV coordinates, if there are any.
        if len(mesh.texturecoords) > 0:
            uv = np.zeros(len(mesh.faces) * 6)
            for idx, face in enumerate(mesh.faces):
                tmp = [mesh.texturecoords[0][_, :2] for _ in face]
                start, stop = 6 * idx, 6 * (idx + 1)
                uv[start:stop] = np.hstack(tmp)
                del start, stop, tmp, idx, face

            # Sanity check.
            assert (len(uv) // 2 == len(vert) // 3)
        else:
            uv = 0.5 * np.ones(2 * (len(vert) // 3))
            uv = []

        # Azrael does not allow 'dots', yet Bullet uses it prominently to name
        # objects. As a quick fix, simply replace the dots with something else.
        # fixme: should be redundant once #149 (https://trello.com/c/wcHX3qGd)
        # is implemented.
        azname = mesh.name.replace('.', 'x')

        # Unpack the position and orientation of the mesh in world coordinates.
        pos, rot, dim = azData['pos'], azData['rot'], np.array(azData['dimensions'])

        # Unpack the interior points and put them into any kind of byte string.
        # This will be attached as yet another file to the fragment data.
        interior_points = json.dumps(azData['interior_points']).encode('utf8')

        # Create a RAW fragment.
        scale = 1
        rgb, width, height = material['RGB'], material['width'], material['height']
        frag = demolib.getFragMetaRaw(vert, uv, rgb, scale, pos, rot)
        frag.files['interior_points'] = interior_points
        frags[azname] = frag

        # Construct the BOX collision shape based on the Blender dimensions.
        hlen_x, hlen_y, hlen_z = (dim / 2).tolist()
        box = aztypes.CollShapeBox(hlen_x, hlen_y, hlen_z)

        # Construct the CollshapeMeta data.
        cshapes[azname] = aztypes.CollShapeMeta('box', pos, rot, box)
        del azData, vert, dim, scale, rgb, width, height, hlen_x, hlen_y, hlen_z
    return frags, cshapes
Ejemplo n.º 19
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))
Ejemplo n.º 20
0
def loadColladaModel(filename):
    """
    Load the Collada modle created in Blender. This function makes the
    following hard coded assumptions about that file:

    * It contains a node called 'Parent'
    * That parent contains a mesh called 'MainBody'.
    """
    # Load the scene.
    scene = pyassimp.load(filename)

    # Find the node called 'Parent' (hard coded assumption that must be matched
    # by Blender model).
    p = None
    print('\nModel file contains the following meshes:')
    for child in scene.rootnode.children:
        print('  *', child.name)
        if child.name == 'Parent':
            p = child

    # The Parent node must exist, and it must contain one mesh called
    # 'MainBody'.
    assert p is not None
    objs = {_.name: _ for _ in p.children}
    assert 'MainBody' in objs

    # For later: compute the inverse transform of MainBody.
    scale, i_transform = inverseTransform(objs['MainBody'].transformation)

    frags, cshapes = {}, {}
    for name in objs:
        # 4x4 transformation matrix for current mesh (this is always in global
        # coordinates, not relative to anything).
        t = np.array(objs[name].transformation)

        # Vertices of current mesh (Nx3).
        vert = objs[name].meshes[0].vertices

        # Transpose vertex matrix to obtain the 3xN matrix. Then add a row of
        # 1s to obtain a 4xN matrix.
        vert = vert.T
        vert = np.vstack((vert, np.ones(vert.shape[1])))

        # Scale/rotatate/translate the vertices relative to the position of the
        # MainBody. Then drop the (auxiliary) last row again to get back to a
        # Nx3 matrix of vertices.
        vert = i_transform.dot(t.dot(vert))
        vert = vert[:-1, :].T

        # Flatten the vertex matrix into a simple list and compile it into a
        # fragment.
        vert = vert.flatten()
        frags[name] = demolib.getFragMetaRaw(vert, uv=[], rgb=[], scale=1)

        # All bodies whose name starts with 'cs' get a spherical collision
        # shape.
        if name.lower().startswith('cs'):
            # Compute the combined transformation matrix that represents the
            # difference between the MainBody's position and this one. To find
            # this, simpy apply the invers transform of the MainBody to the
            # transform of the locat body. The latter would move the current
            # object to its correct position in world coordinates, and the
            # former will undo offset and rotation of the MainBody.
            t = i_transform.dot(t)

            # Determine the position.
            # Fixme: also determine the quaternion and scale from the total
            # transformation matrix.
            _pos = tuple(t[:3, 3].tolist())
            _rot = (0, 0, 0, 1)

            # Create a spherical collision shape and place it relative to the
            # MainBody.
            sphere = aztypes.CollShapeSphere(1)
            cshapes[name] = aztypes.CollShapeMeta('sphere', _pos, _rot, sphere)

    return frags, cshapes
Ejemplo n.º 21
0
def loadColladaModel(filename):
    """
    Load the Collada modle created in Blender. This function makes the
    following hard coded assumptions about that file:

    * It contains a node called 'Parent'
    * That parent contains a mesh called 'MainBody'.
    """
    # Load the scene.
    scene = pyassimp.load(filename)

    # Find the node called 'Parent' (hard coded assumption that must be matched
    # by Blender model).
    p = None
    print('\nModel file contains the following meshes:')
    for child in scene.rootnode.children:
        print('  *', child.name)
        if child.name == 'Parent':
            p = child

    # The Parent node must exist, and it must contain one mesh called
    # 'MainBody'.
    assert p is not None
    objs = {_.name: _ for _ in p.children}
    assert 'MainBody' in objs

    # For later: compute the inverse transform of MainBody.
    scale, i_transform = inverseTransform(objs['MainBody'].transformation)

    frags, cshapes = {}, {}
    for name in objs:
        # 4x4 transformation matrix for current mesh (this is always in global
        # coordinates, not relative to anything).
        t = np.array(objs[name].transformation)

        # Vertices of current mesh (Nx3).
        vert = objs[name].meshes[0].vertices

        # Transpose vertex matrix to obtain the 3xN matrix. Then add a row of
        # 1s to obtain a 4xN matrix.
        vert = vert.T
        vert = np.vstack((vert, np.ones(vert.shape[1])))

        # Scale/rotatate/translate the vertices relative to the position of the
        # MainBody. Then drop the (auxiliary) last row again to get back to a
        # Nx3 matrix of vertices.
        vert = i_transform.dot(t.dot(vert))
        vert = vert[:-1, :].T

        # Flatten the vertex matrix into a simple list and compile it into a
        # fragment.
        vert = vert.flatten()
        frags[name] = demolib.getFragMetaRaw(vert, uv=[], rgb=[], scale=1)

        # All bodies whose name starts with 'cs' get a spherical collision
        # shape.
        if name.lower().startswith('cs'):
            # Compute the combined transformation matrix that represents the
            # difference between the MainBody's position and this one. To find
            # this, simpy apply the invers transform of the MainBody to the
            # transform of the locat body. The latter would move the current
            # object to its correct position in world coordinates, and the
            # former will undo offset and rotation of the MainBody.
            t = i_transform.dot(t)

            # Determine the position.
            # Fixme: also determine the quaternion and scale from the total
            # transformation matrix.
            _pos = tuple(t[:3, 3].tolist())
            _rot = (0, 0, 0, 1)

            # Create a spherical collision shape and place it relative to the
            # MainBody.
            sphere = aztypes.CollShapeSphere(1)
            cshapes[name] = aztypes.CollShapeMeta('sphere', _pos, _rot, sphere)

    return frags, cshapes