So this is still quite bad in Unity - you have aniso level on textures but the warning says enabled for all in settings - OK but what level cuz is just ‘enabled’!!
Thanks for explanations above but clearly Unity could do things better and not mix up trilinear and anisotropic levels
But note that the docs say “The value range of this variable goes from 1 to 9” which I assume is a mistake. The slider of course makes no change between 0 & 1 which is also like…!
Enabled in the Quality settings means it uses whatever value the texture is using, which defaults to 1, which is the same as no anisotropic filtering. If you want a texture to always have anisotropic filtering (at least when Anisotropic Filtering isn’t disabled in the quality settings) you need to change it on the texture.
Yes. That’s been noted a few times in this very post. Similarly setting Anisotropic Filtering to Forced On in the quality settings still only sets any texture set to an aniso level between 1 - 9 to 9. Which I can only assume is a legacy thing because 9 used to be the max value, and when that changed to be a direct mapping to the anisotropic filtering level, 8x Anisotropic* was good enough that no one complained. Though realistically the performance difference between 8x and 16x is almost non-existent, but the visual difference isn’t. I really think it just comes down to it’s something almost no one notices is wrong, and no one complains about, so no one at Unity has ever taken the time to fix it.
Many devices only actually support power of 2, or multiple of 2 anisotropic levels. So an aniso level of 9x for a lot of hardware is visually identical to 8x. What levels a GPU are actually supports changes from generation to generation and maker to maker.
As long as the textures haven’t been set to an aniso level of 0, or you’re using a sample function that doesn’t support it (Sample Texture 2D LOD), or you’re overriding the sampler state with a custom one.
For Shader Graph the correct way to do it is to not set an explicit sampler state for a Sample Texture node. All textures have an implicit sampler state already, and that will be used automatically for any Sample Texture nodes that don’t have it overridden. Sampling textures in a custom function makes things a little more difficult since Unity doesn’t expose a Texture object’s implicit sampler state to Shader Graph, but it can be worked around by just typing the sampler state’s name in the code directly.
@bgolus Do you know if Unity is planning to expose the Aniso Level on the Shader Graph Sampler State nodes? I’m doing some terrain blending in a custom function and only need one sampler state, but there’s no way to set the Aniso Level. I tried using an “Inline Sampler State” from Unity’s Docs (Unity - Manual: Using sampler states) hoping that since we have Anisotropic Textures set to “Forced On” that they would expose the samplers with it, but I can’t tell any difference vs. using the one from my shader graph.
Any hints at how to get to an anisotropic sampler from a custom function?
The Forced On option only affects the textures’ implicit sampler states. Inline sampler states original exist to be able to forcibly override the ones from the texture asset, so it wouldn’t make sense for the Forced On option to affect them.
The work around is to use the texture’s own sampler state. To do that you have to use a Custom Function node and manually, explicitly write out the sampler state’s variable name. Like this:
Note the reference name for the texture is _TestTexture, and the sampler in the Custom Function is sampler_TestTexture. Unity always adds an implicit sampler state for texture properties with that naming scheme. One note of warning: until you have the texture and custom function node connected to a Master node input the Custom Function may show a warning that “sampler_texturename” doesn’t exist, because Unity doesn’t add the texture uniform, or its sampler, to the shader code until it thinks it’s in use, and thus it doesn’t exist until it’s all connected.
It’s tempting to have a Custom Function node that outputs just the texture’s sampler state so you don’t have to have fully custom code like this for every texture, but that’s not an option as you can’t actually use a Sampler State as a Custom Function output. I mean, you can, but it’ll never actually work due to how they have the generated code setup.
Thanks @bgolus ! I was just about to try this since I stumbled across the "Using Sampler States’ doc that mentioned it. It would certainly be better if they would expose the Anisotropic setting in the Sampler State node though as hardcoding the name seems pretty bad and apparently generates warnings like you mention.
Now if I can just figure out how to get ddx_fine() to work in my custom shader, which seems to be just returning ddx() as someone else mentioned 2 years ago with no answer from Unity.
Thanks for the help. I read through your ‘Generating Perfect Normal Maps for Unity’ article this morning. Very helpful!
Yep. They really need to add anisotropic settings to the Sampler State node, and expose the texture’s own sampler state. They already have the Texel Size node which works exactly the same way a texture sampler state node would need to (takes a texture as an input, outputs the texel size by combining the texture’s name with _TexelSize suffix). I really don’t understand why it’s not something that’s been fixed yet.
Hehe, yeah, I just stumbled across another one of your posts from I think 2 years ago mentioning the anisotropic issue way back then. I’d even settle for them making an “inline sampler state” with a 8x default… Something like sampler_anisotropic8_repeat would be fine.
To the question of if it improves performance … it depends on if anisotropic filtering perceptibly affects performance or not at all. And if you’re forcing it on in the quality settings or not.
On desktop GPUs, as noted above, it doesn’t really have any affect on performance one way or the other. So it’s unlikely disabling anisotropic filtering on some textures would have any real performance benefit.
On mobile, it’s not a bad idea. But you’re also probably not forcing anisotropic filtering on to begin with so there’s no difference between it being 1 or 0 since both are the same when not forcing it on in the quality settings. More realistically, you probably want to leave anisotropic filtering quality setting to Per Texture, and setting the aniso filtering level on individual textures you feel need the help.
So that brings us to the first question.
The answer here is … maybe?
You’re right that anisotropic filtering mainly benefits diffuse textures. It’s where its affects are the most obvious, and what it was primarily designed to deal with.
Using anisotropic filtering on normal maps isn’t technically correct, but normal maps themselves are a big lie that aren’t ever actually correct. Anisotropic filtering mainly affects how a texture is sampled when viewing a surface at an oblique angle, especially when closer to parallel with the view direction. I.E…: like a floor. The lighting you get from a detailed normal map using anisotropic filtering won’t match the lighting you’d get if using super sampling, but that’s also true of mip maps of normal maps in general. Neither will match what the original high poly source model would have looked like either, though the anisotropic filtered one may actually end up looking closer. The same is true for anisotropic filtering on specular or metal maps. They won’t quite match a super sampled equivalent, but neither do mip maps anyway. The main benefit is sharp details will remain clear when using anisotropic filtering is used, regardless of if it’s “correct” or not.
Smoothness / roughness and AO maps however probably look pretty good, and mip maps do actually work properly with these (mostly). AO maps, like normal maps, may actually look closer to a high poly source model without anisotropic filtering enabled, but you’ll loose some sharp details you may want to keep.