Problem with UV interpolation

Hello.
I’m trying to make a procedurally generated river and a shader for it. I created a simple GetDirection() function that I call for each vertex of the river mesh. In it, I return the direction of the river for the given point. I’m passing the values returned by this function to the mesh’s uv array.

public Vector2 GetDirection(Vector2 position)
    {
        float minv = 0.0f;
        Vector2 direction = Vector2.zero;

        for (int i = 0; i < Resolution; i++)
        {
            Vector2 P = _spline.GetPoint((float)i / (float)(Resolution - 1));
           
            Vector2 E = position;

            float reqAns = Vector2.Distance(E, P);

            if (i == 0)
            {
                minv = reqAns;

                Vector2 uv;

                Vector3 dir = _spline.GetDirection((float)i / (float)(Resolution - 1));

                uv = new Vector2(dir.x, dir.z);

                direction = uv;

            }
            else
            {
                if (reqAns <= minv)
                {
                    minv = reqAns;

                    Vector2 uv;

                    Vector3 dir = _spline.GetDirection((float)i / (float)(Resolution - 1));

                    uv = new Vector2(dir.x, dir.z);


                    direction = uv;
                }
            }
        }


        return direction ;
    }

My shader looks like this:

struct appdata {
float4 vertex : POSITION;
float2 direction : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 direction : TEXCOORD0;
float2 worlduv : TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
float4 s;
o.pos = UnityObjectToClipPos(v.vertex);

float4 wpos = mul (unity_ObjectToWorld, v.vertex);

o.direction = v.direction;

o.worlduv = wpos.xz;

return o;
}

half4 frag( v2f i ) : COLOR
{
return tex2D(_MainTex, i.worlduv + direction * _Time.y);
}

I am getting wrong result:

With a high resolution mesh, it looks like this:



I get weird zigzag stitches.

How can this be fixed? I tried to pass UV from 0 to 1 instead of directions, but I had the same problem.

This is a much harder thing to solve than it might seem like it would be. The short version is what you’re trying to do is impossible (in the way you want it to be done).

The correct way to handle this would be to set one dimension of the UVs to be the mesh to be the distance along the closest point along the spline, and then pan that UV. Alternatively you’d need a much more complicated shader that breaks up the surface into squares or hexagonal shapes and you get the direction from the quantized center of those shapes, and then blend between the shapes.

Sorry, I don’t quite understand what exactly is meant here. Can you please explain a little more simply or give some example? Do you mean that I need to pass an array of all spline points to the shader? And calculate direction by this array and t in uv? Wouldn’t that be too resource expensive?

No. I mean you can’t just use the world position as the base UVs in the shader and offset them by a vector. That’ll never work if the directions are different on each vertex.

It has to work something like this for generating the mesh:

  1. calculate vertex position (which I assume is calculated using get point on spline + offset width * spline tangent)
  2. calculate UV where the x is the +/- offset width, and y is the distance along the spline (could be length(current point on spline - previous point on splint)

In the shader it’s then uv.y += frac(_Time.y * speed);

I tried to implement, but I still get strange glitches.

uv.x:
8386341--1106145--Screenshot_1.jpg

uv.y:
8386341--1106148--Screenshot_15.jpg

with texture and uv.y *= 3:

8386341--1106151--Screenshot_2.jpg
8386341--1106154--Screenshot_3.jpg
8386341--1106157--Screenshot_4.jpg

This is where things get “fun”. You can look at the uv.y gradient image and see that there are places where it’s going backwards or pinching heavily. Those are causing your problems. You can try getting the distance from the previous vertex on that edge, though that might cause some issues with the texture getting warped in other ways.

Ultimately these are the kinds of problems that anyone doing UV mapping will experience. And the “solution” is … there isn’t one. You just have to fudge the UVs or the mesh itself until you can accept some visual weirdness.

Though, again, I’d recommend that link to flow mapping.