- Home /
Using a Surface Shader's IN.uv_MainTex individual values correctly?
I'm building out a basic "Standard Surface Shader" for a dynamically created mesh. My goal is to clip (or make transparent) regions dynamically.
I am able to set a constant alpha to an arbitrary value... that works. (i.e. an alpha of 0.5 lets objects behind be visible through the mesh).
But when I try to calculate the alpha based on the uv_MainTex values (which I'm assuming are x,y ranging from 0.0 to 1.0), the results are totally unexpected. Below I'm trying to find the distance of the IN.uv_MainTex from the center of the texture:
// Expecting the center to have an alpha of 1.0,
// dissipating out to an alpha of 0.0 at the mesh's edge.
fixed2 center = fixed2(0.0, 0.0);
float distFromCenter = distance( center, IN.uv_MainTex );
o.Alpha = 1.0 - distFromCenter;
Trying something simpler, i just set the alpha based on single components:
// appears to give every pixel an opacity of 1.0,
// where I'd expect a fade from left to right.
o.Alpha = IN.uv_MainTex.x;
and:
// gives every pixel zero opacity,
// where I'd expect a fade from bottom to top
o.Alpha = IN.uv_MainTex.y;
And how could the y component always be zero (or less?) when it is clearly works to extract the right color from _MainTex?
// this is correctly grabbing the right color value... so the uvs are right
fixed4 color = tex2D (_MainTex, IN.uv_MainTex)
Perhaps it comes down to, what values should I be expecting from uv_MainTex? Or is there a transform I should be performing so the component values are as I'm expecting?
FYI I have some background in the world of THREEjs and its (seemingly much simpler) glsl shader world. Still taking confusing and careful first steps through this new terrain :)
Thanks!
A follow up question: How would I end up discovering on my own what values I should be expecting from uv_$$anonymous$$ainTex? Perhaps I'm not adept at the unity docs yet? Is there a way to debug the values directly--I know that's always hard with shaders :)
Answer by Namey5 · Apr 10, 2020 at 11:48 PM
Surface shader UVs are a bit unique. They don't actually contain the base mesh UVs, rather a version of them transformed by the texture's scale and offset values in the material properties. This means that if you want the regular, unadjusted UVs you would need to set your scale to [1,1] and offset to [0,0] or negate the transformation (which unfortunately due to surface shader compilation is impossible). The UVs shouldn't be exclusively less than 0 however, so I would make sure that you have correctly created and assigned UVs during the creation of the mesh. Something else to note is that you are correct in assuming that UVs are in a range of [0,1], therefore the centre of the texture should be (0.5,0.5) rather than (0,0). It would also probably be a good idea to saturate() your alpha values so that you don't end up with incorrect blending.
Thanks @Namey5. I just tried zeroing out all the transforms that are on the object, and ins$$anonymous$$d placed them on a new parent GameObject. It doesn't seem to fix the problem. Is that expected? And if so, and negating the transform is tricky, if not impossible, then I'm not sure I understand what they expect folks to do and why they'd design the system this way. Wacky :)
Perhaps what I want to do is much more easily done another way?
I want to vary the color of an object based on the UV, typically trivial.
I'd like to retain the basics of an object that interacts with light sources, receiving and casting shadows... etc.
When I said transform, I meant the material texture properties, i.e. the 'tiling' and 'offset' properties here;
Unity automatically applies texture transformations in surface shaders because from a user perspective it is an expected behaviour (as there are always controls on the texture, and users will think it's a bug if they don't work). The reason you can't directly negate this transformation is because the parameters it needs are defined after compilation, meaning to use them you would need to define them manually, but that would end up defining them twice thus resulting in an error.
There is a way to get plain UVs in a surface shader, but it requires bypassing the traditional interface to use a custom vertex function and could potentially lead to code duplication post-compilation (although this wouldn't really matter). Something along the lines of;
#pragma surface surf Standard vertex:vert
...
struct Input
{
float2 uv;
};
void vert (inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT (Input, o);
o.uv = v.texcoord0;
}
This will give you your mesh's raw UVs - if these aren't correct then it's a problem with the mesh itself. An easy way to check the UVs is to just output them as a colour, i.e.
//This will give black in the bottom left corner, green in top left, red in bottom right, yellow in top right
o.Emission = float3 (IN.uv, 0);
Your answer

Follow this Question
Related Questions
Spherical Hamonics - ShadeSH9 and Surface Shader issue 0 Answers
Shading is visible through object using surface shader 0 Answers
Surface Shader apply normal map to object normal without pluggin it into o.Normal 1 Answer
Texture lookup in Surface Shader in pixel space 0 Answers
Referencing the current pixel's world coordinates in the SURF block of a shader 1 Answer