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

Texture a trail with the background tex

Discussion in 'General Graphics' started by Domyar_Harris, Apr 5, 2017.

  1. Domyar_Harris

    Domyar_Harris

    Joined:
    Apr 5, 2017
    Posts:
    5
    Im working on a 2d platformer/infinite runner. I am using a gray scaled copy of the original texture as a background. I am trying to texture the player's trail with the original texture, so it will look like the player is coloring the world. Currently, the textures scale is off and it doesn't scroll with the background. I've tried using SetTextureScale and SetTextureOffset, which I'm sure will work, but I'm just not using them properly, or maybe it's how I'm calculating the offset, or what, I don't know. Here is what my scripts update looks like:

    Code (CSharp):
    1. // Update is called once per frame
    2. void Update ()
    3. {
    4.      // player position in world space
    5.      Vector4 pos = player.gameObject.transform.position;
    6.  
    7.      // calculate texture offset by player position
    8.      float offsetX = (pos.x % bg_texture_length) / bg_texture_length;
    9.      float offsetY = (pos.y % bg_texture_height) / bg_texture_height;
    10.  
    11.      // set the texture offset
    12.      //this.gameObject.GetComponent<TrailRenderer>().material.mainTextureOffset = new Vector2(-offsetX,      offsetY);
    13.      this.gameObject.GetComponent<TrailRenderer>().material.SetTextureOffset("_MainTex", new Vector2(offsetX, offsetY));
    14.  
    15.      // set scale of trail texture to match scale of background
    16.      //this.gameObject.GetComponent<TrailRenderer>().material.SetTextureScale("_MainTex", new Vector2(16.25f, 13.0f));
    17. }
     
    Last edited: Apr 13, 2017
  2. Domyar_Harris

    Domyar_Harris

    Joined:
    Apr 5, 2017
    Posts:
    5
    I made some progress but it's still not quite right. Rather than having a script, I'm using a custom vertex/frag shader. I get some weird streaking on certain parts of the trail, which I believe is floating point error. Other than that, the only other thing is that the scale is still off, where the trials texture is slightly smaller than the background texture. Heres the shader:

    Code (CSharp):
    1. Shader "Custom/ColorTrail"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Color Texture", 2D) = "white" {}
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Pass
    11.         {
    12.             CGPROGRAM
    13.  
    14.             #include "UnityCG.cginc"
    15.  
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.  
    19.             #pragma enable_d3d11_debug_symbols
    20.  
    21.             sampler2D _MainTex;
    22.             float4 _MainTex_TexelSize;
    23.  
    24.             struct vertIn
    25.             {
    26.                 float4 vertex : POSITION;
    27.             };
    28.  
    29.             struct fragIn
    30.             {
    31.                 float4 pos : SV_POSITION;
    32.                 float2 uv : TEXCOORD0;
    33.             };
    34.  
    35.             fragIn vert(vertIn IN)
    36.             {
    37.                 fragIn toFrag;
    38.  
    39.                 toFrag.pos = mul(UNITY_MATRIX_MVP, IN.vertex);
    40.  
    41.                 // this code does the same as below without the texel size included, just testing different things
    42.                 //float offsetX = (IN.vertex.x % 16) / 16;
    43.                 //float offsetY = (IN.vertex.y % 13) / 13;
    44.  
    45.                 // 16 is the scaled length of the background
    46.                 // 13 is the scaled height of the background
    47.  
    48.                 float offsetX = ( (IN.vertex.x * 16) % _MainTex_TexelSize.z ) / _MainTex_TexelSize.z;
    49.                 float offsetY = ( (IN.vertex.y * 13) % _MainTex_TexelSize.w ) / _MainTex_TexelSize.w;
    50.  
    51.                 toFrag.uv.x = offsetX;
    52.                 toFrag.uv.y = offsetY;
    53.  
    54.                 return toFrag;
    55.             }
    56.  
    57.             half4 frag(fragIn IN) : SV_TARGET
    58.             {
    59.                 return tex2D(_MainTex, IN.uv);
    60.             }
    61.  
    62.             ENDCG
    63.         }
    64.     }
    65. }
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The weird streaking is due to you doing the UV modification in the vertex shader. You'll have a series of vertices with the UV going from 0.0 to 1.0, but never actually being 1.0, so something like:
    0.6, 0.7, 0.8, 0.9, 0.0, 0.1, 0.2, etc.
    So for one section of your trail you'll have the texture going from nearly the end of the UV to the start rather than nicely wrapping. The fix for that is to do the UV modifications in the fragment shader so that the wrap happens between pixels instead of vertices.

    However the same problem kind of still exists and you'll still get weird thin lines due to how GPUs figure out what mip map to use. That "0.9, 0.0" thing is still happening, just between two pixels, and the change in the UVs between two pixels is how it decides what mip map to use. Luckily there's an easily solution to that too.
    https://forum.unity3d.com/threads/texture2d-array-mipmap-troubles.416799/#post-2715201
     
  4. Domyar_Harris

    Domyar_Harris

    Joined:
    Apr 5, 2017
    Posts:
    5
    Thanks for the response! I have a few questions. I'm not using an atlas, so I'm assuming just omit that part when calculating the uv to sample from? Wouldn't I want to calculate that uv based on the position of the vertex in world space? And what would my scale uv be? Because it uses the distance to calculate which mip map to use, could I just get the uv as an input for the vertex shader? I uploaded a picture of a drawing of what I'm trying to do. I hope it helps to understand what I'm trying to do. If there's a better, more optimal way, PLEASE let me know. Thanks again!
     

    Attached Files:

  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The specific case of using an atlas isn't the problem. The wrapping of the UVs is the problem.

    Using % (modulus) causes the value to loop between 0.0 and 1.0, thus the "0.8, 0.9, 0.0, 0.1" case where for one segment of the trail the texture is traversing nearly the entire length of the texture, backwards.

    The solution is don't wrap in the vertex shader! Just do:

    toFrag.uv.xy = IN.vertex.xy * float2(16.0, 13.0) / _MainTex_TexelSize.zw;

    Then in the fragment shader you can do the wrapping, if even needed. That's what that post I linked to is really talking about. Again, the atlasing part is irrelevant.

    Try it with just the line above, if that fails use this in the fragment shader.

    float2 uv = frac(IN.uv);
    return tex2Dgrad(_MainTex, uv, ddx(IN.uv), ddy(IN.uv));
     
    Last edited: Apr 25, 2017
  6. Domyar_Harris

    Domyar_Harris

    Joined:
    Apr 5, 2017
    Posts:
    5
    I see. I understand now. I now have...

    Code (CSharp):
    1. Shader "Custom/ColorTrail"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture", 2D) = "white" {}
    6.         _Scale("Scale", vector) = (1, 1, 1, 1)
    7.     }
    8.  
    9.     SubShader
    10.     {
    11.         Pass
    12.         {
    13.             CGPROGRAM
    14.  
    15.             #include "UnityCG.cginc"
    16.  
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.  
    20.             #pragma enable_d3d11_debug_symbols
    21.  
    22.             sampler2D    _MainTex;
    23.             float4        _MainTex_TexelSize;
    24.             float2        _Scale;
    25.  
    26.             struct vertIn
    27.             {
    28.                 float4 vertex : POSITION;
    29.             };
    30.  
    31.             struct fragIn
    32.             {
    33.                 float4 pos : SV_POSITION;
    34.                 float2 uv : TEXCOORD0;
    35.             };
    36.  
    37.             fragIn vert(vertIn IN)
    38.             {
    39.                 fragIn toFrag;
    40.  
    41.                 toFrag.pos = mul(UNITY_MATRIX_MVP, IN.vertex);
    42.  
    43.                 toFrag.uv.xy = IN.vertex.xy * _Scale.xy / _MainTex_TexelSize.zw;
    44.  
    45.                 return toFrag;
    46.             }
    47.  
    48.             fixed4 frag(fragIn IN) : SV_TARGET
    49.             {
    50.                 float2 uv = frac(IN.uv);
    51.                 return tex2Dgrad(_MainTex, uv, ddx(IN.uv), ddy(IN.uv));
    52.             }
    53.  
    54.             ENDCG
    55.         }
    56.     }
    57. }
    The streaking is gone and it's beautiful :D
    However, I still have the same scale issue where the texture on the trail is smaller than the background. And I set the _Scale value to be the same as the scale of the background. Any thoughts on what the problem could be? Besides my lack of skill lol....