- Home /
Shader: texture sample exact pixel value
Is it possible to sample a pixel during shading and getting the exact color values as are stored in the texture image? For example if my first pixel has a red byte value of for example 212 (thats 11010100 in binary), is it possible to get exactly this value during the shading process for a point corresponding to that pixels location?
My problem is, that when I tried the following code and debugged the red value, it was slightly off, as if some rounding or interpolation with nearby pixels occured
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
// resolution of the texture is 1024*1024
float texSize = 1024;
// sample the texture but only at positions corresponding to whole pixels
// multiplying the position by the texture width and then flooring it should
// bring it into the [0, 1023] interval with only integer values
// dividing it by the texture width again should return the interval to [0, 1]
float2 myUV = float2(floor(i.uv.x * texSize) / texSize, floor(i.uv.y * texSize) / texSize);
fixed4 texcol = tex2D(_MainTex, myUV);
// I want to get exactly the value that was in the pixel at the sampled location
fixed redPixelValue = floor(texcol.r * 256)
return texcol * _Color;
}
ENDCG
Is there something I am missing? Thank you for any answers!
$$anonymous$$y suggestion would be to use a higher precision format, although there's no guarantee that would work. I've also changed some things just to make it more usable (texSize for any texture, etc.);
CGPROGRA$$anonymous$$
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//fixed4 _Color;
sampler2D _$$anonymous$$ainTex;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _$$anonymous$$ainTex_ST;
float4 _$$anonymous$$ainTex_TexelSize;
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFOR$$anonymous$$_TEX(v.texcoord, _$$anonymous$$ainTex);
return o;
}
float4 frag(v2f i) : SV_Target
{
float2 texSize = 1/_$$anonymous$$ainTex_TexelSize.xy;
// sample the texture but only at positions corresponding to whole pixels
// multiplying the position by the texture width and then flooring it should
// bring it into the [0, 1023] interval with only integer values
// dividing it by the texture width again should return the interval to [0, 1]
float2 myUV = float2(floor(i.uv.x * texSize.x) / texSize.x, floor(i.uv.y * texSize.y) / texSize.y);
float4 texcol = tex2D(_$$anonymous$$ainTex, myUV);
float redPixelValue = texcol.r;
return float4 (texcol, 0, 0, 1); // * _Color;
}
ENDCG
$$anonymous$$ight help, might not.
I already found the culprit - the texture was being compressed on import.
Though your answer did help me to get a cleaner code. Thank you!
Hi, I'm not sure i understand what you want to do: doesn't using "point" filtering on the texture settings does what you want ? (bilinear or trilinear will always sample an interpolation of multiple texels)
I was already using point filtering, I must be overlooking something else. Thank you for you time, though!
Edit: I finally found it! The texture was compressed on import, I found the setting when I double checked the point filtering.
Setting it to uncompressed ARGB 32 bit did the trick!
Thank you!
Answer by Steamc0re · Aug 10, 2018 at 03:29 AM
oh and you need the center of the pixel, so your values are actually .5 to 1023.5