Added player character and step in/out of dialogue in scene 101
This commit is contained in:
+414
@@ -0,0 +1,414 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.ProBuilder.MeshOperations
|
||||
{
|
||||
/// <summary>
|
||||
/// UV actions.
|
||||
/// </summary>
|
||||
static partial class UVEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a reference to the mesh UV array at index.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="channel">The zero-indexed UV channel.</param>
|
||||
/// <returns></returns>
|
||||
internal static Vector2[] GetUVs(ProBuilderMesh mesh, int channel)
|
||||
{
|
||||
switch (channel)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
Mesh m = mesh.mesh;
|
||||
if (m == null)
|
||||
return null;
|
||||
return mesh.mesh.uv2;
|
||||
}
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
if (channel == 2 ? mesh.HasArrays(MeshArrays.Texture2) : mesh.HasArrays(MeshArrays.Texture3))
|
||||
{
|
||||
List<Vector4> uvs = new List<Vector4>();
|
||||
mesh.GetUVs(channel, uvs);
|
||||
return uvs.Select(x => (Vector2)x).ToArray();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
return mesh.texturesInternal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an array to the appropriate UV channel, but don't refresh the Mesh.
|
||||
/// </summary>
|
||||
internal static void ApplyUVs(ProBuilderMesh mesh, Vector2[] uvs, int channel, bool applyToMesh = true)
|
||||
{
|
||||
switch (channel)
|
||||
{
|
||||
case 0:
|
||||
mesh.texturesInternal = uvs;
|
||||
if (applyToMesh && mesh.mesh != null)
|
||||
mesh.mesh.uv = uvs;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (applyToMesh && mesh.mesh != null)
|
||||
mesh.mesh.uv2 = uvs;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
int vc = mesh.vertexCount;
|
||||
if (vc != uvs.Length)
|
||||
throw new IndexOutOfRangeException("uvs");
|
||||
List<Vector4> list = new List<Vector4>(vc);
|
||||
for (int i = 0; i < vc; i++)
|
||||
list.Add(uvs[i]);
|
||||
mesh.SetUVs(channel, list);
|
||||
if (applyToMesh && mesh.mesh != null)
|
||||
mesh.mesh.SetUVs(channel, list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sews (welds) a UV seam using delta to determine which UVs are close enough to be merged.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="indexes"></param>
|
||||
/// <param name="delta"></param>
|
||||
/// <returns></returns>
|
||||
public static void SewUVs(this ProBuilderMesh mesh, int[] indexes, float delta)
|
||||
{
|
||||
Vector2[] uvs = mesh.texturesInternal;
|
||||
|
||||
if (uvs == null || uvs.Length != mesh.vertexCount)
|
||||
uvs = new Vector2[mesh.vertexCount];
|
||||
|
||||
var lookup = mesh.sharedTextureLookup;
|
||||
|
||||
for (int i = 0; i < indexes.Length - 1; i++)
|
||||
{
|
||||
for (int n = i + 1; n < indexes.Length; n++)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
if (!lookup.TryGetValue(indexes[i], out a))
|
||||
lookup.Add(indexes[i], a = lookup.Count);
|
||||
|
||||
if (!lookup.TryGetValue(indexes[n], out b))
|
||||
lookup.Add(indexes[n], b = lookup.Count);
|
||||
|
||||
if (a == b)
|
||||
continue;
|
||||
|
||||
if (Vector2.Distance(uvs[indexes[i]], uvs[indexes[n]]) < delta)
|
||||
{
|
||||
Vector3 cen = (uvs[indexes[i]] + uvs[indexes[n]]) / 2f;
|
||||
|
||||
uvs[indexes[i]] = cen;
|
||||
uvs[indexes[n]] = cen;
|
||||
|
||||
// ToArray prevents delayed execution of linq actions, which cause trouble when modifying the
|
||||
// dictionary values
|
||||
var merge = lookup.Where(x => x.Value == b).Select(y => y.Key).ToArray();
|
||||
|
||||
foreach (var key in merge)
|
||||
lookup[key] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetSharedTextures(lookup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Similar to Sew, except Collapse just flattens all UVs to the center point no matter the distance.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="indexes"></param>
|
||||
public static void CollapseUVs(this ProBuilderMesh mesh, int[] indexes)
|
||||
{
|
||||
Vector2[] uvs = mesh.texturesInternal;
|
||||
|
||||
// set the shared indexes cache to a unique non-used index
|
||||
Vector2 cen = Math.Average(ArrayUtility.ValuesWithIndexes(uvs, indexes));
|
||||
|
||||
foreach (int i in indexes)
|
||||
uvs[i] = cen;
|
||||
|
||||
mesh.SetTexturesCoincident(indexes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates separate entries in shared indexes cache for all passed indexes. If indexes are not present in pb_IntArray[], don't do anything with them.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="indexes"></param>
|
||||
public static void SplitUVs(this ProBuilderMesh mesh, IEnumerable<int> indexes)
|
||||
{
|
||||
var lookup = mesh.sharedTextureLookup;
|
||||
var index = lookup.Count;
|
||||
|
||||
foreach (var vertex in indexes)
|
||||
{
|
||||
int a;
|
||||
|
||||
if (lookup.TryGetValue(vertex, out a))
|
||||
lookup[vertex] = index++;
|
||||
}
|
||||
|
||||
mesh.SetSharedTextures(lookup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates separate entries in shared indexes cache for all passed indexes.
|
||||
/// </summary>
|
||||
internal static void SplitUVs(ProBuilderMesh mesh, IEnumerable<Face> faces)
|
||||
{
|
||||
var lookup = mesh.sharedTextureLookup;
|
||||
var index = lookup.Count;
|
||||
|
||||
foreach(var face in faces)
|
||||
{
|
||||
foreach (var vertex in face.distinctIndexesInternal)
|
||||
{
|
||||
int a;
|
||||
|
||||
if (lookup.TryGetValue(vertex, out a))
|
||||
lookup[vertex] = index++;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetSharedTextures(lookup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects UVs on all passed faces, automatically updating the sharedIndexesUV table as required (only associates
|
||||
/// vertices that share a seam).
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="faces"></param>
|
||||
/// <param name="channel"></param>
|
||||
internal static void ProjectFacesAuto(ProBuilderMesh mesh, Face[] faces, int channel)
|
||||
{
|
||||
if (faces.Length < 1)
|
||||
return;
|
||||
|
||||
int[] ind = faces.SelectMany(x => x.distinctIndexesInternal).ToArray();
|
||||
|
||||
// Get a projection direction by averaging the normals of all selected faces
|
||||
var projectionDirection = Vector3.zero;
|
||||
|
||||
foreach (var face in faces)
|
||||
{
|
||||
var nrm = Math.Normal(mesh, face);
|
||||
projectionDirection += nrm;
|
||||
}
|
||||
|
||||
projectionDirection /= (float) faces.Length;
|
||||
|
||||
// project uv coordinates
|
||||
Vector2[] uvs = Projection.PlanarProject(mesh.positionsInternal, ind, projectionDirection);
|
||||
|
||||
// re-assign new projected coords back into full uv array
|
||||
Vector2[] rebuiltUVs = GetUVs(mesh, channel);
|
||||
|
||||
for (int i = 0; i < ind.Length; i++)
|
||||
rebuiltUVs[ind[i]] = uvs[i];
|
||||
|
||||
// and set the msh uv array using the new coordintaes
|
||||
ApplyUVs(mesh, rebuiltUVs, channel);
|
||||
|
||||
// now go trhough and set all adjacent face groups to use matching element groups
|
||||
foreach (Face f in faces)
|
||||
{
|
||||
f.elementGroup = -1;
|
||||
SplitUVs(mesh, f.distinctIndexesInternal);
|
||||
}
|
||||
|
||||
mesh.SewUVs(faces.SelectMany(x => x.distinctIndexesInternal).ToArray(), .001f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects UVs for each face using the closest normal on a box.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="faces"></param>
|
||||
/// <param name="channel"></param>
|
||||
public static void ProjectFacesBox(ProBuilderMesh mesh, Face[] faces, int channel = 0)
|
||||
{
|
||||
Vector2[] uv = GetUVs(mesh, channel);
|
||||
|
||||
Dictionary<ProjectionAxis, List<Face>> sorted = new Dictionary<ProjectionAxis, List<Face>>();
|
||||
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
{
|
||||
Vector3 nrm = Math.Normal(mesh, faces[i]);
|
||||
ProjectionAxis axis = Projection.VectorToProjectionAxis(nrm);
|
||||
|
||||
if (sorted.ContainsKey(axis))
|
||||
sorted[axis].Add(faces[i]);
|
||||
else
|
||||
sorted.Add(axis, new List<Face>() { faces[i] });
|
||||
|
||||
// clean up UV stuff - no shared UV indexes and remove element group
|
||||
faces[i].elementGroup = -1;
|
||||
faces[i].manualUV = true;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<ProjectionAxis, List<Face>> kvp in sorted)
|
||||
{
|
||||
int[] distinct = kvp.Value.SelectMany(x => x.distinctIndexesInternal).ToArray();
|
||||
|
||||
Vector2[] uvs = Projection.PlanarProject(mesh.positionsInternal, distinct, Projection.ProjectionAxisToVector(kvp.Key));
|
||||
|
||||
for (int n = 0; n < distinct.Length; n++)
|
||||
uv[distinct[n]] = uvs[n];
|
||||
|
||||
SplitUVs(mesh, distinct);
|
||||
}
|
||||
|
||||
/* and set the msh uv array using the new coordintaes */
|
||||
ApplyUVs(mesh, uv, channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the minimal U and V coordinate of a set of an array of UVs
|
||||
/// </summary>
|
||||
internal static Vector2 FindMinimalUV(Vector2[] uvs, int[] indices = null, float xMin = 0f, float yMin = 0f)
|
||||
{
|
||||
int nbElements = (indices == null ? uvs.Length : indices.Length);
|
||||
bool first = (xMin == 0f && yMin == 0f);
|
||||
for (int i = 0; i < nbElements; ++i)
|
||||
{
|
||||
int currentIndex = (indices == null ? i : indices[i]);
|
||||
if (first)
|
||||
{
|
||||
xMin = uvs[currentIndex].x;
|
||||
yMin = uvs[currentIndex].y;
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (uvs[currentIndex].x < xMin)
|
||||
{
|
||||
xMin = uvs[currentIndex].x;
|
||||
}
|
||||
|
||||
if (uvs[currentIndex].y < yMin)
|
||||
{
|
||||
yMin = uvs[currentIndex].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Vector2(xMin, yMin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects UVs for each face using the closest normal on a box and then place the lower left coordinate at the anchor position.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="faces"></param>
|
||||
/// <param name="lowerLeftAnchor"></param>
|
||||
/// <param name="channel"></param>
|
||||
public static void ProjectFacesBox(ProBuilderMesh mesh, Face[] faces, Vector2 lowerLeftAnchor, int channel = 0)
|
||||
{
|
||||
Vector2[] uv = GetUVs(mesh, channel);
|
||||
|
||||
Dictionary<ProjectionAxis, List<Face>> sorted = new Dictionary<ProjectionAxis, List<Face>>();
|
||||
|
||||
for (int i = 0; i < faces.Length; i++)
|
||||
{
|
||||
Vector3 nrm = Math.Normal(mesh, faces[i]);
|
||||
ProjectionAxis axis = Projection.VectorToProjectionAxis(nrm);
|
||||
|
||||
if (sorted.ContainsKey(axis))
|
||||
sorted[axis].Add(faces[i]);
|
||||
else
|
||||
sorted.Add(axis, new List<Face>() { faces[i] });
|
||||
|
||||
// clean up UV stuff - no shared UV indexes and remove element group
|
||||
faces[i].elementGroup = -1;
|
||||
faces[i].manualUV = true;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<ProjectionAxis, List<Face>> kvp in sorted)
|
||||
{
|
||||
int[] distinct = kvp.Value.SelectMany(x => x.distinctIndexesInternal).ToArray();
|
||||
|
||||
Vector2[] uvs = Projection.PlanarProject(mesh.positionsInternal, distinct, Projection.ProjectionAxisToVector(kvp.Key));
|
||||
|
||||
|
||||
Vector2 minimalUV = FindMinimalUV(uvs);
|
||||
|
||||
for (int n = 0; n < distinct.Length; n++)
|
||||
uv[distinct[n]] = uvs[n] - minimalUV;
|
||||
|
||||
SplitUVs(mesh, distinct);
|
||||
}
|
||||
|
||||
/* and set the msh uv array using the new coordintaes */
|
||||
ApplyUVs(mesh, uv, channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects UVs for each face using the closest normal on a sphere.
|
||||
/// </summary>
|
||||
/// <param name="pb"></param>
|
||||
/// <param name="indexes"></param>
|
||||
/// <param name="channel"></param>
|
||||
public static void ProjectFacesSphere(ProBuilderMesh pb, int[] indexes, int channel = 0)
|
||||
{
|
||||
foreach (Face f in pb.facesInternal)
|
||||
{
|
||||
if (ArrayUtility.ContainsMatch<int>(f.distinctIndexesInternal, indexes))
|
||||
{
|
||||
f.elementGroup = -1;
|
||||
f.manualUV = true;
|
||||
}
|
||||
}
|
||||
|
||||
SplitUVs(pb, indexes);
|
||||
|
||||
Vector2[] projected = Projection.SphericalProject(pb.positionsInternal, indexes);
|
||||
Vector2[] uv = GetUVs(pb, channel);
|
||||
|
||||
for (int i = 0; i < indexes.Length; i++)
|
||||
uv[indexes[i]] = projected[i];
|
||||
|
||||
/* and set the msh uv array using the new coordintaes */
|
||||
ApplyUVs(pb, uv, channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns normalized UV values for a mesh uvs (0,0) - (1,1)
|
||||
*/
|
||||
public static Vector2[] FitUVs(Vector2[] uvs)
|
||||
{
|
||||
// shift UVs to zeroed coordinates
|
||||
Vector2 smallestVector2 = Math.SmallestVector2(uvs);
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < uvs.Length; i++)
|
||||
uvs[i] -= smallestVector2;
|
||||
|
||||
float scale = Math.MakeNonZero(Math.LargestValue(Math.LargestVector2(uvs)));
|
||||
|
||||
for (i = 0; i < uvs.Length; i++)
|
||||
uvs[i] /= scale;
|
||||
|
||||
return uvs;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user