- Home /
Normalizing mesh UVS?
I am using Sketchup to create 3D models for my game. Unfortunately, sketchup does not normalize UV coordinates, so the coordinates can be well outside of the normal 0-1 range. I am trying to use OnPostprocessModel to normalize the UVs, but it does not seem to work and in many cases creates more issues.
When I view the imported model in the editor, there are no issues with the UV coordinates. However, building the game out to Android results in glitchy UV coordinates due to lower floating point precision. Does anyone know how I can normalize the UV coordinates or maybe increase the UV precision on Android?
Answer by Eno-Khaon · Jul 08, 2016 at 12:54 AM
(This would be more appropriate as a comment, as I can't fully provide an answer, but it exceeds the 3000 character limit)
Based on your description, it sounds like the UVs appear correctly in the editor, which means that all the UVs are properly aligned between any given 0-1 UV space range. Specifically, this leads me to believe that the UVs are not crossing any given boundary.
Based on that, perhaps this may be of use to verify whether this is the case:
// ViewUVs.cs
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class ViewUVs : MonoBehaviour
{
[SerializeField, HideInInspector]
Mesh m;
[SerializeField, HideInInspector]
int[] t;
[SerializeField, HideInInspector]
Vector2[] uv;
public bool showGrid = true;
public int gridCount = 5;
public bool subGrid = true;
public float subGridSize = 0.1f;
public Vector3 position = new Vector3(0, 0, 0);
public float scale = 5.0f;
public float rotationAngle = 0;
public Vector3 rotationAxis = Vector3.up;
public Camera cCamera;
void Start()
{
if(gameObject.GetComponent<MeshFilter>() == null)
{
Debug.LogError("MeshFilter not found! Script not added to object.");
DestroyImmediate(this);
}
else
{
m = gameObject.GetComponent<MeshFilter>().sharedMesh;
t = m.triangles;
uv = m.uv;
if(cCamera != null)
{
position = cCamera.transform.position + (cCamera.transform.forward * 3 * scale) + (-cCamera.transform.right * 0.5f * scale) + (-cCamera.transform.up * 0.5f * scale);
cCamera.transform.rotation.ToAngleAxis(out rotationAngle, out rotationAxis);
}
else
{
position = transform.position + (Vector3.up * 5);
}
}
}
void OnDrawGizmos()
{
Quaternion rotation = Quaternion.AngleAxis(rotationAngle, rotationAxis.normalized);
if(showGrid && gridCount > 0)
{
if(subGrid && subGridSize > 0)
{
for(float i = -gridCount + 1; i < gridCount; i += subGridSize)
{
if(!Mathf.Approximately(i, Mathf.RoundToInt(i)))
{
if(i > 0 && i < 1)
{
Gizmos.color = new Color(0.0f, 0.0f, 0.33f);
}
else
{
Gizmos.color = new Color(0.33f, 0.33f, 0.33f);
}
Gizmos.DrawLine(position + (rotation * new Vector3((i * scale), ((-gridCount + 1) * scale), 0)), position + (rotation * new Vector3((i * scale), (gridCount * scale), 0)));
Gizmos.DrawLine(position + (rotation * new Vector3(((-gridCount + 1) * scale), (i * scale), 0)), position + (rotation * new Vector3((gridCount * scale), (i * scale), 0)));
}
}
}
for(int i = (-gridCount + 1) + 1; i < gridCount; i++)
{
if(i == 0 || i == 1)
{
Gizmos.color = new Color(0.66f, 0.0f, 0.0f);
}
else
{
Gizmos.color = new Color(0.66f, 0.66f, 0.66f);
}
Gizmos.DrawLine(position + (rotation * new Vector3((i * scale), ((-gridCount + 1) * scale), 0)), position + (rotation * new Vector3((i * scale), (gridCount * scale), 0)));
Gizmos.DrawLine(position + (rotation * new Vector3(((-gridCount + 1) * scale), (i * scale), 0)), position + (rotation * new Vector3((gridCount * scale), (i * scale), 0)));
}
}
if(t != null && uv != null)
{
Gizmos.color = Color.white;
for(int i = 0; i < t.Length; i += 3)
{
Gizmos.DrawLine(position + (rotation * new Vector3(uv[t[i]].x, uv[t[i]].y, 0)) * scale, position + (rotation * new Vector3(uv[t[i + 1]].x, uv[t[i + 1]].y, 0)) * scale);
Gizmos.DrawLine(position + (rotation * new Vector3(uv[t[i + 1]].x, uv[t[i + 1]].y, 0)) * scale, position + (rotation * new Vector3(uv[t[i + 2]].x, uv[t[i + 2]].y, 0)) * scale);
Gizmos.DrawLine(position + (rotation * new Vector3(uv[t[i + 2]].x, uv[t[i + 2]].y, 0)) * scale, position + (rotation * new Vector3(uv[t[i]].x, uv[t[i]].y, 0)) * scale);
}
}
}
}
Specifically, this script will generate a grid (if desired, color-coded to indicate the 0-1 range for the UVs) and a display of the UVs on the object. To start, this would at least help to verify that the coordinates all appear to be in the correct positions.
I can't say for certain whether it would be easy or reasonable to save the result back out afterward, but the uv positions would be able to be normalized using
for(int i = 0; i < uv.length; i++)
{
uv[i] = new Vector2(Mathf.Repeat(uv[i].x, 1.0f), Mathf.Repeat(uv[i].y, 1.0f));
}
... although, that will also only be reasonable if no uv islands cross a whole-number boundary in any given x to (x+1) range.
Edit: Script rewritten. I wasn't happy with it.
Yeah, the problem is that the UVs tile so they have to go outside the 0..1 range. I did do some debug.Log tests earlier and the Uvs would sometimes be in the ten thousands, negative or positive.