Material in IComponentData

Hi!

I would like to select an entity. If it is selected, the material should change. My idea was to work with MaterialMeshInfo and change the material here. I wanted to temporarily save the original material and change the material during the selection process.

The problem now is how to access the Select material.

I have an IComponent:

public struct BuildingPlacementMaterialComponent : IComponentData {
        public Material buildingPlacementMaterial;
    }

And a IAspect:

private readonly RefRO<BuildingPlacementMaterialComponent> _buildingPlacementMaterialComponent;

Problem ist the baker:

AddComponent(placementBuildingEntity, new BuildingPlacementMaterialComponent {
                buildingPlacementMaterial = authoring.buildingPlacementMaterial
});

He makes the mistake that everything should be a reference type. However, material is a value type.

I have now read the documentation and could use the class instead of struct in IComponent. In authoring then AddComponentObject.

But then I have an error in the aspect that _buildingPlacementMaterialComponent should be a nullable value:

private readonly RefRO<BuildingPlacementMaterialComponent> _buildingPlacementMaterialComponent;

Do you have any ideas?

First of all, Material is a reference type, while MaterialMeshInfo is an unmanaged value type. There are quite a few different ways to solve this problem, but I’ll just give one option. The general idea is to, at runtime, replace a managed component containing the Material with an unmanaged component containing the material index used by MaterialMeshInfo. Then when you select an entity, you can just change the material index field in MaterialMeshInfo with this material index.

  • Change the BuildingPlacementMaterialComponent to be a managed class component.

  • Leave the baker as-is.

  • Define a new runtime component, perhaps called BuildingPlacementMaterialIndexComponent that contains an int field called MaterialIndex.

  • Create a system that looks for entities with a BuildingPlacementMaterialComponent that adds a BuildingPlacementMaterialIndexComponent by calling EntitiesGraphicsSystem.RegisterMaterial() using the material from the BuildingPlacementMaterialComponent. Also remove the BuildingPlacementMaterialComponent. (Don’t try to put the managed BuildingPlacementMaterialComponent in an Aspect. Managed components and Aspects don’t play nicely together. Just query the components directly.)

  • At runtime, use this new BuildingPlacementMaterialIndexComponent to swap the MaterialMeshInfo.Material with the material index of your selection material.

It is also possible to generate the material index at bake time, but this is much more complicated. Personally, I don’t mind having a couple of runtime systems that run on the first frame and swap managed components for unmanaged ones. After that is done, the material swapping can be done very fast and efficiently.

Hope that helps!

2 Likes

Many thanks!

1 Like

This worked, marking as solution through text (Cause poster forgot to)

You can use UnityObjectRef to reference Material in a struct

public struct BuildingPlacementMaterialComponent : IComponentData {
        public UnityObjectRef<Material> buildingPlacementMaterial;
    }
4 Likes