// 27 Slicer
// Copyright 2021 Deftly Games
// https://slicer.deftly.games/
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace Slicer.Core
{
///
/// Contains useful methods for slicing meshes
///
public static class MeshUtility
{
///
/// Creates a copy of a mesh.
///
/// The mesh to make a copy of.
/// Returns the copy of the mesh.
public static Mesh CopyMesh(Mesh origMesh)
{
if (origMesh == null)
{
return null;
}
var newMesh = Mesh.Instantiate(origMesh);
var mode = Application.isPlaying ? "Runtime" : "Editor";
newMesh.name = $"{origMesh.name} {mode} Sliced";
newMesh.MarkDynamic();
return newMesh;
}
///
/// Creates a copy of a mesh.
///
/// The mesh to make a copy of.
/// Returns the copy of the mesh.
public static void CopyMesh(Mesh sourceMesh, Mesh destMesh)
{
if (sourceMesh == null)
{
throw new ArgumentNullException(nameof(sourceMesh));
}
if (destMesh == null)
{
throw new ArgumentNullException(nameof(destMesh));
}
destMesh.Clear();
sourceMesh.GetVertices(TempCollections.Vector3);
destMesh.SetVertices(TempCollections.Vector3);
sourceMesh.GetNormals(TempCollections.Vector3);
destMesh.SetNormals(TempCollections.Vector3);
CopyUVs(sourceMesh, destMesh);
sourceMesh.GetColors(TempCollections.Colors);
destMesh.SetColors(TempCollections.Colors);
sourceMesh.GetTangents(TempCollections.Vector4);
destMesh.SetTangents(TempCollections.Vector4);
var subMeshCount = sourceMesh.subMeshCount;
destMesh.subMeshCount = subMeshCount;
for (int i = 0; i < subMeshCount; i++)
{
var meshTopology = sourceMesh.GetTopology(i);
sourceMesh.GetIndices(TempCollections.Integers, i);
destMesh.SetIndices(TempCollections.Integers, meshTopology, i);
}
}
private static void CopyUVs(Mesh sourceMesh, Mesh destMesh)
{
// Reset the modified UVs back to the original
for (int uvChannel = 0; uvChannel < 7; uvChannel++)
{
var uvDimension = sourceMesh.GetVertexAttributeDimension(uvChannel + VertexAttribute.TexCoord0);
switch (uvDimension)
{
case 2:
sourceMesh.GetUVs(uvChannel, TempCollections.Vector2);
destMesh.SetUVs(uvChannel, TempCollections.Vector2);
break;
case 3:
sourceMesh.GetUVs(uvChannel, TempCollections.Vector3);
destMesh.SetUVs(uvChannel, TempCollections.Vector3);
break;
case 4:
sourceMesh.GetUVs(uvChannel, TempCollections.Vector4);
destMesh.SetUVs(uvChannel, TempCollections.Vector4);
break;
default:
continue;
}
}
}
///
/// Converts a meshes bounds into a bounds in slicer space (local space of the parent SlicerComponent).
///
/// The mesh to encapsulate into the returned bounds.
/// The transform of the GameObject that contains the mesh.
/// The transform of the GameObject containing the SlicerController.
/// The bounds that contains the meshes transformed vectors.
public static Bounds CalculateBounds(Mesh mesh, Transform childTransform, Transform rootTransform)
{
// This matrix converts the local mesh vertex dependent on the transform
// position, scale and orientation into a global position
var matrix = MatrixUtility.BuildTransformMatrix(childTransform, rootTransform);
var origSharedMesh = mesh;
origSharedMesh.GetVertices(TempCollections.Vector3);
var transformedBounds = VectorUtility.CalculateBounds(TempCollections.Vector3, matrix);
TempCollections.Vector3.Clear();
return transformedBounds;
}
///
/// Resets the UVs in destMesh back to the UVs in sourceMesh
///
/// The source mesh
/// The destination mesh
public static void ResetUV(Mesh sourceMesh, Mesh destMesh)
{
CopyUVs(sourceMesh, destMesh);
}
}
}