Search code examples
unity-game-enginetextures

Unity: Repeating a texture over a plane depending on it's scale


I've managed to do this with a cube by using the following script. I tried adapting the script to a plane, although it seems difficult.

The most obvious change is to use PrimitiveType.Plane instead of PrimitiveType.Cube inside of the CheckForDefaultSize() function. When trying this out, the texture is just broken all over the plane. I'm suspecting the issue comes up when setting the UVs, although I have no idea of how to fix this.

The cube's UVs:

    //Front
    meshUVs[0] = new Vector2(0, 0);
    meshUVs[1] = new Vector2(width, 0);
    meshUVs[2] = new Vector2(0, height);
    meshUVs[3] = new Vector2(width, height);

    //Back
    meshUVs[4] = new Vector2(0, 0);
    meshUVs[5] = new Vector2(width, 0);
    meshUVs[6] = new Vector2(0, height);
    meshUVs[7] = new Vector2(width, height);

    //Left
    meshUVs[8] = new Vector2(0, 0);
    meshUVs[9] = new Vector2(width, 0);
    meshUVs[10] = new Vector2(0, height);
    meshUVs[11] = new Vector2(width, height);

    //Right
    meshUVs[12] = new Vector2(0, 0);
    meshUVs[13] = new Vector2(width, 0);
    meshUVs[14] = new Vector2(0, height);
    meshUVs[15] = new Vector2(width, height);

Here's how the original script looks on a cube:

1x1x1 scale Cube with scale 1

3x1x1~ish scale The same cube scaled 3 times over the x axis, the texture is now repeated thrice


Solution

  • The correct way to do this is to use a Quad instead. A plane is divided into 200 triangles, while quads only have 2. That's why I was having issues setting the UVs.

    To make it work, you just have to change SetupUvMap and CheckForDefaultSize:

    private Vector2[] SetupUvMap(Vector2[] meshUVs)
    {
        var width = _currentScale.x;
        var height = _currentScale.y;
    
        meshUVs[0] = new Vector2(0, 0);
        meshUVs[1] = new Vector2(width, 0);
        meshUVs[2] = new Vector2(0, height);
        meshUVs[3] = new Vector2(width, height);
    
        return meshUVs;
    }
    
    private bool CheckForDefaultSize()
    {
        if (_currentScale != Vector3.one) return false;
    
        var quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
    
        DestroyImmediate(GetComponent<MeshFilter>());
        gameObject.AddComponent<MeshFilter>();
        GetComponent<MeshFilter>().sharedMesh = quad.GetComponent<MeshFilter>().sharedMesh;
    
        DestroyImmediate(quad);
    
        return true;
    }
    

    Although I did stop using the CheckForDefaultSize function altogether in my case.