AxeGuywithanAxe

Members
  • Content count

    184
  • Joined

  • Last visited

Community Reputation

1214 Excellent

1 Follower

About AxeGuywithanAxe

  • Rank
    Member

Personal Information

  • Interests
    Art
    Programming
  1. Cache Coherency and Object Update

    That just seems like logic inversion to me, either way one thread is accessing it and another by proxy. I would rather contain everything that has to do with the game on the game side , instead of mixing components with the renderer, which has no need to know about component architecture at all. I can already do that, you wouldn't need another inheritance chain. I have an enum that delegates whether or not a component can be moved or not, or just don't ever send a transform update to a component, I don't know why another inheritance chain would be necessary. I have delegates that are called when a transform is updated, but drawable components only send the update to the render thread at the end of the frame, when their transform changes, they notify the world that they need to be synced, which reduces the amount of wasted time sending updates to the render thread mid frame.
  2. Cache Coherency and Object Update

    You created a new sprite component and set it to the transform of the old skeletal mesh component. The Entity gets it's transform from the "root component" which is the scene component that other scene component's attach to. It's separation of concerns, the data is stored differently for synchronization reasons, for instance, lets say that you change the static mesh of a component on the game thread, if the render thread is accessing this same static mesh, that will be a data race condition. What the static mesh component does is , when it changes the static mesh component, it sends a message to the render thread proxy on the rendering thread with the updated static mesh render data. It's equivalent to double buffering. They don't, but I have a function that subclasses override called RegisterWithWorld , the base class (CDrawableComponent) contains logic for when it should be called, when the component should register/unregister with the renderer scene, , when the component should update it's transform/dynamic render data/ etc. The main job of CDrawableComponent base classes are to create the proper render thread representation and to perform the update (i.e sending the newly skinned matrices).
  3. Cache Coherency and Object Update

    I'm not using an abstract drawable interface. I'll try to explain my implementation. All DrawableComponents have a render thread proxy that is created when added to the scene. At the beginning of the rendering frame, culling is performed , after the culling is performed , all render thread proxies are called to generate a list of render objects (this is the equivalent of your drawitems). These are the items that the rendering system works on. I guess that my "render thread proxy" would be the equivalent of your "drawable" in your example. The renderer has no idea what a component is, all it knows is that it will be given a render thread proxy . When CDrawableComponent::Activate is called , the subclassed drawable component creates it's class specific render thread proxy , and sends it to the renderer scene. This is true, but if they do not extent from SceneComponent, I would have to provide a delegate for whenever a SceneComponent's transform is updated, so that the owning DrawableComponent knows to send the updated transform to the rendering thread , and the only thing the skeletal mesh component would contain is a pointer to a shared resource (CSkeletalMesh). It looks like you are advocating for extremely fine grained objects, i.e a skeletal mesh component that's sole purpose is holding a reference to a shared skeletal mesh object, and then that skeletal mesh component would also have a transform component which would only hold position , rotation , and scale. Also , my data-oriented performance-sensitive stuff is only working with data structs, they aren't accessing the component's specifically, like I said previously , the components allocate a "BusData" object, which has the exact data needed for updating the component in the system, nothing more, nothing less.
  4. Cache Coherency and Object Update

    But in my system, I would be using approach 4 also. The skeletal mesh component contains a CSkeletalMesh ( a shared resource ) and a unique transform, it's not a weak pointer, but it is allocated separately and updated itself. In your approach, I assume , that your "sprite" class has a sprite-sheet ( a shared resource) and a unique transform to dictate where it should be in the scene? Is it possible that i'm explaining myself wrong? My character would not be a sprite. Using your example, my character would be an entity that contains a spritecomponent.
  5. Cache Coherency and Object Update

    Maybe I explained myself wrong, I am using a combination of composition and inheritance , I have an entity and multiple types of components. It just so happens that some of my components share similar logic. There are components that must be registered with the renderer scene , which is why they are all under the base class of "CDrawableComponent" , there are also components that require a transform , and the ability to attach to other components, which is why they all subclass from CSceneComponent. Are you saying that composition and inheritance can not be mixed efficiently ? I only use inheritance when there is logic that is shared between components, and I want to abstract it in someway, i.e the renderer collects all objects that are drawables , if inheritance was not used, the renderer would have to have knowledge of all components to gain access to the draw logic and the transform logic. My code isn't running with abstract types , each system knows the exact type of data that they require , I explained the way my code works a couple files back . Components allocate a "BusData" from the component system , i.e MovementComponentBusData, SkeletalMeshComponentBusData .. etc , each frame the component system updates all of the registered BusData objects. Yeah, after some thought I'm working on an approach that might possibly work by building a "system dependency graph". There are some issues i'm currently having. I don't want to fully commit to the idea of having only one entity class (or not a class at all). I like having some subclasses so it's easier to work with in c++, i.e a terrain entity , light entity, character entity.. etc.
  6. Cache Coherency and Object Update

    1) I don't understand the benefit of taking that approach. If a skeletal mesh component has a transform component , or a skeletal mesh has a position and rotation through inheritance, they're identities are still coupled to the fact that they are transformable, all this approach would achieve is adding an unnecessary indirection. Taking a position and a rotation and putting it in a separate class does not remove the fact that a skeletal mesh must be transformable. 2/3) I think we may just have a fundamental difference in how we view OOP. The "is-a" relationship exists to show that an object has similar characteristics to a parent class , thereby reducing code bloat. I don't think it's possible to separate the two. You create base classes because of shared functionality , without this shared functionality, there would be no need for OOP. Yeah , I meant to say architecture and not cache coherency I don't know about that, I think we'd just have to agree to disagree! haha. There are many avenues in which objects share the same functionality , i.e (they are a component - > they have a transform -> they are usable in the renderer scene). I believe that it's because people are using OOP the wrong way, that it becomes convoluted, i.e making a "CSkeletalMeshComponentForUI" instead of a "CUIElementComponent".
  7. Cache Coherency and Object Update

    Actually my ui elements would be inherited as : CEntityComponent - CUIElementComponent They don't need the 3d transform (3d position , 3d scale, and 3d quat rotation) , so they would have no reason to subclass from CSceneComponent , and they are not meshes that animate, so they would have no reason to subclass from CSkeletalMeshComponent. CSceneComponent/CDrawableComponent are for component's that will be placeable in the world, i.e static meshes , skeletal meshes, terrain , water, etc.... So i don't think there is any thing restrictive about it. The "has-a" relationship is still maintained, just not as fine grained as you specify. The SkeletalMeshComponent is a drawable component which has a skeletal mesh and the scene component is a component which has a transform. I don't think the point of composition over inheritance is to remove all inheritance, it is to move further towards the one job principle , and better separation and code usage. The purpose of the base classes (CDrawableComponent/CSceneComponent) is to reduce the amount of unnecessary code bloat. Every skeletal mesh component needs to be movable, just like all other objects that are placed in the world, so why rewrite the same Set(Relative/World)Position/Get(Relative/World)Position/etc code for each class just to avoid inheritance? To the last point, I know that Unreal Engine is not the best example of cache coherency , that's why I also included other engines with available information , either from GDC or github. I have yet to see an engine that almost completely forgoes inheritance in the way you say, and has not become more complicated and bloated because of it. Even Insomniac Games , which has Mike Acton at the helm, use inheritance in their component model .
  8. Cache Coherency and Object Update

    I don't know , that seems like a lot of convoluted steps to reflect inheritance in my opinion. The skeletal mesh component is a subclass because it has a special tick function (performs animation) , and allocates a special render proxy that knows how to render skeletal meshes (CSkeletalMeshRenderProxy) , it also knows what data it needs to send to the rendering thread. Each drawable component has this type of specific logic.
  9. Cache Coherency and Object Update

    Ah.. I'm not exactly ready to make that jump. Hiearchal components Is a model that I see game engines like, unreal , cryengine, lumberyard, decima, and etc use and personally it makes more sense to me. There are a lot of components that in some sense contain similar logic. I.e a skeletal mesh component and a static mesh component. They both require a transform, they both require a render proxy(my engine is multithreaded so the render thread has a version of each "drawablecomponent" which provides draw logic. They both need a way to sync data to the rendering thread, so there is a lot of logic that they share, in reality, the only difference they have is in their "update" function. My hierarchies aren't exactly deep though, they just exist and make maintenance of code a lot easier. They definitely have an issue with cache coherency, which is what I was trying to get at when talking about the benefits of ecs.
  10. Cache Coherency and Object Update

    I don't think that would work in the current component system I have set up. Currently my hierarchy is like this : CEntityComponent (base class of all components) - CSceneComponent (base class of all components with a local/world transform and bounds) - CDrawableComponent ( base class for all components that should be registered with the renderer) - CSkeletalMeshComponent ... etc.. It seems that your approach is for systems that have one "CTransformComponent" . In my engine, a static mesh can be attached to a skeletal mesh , these two items would be in completely different systems, making your approach impossible.
  11. Cache Coherency and Object Update

    Could you give me an example of partitioning components? I don't think I understand what you mean by it.
  12. Cache Coherency and Object Update

    I think it's mostly based on transform information. For example, let say you have a gun attached to a character at point X . The gun requires the animation of the character to be finished before it updates it's own transformation. Or maybe you have a "master" "slave" animation component, where the animation component just copies the transform information from the master component. I think mostly because it would require a resorting for every time you attach and detach an object, it seems somewhat cumbersome.
  13. Cache Coherency and Object Update

    I feel like the only maddening aspect I have about is that I can't seem to find a way to maintain the required entity update order (i.e update parent before child) , that is easily achievable in a entity component model , In that method I would just have an entity put it's parent as it's dependencies , and the component's would put it's owning entity as a dependency, and it's done. With system wide updating, it seems impossible in my mind to maintain this.
  14. Cache Coherency and Object Update

    I don't know if I necessarily agree. Systems would provide the same update logic that an entity would do, but across all components of the same type at once. So in a game object model, you'd have a SkeletalMeshComponent that does the animation processing in a tick function, in ECS you would have a SkeletalMeshComponentSystem which updates all animations at once , even across threads. I think the data access patterns are quite explicit. That seems to be one of the biggest advantages over the game object model.
  15. Cache Coherency and Object Update

    I guess maybe I should of focused on the ideology behind ecs than the ecs paradigm in general. The bus data approach helps in the sense that you only load and focus on the data that is required on updating, no cache misses, no etc. I read the gdc presentation in which insomniac increased the speed of their code through smd by just focusing on the simple data that is required for updating. Even in a game object model , or game object with component, the movement of a character is dependent on input. In UE4 they have a "controller" which is ticked prior to the movement component , through a dependency graph, and pushes commands depending on input , either by the playercontroller or the aicontroller, to the movement component so no matter the paradigm , my ideology is still to push the commands instead of reading. To my point about the "movement component being dependent" it is dependent on the others in that it has to be updated after it's had it's commands pushed, or there will be one frame of latency.