2
\$\begingroup\$

I'm trying to apply a texture from an atlas to a mesh by reiterating through the UV array on that mesh, but I'm a bit lost on converting the coordinates.

For example, if the texture required is at x,y pixels on the material texture atlas, how can I convert and get those coordinates and apply to the mesh? I'm redrawing meshes dynamically with a chunk loader for a voxel game, I have it down for square voxels but now when adding more complex meshes, need to know how to apply the texture to these.

I imagine the code would be something like, but I'm hoping someone can help me fill in the blanks:

   void UpdateMesh()
   {
       UVList.Clear();
       Mesh mesh = this.GetComponent<MeshFilter>().mesh;
       for (int i = 0; i < mesh.uv.Length; i++)
       {
           UVList.Add(GetUVTextureFromAtlas(mesh.uv[i].x, mesh.uv[i].y, voxelType);
       }
      mesh.uv = UVList.ToArray();
   }
  //converts UV position expected from mesh model to position on texture atlas
  Vector2 GetUVTextureFromAtlas(float x, float y, int voxelType)
  {
        Vector2 uv;
        Vector2 textureAtlasPos = GetTextureOffset(voxelType); // returns texture pos from atlas

      //not exactly sure what this would look like for code to convert 
      //from the position on the atlas to the expected UV position based on
      //expected UV position (i.e. from 1,0 to whereever the texture is on the atlas)

        return uv;
  }
\$\endgroup\$
1
\$\begingroup\$

Your base UVs exist on a unit rectangle:

    (0, 1)            (1, 1)
    +-----------------+
    |                 |
    |                 |
    |                 |
    |                 |
    |                 |
    |                 |
    +-----------------+
    (0, 0)            (1, 0)

You're trying to map that space to a different rectangle on the atlas:

    (xmin, ymax)      (xmax, ymax)
    +-----------------+
    |                 |
    |                 |
    |                 |
    |                 |
    |                 |
    |                 |
    +-----------------+
    (xmin, ymin)      (xmax, ymin)

Since your base UVs range from 0 to 1, it's trivial to use Lerp:

float xout = Mathf.Lerp(xmin, xmax, x);
float yout = Mathf.Lerp(ymin, ymax, y);

You'll need appropriate values for xmin, ymin, xmax, and ymax, which means you need to know the location and size of the texture on the atlas.

I've also assumed that those four values are in UV-space. If your atlas coordinates are specified as pixel coordinates, you can convert those to UV coordinates with InverseLerp. Suppose you have a texture at (x, y) with size (xlen, ylen), on an atlas with size (xsize, ysize):

xmin = Mathf.InverseLerp(0, xsize, x);
xmax = Mathf.InverseLerp(0, xsize, x + xlen);
ymin = Mathf.InverseLerp(0, ysize, y);
ymax = Mathf.InverseLerp(0, ysize, y + ylen);

It's absolutely possible to improve on this method, if you're comfortable with the math, but that's the basic gist of it.

\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks, your answer was great explanation and I sincerely appreciate it. \$\endgroup\$ – Euthyphro Oct 30 '15 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.