2024-02-23

Project Dusk #3 - Testing scene graph webbuild 1

I am progressing with my scene graph implementation. I have a simple test project running in the browser now. You can control the plane using arrow keys:

It's a simple start. The plane is a scene object with a few children and components attached - and unlike previously, this is all done in C without any Lua scripting. Not even C++.

The scene graph API is simple and straightforward. It's similar to how it works in Unity. Let's look at some code pieces:

#include "../plane_sim_g.h"

// inserting here the typedef struct from plane_sim_g.h:
typedef struct MeshRendererComponent {
    Material material;
    Mesh* mesh;
} MeshRendererComponent;

static void MeshRendererDraw(Camera3D camera, SceneObject* node, SceneComponentId sceneComponentId, void* component, void* userdata)
{
    MeshRendererComponent* meshRenderer = (MeshRendererComponent*)component;
    Matrix m = SceneObject_getWorldMatrix(node);
    DrawMesh(*meshRenderer->mesh, meshRenderer->material, m);
}

void MeshRendererComponentRegister()
{
    psg.meshRendererComponentId = SceneGraph_registerComponentType(psg.sceneGraph, "MeshRenderer", sizeof(MeshRendererComponent),
        (SceneComponentTypeMethods) {
            .draw = MeshRendererDraw,
        });
}

The code above is a simple mesh renderer. It is a bit of boilerplate code, but in general, it's not much. The advantage of this programming style is, that it's very easily usable in different contexts.

Using this component is very simple:

    ...
    SceneObjectId plane = SceneGraph_createObject(psg.sceneGraph, "plane");
    SceneGraph_setLocalPosition(psg.sceneGraph, plane, position);
    SceneGraph_addComponent(psg.sceneGraph, plane, psg.meshRendererComponentId,
    &(MeshRendererComponent) {
        .material = psg.model.materials[1],
        .mesh = psg.meshPlane,
    });
    ...

Adding the mesh and initializing it's memory - that's all what's done here. A init method can be provided in case things require initialization, but for most stuff, this is really sufficient.

I made a load test with instantiating 1000 planes and it ran acceptably well. The biggest drain is drawing the meshes individually instead of batching them. While this sounds like a nice thing to try out, my priority is to battle prove the scene graph first by making a simple arcade game with this plane you can see there. It would be easier with a scene editor, but this is what I am going for once I have the foundations ready, which are: Scene graph and asset management. Lua scripting will maybe even come earlier ... though I am not sure. The type system I intend to make for the asset management could, if the binding works as I imagine, make the Lua binding much easier, so taking care of that first could be more efficient coding wise to avoid having to rewrite things later.

So much for now, hope to keep adding things soon. Here's a rough plan what I want to implement with this demo:

It would be nice for comparison to implement the game in parallel using pico ECS - though I guess based on my preeliminary tests, that this won't show much of a difference. It could be however a good way to learn more about working with ECS and to see if it's really not a good fit for my project.

🍪