// Shatter Toolkit
// Copyright 2015 Gustav Olsson
using System.Collections.Generic;
using UnityEngine;
namespace ShatterToolkit
{
public class TargetUvMapper : UvMapper
{
///
/// Determines the start of the target area in the texture, in uv-coordinates.
///
public Vector2 targetStart = Vector2.zero;
///
/// Determines the size of the target area in the texture, in uv-coordinates.
///
public Vector2 targetSize = Vector2.one;
///
/// If true, the aspect ratio of the vertex uv-coordinates, before being mapped to the target area, is locked to 1.
/// Useful if the desired target area is square and the final texture should keep it's proportions.
///
public bool square = false;
///
/// If true, the mesh origo (0,0,0) will be the center of the vertex uv-coordinates, before being mapped to the target area.
/// Useful when for example splitting a watermelon multiple times and a coherent mapping is desired.
///
public bool centerMeshOrigo = false;
public override void Map(IList points, Vector3 planeNormal, out Vector4[] tangentsA, out Vector4[] tangentsB, out Vector2[] uvsA, out Vector2[] uvsB)
{
// Calculate texture direction vectors
Vector3 u = Vector3.Cross(planeNormal, Vector3.up);
if (u == Vector3.zero)
{
u = Vector3.Cross(planeNormal, Vector3.forward);
}
Vector3 v = Vector3.Cross(u, planeNormal);
u.Normalize();
v.Normalize();
// Set tangents
Vector4 tangentA = new Vector4(u.x, u.y, u.z, 1.0f);
Vector4 tangentB = new Vector4(u.x, u.y, u.z, -1.0f);
tangentsA = new Vector4[points.Count];
tangentsB = new Vector4[points.Count];
for (int i = 0; i < points.Count; i++)
{
tangentsA[i] = tangentA;
tangentsB[i] = tangentB;
}
// Set uvs
Vector2[] uvs = new Vector2[points.Count];
Vector2 min = Vector2.zero;
Vector2 max = Vector2.zero;
for (int i = 0; i < points.Count; i++)
{
Vector3 point = points[i];
uvs[i].x = Vector3.Dot(point, u);
uvs[i].y = Vector3.Dot(point, v);
if (i == 0)
{
min = uvs[i];
max = uvs[i];
}
else
{
min = Vector2.Min(uvs[i], min);
max = Vector2.Max(uvs[i], max);
}
}
Vector2 originalSize = max - min;
if (square)
{
float largestSide = Mathf.Max(originalSize.x, originalSize.y);
Vector2 offset = new Vector2();
offset.x = (largestSide - originalSize.x) * 0.5f;
offset.y = (largestSide - originalSize.y) * 0.5f;
min -= offset;
max += offset;
}
if (centerMeshOrigo)
{
Vector2 largestExtent = new Vector2();
largestExtent.x = Mathf.Max(Mathf.Abs(min.x), Mathf.Abs(max.x));
largestExtent.y = Mathf.Max(Mathf.Abs(min.y), Mathf.Abs(max.y));
min = -largestExtent;
max = largestExtent;
}
Vector2 size = max - min;
Vector2 invSize = new Vector2(1.0f / size.x, 1.0f / size.y);
for (int i = 0; i < points.Count; i++)
{
// Convert uvs to the range [0, 1]
uvs[i].x = (uvs[i].x - min.x) * invSize.x;
uvs[i].y = (uvs[i].y - min.y) * invSize.y;
// Convert uvs to the range [targetStart, targetStart + targetSize]
uvs[i].x = targetStart.x + targetSize.x * uvs[i].x;
uvs[i].y = targetStart.y + targetSize.y * uvs[i].y;
}
uvsA = uvs;
uvsB = uvs;
}
}
}