Complex flow control in materials?

I’m trying to build a relatively complicated material that requires branching flow control, but having trouble figuring out how to do it.

Let’s say I have a scalar value (x) which can be 0-70, and I want to change various features of the material based on where this value sits in this value range. For example:

x > 0 && x <= 10: Feature Set 1
x > 10 && x <= 20: Feature Set 2
x > 20 && x <= 30: Feature Set 3
… and so on

The only flow control within a material seems to be the Math If node, which takes a float and outputs another value based on three possibilities (<, >, ==). So this works fine for comparing two values, but doesn’t give the opportunity (as in the Branch node in normal Blueprint) to continue testing the value down a more complicated logic branch. Or does it? Am I missing something here?

In ordinary BP, I could either convert my scalar value to an integer and then Switch on Int with the number of outputs as possibilities. Or build logic like this:

x > 0 && x <= 10 ?
True: Feature Set = 1;
False: x > 0 && x <= 10 ?
True: Feature Set = 2;

Is there a way to do this inside a material?

Since the effect I am creating is dependent upon pixel/vertex positions, it doesn’t seem like I can place this logic outside the material, so I need to find a way to have multiple possibilities based upon a value inside the material editor itself, if possible. Am I off the map here?!

For static branching you have such nodes as Static Switch, Static Switch Parameter, Quality switch, Platform Switch.
If,however, you need to do these changes on the fly, you can use whatever means of flow control you need in a custom node. Just keep in mind, that cases, where dynamic flow control is useful, are quite limited.
Tell us what effect you are after. Quite probably that there is an elegant solution to it instead of reliance on flow control.

Ah yes, I see I can build logic in HLSL in the custom node. Thanks!

This is a dynamic effect, and quite a strange one actually. Basically, at certain points I need to be able to affect the material on a per-pixel basis depending on the angle between the pixel’s world position and the camera/player. There are a number of different ‘zones’ based on the angle, and within each zone, there are certain parameters that need to be changed, but the way these parameters change is not contiguous/mappable to the changing zone numbers themselves. In case that all sounds a little abstract, here’s a simplified example. Suppose I have three zones (it’s more in the actual thing), and want to affect the values of three parameters, it might look like this:

Zone 1:
Angle > 0 && Angle <= 30
Fresnel exponent = 4.5
Tint = (0.4, 0.6, 0.1)
Opacity = 1.0

Zone 2:
Angle > 30 && Angle <= 60
Fresnel exponent = 0
Tint = (1.0, 1.0, 1.0)
Opacity = 1.0

Zone 3:
Angle > 60 && Angle <= 90
Fresnel exponent = 7
Tint = (0.2, 0.7, 0.3)
Opacity = 0.2

So, after calculating the angle (which required a custom node using atan2), I then need to work out for each pixel which zone it sits in and apply the corresponding set of parameters.

I now have this working exactly as I intended using custom nodes, but whether it will turn out to be too slow, or whether there is a better, cheaper way of doing this, I do not know!

You can do this much more efficiently by using a few dot products with vectors that are pre-defined to point at the angle you want. That would avoid the atan2s.

Also you don’t really need to use two IFs to see if something is in between to points. You can simply use spheremask type math and check the center of the 2 points and then provide an offset of the distance to the center.

Ie, if you did a dot product between normalized(cameravector * float3(1,1,0) and float3(1,0,0) that would return the cosine of the angle between the camera and the vector pointing to the right in world space which would be 90 degrees from the camera in worldspace. Then you could clamp, do 1-x and use “alpha offset” to the dead zone and use ceil. Then you can just use a Lerp to pick your value. As long as your areas are not overlapping you can lerp in any order, otherwise you’d need to order the lerps to sort the one you want on top to be last.

You didn’t say in your post, but are these angles relative to the camera or in actual world space? if its relative to the camera my suggested math needs a few tweaks.

RyanB: thanks for this. To be honest, I don’t fully understand what you’re saying because my knowledge of vector math is very limited. I’m going through what you’ve written and trying to understand/implement it. Might have to come back with further questions!

here is a super quick example that makes 3 nested cones, relative to the camera direction, meaning the cone always point forwards.



The values cos1, cos2, cos3 correspond to the angles of cutoff.

Ie cos3 at 0.954 corresponds to an angle of around 17 degrees.

if you want a 1 degree cone, do cosd(1) = 0.99984

Notice the cones are ordered widest to narrowest which enforces a sort order. you can structure that however you want.