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:
// Update is called once per frame
void Update ()
{
// player position in world space
Vector4 pos = player.gameObject.transform.position;
// calculate texture offset by player position
float offsetX = (pos.x % bg_texture_length) / bg_texture_length;
float offsetY = (pos.y % bg_texture_height) / bg_texture_height;
// set the texture offset
//this.gameObject.GetComponent<TrailRenderer>().material.mainTextureOffset = new Vector2(-offsetX, offsetY);
this.gameObject.GetComponent<TrailRenderer>().material.SetTextureOffset("_MainTex", new Vector2(offsetX, offsetY));
// set scale of trail texture to match scale of background
//this.gameObject.GetComponent<TrailRenderer>().material.SetTextureScale("_MainTex", new Vector2(16.25f, 13.0f));
}
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:
Shader "Custom/ColorTrail"
{
Properties
{
_MainTex("Color Texture", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
#pragma enable_d3d11_debug_symbols
sampler2D _MainTex;
float4 _MainTex_TexelSize;
struct vertIn
{
float4 vertex : POSITION;
};
struct fragIn
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
fragIn vert(vertIn IN)
{
fragIn toFrag;
toFrag.pos = mul(UNITY_MATRIX_MVP, IN.vertex);
// this code does the same as below without the texel size included, just testing different things
//float offsetX = (IN.vertex.x % 16) / 16;
//float offsetY = (IN.vertex.y % 13) / 13;
// 16 is the scaled length of the background
// 13 is the scaled height of the background
float offsetX = ( (IN.vertex.x * 16) % _MainTex_TexelSize.z ) / _MainTex_TexelSize.z;
float offsetY = ( (IN.vertex.y * 13) % _MainTex_TexelSize.w ) / _MainTex_TexelSize.w;
toFrag.uv.x = offsetX;
toFrag.uv.y = offsetY;
return toFrag;
}
half4 frag(fragIn IN) : SV_TARGET
{
return tex2D(_MainTex, IN.uv);
}
ENDCG
}
}
}
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
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!
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:
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.
The streaking is gone and it’s beautiful
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…