How do I convert a LayerMask into the correct layer number value to set GameObject.layer?

It’s 2025 and despite this coming up multiple times over the years (since at lest 2011!!!) no-one has added an API function to LayerMask to convert it to a valid value to set GameObject.layer from…

I’m posting this question so I can answer it with a sensible solution, and save anyone who comes after me from having to trawl about to find an answer.

Previous answers I found all seemed to involve looping over LayerMask.value right-shifting it or dividing by 2 until you get to the layer number which is completely unnecessary.

If you add the below helper class to your project you can now simply convert from a LayerMask to a layer number you can use to set GameObject.layer using LayerMask.ToLayerNumber()

// this code is released under the Unlicense: https://choosealicense.com/licenses/unlicense/
// i.e. do anything you like with it except blame me for any consequence of using it
public static class LayerMaskExtensions
{
	// you can use this to convert from a LayerMask with a _single_ layer set in it
	// to the corresponding layer number you can use to set GameObject.layer
	// returns the layer number in range 0-31
	// or -1 if more than one layer is specified in the mask
	public static int ToLayerNumber( this LayerMask self )
	{
		switch( self.value )
		{
		case 0:       return 0;
		case 1 << 1:  return 1;
		case 1 << 2:  return 2;
		case 1 << 3:  return 3;
		case 1 << 4:  return 4;
		case 1 << 5:  return 5;
		case 1 << 6:  return 6;
		case 1 << 7:  return 7;
		case 1 << 8:  return 8;
		case 1 << 9:  return 9;
		case 1 << 10: return 10;
		case 1 << 11: return 11;
		case 1 << 12: return 12;
		case 1 << 13: return 13;
		case 1 << 14: return 14;
		case 1 << 15: return 15;
		case 1 << 16: return 16;
		case 1 << 17: return 17;
		case 1 << 18: return 18;
		case 1 << 19: return 19;
		case 1 << 20: return 20;
		case 1 << 21: return 21;
		case 1 << 22: return 22;
		case 1 << 23: return 23;
		case 1 << 24: return 24;
		case 1 << 25: return 25;
		case 1 << 26: return 26;
		case 1 << 27: return 27;
		case 1 << 28: return 28;
		case 1 << 29: return 29;
		case 1 << 30: return 30;
		case 1 << 31: return 31;

		}
	
		Debug.LogError
		(
			"cannot convert a LayerMask with > 1 layer set " +
			"to a valid layer number; will return -1"
		);

		return -1;
	}
}

For (admittedly silly) example you can now do this to set GameObject.layer to a specified value in MonoBehaviour.Awake

using UnityEngine;

public class TestLayerSetter : MonoBehaviour
{
 	// this gives a nice drop down in the editor allowing you to select a collision layer
	[SerializeField] private LayerMask m_layerToSetSelfTo;

	private void Awake()
	{
		// note:  ToLayerNumber() will return -1 if > layer is set in m_layerToSetSelfTo
		// Unity will assert internally if you set gameObject.layer to an invalid value
		gameObject.layer = m_layerToSetSelfTo.ToLayerNumber();
	}

	// note: since the editor UI for LayerMask allows you to set more than one layer
	// we use OnValidate to ensure that the value set is just a single layer
	private void OnValidate()
	{
		Debug.Assert
		( 
			m_layerToSetSelfTo.ToLayerNumber() != -1, 
			"please set 'Layer To Set Self To' to a single layer" 
		);
	}
}

Is there any reason you need this functionality? Layer masks are meant to be used when you need a set of multiple layers to work with. If you need just the one layer your game object is in, you can just work with ints in the first place.

I also can’t think of a use-case where you’d want to go back from a layer bitfield to a layer index.

@darbotron
That method also assumes that just a single bit is set or it’s zero, in all other cases it returns -1. That makes this method defunct or at least misleading because a mask can and often has multiple bits set.

Try calling it like this for instance (untested code):

var layerNames = new string[] {"Default", "TransparentFX", "Ignore Raycast", "Water"};
LayerMask mask = LayerMask.GetMask(layerNames);
var layerIndex = mask.ToLayerNumber();
Debug.Log($"layer index = {layerIndex}");

It still takes looping over the bitfield and ideally you’d return an IEnumerable containing the indexes of any bits that are set. Which one you use as the index is anyone’s guess.

@drgrandayy / @CodeSmile:

I can think of lots of reasons I might want to this, and I’ve solved this exact problem several times in the past which is why I’ve asked and answered the question here.

Today’s specific use case: I have a single projectile prefab which I want to use in 2 separate object pools one for player and one for enemy projectiles.

For various reasons I want to keep the pooled projectiles for the player on a different collision layer from the pooled projectiles of the enemy; and since both projectile pools use the same prefab, I can’t set the layer in the prefab.

To handle this I have a projectile pool monobehaviour which exposes “projectile collision layer” as an editor property.

When I clone the prefab in the projectile pool manager I set GameObject.layer for all GameObject instances in the projectile prefab to match the appropriate layer as defined in the the projectile manager properties.

The simplest way to allow the user to set the collision layer in a way which has nice UX in the editor is to use a LayerMask as a property; but obviously the LayerMask value for a layer is (2^layer) so you can’t use it to set GameObject.layer - hence the question / solution I posted.

Sure I could have used an int for this property but then I would have had to either manually check the layer number in the editor UI every time you wanted to set it or to visually check which layer it was, or maybe write a property drawer for something which really doesn’t need to be one.

Similarly, I could have used a string but that suffers from almost all the same issues as well as the fact it’s very easy to make a typo in a string (or, again, write a property drawer).

Using the extension method I posted above for LayerMask have relatively nice editor UX for the property with basically no code written.

Also, fwiw returning -1 in the case where multiple bits are set is 100% intentional - it says so in the comment, and the sample code below that shows you why - you can’t convert a LayerMask with more than 1 bit set in it to a value which can be used to GameObject.layer to a valid layer number; and if you try to then a Unity assert will tell you that the value is out of range.

If I’m honest I’d also have to say that two people with the “know-it-all” tag jumping onto a new post just to “well actually” someone is not exactly setting a shining example of good forum etiquette.

I’ve amended the extension method I posted to have nicer error reporting.

Lol I’m just trying to help you dude, no need for that reaction.

Anyway, so the reason you’re doing this is to have nice UI, which is fair enough. I still don’t like using a layer mask for a case like this, as again that is meant to be used for when you want a mask with potentially multiple selected layers, and only complicates things in this case.

For this case I would personally create a custom enum with values that have the same name and int representation as the layers, and then use that for the inspector field. This solves both the nice UI issue and the whole converting from layer mask to int issue. But that’s just what I would do.

Fair enough. Sorry if you feel I overreacted - I was deliberately asking the question just to answer it, not really looking for help tbh :sweat_smile:

I get where you’re coming from, but I wouldn’t do that - though I did consider it (and have done it in the past).

I generally prefer to have one authoritative version of data like this… making an enum to match the layer numbers is jsut introducing another place where the editor data & code can get out of sync.

If I was checking / using collision layers all over the codebase then I probably would do that, but since this is literally just for one class it didn’t seem worth the hassle.

When I’ve had a collision setup complex enough to warrant the enum solution I’ve always written a quick editor tool to run on build / enter play mode and validate that the layers in TagManager.asset match the enum and another to update them if they don’t - this way the code / editor setup don’t (can’t) get out of sync.

All good! Yes that’s the main disadvantage with the enum solution, the fact that with it there’s now two sources of truth. Ideally, the best and nicest solution would probably be a custom property drawer like you mentioned, but then that’s also kind of a lot of work for a simple issue. So yeah I guess it depends on what you prefer in the end.

Btw I think just a simple return (int)Math.Log2(mask); would also work to convert a mask to an int, and it’s just one single line. Drawback being that it’ll be more computationally heavy. And also it will silently ignore cases where more than 1 layer is selected.

Yep. You could just do the log2 thing but the implementation posted should be way faster (theoretically, if we’re looking at big O).

Will update the solution to include that :+1:

You know what, I’m not going to update the solution because you can pass any old value to Math.Log2() and it will return you a float you can cast to an int which may or may not be the layer number - so you’d have to have an error check that the input LayerMask is po2 (very easy, but more code).

int LayerNumberFromLog2( LayerMask layerMask )
{
	Debug.Assert
	( 
		// well known binary test, but just in case: 
		// http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
		( layerMask.value & ( layerMask.value - 1 ) == 0 ), 
		"layerMask has more than one layer set - can't guarantee conversion to valid layer number" 
	);
	return (int)Math.Log2( layerMask.value );
}

A more elegant solution would just be a property attribute + property drawer that you apply to an int, and draw a dropdown for selecting a layer.

I definitely considered a property drawer, but I chose not to do that because it:

  1. is significantly more work than converting a LayerMask into a layer number (with more or less the same outcome)
  2. doesn’t do anything to fix the problems of converting between / comparing LayerMask bitfields and layer numbers.

IMO the most elegant solution is the “map layer numbers to enum” solution.

Combined with some editor code / a tool which validates that layers in the project settings match those defined in the enum, and with a bunch of qol extension methods to allow for converting / comparing layer numbers and LayerMask more easily this would address all the qol issues I regularly have when working with collision layers in code.