Efficient way to randomly pick a color channel in materials?

Trying to squeeze as much as I can out of a single texture, I’ve been randomly picking color channels in addition to sub uv frames, but I’m not sure how expensive IFs are in a material. Currently, I have a Dynamic parameter randomly picking a number in a range, and testing that number between 0, .333 and .667 to determine what channel is used when the particle spawns. Something in the back of my brain is telling me though that If nodes are a bit expensive, so I’m wondering if there’s a better way to randomly pick a texture channel for a particle in an active system.

2 Likes

Lerps are a bit cheaper, they say :slight_smile:
If you can spare two random values: you can round them and use the first value to lerp between R+G and the second value to lerp between the result and B.
(Gives a bit of a bias to B, so you could remap the 2nd random value to sth like 0 - 0.8 before rounding, to balance that).
There must be a smarter way, only using one random value and lerps, can’t think of it from the top of my head

1 Like

How about this?

7 Likes

Didn’t know a dot product could be used that way. Nice one

Same! I learn so much from everyone on here :sparkling_heart:

hueshifts ftw.

While not a channel picker:
Another way is to just make a tiny “flipbook” and let a particle random/dynamic node pick one on spawn.
If they are grayscale and you set the compression to alpha you can keep the texture size rather small and often more crisp as there is no channel packing compression artifacts.


(the flipbook function)

4 Likes

Not sure the cost of various things but if you just want random channels here is another way:

Could add a round if you are worried about decimals.

2 Likes

The only reason this wouldn’t work is I’m constantly swapping texture use between color and alpha/opacity masks, and it yells at me when I have the texture compression set to Alpha and I’m trying to use it in color :tired_face:

It works fine for me, as I tend to use a lot of alpha setups.
I’d probably have another master, or another way inside the shader to flip between them.

Oh, it’s probably because I set it to that with a rgb packed texture :thinking:

Yeah the whole thing turns red when I try to use a channel in the texture for emissive :frowning: any ideas?

when you just changed a texture into alpha, it can turn red unless you set the sampler to alpha as well.

If you can give me a detailed explanation on what you want, I can prolly set up a good mat function for you :slight_smile:

If tech say you are allowed to, you can always fold it in to an array and do a v. simple look up:
image

Custom node:
float Channels[4] =
	{
  A,
  B,
  C,
  D
	};

return Channels[(int)Key];

It’s then your responsibility to make sure your key doesnt go out of bounds. The conversion to int is done as a cast so you can pass through floats.
Can’t guarantee safety across platforms, although array initialization is fairly standard there…

Some pluses are that it’s scalable; in no way limited to just 4 choices, the 4 choices dont have to be floats (you could use full colour), it’s a single tex sample in this case, and no lerps or decision trees.

7 Likes

That was probably it. I think my texture nodes are set to either color or mask in my master material, and I was only changing the compression setting on the texture. I’m using rgb packed textures for both opacity and color, and I tend to interchange them a lot (especially tiling noise textures). I’m just trying to find a good balance of compression and texture size for my textures, and an efficient way to pick a random channel via material & dynamic parameter.

1 Like

ooh, interesting.
/me likes!

Edit: when used for four inputs, an IF-setup is slightly cheaper (3 instructions), but once you add more choices, it might become slightly cheaper actually.

I’m not so confident in instruction count reports here. I wouldn’t have thought that two if statements are cheaper than an array look up, but stranger things have happened at sea

Also you can const qualify it and Unreal reports it as an instruction cheaper than the if statements.

Just use

const float Channels[4] =

instead. This will need to be a constant though, and not change at runtime afaik. But I would probably just leave it as above tbqh. Again, if you are using floats you can probably get away with the nested if’s, but if you wanted to have various sets of colors, float2s, etc, it should be better.

You mention that you’re picking color and sub uv…are they flipbooks or are you just looking for variation?

Most variation with least amount of texture use. So a 512 2x2 texture with 3 variations of each texture. I’m using this more for my larger texture sizes with no alpha as well. So if I have something that’s 1-2k (for whatever reason) I’m at least getting 3 different textures for the memory value. Each channel is being used for opacity and color tint, with modifications and control for both within its instance.

1 Like

When the compression artifacts mess it up I tend not to think of it as a bargain. :slight_smile:
I try to use greyscale whenever it’s purely tinting.

But honestly, do you want to pay with fill rate and image quality instead of memory?
If you have large numbers of these guys on screen, it might get less attractive on a per pixel basis.

Hue shift is kind of expensive compared to tinting, isn’t it?