Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Limit min mipmap index

Discussion in 'General Graphics' started by exltus, Aug 7, 2020.

  1. exltus

    exltus

    Joined:
    Oct 10, 2015
    Posts:
    58
    Is somehow possible to tell specific material/renderer or whatever to do NOT use texture mip level 0 and force it to start from 1st mip?
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    2,983
  3. exltus

    exltus

    Joined:
    Oct 10, 2015
    Posts:
    58
    I affraid that mip map bias is solution per texture - but Iam looking for per renderer or per material solution :(
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    You'd have to write a custom shader that uses
    tex2Dbias
    to sample the texture, or possibly even
    tex2Dlod
    and manually calculate the appropriate mip level in the shader.

    Though I prefer using
    tex2Dgrad
    and clamping the derivatives instead as it doesn't break anisotropic filtering and is a little easier to implement.
     
    Last edited: Aug 10, 2020
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Here's an example shader that implements min & max mip + bias using
    tex2Dlod
    . I realized my simple
    tex2Dgrad
    implemenation I had was only handling a limited use case and didn't work when generalized to a min and max clamp.
    Code (CSharp):
    1. Shader "Unlit/MipClamping"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.         _MinLOD ("Mip Min", Range(0, 12)) = 0
    7.         _MaxLOD ("Mip Max", Range(0, 12)) = 12
    8.         _BiasLOD ("Mip Bias", Float) = 0
    9.     }
    10.     SubShader
    11.     {
    12.         Tags { "RenderType"="Opaque" }
    13.         LOD 100
    14.  
    15.         Pass
    16.         {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.  
    21.             #include "UnityCG.cginc"
    22.  
    23.             struct appdata
    24.             {
    25.                 float4 vertex : POSITION;
    26.                 float2 uv : TEXCOORD0;
    27.             };
    28.  
    29.             struct v2f
    30.             {
    31.                 float4 vertex : SV_POSITION;
    32.                 float2 uv : TEXCOORD0;
    33.             };
    34.  
    35.             sampler2D _MainTex;
    36.             float4 _MainTex_ST;
    37.             float4 _MainTex_TexelSize;
    38.  
    39.             float _MinLOD, _MaxLOD, _BiasLOD;
    40.  
    41.             float CalcMipLevel(float2 texture_coord)
    42.             {
    43.                 float2 dx = ddx(texture_coord);
    44.                 float2 dy = ddy(texture_coord);
    45.                 float delta_max_sqr = max(dot(dx, dx), dot(dy, dy));
    46.                
    47.                 return max(0.0, 0.5 * log2(delta_max_sqr));
    48.             }
    49.  
    50.             v2f vert (appdata v)
    51.             {
    52.                 v2f o;
    53.                 o.vertex = UnityObjectToClipPos(v.vertex);
    54.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    55.                 return o;
    56.             }
    57.  
    58.             fixed4 frag (v2f i) : SV_Target
    59.             {
    60.                 float mipLevel = CalcMipLevel(i.uv * _MainTex_TexelSize.zw);
    61.                 fixed4 col = tex2Dlod(_MainTex, float4(i.uv, 0.0, clamp(mipLevel + _BiasLOD, _MinLOD, _MaxLOD)));
    62.                 return col;
    63.             }
    64.             ENDCG
    65.         }
    66.     }
    67. }
     
  6. exltus

    exltus

    Joined:
    Oct 10, 2015
    Posts:
    58
    Ohhh I see... Shader solution is great idea! Thanks...
    Lastly I want to hear your opinion about what I want to achive, because I am not sure if is it good idea. I have FPS game where I am using 2k textures for fps gun models. I want to also use same texture for gun TPV models (to reduce some build size) of my guns where 2k texture is useless - so I want to skip first mip from texture to reduce texture overhead on gpu. Is it good idea, or would be better to just duplicate texture -> set size to 1k and use it for TPV guns?
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Don't do anything. If you're already reusing the texture, just do that and nothing else. Don't even bother with using a shader like above.

    There's no need to prevent the top mip from being used as it'll already never be used, assuming the camera doesn't get close enough to see it, and there won't be any performance penalty for having the top mip sitting in memory for when it is needed for the first person view.
     
  8. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    141
    Is there really no way to get the mipbias back into the tex2Dgrad function? (And how limited is the hack you were talking about?)

    I'm sampling a 2darray from an index texture and want to apply bilinear filtering to that. I get the same artifacts, because of a frac, but dont think i can get around the frac ( https://forum.unity.com/threads/str...dotted-white-lines-along-quad-borders.795870/ ) You also mentioned the 2Dgrad method there, which solves the problem with the artifacts, but removes the mipbias-
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    I was just saying my specific hack that I was using in some existing shader was limited. You can absolutely implement the equivalent of
    tex2Dbias
    /
    tex2Dlod
    using
    tex2Dgrad
    .
     
    flogelz likes this.
  10. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    141
    Do you have an idea on how you'd get the normal auto mipbias back? (Now that i think about it tho, wouldn't that bring back the artifacts aswell, as the mip than can again change rapidly in the 0.9999 -> 0.0001 areas?)

    Edit: Maybe to clarify, i want the normal automatic mipbias (so that textures change mips automatically), but remove these artifacts!
     
    Last edited: Mar 29, 2021
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Funny enough, I was planning on writing an article about this exact topic soon.
    Code (csharp):
    1. // get derivatives
    2. float4 uv_df = float4(ddx(uv), ddy(uv));
    3.  
    4. // mip bias
    5. uv_df *= pow(2.0, _MipBias);
    6.  
    7. // sample
    8. float4 col = tex2Dgrad(_Tex, uv, uv_df.xy, uv_df.zw);
     
    flogelz likes this.
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    In the case of something like atlas UVs with discontinuities, like when using
    frac()
    on previously continuous UVs, the trick is very simply to use the derivatives from the original UVs before applying
    frac()
    , and possibly scaled by the same amount as the sample position UV.
    Code (csharp):
    1. float4 uv_df = float4(ddx(uv), ddy(uv));
    2. float2 atlasUV = frac(uv) * _TileScaleOffset.xy + _TileScaleOffset.zw;
    3. float4 col = tex2D(_Tex, atlasUV, uv_df.xy * _TileScaleOffset.xy, uv_df.zw * _TileScaleOffset.xy);
    If you're getting discontinuities from procedural circular UVs like from using
    atan()
    , then you need to calculate two sets of UVs with the discontinuity in different positions and use the smallest magnitude derivatives. For
    atan()
    it returns a value between -pi and +pi, so if you divide it by tau you have a range from -0.5 to +0.5, and you can then use
    frac()
    to get a 0.0 to 1.0 range and you can compare them like this:
    Code (csharp):
    1. float2 uv = atan(y, x) / (UNITY_PI * 2.0);
    2. float2 uvB = frac(uv);
    3. uv = fwidth(uv) < fwidth(uvB) ? uv : uvB;
    4. float4 uv_df = float4(ddx(uv), ddy(uv));
    5. float4 col = tex2Dgrad(_Tex, uv, uv_df.xy, uv_df.zw);
     
    flogelz likes this.
  13. flogelz

    flogelz

    Joined:
    Aug 10, 2018
    Posts:
    141
    @bgolus Just got around to try it out and the small changes solved the artifacts problem! Thank you!! (Now my terrain shader finally doesn't have any artifacts anymore~ Also i can change the bias now, so thats neat!)

    Also for some reasons this feels like a dejavu, I think we had a similar situation once, where I had questions about a topic you were planning on writing aboutxD Thx for helping again!