15. API - Rendering

The render module defines a series of classes for interpreting and rendering models in the Wavefront object format.

Note

All items in this module are available from the picraft namespace without having to import picraft.render directly.

The following items are defined in the module:

15.1. Model

class picraft.render.Model(source, swap_yz=False)[source]

Represents a three-dimensional model parsed from an Alias|Wavefront object file (.obj extension). The constructor accepts a source parameter which can be a filename or file-like object (in the latter case, this must be opened in text mode such that it returns unicode strings rather than bytes in Python 3).

The optional swap_yz parameter specifies whether the Y and Z coordinates of each vertex in the model will be swapped; some models require this to render correctly in Minecraft, some do not.

The faces attribute provides access to all object faces extracted from the file’s content. The materials property enumerates all material names used by the object. The groups mapping maps group names to subsets of the available faces. The bounds attribute provides a range describing the bounding box of the unscaled model.

Finally, the render() method can be used to easily render the object in the Minecraft world at the specified scale, and with a given material mapping.

render(scale=1.0, materials=None, groups=None)[source]

Renders the model as a dict mapping vectors to block types. Effectively this rounds the vertices of each face to integers (after applying the scale multiplier, which defaults to 1.0), then calls filled() and lines() to obtain the complete coordinates of each face.

Each coordinate then needs to be mapped to a block type. By default the material name is simply passed to the Block constructor. This assumes that material names are valid Minecraft block types (see NAMES).

You can override this mechanism with the materials parameter. This can be set to a mapping (e.g. a dict) which maps material names to Block instances. For example:

from picraft import Model, Block

m = Model('airboat.obj')
d = m.render(materials={
    'bluteal':  Block('diamond_block'),
    'bronze':   Block('gold_block'),
    'dkdkgrey': Block((64, 64, 64)),
    'dkteal':   Block('#000080'),
    'red':      Block('#ff0000'),
    'silver':   Block.from_color('#ffffff'),
    'black':    Block(id=35, data=15),
    None:       Block('stone'),
    })

Note

Some object files may include faces with no associated material. In this case you will need to map None to a block type, as in the example above.

Alternatively, materials can be a callable which will be called with the ModelFace being rendered, which should return a block type. The following is equivalent to the default behaviour:

from picraft import Model, Block

m = Model('airboat.obj')
d = m.render(materials=lambda f: Block(f.material))

If you simply want to preview a shape without bothering with any material mapping you can use this method to map any face to a single material (in this case stone):

from picraft import Model, Block

m = Model('airboat.obj')
d = m.render(materials=lambda f: Block('stone'))

If the materials mapping or callable returns None instead of a Block instance, the corresponding blocks will not be included in the result. This is a simple mechanism for excluding parts of a model. The other mechanism for achieving this is the groups parameter which specifies which sub-components of the model should be rendered. This can be specified as a string (indicating that only that sub-component should be rendered) or as a sequence of strings (indicating that all specified sub-components should be rendered).

The result is a mapping of Vector to Block instances. Rendering the result in the main world should be as trivial as the following code:

from picraft import World, Model

w = World()
m = Model('airboat.obj').render(scale=2.0)
with w.connection.batch_start():
    for v, b in m.items():
        w.blocks[v] = b

Of course, you may choose to further transform the result first. This can be accomplished by modifying the vectors as you set them:

from picraft import World, Model, Y

w = World()
m = Model('airboat.obj').render(scale=2.0)
with w.connection.batch_start():
    for v, b in m.items():
        w.blocks[v + 10*Y] = b

Alternatively you may choose to use a dict-comprehension:

from picraft import Model, Vector

m = Model('airboat.obj').render(scale=2.0)
offset = Vector(y=10)
m = {v + offset: b for v, b in m.items()}

Note that the Alias|Wavefront object file format is a relatively simple text based format that can be constructed by hand without too much difficulty. Combined with the default mapping of material names to block types, this enables another means of constructing objects in the Minecraft world. For example, to construct a small house:

house.py
from picraft import Model, World

with World() as w:
    with w.connection.batch_start():
        for v, b in Model('house.obj').render().items():
            w.blocks[v] = b
house.obj
# This is an object file describing a house. First we define the
# required vertices with the "v" command, then reference these
# from faces (with the "f" command). Negative indices in the "f"
# command count back from the most recently defined vertices.

usemtl brick_block

g front-wall
v 0 1 0
v 8 1 0
v 8 4 0
v 0 4 0
v 3 1 0
v 5 1 0
v 3 3 0
v 5 3 0
f -8 -4 -2 -1 -3 -7 -6 -5

g back-wall
v 0 1 8
v 8 1 8
v 8 4 8
v 0 4 8
f -1 -2 -3 -4

g left-wall
f -12 -4 -1 -9

g right-wall
f -11 -3 -2 -10

g ceiling
f -10 -9 -1 -2
bounds

Returns a vector range which completely encompasses the model at scale 1.0. This can be useful for determining scaling factors when rendering.

Note

The bounding box returned is axis-aligned and is not guaranteed to be the minimal bounding box for the model.

faces

Returns the sequence of faces that make up the model. Each instance of this sequence is a ModelFace instance which provides details of the coordinates of the face vertices, the face material, etc.

groups

A mapping of group names to sequences of ModelFace instances. This can be used to extract a component of the model for further processing or rendering.

materials

Returns the set of materials used by the model. This is derived from the material assigned to each face of the model.

15.2. ModelFace

class picraft.render.ModelFace(vectors, material=None, groups=None)[source]

Represents a face belonging to a Model. A face consists of three or more vectors which are all coplanar (belonging to the same two-dimensional plane within the three-dimensional space).

A face also has a material. As Minecraft’s rendering is relatively crude this is simply stored as the name of the material; it is up to the user to map this to a meaningful block type. Finally each face belongs to zero or more groups which can be used to distinguish components of a model from each other.

groups

The set of groups that the face belongs to. By default all faces belong to a Model. However, in additionl to this a face can belong to zero or more “groups” which are effectively components of the model. This facility can be used to render particular parts of a model.

material

The material assigned to the face. This is simply stored as the name of the material as it would be ridiculous to even attempt to emulate the material model of a full ray-tracer as Minecraft blocks.

The Model.render() method provides a simple means for mapping a material name to a block type in Minecraft.

vectors

The sequence of vectors that makes up the face. These are assumed to be coplanar but this is not explicitly checked. Each point is represented as a Vector instance.