- Home /
UV offset in surface shader.
Hello there, I am working on a simple surface shader that blurs its texture, mainly as an experiment for uv coordinate offsets. Here is the code that i am using.
half4 p;
for(i=0;i<3;i++)
for(j=0;j<3;j++){
p.rgb+=tex2D (_MainTex, float2(IN.uv_MainTex.x+(i-1),IN.uv_MainTex.y+(j-1)))/9;
}
o.Albedo=p.rgb;
Unfortunately, this makes the object's surface completely black. Removing the +(i-1) and +(j-1) parts makes the shader behave normally again, but obviously without the desired result.
What am i doing wrong?
Answer by CHPedersen · Jul 10, 2013 at 11:00 AM
It's hard to say why the lookup becomes black without knowing what the texture looks like and whether its wrap mode is set to Repeat or Clamp. But I think part of your problem stems from a slight misunderstanding about UVs: They are not discrete, integer pixel coordinates. You can't "move to the next pixel" by adding or subtracting 1. Instead, they are normalized ranges across the texture. 0,0 is the lower left corner of the texture and 1,1 is the upper right corner. So when you add whole integers to the UV coordinates before your lookup, you're causing the UVs to leave the 0-1 range, becoming < 0 and > 1 as the loops iterate.
To grab the next pixel, you have to include a division by the texture's height and width and then add that to the pixel's interpolated UV. Try that, and see if it has an effect on the calculated color.
On another note, try to limit divisions or avoiding them entirely in shaders where possible. A division is a lot more computationally expensive than a multiplication. E.g. here, instead of dividing by 9, multiply by 0.111111f. :)
I forgot to mention that i also tried IN.uv_$$anonymous$$ainTex.x+((i-1)*0.005)
, as well as replacing 0.005 with a multitude of other <1 floats. Tried
float2(IN.uv_$$anonymous$$ainTex.x+((i-1)*0.00005f),IN.uv_$$anonymous$$ainTex.y+((j-1)*0.00005f))
with various textures and import settings, but the result is still the same.
Well, 0.00005 isn't gonna work because if the next pixel is that close in normalized UVs, it means your texture's resolution is 1/0.00005 = 20000x20000. ;) You should be multiplying by 1 / textureWidth on the x and 1 / textureHeight on the y.
But that's not the issue, yet. First, we gotta figure out why you're getting all blacks. Can you try to simplify the shader a little to see if the look-ups are giving you what you expect? $$anonymous$$aybe something is wrong in the calculation of the color average in that loop. What happens if you unroll it manually and do the 9 lookups side by side? Can you get a sensible color out of them outside the loops?
Oh, and one more thing: Beware that Cg/HLSL does not have loop count registers until Shader$$anonymous$$odel 3 and above. See this list:
http://en.wikipedia.org/wiki/HLSL#Shader_model_comparison
I don't think that's the issue because your shader does compile, but for good measure, make sure it compiles to profile 3 or above.
I used that small a number purely for testing, as it should produce similar results to +0. Strangely enogh, doing everything manually ins$$anonymous$$d seemed to work, even though i added #pragma target 3.0 at the top of my shader.
I think the compiler had a problem parsing those for-loops, though I have no idea why, and if so, why it didn't warn you. $$anonymous$$aybe it had to do with the loops being nested. This is kind of an anti-solution since you ended up with working, but uglier code. ;) But I'm glad you got it working nonetheless.