 As I've mentioned, Unity as of yet provides very few stock ECS components and systems. And so as of yet, a lot of the functionality that's in the old GameObject components, only a small subsection of that right now has an analog in ECS. Really, all we have at the moment are two namespaces, Unity.rendering and Unity.transforms, that allows to position objects in space and to do basic rendering. Here I have an example that uses both rendering and transforms. This is based on an example I got from this GitHub repo by S.Tariq Satin. And because in this example we're going to need a mesh object and a material object, well, we want those to be loaded by Unity as conventionally done in scenes. And so we're not in a system here, we're in an ordinary monobehavior which I've called BootStrap, given it these mesh and material fields. And then over in Unity I have this BootStrap object which has an instance of this BootStrap script and I've plugged in the stock cube mesh for the mesh and this red material, which is just a solid red material. So once the scene loads, we'll have this GameObject with this component with these two properties and so Unity will do the business for us of creating this mesh object and this material object. So back here in my code, I want to do some business after the scene loads and the way I can do that is I create this static method, taking nothing and returning nothing and give it this attribute called runtime initialize on load method, specifying that we want it to run after scene load. And inside the method, we find the object, get its BootStrap component, assign it to this BootStrap variable and now we can get at the mesh and the material which Unity has loaded for us. And what we're creating here, mesh instance renderer is defined in Unity.rendering and we provided a mesh, a material, we specify which submesh of the mesh we want to render. So this is an index and in this case the cube just has one submesh and we want that first submesh zero. We specify if we want this thing to cast shadows and we'll say no and do we want it to receive shadows, also no. And this mesh instance renderer is a shared component type. So we're going to create multiple entities but they will all have the same value cube renderer. So now to create the entities, we get the entity manager, we create a cube archetype which consists of a position, heading, transform matrix, move speed and move forward. These are all non-shared component types defined in Unity.transforms. And now having to find this archetype in a loop, I'll create a bunch of entities of this archetype and set component data for the position, the heading and the move speed. Well to say the speed is just one, the heading, that's the direction we're moving in also effectively determines the rotation but we express the heading as a unit vector which here we just want to be random so there's this handy property on unit sphere that gets us a random vector three. But the value expected here is supposed to be a float three which is a type defined in Unity.mathematics which is a new library used a lot in conjunction with ECS and the job system. Float three as the name implies is three float values and it's basically the Unity.mathematics equivalent of the vector three class and there's an automatic coercion method for converting from vector threes to float three so that's why we don't have to convert here, it's implicitly converted. And the position here will just set to be the origin zero zero zero so everything just starts at the origin and then we'll move away from it in a random direction and lastly to make all these things render we need to add in the mesh instance render component and because they're all sharing the same component value they'll all be rendered in the same way they'll all be rendered as this mesh with this material and then we'll cast shadows or receive shadows. So now this is actually all the code I need to render some cubes starting at the origin and which will slowly move off in random directions because having to find these entities with these components there are systems in Unity.transforms in Unity.rendering which will take these entities and render them and we'll look at that code in a second but let's just go over to Unity and see this in action, hit play and there they all spawn at the origin but they have different headings and they're heading off in different directions but at the same speed before looking at the system code looking here at the definition of the mesh instance render shared component you'll see down here there's also this class called mesh instance render component which is inherited from shared component data wrapper there's this class which allows us to wrap our shared components and there's also a non-shared version of this wrapper class just called component data wrapper but here we're wrapping the shared component instance mesh instance render in this new class and what this does is it creates an old style component a game object component which simply holds a value of this component type in this case a shared component type and then in the editor it exposes all these fields as properties so with this wrapper of mesh instance render I can come into the editor and add a component and under scripts because it's considered like a custom script under rendering there's mesh instance render component and if we open this up it exposes under this serialized data exposes all of the elements of the struct so we can plug in here say our cube mesh and we can plug in the material and we can specify the submesh index and whether this thing should cast shadows or whether it should receive shadows and now back on our code to get a mesh instance renderer with that mesh and material and all those properties we simply get at that mesh instance renderer component the wrapper and then from that it has a value property and this value is the wrapped I shared component data which we hear then assigned to cube renderer and then the rest of this code is the same so arguably this is a more convenient way to set up our cube renderer so I might just verify that this version has the same behavior come here hit play and yep we get the same result we get a bunch of cubes just spawning at the origin and heading off in random directions you may have noticed that when I added mesh instance renderer component this wrapper type it automatically added a game object entity to the same object and that's just a rule anytime you have one of these wrapper types you have to have this game object entity and what this game object entity script does is it automatically creates an entity in the default world so for this bootstrap game object there will be an entity equivalent automatically in the default world which has a mesh instance renderer ECS component not a game object component now actually in this case we don't really use that entity that entity that's being created here automatically doesn't actually do anything it's not being used we just really wanted an easy way to set up a value of the mesh instance renderer shared component type so the fact that this is required in this case that I can't have my mesh instance renderer component wrapper without the game object entity in this case there's really no good reason in this case why it's required but in other cases you may find it useful also understand that this game object this bootstrap game object and its entity equivalent they are not bound together there's no two-way data binding going on it's not a live relationship where changes to the one affect the other after creation the entity derived from this bootstrap game object is just an independent thing from the game object so changes to one do not affect the other I've seen some talk on the forms of this is something they want to address so that you can have live two-way data binding relationships between game objects and entities but as of yet that's not how it works one more thing to talk about in the editor before looking at the system code is that we can bring up the new entity debugger window what it allows us to do is introspect all of our systems and all of our entities and right now without the game running as far as the editor knows it you see this pull down that's showing us the worlds and I don't play the game it's showing me the so-called editor world and in the editor world the only entity that exists is the one created from this bootstrap game object because the other entities we create are going to be created at runtime by our code but if I now play the game and hit pause you'll see it's now showing us the default world and in the default world the actual world we have at runtime we have that original entity that was created via the game object entity script and now we have those other nine entities that we created and as you can see we can introspect these and see the transfer matrix they have the position they have, they're heading, they move forward all the components that make up that entity and then here on the left you can see we have actually a lot of systems going on because we did bring in the Unity rendering and Unity transforms namespaces and that's where these systems are coming from in our own code we didn't create any systems remember we just have a single amount of behavior with a static run on load method that's all we have so this is all provided by Unity itself and unfortunately at the moment I think there's something they'll change but right now it's just showing the systems in alphabetical order whereas pretty obviously you'd want to be able to look at the systems in order of their execution but right now it's just alphabetical and at the top of the list you see entity manager, you click that and it just shows you all the entities but if I click on some specific system like here it's telling me which component groups this system concerns so there's two component groups, one that's looking for move forward components, move speed, rotation and position components I probably can't see it on the video but the blue ones are labeled RO as in read only and the green ones are labeled RW and the second component group is looking for entities with a heading and move forward and move speed and those are all read only and then read right for position and then the red one here that's a minus sign so this component group only matches entities which don't have a rotation and this number here on the right that's showing currently as we're pausing the debugger how many currently existing entities have matched this component group for the second component group there are nine and then for this first one there are zero the systems that are grayed out are the ones that have currently for their component groups no matching entities when we do have entities matching the component group we can look in the component group and click on an entity and then see its details in the inspector so now let's actually look at the mesh instance renderer system, this is the system in the Unity rendering namespace which will take our entities and actually render them and the component group which this system is looking for is expecting the entities to have a mesh instance renderer a transfer matrix component and not have a mesh cold component and a mesh LOD an active component these two component types are actually just tag components if you go look at their actual definitions there's nothing in them, they're so called tag components because they have no data you just put them in entities to effectively mark that entity and so if an entity is marked by either one of these components then it won't be rendered because the idea is if you've cold a component it shouldn't be rendered and if it's not within the current level of detail then it should be LOD inactive the cooling system and the LOD system are much more complicated than just the simple rendering system so I won't go into them but if you're interested you can go look at their code anyway so our mesh instance renderer system is looking for entities with a mesh instance renderer component and a transfer matrix and in each update remember mesh instance renderer is a shared component and so first off it's getting all the unique mesh instance renderers that's what this code does here mcached unique renderer types is a list of mesh instance renderers which you pass in and it gets populated with all the unique mesh instance renderer values and then we create a forage filter from those unique values and then in this loop for each unique mesh instance renderer we get that renderer, that mesh instance renderer value and we get a component data array of the transfer matrices passing in the forage filter and the index and if you recall from the previous video this transforms array is only going to iterate to the entities which have this particular renderer value so with the renderer and all the transforms that are using that renderer we then want to render all those objects because what we're doing in this loop is we're rendering as a batch, we're rendering all the entities which use the same mesh instance renderer the things that have the same mesh and material so they're rendered in the same way now the actual rendering work is done by the draw mesh instance static method of the graphics class which is a class actually that's been around for a while in Unity and it allows us to draw for that one frame to draw something in our game without necessarily using any of the old game objects in their components so it has for a while been possible to render in Unity without any game objects and so that's what we're doing here you pass in the mesh you pass in the sub mesh the material and this here is an array of transfer matrices because this one call is rendering multiple instances of the same mesh and material it's rendering them at the different positions specified by the transfer matrices that make up this array and here length is the count of instances to render which may not necessarily be the same thing as the length that they render because you might have an array of matrices that's larger than the number you actually want to render so that's why it's specified separately null here is passed to a properties argument which is additional properties about how to render materials but we're not using any of that here so it's just null and then the last two arguments here are specifying whether we cast shadows and receive shadows which again is coming from the renderer component because that's where we specified that option and the reason we have to call draw mesh instance in this loop is because there's limitation that draw mesh instance can only render up to 1,023 instances at a time so we might have more than 1,023 entities all using the same renderer and so we have to actually go through a loop and split them into bunches of 1,023 the other issue here is that we can't just take the transforms as is because in their entity component form it's a different representation than what this method is expecting the draw mesh instance method is expecting this array of matrix 4x4 whereas ideally we'd be able to take the transfer matrix data as it exists in the entity component chunks and just pass that in but the graphics class long predates ECS so they didn't design it with this in mind so this is something they're talking about rectifying and I guess adding an overload of draw mesh instance that will take in a native array rather than a matrix of 4x4 in the meantime then what has to happen is we actually have to copy all the matrices from their ECS form in the ECS chunks into these matrix 4x4 arrays and we have to do so every frame so there actually isn't at the moment a very obvious and serious performance inefficiency in the mesh instance renderer system and that's what this method appears doing it's taking the transforms from the component data array and then taking that data and just packing it into a matrix 4x4 array that's all this is doing oh and one little detail you have to get right when using the mesh instance renderer system is that the material you use must have this checkbox enabled enable GPU Instancing without this checked we'll get an exception when it calls graphics.drawMeshInstinst so that is how the mesh instance renderer system works you may be wondering though well we added a transform matrix to our entities but we're not actually setting that value on our entities well what's happening is that by virtue of giving our entities a position and a heading and a move speed there are other systems in the Unity Transforms namespace that are taking our entities and computing a new transform matrix value from those other components and that is done here in the transform system which is quite lengthy and so I don't think I'll really go into the details here but understand this is how that is happening the transform matrix components are computed from the other components much more simple is this move forward system which is taking our entities with their headings and move speeds and modifying the position it also does the same thing as you can see for an entity which has a position rotation and move speed heading in a sense is just a different way of expressing the rotation I imagine like a handle sticking out of an object and if that's your forward heading well what if you point the heading in some other direction and that's just another kind of way of specifying a rotation so a heading is like a rotation expressed as just a vector whereas these rotation components if you go look at the rotation component class it's a quaternion again we have the Unity.mathematics namespace which has its own quaternion struct type which is I'm honestly not exactly sure what's inadequate about the old quaternion and vector three types because those are of course and so I would think they would be just as efficient as these new types but perhaps there's something I'm missing anyway so back in the move forward system you can see here it's a job-ified kind of system the actual work is being done in this job if we go look at the actual on-update method this is a job component system rather than a component system and so the on-update is expecting a job handle for the input dependencies and we return a job handle which we've defined in this class we've defined two job types there's a move forward rotation job and a move forward heading job both I job parallel fours which if you recall it's for a job where you're going through some range of indices from zero up to some number of iterations and you want to logically behind the scenes have that split into separate jobs such that the ranges can be processed in separate smaller jobs that's what that automatically happens with I job parallel fours based on its current position its current move speed and its current rotation and then the move forward heading is almost exactly the same thing except the way we compute the rotation is different because we're dealing with a vector heading instead of a quaternion rotation so both these jobs are bringing in component data arrays notice that the heading and move speed data arrays are read only because we only need to read the data as in delta time both these jobs are doing a calculation based on the amount of time elapsed that has to be passed into the job so down here on update when we create these jobs we create the move forward rotation we get the component data arrays from our component group set those up and then for DTE we get that from time dot delta time just like we do in model behavior code so we have the move forward rotation job and the move forward heading job and because these are I job parallel fours we have to specify the number of iterations that's from the length of the component groups and we specify a batch size 64 is a quite typical size for when each execute does just a small amount of work and we make these jobs dependencies of the input dependencies the job handle passed in because it might be the case that there are other systems that have created jobs that might conflict with these and we need to make sure that the appropriate dependencies are set up when we schedule the jobs we know for sure are okay to run concurrently because they don't interfere with each other if you go look at the component groups you'll see that the forward heading group will not match any entities that have a rotation so any entity matched by this component group will not be matched by this component group they're mutually exclusive sets of entities so that's why one of these jobs doesn't have to be a dependency of the other it's okay if they run concurrently but then we need to return a single job handle so if we have component systems if they happen to touch component groups that conflict with these component groups they won't interfere with these jobs that will have set up the appropriate scheduled dependencies and so we combine both of these two job handles from our jobs that we created combine them into one handle and that's what we return so we have a system here that every frame is going to set up some jobs that will move our objects which have headings or rotations and have a move speed