As you may already know, it is possible to use textures to drive the mapping of coordinates in order to achieve various effect, for instance inputting a noise texture as the vector of another texture to distort it. When using a gradient texture to drive coordinates, I stumbled upon an issue which I am not sure is expected behavior or not: I am posting here before submitting it as a bug/suggestion.
Gradient textures output pure black at 0, pure white at 1, and everything in between on the axes onto which they are mapped, which is what one would expect of a gradient. However, it appears that all coordinates below 0 are RGB(0,0,0) and all above 1 are RGB(1,1,1). In other words, the gradient does not extrapolate above zero to values above white and below zero to values below black, which is unfortunate when you use the gradient to map coordinates because the textures will stretch to infinity above 1 and below 0.
I attached a picture that shows the issue, showing what happens when a gradient is used to drive the X coordinates of a noise texture on a simple cube (This is not the effect I am trying to achieve, I’m actually using a radial and spherical gradient in order to achieve a polar coordinate system, but I made this because it is uncluttered)
I understand that RGB values above 1 and below 0 are not meant to be seen, and that using them as colors could actually start emitting light or absorb light from the scene. But shouldn’t the node extrapolate by default, with a clamp option to prevent this issue like we already have on math nodes? Am I overlooking something as to why the node was programmed this way? If not, do you think I should submit the idea to developers?
You can still scale and translate this output to fit your needs, or to recreate the texture node to allow values in any range (the gradient texture is fairly easy to build).
Anyway, I don’t think it’s a big problem for some nodes to clamp their values (or even to throw negative numbers like the Musgrave node).
If you know the limits of the texture nodes, you can use them with better control.
Yes indeed I can scale the texture coordinates by multiplying them which is what I am doing at the moment, but I think of it more as a workaround: the point of using procedural textures with object coordinates is usually to keep the scale consistent across all objects without having to tweak it for each individual instance (remember that if you scale the gradient and that you use that gradient for mapping coordinates, you’re gonna have to tweak all the scaling values in your material that depend on it if you want to keep things consistent). I believe what I am advocating here is that I think it would be more flexible to have the control over having clamping or not, rather than forcing clamping.
I’m very curious as to how you would rebuild a gradient texture without clamping, especially radial and spherical (linear is pretty much what coordinates are themselves by default). Do you mean using only cycles nodes to recreate it or scripting it in OSL? If you mean the former and you have time, I’m sure some people could benefit from knowing how you do it. As for OSL, I know it’s very powerful and some like it, but my main issue with it is that it cannot run on GPU and that’s kind of a deal breaker for me. Yet I’m sure some people would benefit from knowing that as well.
This is basically how the gradient node works… (took it out of the svm, but the osl is the same)
The node still applies a clamp after these functions… but I didn’t include it here.
I forgot to include the ‘Linear’ but the node only returns the x component of the coordinates.
The Radial could be simpler if we had atan2 in the math node…
Thank you so much for taking the time to show us, much appreciated. I played with your spherical set-ups (linear and quadratic) since they’re the ones that I need the most and noticed that they don’t have the same falloff as the cycles default. You can compare them on this picture:
Yours are much sharper, I believe it has to do with the dot product node because playing with the subtraction and maximum didn’t seem get me the desired result. However, my mathematical knowledge is a bit limited and I am not sure how the dot product translates into a gradient, so this setup is a bit harder to comprehend for me.
Nonetheless, I find that I am still stuck with the same issue, that is the values below 0 do not extrapolate into below pure black. Do you know any way to extend this node set up so they do?
To give you a better context, I’m simply trying to transform cartesian coordinates into polar coordinates. I use a radial gradient for the X axis, which obviously doesn’t need to extrapolate because the X axis turns back on itself at 0 / 2pi and it specified by a value between 0 and 1. For my Y axis, I use a sphere gradient stretched to infinity (0) on the Z axis (effectively giving a cylinder), but this is where the lack of extrapolation is causing me issues: a noise texture mapped this way would not be mapped below 0 (or above 1 if you invert the gradient) on Y, and I would have to scale the gradient up to where I want it to end depending on my object, and then adjust the scale of the noise for it to be consistent with another object with the same texture as a consequence of that scaling. The Z axis in a 3D polar coordinate system would remain cartesian , so I just leave it as is.
I’ve attached a picture that illustrate the project with a simple noise texture on a plane (this is two dimensional therefore there was no need to scale the sphere to infinity on Z).
@BartekSkorupa, I used the dot product because it’s faster to build. Since dot(V, V)= VxVx + VyVy + Vz*Vz = Vx²+Vy²+Vz², both methods give the same result (I suppose the power function can be a bit slower than just multiplying the value by itself)
Also, the purpose of these nodes is just to illustrate how the Gradient node works. I personally don’t even use gradient so much, since we can access coordinates directly.
You’re right. Didn’t look at dot product this way, when in fact it’s exactly what it is, but I simply didn’t notice.
The other thing is that I somehow got fixed to connection between dot product and cosine, and I kind of forgot that dot product in fact MAY be greater than 1
Didn’t know that math multiply works faster that power. Thanks for the tip. From now on I will be “squaring” by multiplying by self.
I have a very simple solution that may be irrelevant for purposes other than mine, but I simply connected a [texture coordinated] Gradient Texture node set to Quadratic Sphere from its factor output to the vector input of a Noise Texture node with the Scale to 74, Detail to 16, and Distortion to 24.7. For my purposes, I connected the color output to the Displacement of my main Material Output Node. I just have a Principled shader for the Surface input.
Unfortunately, this solution doesn’t work with baking as you can see in my UV editor where I had to move the radial faces to line up with the radial noise. I haven’t found a solution to this yet.