BITFALL/Assets/Plugins/FImpossible Creations/Plugins - Level Design/Generators Shared/Mesh Generating/FMeshUtils.cs

286 lines
8.6 KiB
C#

using Parabox.CSG;
using System.Collections.Generic;
using UnityEngine;
namespace FIMSpace.Generating
{
public static partial class FMeshUtils
{
public static void SmoothMeshNormals(Mesh m, float hard)
{
var verts = m.vertices;
var triangles = m.triangles;
Vector3[] normals = new Vector3[verts.Length];
List<Vector3>[] vertexNormals = new List<Vector3>[verts.Length];
for (int i = 0; i < vertexNormals.Length; i++)
{
vertexNormals[i] = new List<Vector3>();
}
for (int i = 0; i < triangles.Length; i += 3)
{
Vector3 currNormal = Vector3.Cross(
(verts[triangles[i + 1]] - verts[triangles[i]]).normalized,
(verts[triangles[i + 2]] - verts[triangles[i]]).normalized);
vertexNormals[triangles[i]].Add(currNormal);
vertexNormals[triangles[i + 1]].Add(currNormal);
vertexNormals[triangles[i + 2]].Add(currNormal);
}
for (int i = 0; i < vertexNormals.Length; i++)
{
normals[i] = Vector3.zero;
float numNormals = vertexNormals[i].Count;
for (int j = 0; j < numNormals; j++)
{
normals[i] += vertexNormals[i][j];
}
normals[i] /= numNormals;
if (hard > 0.05f)
{
if (normals[i].sqrMagnitude > Mathf.Epsilon)
{
Quaternion look = Quaternion.LookRotation(normals[i]);
Vector3 sm = look.eulerAngles;
sm = FVectorMethods.FlattenVector(sm, hard * 90f);
normals[i] = Quaternion.Euler(sm) * Vector3.forward;
}
}
}
m.normals = normals;
}
public static Mesh MeshesOperation(Mesh combined, Mesh removeCombination, Parabox.CSG.CSG.BooleanOp operation, bool flipCaps = false)
{
if (operation == Parabox.CSG.CSG.BooleanOp.None) return combined;
Material defMat = new Material(Shader.Find("Diffuse"));
Model result;
if (operation == CSG.BooleanOp.Intersection)
result = CSG.Intersect(combined, defMat, Matrix4x4.identity, removeCombination, defMat, Matrix4x4.identity, true);
else if (operation == CSG.BooleanOp.Subtraction)
result = CSG.Subtract(combined, defMat, Matrix4x4.identity, removeCombination, defMat, Matrix4x4.identity, true, flipCaps);
else //if (operation == CSG.BooleanOp.Union)
result = CSG.Union(combined, defMat, Matrix4x4.identity, removeCombination, defMat, Matrix4x4.identity, true);
return result.mesh;
}
public static Mesh AdjustOrigin(Mesh m, EOrigin origin)
{
m.RecalculateBounds();
if (origin == EOrigin.Unchanged) return m;
else if (origin == EOrigin.Center)
{
Vector3 off = -m.bounds.center;
var verts = m.vertices;
// Center Offset
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
else if (origin == EOrigin.BottomCenter)
{
Vector3 off = new Vector3(-m.bounds.center.x, -m.bounds.min.y, -m.bounds.center.z);
var verts = m.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
else if (origin == EOrigin.TopCenter)
{
Vector3 off = new Vector3(-m.bounds.center.x, -m.bounds.max.y, -m.bounds.center.z);
var verts = m.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
else if (origin == EOrigin.BottomLeft)
{
Vector3 off = new Vector3(-m.bounds.min.x, -m.bounds.min.y, -m.bounds.min.z);
var verts = m.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
else if (origin == EOrigin.BottomCenterBack)
{
Vector3 off = new Vector3(-m.bounds.center.x, -m.bounds.min.y, -m.bounds.min.z);
var verts = m.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
else if (origin == EOrigin.BottomCenterFront)
{
Vector3 off = new Vector3(-m.bounds.center.x, -m.bounds.min.y, -m.bounds.max.z);
var verts = m.vertices;
for (int v = 0; v < verts.Length; v++) verts[v] += off;
m.SetVerticesUnity2018(verts);
}
return m;
}
#region Unity 2018 Support
public static void SetVerticesUnity2018(this Mesh m, Vector3[] verts)
{
#if UNITY_2019_4_OR_NEWER
m.SetVertices(verts);
#else
m.vertices = verts;
#endif
}
public static void SetUVUnity2018(this Mesh m, Vector2[] uv)
{
#if UNITY_2019_4_OR_NEWER
m.SetUVs(0, uv);
#else
m.uv = uv;
#endif
}
public static void SetNormalsUnity2018(this Mesh m, Vector3[] norm)
{
#if UNITY_2019_4_OR_NEWER
m.SetNormals(norm);
#else
m.normals = norm;
#endif
}
public static void SetTrianglesUnity2018(this Mesh m, int[] tris)
{
#if UNITY_2019_4_OR_NEWER
m.SetTriangles(tris, 0);
#else
m.triangles = tris;
#endif
}
public static void SetColorsUnity2018(this Mesh m, List<Color> c)
{
#if UNITY_2019_4_OR_NEWER
m.SetColors(c);
#else
m.colors = c.ToArray();
#endif
}
#endregion
public static void OffsetUV(Mesh mesh, Vector2 uVOffset)
{
Vector2[] uvs = mesh.uv;
for (int u = 0; u < uvs.Length; u++)
{
uvs[u] = new Vector2((uvs[u].x + uVOffset.x), (uvs[u].y + uVOffset.y));
}
mesh.SetUVUnity2018(uvs);
}
public static void RotateUV(Mesh mesh, float angle)
{
Vector2[] uvs = mesh.uv;
float rad = angle * Mathf.Deg2Rad;
float rotMatrix00 = Mathf.Cos(rad);
float rotMatrix01 = -Mathf.Sin(rad);
float rotMatrix10 = Mathf.Sin(rad);
float rotMatrix11 = Mathf.Cos(rad);
Vector2 halfV2 = new Vector2(0.5f, 0.5f);
for (int j = 0; j < uvs.Length; j++)
{
uvs[j] = uvs[j] - halfV2;
float u = rotMatrix00 * uvs[j].x + rotMatrix01 * uvs[j].y;
float v = rotMatrix10 * uvs[j].x + rotMatrix11 * uvs[j].y;
uvs[j].x = u; uvs[j].y = v;
uvs[j] = uvs[j] + halfV2;
}
mesh.SetUVUnity2018(uvs);
}
public static void RescaleUV(Mesh mesh, Vector2 uVReScale)
{
Vector2[] uvs = mesh.uv;
for (int u = 0; u < uvs.Length; u++)
{
uvs[u] = new Vector2((uvs[u].x * uVReScale.x), (uvs[u].y * uVReScale.y));
}
mesh.SetUVUnity2018(uvs);
}
public static void FlipNormals(Mesh mesh)
{
Vector3[] normals = mesh.normals;
for (int i = 0; i < normals.Length; i++) normals[i] = -normals[i];
mesh.SetNormalsUnity2018(normals);
int[] triangles = mesh.GetTriangles(0);
for (int i = 0; i < triangles.Length; i += 3)
{
int temp = triangles[i + 0];
triangles[i + 0] = triangles[i + 1];
triangles[i + 1] = temp;
}
mesh.SetTrianglesUnity2018(triangles);
}
public static void SmoothNormals(Mesh mesh)
{
Vector3[] normals = mesh.normals;
for (int i = 0; i < mesh.vertices.Length; i++)
for (int j = i + 1; j < mesh.vertices.Length; j++)
if (mesh.vertices[i] == mesh.vertices[j])
{
Vector3 averagedNormal = (normals[i] + normals[j]) / 2;
normals[i] = averagedNormal;
normals[j] = averagedNormal;
}
mesh.normals = normals;
}
}
}