Power ignores Y, Z components of float 3 in Exp pin if base is Float 1. Is it intended behaviour or is it a bug?
Providing float 3 to Base of Power solves the issue:
Power ignores Y, Z components of float 3 in Exp pin if base is Float 1. Is it intended behaviour or is it a bug?
Normally, you put the color value (vector) into the base and set the exponent to a float value. Then this exponent is applied to each of the vector components, e.g. making higher contrast etc…
Maybe you just mixed up Base and Exp, but I’m not sure, what you want to achieve exactly. To my knowledge, Exp is always uses as a scalar.
EDIT: here’s a Tutorial by Mathew Wadstein about the power node.
EDIT2: I was curious, doing some tests. It looks like passing in an exponent as vector is possible and has an influence when changing y and z indeed. So these definitely do not just get dropped but instead do a power calculation per component.
You made a very interesting observation. Simply having a float as base shows the same behaviour for me as you observe. While this produces a vector color output, the y and z values of the Exp get ignored. Looks like the shader compiler first checks the dimension of the Base input node you connect and then applies the same dimension to the Exp instead of using the dimension of the output or the expanded input.
So regardless if this is a bug nor not (and it looks a little but like it is), at least you have found a cool workaround. At least I even was not aware of using Exp with vector input at all ![]()
Revisiting my own thread, the case does look odd now for me too - typically you wouldn’t use float as base and float3 as exp - you would more likely to use float / float3 as base and float as exp, or maybe float3 base and float3 - e.g. if base is three of some kind of noise textures combined and you want to do exp for them separately. But float base and float3 exp sounds really odd - even if there’s such case, it’s better to use 3 pow instead of 1 to keep it readable.
Anyways, I just curious why though it does discard Y, Z from exp pin in this case and wanted to figure it out. Looking at the code, PositiveClampedPow hlsl function used under the hood just don’t have float+float3 definition and it picks up float+float definition and does coercion from float3 to float somewhere along the way.
MaterialFloat PositiveClampedPow(MaterialFloat Base, MaterialFloat Exponent)
{
return (Base <= 2.980233e-8) ? 0.0f : pow(Base, Exponent);
}
MaterialFloat2 PositiveClampedPow(MaterialFloat2 Base, MaterialFloat2 Exponent)
{
return MaterialFloat2(PositiveClampedPow(Base.x, Exponent.x), PositiveClampedPow(Base.y, Exponent.y));
}
MaterialFloat3 PositiveClampedPow(MaterialFloat3 Base, MaterialFloat3 Exponent)
{
return MaterialFloat3(PositiveClampedPow(Base.xy, Exponent.xy), PositiveClampedPow(Base.z, Exponent.z));
}
MaterialFloat4 PositiveClampedPow(MaterialFloat4 Base, MaterialFloat4 Exponent)
{
return MaterialFloat4(PositiveClampedPow(Base.xy, Exponent.xy), PositiveClampedPow(Base.zw, Exponent.zw));
}
I actually found another example of this type of coercion, but this one is much more likely to meet and I’ve met it a few times.
Material functions have input types strictly defined, but it’s not very strict - it raises no errors and just silently discards values. Sometimes it’s just error prone and introduces silent bugs, somtimes it requires you to fork/rewrite material function to allow it to pass float3 instead of just float.
Would be great if it would just error as when you would try to multiply float3 by float2.