# Models

The full source code for this part of the tutorial is available in the file `root/tutorials/s3d/model.bs`. You can run it using `storm -f tutorials.s3d.model`. As in the previous parts, the code is fairly well-documented, and is likely possible to read on its own.

As before, this tutorial focuses on the differences from the first tutorial. If you started working on your own previously, you can resume from the code you wrote as a part of that tutorial. Note, however, that the painter, the pipeline, and the shaders are renamed from `Simple...` to `Model...` to avoid name clashes in the tutorials package.

## The Model Class

The center piece of this tutorial is the `ui.s3d.Model` class, and how it interacts with the rest of the rendering system. At its core, the `ui.s3d.Model` class is fairly simple. It is conceptually a class that contains a set of vertices and a set of indices as follows:

    class Model {
        // Vertex buffer.
        VertexBuffer<Vertex> vertices;

        // Index buffer.
        IndexBuffer indices;

        // Additional members...
    }

What makes this useful is that it defines a standard interface which different systems can use to exchange geometry between each other. As a part of this, the `Model` class also defines its own vertex type: `ui.s3d.Vertex`, which can be used in rendering. It has the following members.

    vertex Vertex {
        // Vertex position.
        Vector pos;

        // Vertex normal. Assumed to be normalized to length 1.
        Vector normal;

        // Vertex color.
        Color color;

        // Texture coordinate. Each coordinate is normally between 0 and 1.
        Point tex;
    }

Apart from defining a standard data layout, the `Model` class also provides a number of utilities to manipulate geometry. For example, loading `.obj` files, creating simple geometric shapes, and manipulating them. We will see a few of them in the remainder of this tutorial.

## Adjusting the Pipeline

Since we will represent the geometry using the `ui.s3d.Vertex` type, we will once again have to adapt our pipeline accordingly. In this case, we will define the pipeline and the intermediate vertex type like below. Note that `ModelIntermediate` is the same as `SimpleIntermediate`.

    vertex ModelIntermediate {
        // Position.
        Vector4 pos : position, perspective;

        // Color.
        Color color : perspective;
    }

    pipeline ModelPipeline {
        // Note that the source type refers to ui:s3d:Vertex.
        data (Vertex vertex) -> ModelIntermediate -> Output;

        // Camera transform.
        Transform camera;
    }

We will also have to modify our shaders slightly from the shaders used in the first tutorial, mainly by adjusting the name of the input in the vertex shader.

    vertex shader for ModelPipeline: ModelIntermediate modelVertexShader(Vertex point) {
        ModelIntermediate(Vector4(point.pos) * camera, point.color);
    }

    pixel shader for ModelPipeline: Output modelPixelShader(ModelIntermediate point) {
        Output(point.color);
    }

## Rendering Models

Now that we have adapted the pipeline, we can turn our attention to our painter. We will modify it to render a `Model`. As such, our first order of business is to replace the vertex buffer and index buffer with a `Model`. The `Model` class contains a vertex buffer and an index buffer after all. As a starting point, we will just create a simple cube using the `Model:cube` static member.

At this time, our painter will look like below:

    class ModelPainter extends SamplePainter3D {
        // The pipeline.
        ModelPipeline pipeline;

        // Model to render.
        Model model;

        // Transform for the camera position.
        Transform cameraPos;

        // Create.
        init() {
            init {
                // Create the pipeline and attach shaders.
                pipeline = ModelPipeline:create(modelVertexShader, modelPixelShader);

                // Create the camera transform.
                cameraPos = rotateX(-35 deg) * translate(Vector(0, 0, 8));

                // Create a default model.
                model = Model:cube(2);
            }
        }

        // Render.
        Bool render(Size size, Graphics3D g) : override {
            Float time = animationTime(5 s);

            g.clearDepth();
            g.fill(black);

            pipeline.camera = rotateY(360 deg * time) * cameraPos * perspectiveProject(100 deg, size.aspect, 0.1, 100);
            pipeline.render(g, model.indices, model.vertices);

            true;
        }
    }

The code above is not too different from what we have seen so far, at least as long as we keep in mind that the model is just a vertex buffer and an index buffer wrapped in a class to make them easier to manipulate. However, since the `Model` class is a part of the 3D rendering package, it does receive some special treatment from other parts of the system. For example, we can simplify the call to `render` by just passing the `model` as a whole unit:

    pipeline.render(g, model);

At this time, you can run the example to see a rotating white cube.

## Manipulating Models

Now it is time to explore the capabilities provided by the `Model` class. As a starting point, we can easily set the color of all vertices in a model using the `color` assign function. For example, we can make the cube red by adding the following line to the end of the constructor:

    model.color = red;

Perhaps more interesting is the fact that the 3D library provides a simple loader for `.obj` files, to make it easier to implement more complex 3D geometry. For example, we can import a version of the Utah teapot by replacing the initialization of `model` with the following line:

    model = loadOBJ(resUrl("teapot.obj"));

Due to the name resolution rules in Basic Storm, this can also be written as follows:

    model = resUrl("teapot.obj").loadOBJ();

As in the texture tutorial, the `resUrl` function is a helper function that finds the file `teapot.obj` in any of the `res/` directories for us. We can then pass the resulting `core.io.Url` to the `loadOBJ` function to load the file data (there is also an overload that accepts an `core.io.IStream` if that is more convenient).

If we run the program at this point, we will see that the cube is replaced with a rotating teapot!

The `Model` class also allows concatenating and transforming the geometry contained within. For example, we can add a translated green cube to the same model as the teapot as follows. Another option would, of course, be to have two `Model` instances and render them separately. However, GPUs tend to like working in batches, so few calls to `render` with large amounts of geometry tend to give better performance compared to many calls with less geometry.

    model.append(Model:cube(2).withColor(green).transform(translate(Vector(5, 0, 0))));

As you can see, the API makes it quite easy to nest things nicely. Let's walk through what happens step by step.

1. First, we create a cube with sides of 2 units using `Model:cube(2)`. As we saw before, this creates a `Model` instance.
2. After that, we call `withColor(green)` on the newly created model. As with `model.color = green`, this changes the color of all vertices in the model. The difference is that `withColor` returns the original model, so that it works a bit nicer in pipelines.
3. After that, we call `.transform(translate(Vector(5, 0, 0)))`. The expression `translate(Vector(5, 0, 0))` creates a `core.geometry.Transform` that represents a translation in the X direction. The `transform` member of `Model` then applies the transform to all vertices (in particular, to `pos` and `normal`).
4. Finally, the translated model is appended to the teapot model using `.append`.

Similarly, we can also add a sphere to balance the geometry a bit:

    model.append(Model:sphere(2, 30, 30).withColor(blue).transform(translate(Vector(-5, 0, 0))));

At this point, we see a red teapot, a green cube, and a blue sphere in a line, all rotating on the screen.