0
\$\begingroup\$

I created a script that allows me to change my meshes configuration while the app is running. I don't know meshes all that well and am running into issues with texturing. How do I need to set my uv's so that my texture shows correctly? There's likely other issues too so please bear with me.

custom 10x10 mesh is on the left, standard plane right

custom mesh v plane

script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UpMesh : MonoBehaviour
{
    public int width = 1;
    public int height = 1;

    private Vector2 _lastSize = Vector2.zero;
    private Mesh mesh;


    private void Start() {
        _lastSize.x = width;
        _lastSize.y = height;
    }

    void OnValidate() {
        if(Application.isPlaying != true) return;
        if(width == _lastSize.x && height == _lastSize.y) return;
        
        MakeMesh();
    }

    void MakeMesh() {

        mesh = GetComponent<MeshFilter> ().mesh;

        Vector3[] vertices = new Vector3[4 * width * height];
        Vector4[] tangents = new Vector4[4 * width * height];
        Vector2[] uv = new Vector2[4 * width * height];
        int[] triangles = new int[6 * width * height];

        var uvH = 1f / height;
        var uvW = 1f / width;

        for(int col = 0; col < width; ++col) {
            for(int row = 0; row < height; ++row) {
                int index = row * width + col;
                float x = transform.position.x - width/2;
                float y = transform.position.y;
                float z = transform.position.z + height/2;

                vertices[index*4 + 0] = new(x + col,         y,     z - row);
                vertices[index*4 + 1] = new(x + col+1,       y,     z - row);
                vertices[index*4 + 2] = new(x + col+1,       y,     z - row-1);
                vertices[index*4 + 3] = new(x + col,         y,     z - row-1);

                tangents[index*4 + 0] = new(1f, 0f, 0f, -1f);
                tangents[index*4 + 1] = new(1f, 0f, 0f, -1f);
                tangents[index*4 + 2] = new(1f, 0f, 0f, -1f);
                tangents[index*4 + 3] = new(1f, 0f, 0f, -1f);
                

                uv[index*4 + 0] = new(col + col*uvW + uvW,        row + row*uvH);
                uv[index*4 + 1] = new(col + col*uvW,              row + row*uvH);
                uv[index*4 + 2] = new(col + col*uvW,              row + row*uvH + uvH);
                uv[index*4 + 3] = new(col + col*uvW + uvW,        row + row*uvH + uvH);


                triangles[index*6 + 0] = index*4 + 0;
                triangles[index*6 + 1] = index*4 + 1;
                triangles[index*6 + 2] = index*4 + 2;
                triangles[index*6 + 3] = index*4 + 0;
                triangles[index*6 + 4] = index*4 + 2;
                triangles[index*6 + 5] = index*4 + 3;
            }
        }

        mesh.Clear ();
        mesh.vertices = vertices;
        mesh.tangents = tangents;
        mesh.triangles = triangles;
        mesh.uv = uv;
        // mesh.Optimize ();
        // mesh.RecalculateNormals ();

        Debug.Log($"MAKE {height}x{width} v{vertices.Length} t{triangles.Length}");

    }
}

texture

topograph texture

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I notice you're generating four copies of the vertex at each lattice point on the interior of the plane, instead of sharing one vertex among the six triangles meeting there. Is there a reason for this? This will increase video memory usage and vertex shader invocations, and decrease cache utilization, so we usually only want to do that when we need a sharp shading crease or UV discontinuity. \$\endgroup\$
    – DMGregory
    Commented Nov 10, 2023 at 17:26
  • \$\begingroup\$ @DMGregory the reason is that this is a rough draft. If anything I'll want to err on the side of optimization on this one. How can I go about doing what you're talking about? \$\endgroup\$
    – Jacksonkr
    Commented Nov 10, 2023 at 19:44
  • \$\begingroup\$ It looks like your UV mapping problem is that you have the slices in reverse order horizontally. \$\endgroup\$
    – Kevin
    Commented Nov 13, 2023 at 22:30

1 Answer 1

2
\$\begingroup\$

Here's how to get rid of both the duplicated vertices and the reversed UVs:

mesh = GetComponent<MeshFilter> ().mesh;

// "Fencepost" math: one post for each span, plus one at the end.
int vertexCount = (width + 1) * (height + 1);
Vector3[] vertices = new Vector3[vertexCount];
Vector2[] uv = new Vector2[vertexCount];

int[] triangles = new int[6 * width * height];

var uvH = 1f / height;
var uvW = 1f / width;

// Position of vertex zero, at the "top left".
Vector3 corner = transform.position;
corner.x -= width/2f;
corner.z += height/2f;

// First, make the vertices.
int v = 0;
for(int col = 0; col <= width; ++col) {
    Vector3 vertex = corner;
    vertex.x += col;

    for(int row = 0; row <= height; ++row) {        
        vertex.z = corner.z - row;

        vertices[v] = vertex;
        uv[v] = new(col*uvW, 1f - row*uvH);
        v++;
    }
}

// Second, sequence the vertices into triangles.
int t = 0;
int stride = height + 1;
for (int col = 0; col < width; col++) {
    // This is the index of the vertex in the top-left corner of this quad.
    int tBase = col * stride;
    for (int row = 0; row < height; row++) {

        // Top-right triangle:        
        triangles[t++] = tBase;               // Top-left
        triangles[t++] = tBase + stride;      // Top-right (one column over)
        triangles[t++] = tBase + stride + 1;  // Bottom-right
        
        // Bottom-left triangle:
        triangles[t++] = tBase;               // Top-left
        triangles[t++] = tBase + stride + 1;  // Bottom-right
        triangles[t++] = tBase + 1;           // Bottom-left
    }
}

The backwards UVs were coming from the fact that you were moving the 1st and 4th vertex of each quad to the right, but moving the UVs of the 2nd and 3rd vertex to the right, instead of the 1st and 4th to match the positions, effectively mirroring the texture chunk shown within each quad.

\$\endgroup\$
2
  • \$\begingroup\$ Unity was complaining about base so I changed it to tBase. I'm curious, did you write this off the cuff? Color me impressed either way. \$\endgroup\$
    – Jacksonkr
    Commented Nov 22, 2023 at 20:15
  • 1
    \$\begingroup\$ Oops, thanks for the fix. Yeah, procedural geometry code gets a little easier every time you write it, and I've been answering variants on this question for about a decade, so I can just about do simple cases like planes or UV spheres in my sleep now (minus forgetting about reserved keywords, apparently) 😉 \$\endgroup\$
    – DMGregory
    Commented Nov 22, 2023 at 22:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .