205 lines
9.4 KiB
C#
205 lines
9.4 KiB
C#
using UnityEngine;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace UnityEngine.ProBuilder
|
|
{
|
|
/// <summary>
|
|
/// Contains a set of commonly used functions for modifying mesh positions.
|
|
/// </summary>
|
|
public static class VertexPositioning
|
|
{
|
|
static List<int> s_CoincidentVertices = new List<int>();
|
|
|
|
/// <summary>
|
|
/// Returns a copy of a mesh positions array transformed into world coordinates.
|
|
/// </summary>
|
|
/// <param name="mesh">The source mesh.</param>
|
|
/// <returns>An array containing all vertex positions in world space.</returns>
|
|
public static Vector3[] VerticesInWorldSpace(this ProBuilderMesh mesh)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
|
|
int len = mesh.vertexCount;
|
|
Vector3[] worldPoints = new Vector3[len];
|
|
Vector3[] localPoints = mesh.positionsInternal;
|
|
|
|
for (int i = 0; i < len; i++)
|
|
worldPoints[i] = mesh.transform.TransformPoint(localPoints[i]);
|
|
|
|
return worldPoints;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translates a set of vertices with a world space offset.
|
|
///
|
|
/// This applies the mesh positions to both the <see cref="ProBuilderMesh"/> and the <see cref="UnityEngine.Mesh"/>.
|
|
/// </summary>
|
|
/// <param name="mesh">The mesh containing the vertices you want to translate.</param>
|
|
/// <param name="indexes">An array of triangles pointing to the vertex positions that you want to translate.</param>
|
|
/// <param name="offset">The offset to apply in world coordinates.</param>
|
|
public static void TranslateVerticesInWorldSpace(this ProBuilderMesh mesh, int[] indexes, Vector3 offset)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
|
|
mesh.TranslateVerticesInWorldSpace(indexes, offset, 0f, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translate a set of vertices with a world space offset.
|
|
/// <br />
|
|
/// Unlike most other mesh operations, this function applies the mesh positions to both ProBuilderMesh and the UnityEngine.Mesh.
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
/// <param name="indexes">A distinct list of vertex indexes.</param>
|
|
/// <param name="offset">The direction and magnitude to translate selectedTriangles, in world space.</param>
|
|
/// <param name="snapValue">If > 0 snap each vertex to the nearest on-grid point in world space.</param>
|
|
/// <param name="snapAxisOnly">If true vertices will only be snapped along the active axis.</param>
|
|
internal static void TranslateVerticesInWorldSpace(this ProBuilderMesh mesh,
|
|
int[] indexes,
|
|
Vector3 offset,
|
|
float snapValue,
|
|
bool snapAxisOnly)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
|
|
int i = 0;
|
|
|
|
mesh.GetCoincidentVertices(indexes, s_CoincidentVertices);
|
|
|
|
Matrix4x4 w2l = mesh.transform.worldToLocalMatrix;
|
|
|
|
Vector3 localOffset = w2l * offset;
|
|
|
|
Vector3[] verts = mesh.positionsInternal;
|
|
|
|
// Snaps to world grid
|
|
if (Mathf.Abs(snapValue) > Mathf.Epsilon)
|
|
{
|
|
Matrix4x4 l2w = mesh.transform.localToWorldMatrix;
|
|
var mask = snapAxisOnly ? new Vector3Mask(offset, Math.handleEpsilon) : Vector3Mask.XYZ;
|
|
|
|
for (i = 0; i < s_CoincidentVertices.Count; i++)
|
|
{
|
|
var v = l2w.MultiplyPoint3x4(verts[s_CoincidentVertices[i]] + localOffset);
|
|
verts[s_CoincidentVertices[i]] = w2l.MultiplyPoint3x4(ProBuilderSnapping.Snap(v, ((Vector3)mask) * snapValue));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < s_CoincidentVertices.Count; i++)
|
|
verts[s_CoincidentVertices[i]] += localOffset;
|
|
}
|
|
|
|
// don't bother calling a full ToMesh() here because we know for certain that the vertices and msh.vertices arrays are equal in length
|
|
mesh.positionsInternal = verts;
|
|
mesh.mesh.vertices = verts;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translates a set of vertices with an offset provided in local (model) coordinates.
|
|
///
|
|
/// This applies the mesh positions to both the <see cref="ProBuilderMesh"/> and the <see cref="UnityEngine.Mesh"/>.
|
|
/// </summary>
|
|
/// <param name="mesh">The mesh containing the vertices that you want to translate.</param>
|
|
/// <param name="indexes">A set of triangles pointing to the vertex positions that you want to translate.</param>
|
|
/// <param name="offset">The offset to apply in local coordinates.</param>
|
|
public static void TranslateVertices(this ProBuilderMesh mesh, IEnumerable<int> indexes, Vector3 offset)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
mesh.GetCoincidentVertices(indexes, s_CoincidentVertices);
|
|
TranslateVerticesInternal(mesh, s_CoincidentVertices, offset);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translates a set of edges with an offset provided in local (model) coordinates.
|
|
///
|
|
/// This applies the mesh positions to both the <see cref="ProBuilderMesh"/> and the <see cref="UnityEngine.Mesh"/>.
|
|
/// </summary>
|
|
/// <param name="mesh">The mesh containing the edges that you want to translate.</param>
|
|
/// <param name="edges">The set of edges that you want to translate.</param>
|
|
/// <param name="offset">The offset to apply in local coordinates.</param>
|
|
public static void TranslateVertices(this ProBuilderMesh mesh, IEnumerable<Edge> edges, Vector3 offset)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
mesh.GetCoincidentVertices(edges, s_CoincidentVertices);
|
|
TranslateVerticesInternal(mesh, s_CoincidentVertices, offset);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Translates a set of faces with an offset provided in local (model) coordinates.
|
|
///
|
|
/// This applies the mesh positions to both the <see cref="ProBuilderMesh"/> and the <see cref="UnityEngine.Mesh"/>.
|
|
/// </summary>
|
|
/// <param name="mesh">The mesh containing the faces that you want to translate.</param>
|
|
/// <param name="faces">The set of faces that you want to translate.</param>
|
|
/// <param name="offset">The offset to apply in local coordinates.</param>
|
|
public static void TranslateVertices(this ProBuilderMesh mesh, IEnumerable<Face> faces, Vector3 offset)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
mesh.GetCoincidentVertices(faces, s_CoincidentVertices);
|
|
TranslateVerticesInternal(mesh, s_CoincidentVertices, offset);
|
|
}
|
|
|
|
static void TranslateVerticesInternal(ProBuilderMesh mesh, IEnumerable<int> indices, Vector3 offset)
|
|
{
|
|
Vector3[] verts = mesh.positionsInternal;
|
|
|
|
for (int i = 0, c = s_CoincidentVertices.Count; i < c; i++)
|
|
verts[s_CoincidentVertices[i]] += offset;
|
|
|
|
// don't bother calling a full ToMesh() here because we know for certain that the vertices and msh.vertices arrays are equal in length
|
|
mesh.mesh.vertices = verts;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Takes a <see cref="SharedVertex"/> index (index of the triangle in the <see cref="ProBuilderMesh.sharedVertices">sharedIndexes</see>
|
|
/// array), and changes its vertices to a new position in model space coordinates.
|
|
///
|
|
/// Use <see cref="ProBuilderMesh.sharedVertices">sharedIndexes</see> and <see cref="UnityEditor.ArrayUtility.IndexOf"/> to get a shared (or common) index.
|
|
/// </summary>
|
|
/// <param name="mesh">The mesh containing the vertices you want to modify.</param>
|
|
/// <param name="sharedVertexHandle">The shared (or common) index to set the vertex position of.</param>
|
|
/// <param name="position">The new position in model coordinates.</param>
|
|
public static void SetSharedVertexPosition(this ProBuilderMesh mesh, int sharedVertexHandle, Vector3 position)
|
|
{
|
|
if (mesh == null)
|
|
throw new ArgumentNullException("mesh");
|
|
|
|
Vector3[] v = mesh.positionsInternal;
|
|
|
|
foreach (var index in mesh.sharedVerticesInternal[sharedVertexHandle])
|
|
v[index] = position;
|
|
|
|
mesh.positionsInternal = v;
|
|
mesh.mesh.vertices = v;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set a collection of mesh attributes with a Vertex.
|
|
/// <br /><br />
|
|
/// Use @"UnityEngine.ProBuilder.ProBuilderMesh.sharedIndexes" and IntArrayUtility.IndexOf to get a shared (or common) index.
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
/// <param name="sharedVertexHandle"></param>
|
|
/// <param name="vertex"></param>
|
|
internal static void SetSharedVertexValues(this ProBuilderMesh mesh, int sharedVertexHandle, Vertex vertex)
|
|
{
|
|
Vertex[] vertices = mesh.GetVertices();
|
|
|
|
foreach (var index in mesh.sharedVerticesInternal[sharedVertexHandle])
|
|
vertices[index] = vertex;
|
|
|
|
mesh.SetVertices(vertices);
|
|
}
|
|
}
|
|
}
|