I’m not talking about mip-bleeding and I don’t want to pad my sub-textures as I think it should be possible to fix filtering in my fragment shader… just wondering how ![]()
I heard about ddx/ddy (aka dfdx/dfdy in GL) to be passed to tex2D(tex, uv, ddx(foo), ddy(foo)) but have no idea what to use for ‘foo’ ![]()
First off, my setup. Here’s my debug atlas, 2048x512 with 4x non-padded 512px sub-textures in it:
https://dl.dropboxusercontent.com/u/136375/img/atlas.png
Now the individual images have what may look like borders but they’re supposed to be part of the respective sub-texture, keep that in mind
they’re not supposed to provide padding. Probably should switch to better real-world textures…
Here are the import settings for this atlas.png — no mips, no aniso, no trilinear (only bilinear) filtering, no compression, no downsizing:
https://dl.dropboxusercontent.com/u/136375/img/screens/unity-atlas-01.png
(This is because I want to attack standard filtering artifacts before tackling any possible mip-bleeding that may occur later on…)
Here’s my “texture-atlas tiling” surface shader, pretty simple (prototyping quality code) and overall almost does the job finely, except for the border seam that’s bothering me:
Shader "Custom/azAtlased" {
Properties {
_MainTex("Base (RGB)", 2D) = "white" {}
// xy is atlas slicing (here we have 4 sprites in 1 row)
// zw is tiling (here repeat 2x in X and 3x in Y)
_SlicingAndTiling("_SlicingAndTiling", Vector) = (0.25, 1.0, 2.0, 3.0)
// which sub-texture to render, anything between 0 and 3 in this setup
_TexIndex("_TexIndex", Float) = 1
}
SubShader {
Tags {
"RenderType"="Opaque"
}
CGPROGRAM
#pragma glsl
#pragma target 3.0
#pragma surface surf BlinnPhong exclude_path:prepass nolightmap noforwardadd novertexlights
sampler2D _MainTex;
float4 _SlicingAndTiling;
float _TexIndex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
float2 uv = IN.uv_MainTex;
uv = (frac(uv * _SlicingAndTiling.zw) + _TexIndex) * _SlicingAndTiling.xy;
float4 col = tex2D(_MainTex, uv);
o.Albedo = col.rgb;
o.Alpha = col.a;
}
ENDCG
}
FallBack "Diffuse"
}
Now there’s a tiny seam that always appears the same way. Tried all combinations of different filtering (bi/tri), mips on/off, wrap clamp/repeat, aniso 0/1/2/9 — it’s always there, and it’s always at most 1px wide no matter how far or close to the geometry the camera is:
https://dl.dropboxusercontent.com/u/136375/img/screens/unity-atlas-02.png
[right-click / open-in-new-tab for full-size view)
So if this happens with mips off it cannot be LOD related so I’m thinking ddx/ddy won’t help here anyway.
The seam only occurs across one axis (because there’s only 1 row in the atlas). It’s always flickering between the neighboring tiles’ white and/or orange tint, so the shader is clearly sampling into those areas of the atlas.
The only mode that this seam does not appear is Point filtering.
I vaguely remember from earlier days of playing with GLSL there’s a way to change the default “center of a texel” for the vertex (uv) interpolator but not sure if this would even help, and then we probably don’t get access to that from ShaderLab?
Would ddx/ddy help here at all, seeing as this isn’t a LOD issue because I get this even with mips off? I’m using floats instead of halfs so maybe there’s a smart way to ever so slightly downscale the uv by that tiny fraction that is actually “oversampling”?