Advertisement

How do you handle resource dependencies in your engine?

Started by November 04, 2021 03:04 AM
4 comments, last by hplus0603 3 years ago

I'm try to write my own little game engine, modern game engines has some resources dependency manager, like in Unity or UE4, a Model depends Mesh, Skeleton, Animation, and Material , Material depends texture and shader;
How do I determine some resource depends others? Write a rule for this like a Model resources may depends Mesh, Skeleton etc, so each time when load a model, the function need provide Mesh, Skeleton, Animation resources to it?

Or manually specify dependencies in editor, like in Unity one can specify which Texture and shader to use in material, and save the dependency in some custom file format, so when I load the model, I know from the file format that this resource depends some other resrouces? what if I don't have and editor?

Do you guys has some addvice or share your solution, or give me some reference that I can dig further

You should first define all of those different objects for your engine. Break everything down and then see what dependencies are possible and how do they appear in the base files.

A 3D model for example may already have an animation included and so also defines the skeleton. Mesh, Skeleton and Animation so aren't separated from each other. It however gets difficult if you want to decouple 3D model and animation from each other, then you need some kind of data structure which tells your engine of which components an entity consists. Textures are just image files and metadata must be added from the engine in order to have the right parameters, for example pixel format, texture type (2D, Cube), mipmaps and so on.

Do you plan to have an ECS or pure OOP approach? This makes a difference as an ECS has the advantage to already provide a platform for associative decoupled data.

However, you need some kind of data structure to define your assets and their properties to be read easily from the engine later. Then you know how you can detect dependencies. A set of possible data structures could for example look like

struct Model
{
    public Mesh Mesh { get; set; }
    public Animation Animation { get; set; }
    public Skeleton Skeleton { get; set; }
    public Material Material { get; set; }
}

struct Mesh
{
    public Vector3 Vertices { get; set; }
    public Vector3 Normals { get; set; }
    public Vector2 TexCoords { get; set; }
}

struct Material
{
    public Shader Shader { get; set; }
    public Texture[] Textures { get; set; }
}

struct Shader
{
    public UInt32 Id { get; set; }
    public string Source { get; set; }
}

struct Texture
{
    public TextureType Type { get; set; }
    public PixelFormat Format { get; set; }
    ...
    public byte[] Raw { get; set; }
}

Now you know the dependency between a Material and a Texture by a simple lookup. You however have to serialize those data structures properly in order to make them accessible fast. This is C# but I you could do the same in C++ or anything else. When you serialize the data, you have to provide some unique identifier, for example the FNV hashed file name as 32 bit ID and instead of object references, you add that ID to point to the reference.

You need a resource manager in your engine to resolve references at runtime. That manager must also provide some ref counting for you to not load a certain texture into memory twice if you have multiple materials using it.

liuhao said:
what if I don't have and editor?

Auto detection is quiet difficult so you have the choice of either doing that or requiere a user to write those data structure in a file format which is easy and human readable, like for example JSON. Or you do what we're doing for our config files and provide a text engine which converts input to valid JSON files; or whatever file format you prefer. In my opinion, JSON is the best file format because it doesn't requiere whitespace counting or other formatting rules and is complex enough to allows for deep object structures. Our Alchemy text engine helps us to make JSON a little bit more convenient, it is a preprocessor with C like capabilities (comments, conditionals, macros and including is supported). What you need is a tool to convert the human readable data into fast machine accessible data in the next step to create an asset database/package for your engine to load from disk.

For the auto detection solution, you must first provide a strict and clear ruleset. This will be difficult as you have to pre-think any possible scenario and side effect that could occur. Do you want to have some configuration files/scripts which should be taken into account or do a pure logic based approach? Personally, I wouldn't spend the time for doing that and instead have an editor or at least another nice UI

Advertisement

Shaarigan said:
It however gets difficult if you want to decouple 3D model and animation from each other, then you need some kind of data structure which tells your engine of which components an entity consists

Yes , This is what I want to do;

I have used an inhouse engine in the past time, it can share Skeleton data between different model, and there are many models which only has different mesh, they share skeleton and animations; this is my aim

For built assets, in the past, I have used a custom file format. The file format has a section of metadata that is standard for all assets: Asset type, asset source file, build version/hash, and list of dependent assets.

Then there's a block of data inside the asset which is the “type specific data” – a sound file with wave data, or a built mesh with vertex and index arrays, or a texture with compressed mip maps, or whatever.

Then I can use tools that know about the general asset file format, without having to know about each individual asset type, to traverse dependency graphs, bundle assets that go together into packed files, etc.

So, file format is something like:

magic-number
metadata-size
  metadata: asset type
  metadata: asset id
  metadata: asset hash
  metadata: asset source file path
  metadata: list of dependent asset id
data-size
  type-specific data
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement