GameObject conversion and SubScene code tour
This article is outdated for Entities preview.33, it had several class name changes and various additions..
You can just give your GameObject
to GameObjectConversionUtility
static class and witness the magic. But it's always nice to know what it does inside so you are sure it really suits your need, ready to extend when it isn't, and not caught off guard by some unexpected behaviour or new patch notes.
What is a conversion
We are trying to change any GameObject
to Entity
successfully. This is difficult as ideally you want something like :
- Converted
Entity
has allMonoBehaviour
as component object and all proxies asIComponentData
like whatGameObjectEntity
can do. BUT I don't want the link. Whatever happen to the originalGameObject
should not affect convertedEntity
. (Or just destroy it, I wanna go pure) - If that
GameObject
is a prefab, I want the converted result to be attached withPrefab
(the component type name). Because I want to instantiated them ECS-style. - If that
GameObject
has children, I should get manyEntity
that somehow connected to each other transform-wise, and also destroy-wise. Also I want to operate on only the top levelEntity
not having to care about any of its child. They should somehow comes together automatically. - Combining 2 points together, a prefab with children should have its converted counterpart instantiate together by just instantiating the top prefab entity. Oh, and all child should have
Prefab
as well so those do not show up in queries. - Maybe the original
GameObject
should be destroyed too, or sometimes not. - My
xxx : MonoBehaviour
should be 10D fourier transformed/*insert your custom transformation* intoyyy : IComponentData
- As a principle I want to work on my things in edit mode in hierarchical presentation, but in runtime I want them flat and fast (But somehow works together like they are hierarchical) rather than caring about how it looks on the Hierarchy in play mode.
- Maybe each converted
Entity
should know something about scenes as well?GameObject
are scene being after all! ECS scene? - etc.
The conversion ecosystem can address all these problems!
GameObjectEntity
You used to need GameObjectEntity
to take Unity things to ECS. You used to paste those proxies (formerly "wrapper") on the GameObject
to make them turn into ECS. However GOE is not really conversion. It is linking so it exists on both side at the same time.
The new conversion tool, by not having to worry about maintaining link with regular Unity we can do a full blown heavylifting to make a "really Unity" ECS Entity
. Conversion is a one-way operation.
Conversion world & destination world
The general idea of this ecosystem goes in this order :
- Create a new "conversion world" programmatically.
- Add some specialized systems to it as workhorses.
- Desired
GameObject
are added to conversion world asEntity
in a dumb way. This is like putting them on cutting board. From now when I said "add", it is different from "convert". "Convert" means changing into final product. Adding is not quite there yet. - Teach the conversion world more about the real, intended relationship of those dumb
Entity
what they were when they wereGameObject
. - "Run" the conversion world. All dumb
Entity
in conversion world are processed and finally converted, sent to destination world. They are now sophisticated and no longer dumb. - Conversion world disposed.
- Optionally you may destroy the original
GameObject
if you don't need it anymore.
"Conversion world" is full of GameObjectConversionSystem
subclasses and one GameObjectConversion*Mapping*System
. That one mapping system collects all knowledge to make the final product.
Also this convesion world will be added some Entity
to work on. "Dumb Entity" is from this point, a made-up term referring to incomplete Entity
converted from GameObject
, staying in conversion world. It looks like what you get after attaching GameObjectEntity
and just call it a day.
If you are not familiar with GOE, it make 1 Entity
with all proxies as real IComponentData
and also all Unity MonoBehaviour
as "component object". It also maintains sync but we are only talking about conversion ability of GOE not synching ability. This conversion is quite useful, but not quite enough the real conversion we need.
This pipeline is just for your understanding, you will never need to do this yourself. You should let GameObjectConversionUtility
static class (the entry point of all) to do it. It knows how to prepare conversion world with your custom conversion system added, then run the whole thing. (explained later)
GameObjectConversionSystem
An abstract
class for you to use by inheritance, that would become one of the workhorse in the conversion world.
On this abstract
class there is no OnUpdate
, you have to make one. You will be doing conversion work in OnUpdate
. Additionally you get GameObjectConversionMappingSystem
to do your work on your OnUpdate
. This mapping system is shared for the entire conversion world.
Then when you "run" the conversion world (that is to update them all) it is like everything (GameObject
) got moved pass a processing pipeline into final, converted product (Entity
). "Everything" has to be moved into conversion world first, like putting them on cutting board.
How to register your own system as one of the conversion systems
- By having
[WorldSystemFilter(WorldSystemFilterFlags.GameObjectConversion)]
on the class, but fortunately this attribute will be inherited from subclassingGameObjectConversionSystem
. So just subclassing works. - Your system will be put into one of 3 system groups : init, conversion, after conversion. By saying nothing, you get to be in conversion group. By saying
[UpdateGroup(typeof(GameObjectAfterConversionGroup))]
, your system will run in the after conversion group. You cannot add your system to init group. override
theOnUpdate
, because otherwise your system do nothing when the update group runs.
Unity-made inheritances as of March 2019 :
- (init group)
ConvertGameObjectToEntitySystemDeclarePrefabs : GameObjectConversionSystem
- (init group)
ComponentDataProxyToEntitySystem : GameObjectConversionSystem
- (conversion group)
ConvertGameObjectToEntitySystem : GameObjectConversionSystem
- (conversion group)
TransformConversion/MeshRendererConversion/... : GameObjectConversionSystem
Nothing (yet) are preconfigured to be in the after conversion group, so if yours are in the GameObjectAfterConversionGroup
, you can make sure you can do something on top of Unity's built-in conversions.
For now let's not worry how to turn your GameObject
into a dumb entity in the conversion world. Imagine that they are already there. There are interface
you could add to MonoBehaviour
you could prepare to pass on some knowledge to the conversion system. They will tag along with the dumb entities.
IDeclareReferencedPrefabs & ConvertGameObjectToEntitySystemDeclarePrefabs
Added this contract to your MonoBehaviour
. It is featuring :
void DeclareReferencedPrefabs(List<GameObject> gameObjects);
What you should do in your implementation is adding GameObject
prefab from your exposed field to that list. You can add multiple.
Then, when that GameObject
is converted to "dumb entity", it brought along this interface.
The conversion world then will have Unity's built-in ConvertGameObjectToEntitySystemDeclarePrefabs
, a GameObjectConversionSystem
subclass that search for all IDeclareReferencedPrefabs
to collect them together on OnUpdate
. (Remember that the conversion world "runs" once, so OnUpdate
is not really running constantly but just once.) It is one of the 4 Unity-made conversion systems I mentioned.
As I said all GameObjectConversionSystem
shares a single GameObjectConversionMappingSystem
. All prefabs needed are now usable by all conversion system to make the final non-dumb Entity
. All prefabs are collected into "List #2" that I will explain later.
IConvertGameObjectToEntity & ConvertGameObjectToEntitySystem
An another dumb entity's guide to civilization. This interface is featuring
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
Again you add this contract to your MonoBehaviour
, to describe how to include something more in this MonoBehaviour
to its Entity
counterpart so it is not as dumb. When the dumb entity is made it would carry over this interface. The conversion system would then ask them all to Convert
itself.
The given entity
in Convert
is in fact the converted product of this GameObject
. And dstManager
are of the destination. Convert
occurs once when the pipeline runs, so you can do something like dstManager.AddComponent
without worrying about the duplicate component error. While in Convert
, please keep reminding yourself "I am still in the middle of conversion".
conversionSystem
is also given just in case you need more power. You could access the "power tool" GameObjectConversionMappingSystem
inside that.
The built-in system called ConvertGameObjectToEntitySystem
will be added later to your conversion world to work on ALL IConvertGameObjectToEntity
in existence. Calling Convert
on each. This system is NOT in your default world thanks to the new system flag feature.
GameObjectConversion*Mapping*System
From this point when I say "mapping system" I meant this one. When I say "conversion system" I meant the other subclasses of GameObjectConversionSystem
.
An internal
ComponentSystem
class. It acts as a big brain on the conversion along with providing "power tools" for you to do something in your own code during conversion. You can't make this directly being internal
but there are several points you can access the mapping system :
- In your
IConvertGameObjectToEntity
'sConvert
. Remember that you getGameObjectConversionSystem
as the 3rd argument, which contains the mapping system inside as a public field. So use dot notation to get to it. - In your any of your own subclass of
GameObjectConversionSystem
. You get the shared mapping system in its public field.
It also contains several public methods for you to add any/more GameObject
as "dumb entities" to conversion world.
The mapping system maintains 3 lists.
List #1 : The GameObject to entities mapping
It is Dictionary<GameObject, List<Entity>>
. That is a one-to-many mapping from every GameObject
to its potentially many Entity
. Value of this dictionary should be a live, converted entities in the destination world. The reason why it is a List
rather than a single Entity
because this tooling supports converting one GameObject
to many Entity
.
It is representing a history of conversion. It is important because we want to post-process the converted Entity
a bit more.
The first Entity
in that list of any particular GameObject
is called the "Primary Entity". All other Entity
means that you converted one GameObject
to many Entity
that looks identical. This list can keep track of them all.
Because GameObjectConversionMappingSystem
is shared in a conversion World
, you can imagine this Dictionary
containing all the knowledge about which GameObject
turned into which Entity
in the destination world.
Some of GameObject
(key) in this list are a prefab, and some are not. It will be important to use with List #2...
List #2 : Referenced prefab
It keeps a List<GameObject>
. This time it's a prefab collection. It's purpose is, when the conversion happen, we want the converted ECS side of all GameObject
to have Prefab
component correctly (if it was a prefab), then we gain ECS's fast "memory instantiation" and never having to touch the original GameObject
prefab again.
While the conversion world is running, all List #1 's key (GameObject
) will be checked with List #2 to confirm their prefab status. If it is, its (potentially many) Entity
will all get Prefab
component after the conversion.
So it is important that this List #2 is properly populated for what GameObject
you want to be reborn as "instantiable Entity
" in ECS side. (That is with Prefab
component, but just Prefab
is not quite enough as I will explain soon.)
ConvertGameObjectToEntitySystemDeclarePrefabs
that you have already learned will look through all dumb entities and collect all prefabs as declared in IDeclareReferencedPrefabs
to this List #2 while you are running the conversion world.
List #3 : Linked entity group
A List<GameObject>
again despite the name says "entity". Any GameObject
added to this list will have a relationship with all their children carry over to its Entity
counterpart.
Thanks to the new LinkedEntityGroup
built-in IBufferElementData
, it makes every Entity
in that buffer instantiate and destroys together with the one with LinkedEntityGroup
. This mirrors the behaviour of GameObject
hierarchy. Ideally that entity should have Prefab
attached so it doesn't show up in queries.
The Prefab
component does nothing about chaining instantiate, it just hide from query along with remove the Prefab
component after instantiate. The new LinkedEntityGroup
complement it, so that instantiation chains to related entities and also destroys together. Now instantiation feels very Unity, but in ECS. Prefab
and LinkedEntityGroup
completes the workflow. That's why I said just Prefab
was not quite enough.
You could add that magical buffer component yourself after conversion, but wouldn't it be great if the conversion ecosystem do that for you?
You see where this is going. By registering a GameObject
to this LEG list before conversion, when the conversion happen, its Entity
will get LinkedEntityGroup
setup nicely along with the buffer pre-populated with its related Entity
. (Which they comes from asking list #1 !) List #2 will add Prefab
to all of them which works together with List #1. 3 lists together, get you a "very Unity" converted Entity
.
At last we can see a glimpse of future of Unity. Where in edit mode is kinda GameObject
but in play mode suddenly they are all turned into Entity
while retaining all GameObject
's strength.
Public methods on the mapping system
These are 3 helper tools you can use during conversion :
- public Entity GetPrimaryEntity(GameObject go) : Get the 1st
Entity
from the list #1. You don't need to worry if the conversion had happened or not, because if the conversion didn't happen yet, you get the 1st conversion right now and also get back theEntity
result because that's now your primary entity. So this "get" is actually a "create" built-in.
This "create" is a dry create. Like it is really just an emptyEntity
! However the point is to get you thatEntity
reference to the final result while still being in the middle of conversion pipeline.
In the pipeline, there are several Unity built-in system that ensure all yourGameObject
got "primary entitied" at least once. - public Entity CreateAdditionalEntity(GameObject go) : Add more dry entity from the same
GameObject
by doing the same "create" routine asGetPrimaryEntity
, but this is repeatable. Errors when you haven'tGetPrimaryEntity
to ensure at least one convertedEntity
first. - public IEnumerable<Entity> GetEntities(GameObject go) : Get all converted
Entity
so far for anyGameObject
. That is the wholeList
per oneGameObject
.
Primary Entity revisited
During conversion, if the conversion world knows enough we can now make use of primary entity in a meaningful way in our own conversion. (Make use = somewhere in IConvertGameObjectToEntity
's Convert
or our subclass of GameObjectConversionSystem
's OnUpdate
)
I mentioned that one of the key in List #1 can be a prefab. For example, if you use that as a key to ask its primary entity (index 0 of that list) you get the correct converted Entity
of that original prefab, that is ready to be instantiate by ECS.
If you are looking to instantiate the converted Entity
right away by someone, here's your chance to grab that converted Entity
during conversion and assign as an Entity
field to that someone. You can do this early even before the conversion is finished because you are given that final Entity
reference which will be completed down the line.
Remember 2 points where we could use the mapping system? One of them is the IConvertGameObjectToEntity
's Convert
, it is already later than IDeclareReferencedPrefabs
collecting by ConvertGameObjectToEntitySystemDeclarePrefabs
by the pipeline's fixed ordering (more on this later).
So you are ready to use that mentioned trick in the Convert
method scope. Convert
gives you the mapping system as the 3rd argument. You got your original prefab GameObject
somewhere here also. That conversion system already known about prefab declaration. Finally, you got everything to do GetPrimaryEntity
with the prefab GameObject
.
See this official example which pass on the prefab conversion result to ECS. Without this you will have trouble looking for the converted Prefab + LinkEntityGroup
Entity
of a particular original prefab GameObject
. Now you get the correct one thanks to the mapping system. (Now the word "mapping" make sense right?)
But there are more than those 3 public methods. This 2 "add" public method are different that it adds any GameObject
to conversion world as a dumb entity. But they are added with care, it recurses and do things you are expecting :
- public void AddReferencedPrefabAsGroup(GameObject prefab) : Keyword is "referenced". Manually do the thing you could have done at
IDeclareReferencedPrefabs
, just in case you don't have a chance to bring thoseGameObject
with the interface to conversion world.
Add that prefab to List #3, then itself and all its children to List #2. By "add", the conversion do not happen unlike withGetPrimaryEntity
, but rather the add is still in conversion world. This is the gateway to populate conversion world so that all the conversion systems get something to work on in the first place.
The "add" is byGameObjectEntity.AddToEntityManager
, a static method available from long ago that make a dumb entity with allMonoBehaviour
to component object + all proxies toIComponentData
. "ToEntityManager" 's entity manager is now referring to conversion world's entity manager not the destination world ones.
Duplicate add of the same prefab is prevented by checking with List #2 and no addition will occur, as it does not make sense to have duplicate "blueprint entity" generated in the destination world, who is intended to be the "duplicator" itself later. Why do you want multiple prefab entities? You usually want multiple normal entities. - public void AddGameObjectOrPrefabAsGroup(GameObject prefab) : Similar but this time it works for non-prefab too. It is added to List #3 to indicate that you explicitly want the converted
Entity
side to be grouped withLinkedEntityGroup
even if it is not a prefab. If it is a prefab, itself and all its children will be registered to List #2 to remember they are all prefabs. Again, the conversion didn't occur yet and still in conversion world. And again duplicate prefab add is prevented.
This 2 will be called automatically at some point but you could be doing it manually too. That makes it 5 public methods of the mapping system. Next, we will finally use everything we learned so let's take a small break with this divider.
GameObjectConversionUtility
static
utility that accepts any GameObject
you throw at it. Finally we can apply all knowledge so far to understand this power tool!
Conversion world revisited, how it REALLY works in steps
I said that a conversion world is full of GameObjectConversionSystem
subclasses and one GameObjectConversionMappingSystem
. From now on when I say "create a new conversion world" these systems are prepared first together as a group.
1st group : GameObjectConversionInitializationGroup
ConvertGameObjectToEntitySystemDeclarePrefabs
added. Explained, works withIDeclareReferencedPrefabs
on the dumb entities brought into conversion world to collect prefabs together to one shared mapping system.ComponentDataProxyToEntitySystem
added. Not explained yet but I will explain now real quick.
ComponentDataProxyToEntitySystem
Remember that the conversion world is likely populated with either AddReferencedPrefabAsGroup
or AddGameObjectOrPrefabAsGroup
of the mapping system. Those "add" are dumb with components kinda copied from the original GameObject
in the same style that GOE did.
On the other hand when something like GetPrimaryEntity
is getting called, the destination world is getting populated with the real, wanted Entity
result. However, those result are dry entity as in just an empty Entity
. We need someone to make the result looks better.
This ComponentDataProxyToEntitySystem
which runs in the pipeline will make those dry entities in the destination world not dry anymore with GameObjectEntity.CopyAllComponentsToEntity
, an another GOE static tool besides GameObjectEntity.AddToEntityManager
. The copy source are the dumb entities in conversion world. The "to entity" target is the conversion result in destination world (the currently dry entity) known thanks to List #1, and thanks to GetPrimaryEntity
.
Also because this system is doing GetPrimaryEntity
on all dumb entities, it is the first one that ensure the final Entity
in the destination world are there because GetPrimaryEntity
has built-in dry create.
Those two are in the same group, updates first on conversion world "run". You can imagine that at this point if dumb entities are properly placed in the conversion world, you get (an unfinished) Entity
result in the destination world already.
Then we have the 2nd group following it to finish them up.
2nd group : GameObjectConversionGroup
- All other subclasses of
GameObjectConversionSystem
that's not those 2 added. It finds all built-in and also your custom subclasses thanks to[WorldSystemFilter(WorldSystemFilterFlags.GameObjectConversion)]
flag inherited to your class. This is assuming you didn't put in anyUpdateInGroup
.
Currently in addition to your own you will get Unity's : ConvertGameObjectToEntitySystem : GameObjectConversionSystem
, this is essentailly aIConvertGameObjectToEntity
'sConvert
runner. Because this is in later group, you have all the knowledge of "declared" prefab too. Of course you could "declare" more because you got the mapping system here, and you have thatAddReferencedPrefabAsGroup
method. This let you modify the destination world's entity with something more. More than what GOE scan-and-migrate static methods can do for you.
Maybe you don't have to make any your own customGameObjectConversionSystem
subclass! Just put a custom logic per-GO type inConvert
, then let this one system run them all.TransformConversion : GameObjectConversionSystem
put necessary transform related components so they are linked together transform-wise (One of the good stuff isParent
which ensure things go together in hierarchy like in normal Unity). This make it as "Unity" as it can get for anEntity
.- Some conversion system from the other packages?
Finally when all steps are done (2 groups had passed)...
3rd group : GameObjectAfterConversionGroup
If you use UpdateInGroup
on your conversion system you could instead put them in this conversion pass. I think the point is so you can process what Unity-made conversion system did one more time. Or maybe just categorize your own conversion into 2 passes.
I believe you could not put any other group on conversion system than GameObjectConversionGroup
and GameObjectAfterConversionGroup
. (You cannot force your systems in the init group!)
Imagine you want the transform Parent
chain to change material together the same way. You can put your MaterialLinkingConversionSystem
in this group and expect to find all Entity
got the Parent
linked up already.
Prefab and LinkEntityGroup finalizing step
The really last step is it will add Prefab
and LinkEntityGroup
correctly to the finished product in the destination world.
This is possible by List #1 #2 #3 in that single mapping system working together, having know everything possible from all interface prefab declaration, you custom declaration by mapping system's public method, etc.
At this point you better make sure nothing you want the convertor to do is unknown or you may get a "disconnected" converted Entity
. Remember that at this step all your custom Convert
are executed. Also all your custom GameObjectConversionSystem
are executed. Use those chance to finish remaining missing links by telling the mapping system something.
With that explained, let's go through all static
methods of this utility.
public static Entity ConvertGameObjectHierarchy(GameObject root, World dstEntityWorld)
Single conversion. You prepare your own world that is to receive converted entities. Also give you back the reference to the result's primary entity.
Create a new "conversion world", then add that single root
GameObject
to the conversion world with AddGameObjectOrPrefabAsGroup
of the mapping system. It would then recurse add everything down the line.
Prefab or not, all its children are now eligible to be in LinkedEntityGroup
's buffer of the top level Entity
.
Run the conversion world, everything happen as explained then dispose the conversion world. Done!
public static void ConvertScene(Scene scene, Hash128 sceneHash, World dstEntityWorld, bool addEntityGUID = false)
This one looks OP. All GameObject
at root level in the scene will be recursive converted down to their last child in the same way as ConvertGameObjectHierarchy
.
But wait, there's something more about sceneHash
and addEntityGUID
. I mentioned at first, ideally the converted Entity
should have some sophisication about the scene. After all, its original form was GameObject
who is a scene being. If you use ConvertScene
you are eligible to receive these kind of data tagging along with your converted Entity
!
Sub scene
There's a catch, those scenes that entities can belong to must be a SubScene
. The converted entity can belong to one SubScene
if you use ConvertScene
on a Scene
containing SubScene
. Entity
cannot belongs to that classic, top-level Unity "scene".
Sub scene has that "ECS" smell. First of all it is just a GameObject
inside the scene with SubScene
component. This make the conversion tooling able to recurse the same way. See this, it looks like an another scene nested inside but looking at the Inspector RotatingCube
is really just a GameObject
when I click on it.
Sub scene entity : allows scene streaming
By the conversion pipeline running through this sub scene game object, this means you will get that one bonus Entity
that represent this GameObject
with SubScene : MonoBehaviour
too! It is an Entity
with component object SubScene
. There is no dedicated IComponentData
version of SubScene
.
However this is not just a junk. Meet the public struct RequestSceneLoaded : IComponentData
.
That bonus Entity
converted from GO with SubScene:MonoBehaviour
will have this added based on Auto Load Scene check box. If not checked you can add it later yourself. There is a system called SubSceneStreamingSystem : ComponentSystem
, that looks for RequestSceneLoad
and load the scene. The request seems to be removed after the load.
The subscene entity will also have SceneData : IComponentData
remembering various metadata.
Scene hash
How an Entity
belongs to any scene is by remembering the scene hash. Because originally Unity differentiate scene by its string
name we need something compatible with ECS. So we are using Hash128
instead.
SubScene
component contains public GUID SceneGUID
property. The GUID
data type is usable in place of Hash128
.
With sceneHash
as something not default inputted into this magical ConvertScene
method you will pleasantly notice some more scene related components popped up on the ECS side. If you do not provide the scene hash, you are not getting any scene features in the converted Entity
. It just convert the entire scene.
Scene section
This new feature allows an entity to not only belongs to a (sub) scene, but as well belongs to an integer section inside that.
To make scene section happen, we need to know about these :
- public class SceneSectionComponent : MonoBehaviour - Holding an integer. You could further divide the sub scene in to sections by adding this component to
GameObject
to be converted, that is a parent of something more. AfterGameObject
conversion, all theEntity
converted children of thatGameObject
now belongs to that integer section marked by SCDSceneSection
. If there is an another section nested down the hierarchy, each child get its nearest section recurse upwards. (The same fasion asasmdef
folder if you had used it) I guess it does not do anything if outside of a sub scene. - public class SceneSectionProxy : SharedComponentDataProxy - Seems to be for use instead of
SceneSectionComponent
if you don't want to do conversion, but want to do hybrid style linking and wanted a scene section at the same time.
There's one more thing you can add along with SceneSectionComponent
to the GameObject
to be converted :
- public class StaticOptimizeEntity : MonoBehaviour - Add it the same style as
SceneSectionComponent
but this time it make all its child getStatic
component after the conversion. (you could say all its children are now optimized?)Static
entities update once to compute transforms then addFrozen
, which make it receive no more transform updates.
And finally, meets the public struct SceneSection : ISharedComponentData
.
The component tags integer section in the converted Entity
. Maybe you can plan to do something fun to everything in the same section later.
However this is not only remembering the integer section but also sub scene's scene hash as well. Ensuring that you could use the same integer in a different sub scene and not conflicting when you query the SCD.
This also doubles as to say which entity belongs to which sub scene even if it doesn't belong to any scene section. If you provide scene hash in ConvertScene
, but as it recurse it found an object under subscene but not in any scene section parent it will still get SceneSection
added but with section integer = 0. Don't name your section 0!
Also everyone will get public struct SceneTag : ISharedComponentData
along with SceneSection
, it can be used to get back to the "sub scene entity".
ConvertToEntity : MonoBehaviour
With this you don't even need to find somewhere in the code to call any of GameObjectConversionUtility
's static method, because it will throw itself to the utility on Awake
. Has an option to delete the original object too!
Modes
- ConvertAndDestroy : Convert the entire hierarchy and destroy itself.
- ConvertAndInjectGameObject : Do things like
GameObjectEntity
. Convert just itself (not drilling down) and then add all mono component of itself to that new entity. (ExceptGameObjectEntity
,ConvertToEntity
, and proxies since those will add its counterpart on their own.)
But that's not all, this class is not just MonoBehaviour
but comes with several public static
methods..
- public static void ConvertHierarchy(GameObject root) : Exactly what it did at
Awake
withConvertAndDestroy
mode but manually.
VSGameObjectConversionUtility.ConvertGameObjectHierarchy(GameObject root, World dstEntityWorld)
?
This one usesWorld.Active
as the destination. Also this one returnsvoid
where the utility ones returnsEntity
. This one also destroy the original. And lastly this one do not handle the case whereroot
is a prefab. (You get a normal product, notPrefab
component attached product) - public static void ConvertAndInjectOriginal(GameObject root) : Exactly what it did at
Awake
withConvertAndInjectGameObject
mode but manually.
You can imagine using those static
method multiple times with disabled GameObject
(I think that's the use case?)
- public static void AddRecurse(EntityManager manager, Transform transform) : Add recurse is a subset of
ConvertHierarchy
. It just make a tons ofEntity
without putting them into conversion pipeline for the whole hierarchy. (So you get just theGameObjectEntity
style behaviour, not any other transform linking, etc.) - public static bool InjectOriginalComponents(World srcGameObjectWorld, EntityManager simulationWorld, Transform transform) : This one I have no good idea how to use it!
The internal use while in the conversion pipeline is thatsrcGameObjectWorld
is the temporary conversion world (Which must containGameObjectConversionMappingSystem
with all the history of conversion). So it could look for convertedEntity
by giving ittransform.gameObject
, then after found one, migrate all component objects from that game object to that entity. Well, you know you have already got that kind of result from the conversion so it must be that this is already used internally.
However by using various conversion opened to public, you are never given the conversion world at any moment. It is created and destroyed before you know it. So I don't know how thispublic static
method could be used to great effect? Also note thatGameObjectConversionMappingSystem
needed to be insrcGameObjectWorld
to work is also aninternal
class. Hmm 🤔
Other built-in conversion systems added to the conversion world
TransformConversion
It adds LocalToWorld
, Translation
, Rotation
, NonUniformScale
to all. There are optimization paths, if it has Static
then only LTW will be added. If it has exactly 1, 1, 1
GO scale NonUniformScale
is not added. It is usually the case, so this optimization is welcomed. (And uh, go clean up those (0.9998, 0.9998, 0.9998)
scales on your objects to take advantage of this) But remember you cannot scale later without adding NonUniformScale
by yourself first.
MeshRendererConversion
MeshRenderer
and MeshFilter
, two bread and butter classic mono component which make you see something since forever. They can be now converted to RenderMesh
SCD component. Finally you can comfortably see something tangible in edit mode and that become an efficient entity-based rendering in play mode.
LODGroupConversion
I didn't mention this but it is hidden in hybrid rendering package.. it converts the LODGroup
MonoBehaviour
component to MeshLODGroupComponent
, the ECS version.
HLODGroupConversion
This HLOD
mono component comes with the hybrid rendering package. This time it converts to MeshLODComponent
. The GO with HLOD
should also use LODGroup
.