gfx-rs / gfx_scene

deprecated
Apache License 2.0
15 stars 1 forks source link

ECS compatibility #37

Closed kvark closed 9 years ago

kvark commented 9 years ago

Entity being a struct is not compatible. We should turn it to a trait (as proposed by @csherratt), which fits nicely into the design. We can think of an entity as something abstract with a number of mandatory components (space node, fragments) and some optional ones (skeleton). The fact that there are multiple fragments may introduce some difficulties though.

Following this route, a camera should also be treated as something abstract with a space node and projection. Abstracting the scene though seems difficult in terms of ECS. Perhaps, I'll just move the current one into claymore_scene and leave the spot open in gfx_scene.

ghost commented 9 years ago

I will need to investigate how we are using the Entities right now. But it makes sense that this extends what the World does. An entity should only really have meaning when referenced to a World object.

trait Entity {
    type Bounding;
    type Position;

    fn get_position(&self, world: &World) -> Position;
    fn get_bounding(&self, world: &World) -> Bounding;
}

With a design like this, the user could have a Resolved Object or a Referenced one. A Resolved object being like the current Entity where everything is inside of the object. A Referenced could be a pointer, or just an NodeID that is to be looked up from the world.

kvark commented 9 years ago

First off, I believe entities and other things should operate on transforms, not positions. Changing to transforms, however, introduces an ambiguity - is the bounding in world space or the entity space?

The approach you propose would effectively hide NodePtr/SkeletonPtr types as well as the World trait, which is very nice. One possible downside of this may be a difficulty in connecting cameras with entities and types. While the old approach would have a World trait dictating all the associated types related to the space, without it they'll need to match each other with a set of where clauses, probably.

Edit: also, do you see how a list of fragments per entity fits into (your/general) ECS?

ghost commented 9 years ago

Iterating on what I posted before.

trait Entity {
    type Bounding;
    type WorldTransform;
    /// An iterator for the fragments
    type Fragments;

    fn is_visiable(&self, world &World) -> bool;
    fn get_transform(&self, world: &World) -> WorldTransform;
    fn get_bounding(&self, world: &World) -> Bounding;
    fn get_fragments(&self, world: &World) -> Fragments;
}

trait Camera {
    type View;
    type Projection;

    fn view(&self, world: &World) -> View;
    fn projection(&self, world: &World) -> Projection;

    fn get_view_projection(&self, world: &W) -> cgmath::Matrix4<S> {
        use cgmath::{Matrix, Transform};
        let node_inverse = self.view(world).invert().unwrap();
        self.projection(world).into().mul_m(&node_inverse.into())
    }
}
kvark commented 9 years ago
trait Node {
    type Transform;
    fn get_transform(&self, world: &World) -> Transform;
}
trait Entity: Node {
...
}
trait Camera: Node {
...
}
ghost commented 9 years ago

Looks good to me.

ghost commented 9 years ago

On the topic of Fragments. The easiest way is just to return a Vec, it's not optimal of course but it gives us an easy way forward.

kvark commented 9 years ago

My biggest concern about fragments is how to map them to an ECS. If they are components (would be highly desirable), then the ECS has to support multiple components per entity.

If we put ECS aside, I can see the fragments interface as follows:

fn get_fragments<'a>(&'a self, &'a Storage) -> &'a [Fragment];

where Storage is the rendering equivalent of World. It may contain an array of fragments, where each entity points to (nice memory layout, less allocations on entity loading, but less flexibility of changing the fragments after they are loaded).

Slightly off-topicky - a ECS supporting multiple components could look like that:

type SliceStart = u32;
type SliceEnd = u32;
struct ComponentSlice<T>(SliceStart, SliceEnd, PhantomData<T>);
// start == end means no components of this type
struct Entity {
    component_a: ComponentSlice<ComponentA>,
    component_b: ComponentSlice<ComponentB>,
    ...
}

I know, it's much closer to simplecs than to your ECS, and we have no chance to use it. Just though I'd leave the idea here for future reference.

kvark commented 9 years ago

I'm in process of implementing this (Node, Entity, Camera traits). This interface is so good it will also provide #16 for free!