add floorplan 2.0 package

This commit is contained in:
Vova
2023-10-06 10:09:30 +03:00
parent b791681d51
commit c2bb35a46d
129 changed files with 9157 additions and 8 deletions
+571
View File
@@ -0,0 +1,571 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace alexism.Floorplan.Core.Static
{
public static class GridEditorUtility
{
private const int k_GridGizmoVertexCount = 32000;
private const float k_GridGizmoDistanceFalloff = 50f;
public static Vector3Int ClampToGrid(Vector3Int p, Vector2Int origin, Vector2Int gridSize)
{
return new Vector3Int(
Math.Max(Math.Min(p.x, origin.x + gridSize.x - 1), origin.x),
Math.Max(Math.Min(p.y, origin.y + gridSize.y - 1), origin.y),
p.z
);
}
public static Vector3 ScreenToLocal(Transform transform, Vector2 screenPosition)
{
return ScreenToLocal(transform, screenPosition, new Plane(transform.forward * -1f, transform.position));
}
public static Vector3 ScreenToLocal(Transform transform, Vector2 screenPosition, Plane plane)
{
Ray ray;
if (Camera.current.orthographic)
{
Vector2 screen = EditorGUIUtility.PointsToPixels(screenPosition);
screen.y = Screen.height - screen.y;
Vector3 cameraWorldPoint = Camera.current.ScreenToWorldPoint(screen);
ray = new Ray(cameraWorldPoint, Camera.current.transform.forward);
}
else
{
ray = HandleUtility.GUIPointToWorldRay(screenPosition);
}
float result;
plane.Raycast(ray, out result);
Vector3 world = ray.GetPoint(result);
return transform.InverseTransformPoint(world);
}
public static RectInt GetMarqueeRect(Vector2Int p1, Vector2Int p2)
{
return new RectInt(
Math.Min(p1.x, p2.x),
Math.Min(p1.y, p2.y),
Math.Abs(p2.x - p1.x) + 1,
Math.Abs(p2.y - p1.y) + 1
);
}
public static BoundsInt GetMarqueeBounds(Vector3Int p1, Vector3Int p2)
{
return new BoundsInt(
Math.Min(p1.x, p2.x),
Math.Min(p1.y, p2.y),
Math.Min(p1.z, p2.z),
Math.Abs(p2.x - p1.x) + 1,
Math.Abs(p2.y - p1.y) + 1,
Math.Abs(p2.z - p1.z) + 1
);
}
// http://ericw.ca/notes/bresenhams-line-algorithm-in-csharp.html
public static IEnumerable<Vector2Int> GetPointsOnLine(Vector2Int p1, Vector2Int p2)
{
int x0 = p1.x;
int y0 = p1.y;
int x1 = p2.x;
int y1 = p2.y;
bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
if (steep)
{
int t;
t = x0; // swap x0 and y0
x0 = y0;
y0 = t;
t = x1; // swap x1 and y1
x1 = y1;
y1 = t;
}
if (x0 > x1)
{
int t;
t = x0; // swap x0 and x1
x0 = x1;
x1 = t;
t = y0; // swap y0 and y1
y0 = y1;
y1 = t;
}
int dx = x1 - x0;
int dy = Math.Abs(y1 - y0);
int error = dx / 2;
int ystep = (y0 < y1) ? 1 : -1;
int y = y0;
for (int x = x0; x <= x1; x++)
{
yield return new Vector2Int((steep ? y : x), (steep ? x : y));
error = error - dy;
if (error < 0)
{
y += ystep;
error += dx;
}
}
}
public static void DrawBatchedHorizontalLine(float x1, float x2, float y)
{
GL.Vertex3(x1, y, 0f);
GL.Vertex3(x2, y, 0f);
GL.Vertex3(x2, y + 1, 0f);
GL.Vertex3(x1, y + 1, 0f);
}
public static void DrawBatchedVerticalLine(float y1, float y2, float x)
{
GL.Vertex3(x, y1, 0f);
GL.Vertex3(x, y2, 0f);
GL.Vertex3(x + 1, y2, 0f);
GL.Vertex3(x + 1, y1, 0f);
}
public static void DrawBatchedLine(Vector3 p1, Vector3 p2)
{
GL.Vertex3(p1.x, p1.y, p1.z);
GL.Vertex3(p2.x, p2.y, p2.z);
}
public static void DrawLine(Vector2 p1, Vector2 p2, Color color)
{
if (Event.current.type != EventType.Repaint)
return;
GL.PushMatrix();
GL.MultMatrix(GUI.matrix);
GL.Begin(GL.LINES);
GL.Color(color);
DrawBatchedLine(p1, p2);
GL.End();
GL.PopMatrix();
}
public static void DrawBox(Rect r, Color color)
{
if (Event.current.type != EventType.Repaint)
return;
GL.PushMatrix();
GL.MultMatrix(GUI.matrix);
GL.Begin(GL.LINES);
GL.Color(color);
DrawBatchedLine(new Vector3(r.xMin, r.yMin, 0f), new Vector3(r.xMax, r.yMin, 0f));
DrawBatchedLine(new Vector3(r.xMax, r.yMin, 0f), new Vector3(r.xMax, r.yMax, 0f));
DrawBatchedLine(new Vector3(r.xMax, r.yMax, 0f), new Vector3(r.xMin, r.yMax, 0f));
DrawBatchedLine(new Vector3(r.xMin, r.yMax, 0f), new Vector3(r.xMin, r.yMin, 0f));
GL.End();
GL.PopMatrix();
}
public static void DrawFilledBox(Rect r, Color color)
{
if (Event.current.type != EventType.Repaint)
return;
GL.PushMatrix();
GL.MultMatrix(GUI.matrix);
GL.Begin(GL.QUADS);
GL.Color(color);
GL.Vertex3(r.xMin, r.yMin, 0f);
GL.Vertex3(r.xMax, r.yMin, 0f);
GL.Vertex3(r.xMax, r.yMax, 0f);
GL.Vertex3(r.xMin, r.yMax, 0f);
GL.End();
GL.PopMatrix();
}
public static void DrawGridMarquee(GridLayout gridLayout, BoundsInt area, Color color)
{
switch (gridLayout.cellLayout)
{
case GridLayout.CellLayout.Hexagon:
DrawSelectedHexGridArea(gridLayout, area, color);
break;
case GridLayout.CellLayout.Isometric:
case GridLayout.CellLayout.IsometricZAsY:
case GridLayout.CellLayout.Rectangle:
var cellStride = gridLayout.cellSize + gridLayout.cellGap;
var cellGap = Vector3.one;
if (!Mathf.Approximately(cellStride.x, 0f))
{
cellGap.x = gridLayout.cellSize.x / cellStride.x;
}
if (!Mathf.Approximately(cellStride.y, 0f))
{
cellGap.y = gridLayout.cellSize.y / cellStride.y;
}
Vector3[] cellLocals =
{
gridLayout.CellToLocal(new Vector3Int(area.xMin, area.yMin, area.zMin)),
gridLayout.CellToLocalInterpolated(new Vector3(area.xMax - 1 + cellGap.x, area.yMin, area.zMin)),
gridLayout.CellToLocalInterpolated(new Vector3(area.xMax - 1 + cellGap.x, area.yMax - 1 + cellGap.y, area.zMin)),
gridLayout.CellToLocalInterpolated(new Vector3(area.xMin, area.yMax - 1 + cellGap.y, area.zMin))
};
GL.PushMatrix();
GL.MultMatrix(gridLayout.transform.localToWorldMatrix);
GL.Begin(GL.LINES);
GL.Color(color);
int i = 0;
for (int j = cellLocals.Length - 1; i < cellLocals.Length; j = i++)
DrawBatchedLine(cellLocals[j], cellLocals[i]);
GL.End();
GL.PopMatrix();
break;
}
}
public static void DrawSelectedHexGridArea(GridLayout gridLayout, BoundsInt area, Color color)
{
int requiredVertices = 4 * (area.size.x + area.size.y) - 2;
if (requiredVertices < 0)
return;
Vector3[] cellLocals = new Vector3[requiredVertices];
int horizontalCount = area.size.x * 2;
int verticalCount = area.size.y * 2 - 1;
int bottom = 0;
int top = horizontalCount + verticalCount + horizontalCount - 1;
int left = requiredVertices - 1;
int right = horizontalCount;
Vector3[] cellOffset =
{
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0, gridLayout.cellSize.y / 2, area.zMin)),
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(gridLayout.cellSize.x / 2, gridLayout.cellSize.y / 4, area.zMin)),
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(gridLayout.cellSize.x / 2, -gridLayout.cellSize.y / 4, area.zMin)),
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0, -gridLayout.cellSize.y / 2, area.zMin)),
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(-gridLayout.cellSize.x / 2, -gridLayout.cellSize.y / 4, area.zMin)),
Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(-gridLayout.cellSize.x / 2, gridLayout.cellSize.y / 4, area.zMin))
};
// Fill Top and Bottom Vertices
for (int x = area.min.x; x < area.max.x; x++)
{
cellLocals[bottom++] = gridLayout.CellToLocal(new Vector3Int(x, area.min.y, area.zMin)) + cellOffset[4];
cellLocals[bottom++] = gridLayout.CellToLocal(new Vector3Int(x, area.min.y, area.zMin)) + cellOffset[3];
cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(x, area.max.y - 1, area.zMin)) + cellOffset[0];
cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(x, area.max.y - 1, area.zMin)) + cellOffset[1];
}
// Fill first Left and Right Vertices
cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, area.min.y, area.zMin)) + cellOffset[5];
cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, area.max.y - 1, area.zMin)) + cellOffset[2];
// Fill Left and Right Vertices
for (int y = area.min.y + 1; y < area.max.y; y++)
{
cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, y, area.zMin)) + cellOffset[4];
cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, y, area.zMin)) + cellOffset[5];
}
for (int y = area.min.y; y < (area.max.y - 1); y++)
{
cellLocals[right++] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, y, area.zMin)) + cellOffset[2];
cellLocals[right++] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, y, area.zMin)) + cellOffset[1];
}
GL.PushMatrix();
GL.MultMatrix(gridLayout.transform.localToWorldMatrix);
GL.Begin(GL.LINES);
GL.Color(color);
int i = 0;
for (int j = cellLocals.Length - 1; i < cellLocals.Length; j = i++)
{
DrawBatchedLine(cellLocals[j], cellLocals[i]);
}
GL.End();
GL.PopMatrix();
}
public static void DrawGridGizmo(GridLayout gridLayout, Transform transform, Color color, ref Mesh gridMesh, ref Material gridMaterial)
{
// TODO: Hook this up with DrawGrid
if (Event.current.type != EventType.Repaint)
return;
if (gridMesh == null)
gridMesh = GenerateCachedGridMesh(gridLayout, color);
if (gridMaterial == null)
{
gridMaterial = (Material)EditorGUIUtility.LoadRequired("SceneView/GridGap.mat");
}
if (gridLayout.cellLayout == GridLayout.CellLayout.Hexagon)
{
gridMaterial.SetVector("_Gap", new Vector4(1f, 1f / 3f, 1f, 1f));
gridMaterial.SetVector("_Stride", new Vector4(1f, 1f, 1f, 1f));
}
else
{
gridMaterial.SetVector("_Gap", gridLayout.cellSize);
gridMaterial.SetVector("_Stride", gridLayout.cellGap + gridLayout.cellSize);
}
gridMaterial.SetPass(0);
GL.PushMatrix();
if (gridMesh.GetTopology(0) == MeshTopology.Lines)
GL.Begin(GL.LINES);
else
GL.Begin(GL.QUADS);
Graphics.DrawMeshNow(gridMesh, transform.localToWorldMatrix);
GL.End();
GL.PopMatrix();
}
public static Vector3 GetSpriteWorldSize(Sprite sprite)
{
if (sprite != null && sprite.rect.size.magnitude > 0f)
{
return new Vector3(
sprite.rect.size.x / sprite.pixelsPerUnit,
sprite.rect.size.y / sprite.pixelsPerUnit,
1f
);
}
return Vector3.one;
}
private static Mesh GenerateCachedGridMesh(GridLayout gridLayout, Color color)
{
switch (gridLayout.cellLayout)
{
case GridLayout.CellLayout.Hexagon:
return GenerateCachedHexagonalGridMesh(gridLayout, color);
case GridLayout.CellLayout.Isometric:
case GridLayout.CellLayout.IsometricZAsY:
case GridLayout.CellLayout.Rectangle:
int min = k_GridGizmoVertexCount / -32;
int max = min * -1;
int numCells = max - min;
RectInt bounds = new RectInt(min, min, numCells, numCells);
return GenerateCachedGridMesh(gridLayout, color, 0f, bounds, MeshTopology.Lines);
}
return null;
}
public static Mesh GenerateCachedGridMesh(GridLayout gridLayout, Color color, float screenPixelSize, RectInt bounds, MeshTopology topology)
{
Mesh mesh = new Mesh();
mesh.hideFlags = HideFlags.HideAndDontSave;
int vertex = 0;
int totalVertices = topology == MeshTopology.Quads ?
8 * (bounds.size.x + bounds.size.y) :
4 * (bounds.size.x + bounds.size.y);
Vector3 horizontalPixelOffset = new Vector3(screenPixelSize, 0f, 0f);
Vector3 verticalPixelOffset = new Vector3(0f, screenPixelSize, 0f);
Vector3[] vertices = new Vector3[totalVertices];
Vector2[] uvs2 = new Vector2[totalVertices];
Vector3 cellStride = gridLayout.cellSize + gridLayout.cellGap;
Vector3Int minPosition = new Vector3Int(0, bounds.min.y, 0);
Vector3Int maxPosition = new Vector3Int(0, bounds.max.y, 0);
Vector3 cellGap = Vector3.zero;
if (!Mathf.Approximately(cellStride.x, 0f))
{
cellGap.x = gridLayout.cellSize.x / cellStride.x;
}
for (int x = bounds.min.x; x < bounds.max.x; x++)
{
minPosition.x = x;
maxPosition.x = x;
vertices[vertex + 0] = gridLayout.CellToLocal(minPosition);
vertices[vertex + 1] = gridLayout.CellToLocal(maxPosition);
uvs2[vertex + 0] = Vector2.zero;
uvs2[vertex + 1] = new Vector2(0f, cellStride.y * bounds.size.y);
if (topology == MeshTopology.Quads)
{
vertices[vertex + 2] = gridLayout.CellToLocal(maxPosition) + horizontalPixelOffset;
vertices[vertex + 3] = gridLayout.CellToLocal(minPosition) + horizontalPixelOffset;
uvs2[vertex + 2] = new Vector2(0f, cellStride.y * bounds.size.y);
uvs2[vertex + 3] = Vector2.zero;
}
vertex += topology == MeshTopology.Quads ? 4 : 2;
vertices[vertex + 0] = gridLayout.CellToLocalInterpolated(minPosition + cellGap);
vertices[vertex + 1] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap);
uvs2[vertex + 0] = Vector2.zero;
uvs2[vertex + 1] = new Vector2(0f, cellStride.y * bounds.size.y);
if (topology == MeshTopology.Quads)
{
vertices[vertex + 2] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap) + horizontalPixelOffset;
vertices[vertex + 3] = gridLayout.CellToLocalInterpolated(minPosition + cellGap) + horizontalPixelOffset;
uvs2[vertex + 2] = new Vector2(0f, cellStride.y * bounds.size.y);
uvs2[vertex + 3] = Vector2.zero;
}
vertex += topology == MeshTopology.Quads ? 4 : 2;
}
minPosition = new Vector3Int(bounds.min.x, 0, 0);
maxPosition = new Vector3Int(bounds.max.x, 0, 0);
cellGap = Vector3.zero;
if (!Mathf.Approximately(cellStride.y, 0f))
{
cellGap.y = gridLayout.cellSize.y / cellStride.y;
}
for (int y = bounds.min.y; y < bounds.max.y; y++)
{
minPosition.y = y;
maxPosition.y = y;
vertices[vertex + 0] = gridLayout.CellToLocal(minPosition);
vertices[vertex + 1] = gridLayout.CellToLocal(maxPosition);
uvs2[vertex + 0] = Vector2.zero;
uvs2[vertex + 1] = new Vector2(cellStride.x * bounds.size.x, 0f);
if (topology == MeshTopology.Quads)
{
vertices[vertex + 2] = gridLayout.CellToLocal(maxPosition) + verticalPixelOffset;
vertices[vertex + 3] = gridLayout.CellToLocal(minPosition) + verticalPixelOffset;
uvs2[vertex + 2] = new Vector2(cellStride.x * bounds.size.x, 0f);
uvs2[vertex + 3] = Vector2.zero;
}
vertex += topology == MeshTopology.Quads ? 4 : 2;
vertices[vertex + 0] = gridLayout.CellToLocalInterpolated(minPosition + cellGap);
vertices[vertex + 1] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap);
uvs2[vertex + 0] = Vector2.zero;
uvs2[vertex + 1] = new Vector2(cellStride.x * bounds.size.x, 0f);
if (topology == MeshTopology.Quads)
{
vertices[vertex + 2] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap) + verticalPixelOffset;
vertices[vertex + 3] = gridLayout.CellToLocalInterpolated(minPosition + cellGap) + verticalPixelOffset;
uvs2[vertex + 2] = new Vector2(cellStride.x * bounds.size.x, 0f);
uvs2[vertex + 3] = Vector2.zero;
}
vertex += topology == MeshTopology.Quads ? 4 : 2;
}
var uv0 = new Vector2(k_GridGizmoDistanceFalloff, 0f);
var uvs = new Vector2[vertex];
var indices = new int[vertex];
var colors = new Color[vertex];
var normals = new Vector3[totalVertices]; // Normal channel stores the position of the other end point of the line.
var uvs3 = new Vector2[totalVertices]; // UV3 channel stores the UV2 value of the other end point of the line.
for (int i = 0; i < vertex; i++)
{
uvs[i] = uv0;
indices[i] = i;
colors[i] = color;
var alternate = i + ((i % 2) == 0 ? 1 : -1);
normals[i] = vertices[alternate];
uvs3[i] = uvs2[alternate];
}
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.uv2 = uvs2;
mesh.uv3 = uvs3;
mesh.colors = colors;
mesh.normals = normals;
mesh.SetIndices(indices, topology, 0);
return mesh;
}
private static Mesh GenerateCachedHexagonalGridMesh(GridLayout gridLayout, Color color)
{
Mesh mesh = new Mesh();
mesh.hideFlags = HideFlags.HideAndDontSave;
int vertex = 0;
int max = k_GridGizmoVertexCount / (2 * (6 * 2));
max = (max / 4) * 4;
int min = -max;
float numVerticalCells = 6 * (max / 4);
int totalVertices = max * 2 * 6 * 2;
var cellStrideY = gridLayout.cellGap.y + gridLayout.cellSize.y;
var cellOffsetY = gridLayout.cellSize.y / 2;
var hexOffset = (1.0f / 3.0f);
var drawTotal = numVerticalCells * 2.0f * hexOffset;
var drawDiagTotal = 2 * drawTotal;
Vector3[] vertices = new Vector3[totalVertices];
Vector2[] uvs2 = new Vector2[totalVertices];
// Draw Vertical Lines
for (int x = min; x < max; x++)
{
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(x, min, 0));
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(x, max, 0));
uvs2[vertex] = new Vector2(0f, 2 * hexOffset);
uvs2[vertex + 1] = new Vector2(0f, 2 * hexOffset + drawTotal);
vertex += 2;
// Alternate Row Offset
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(x, min - 1, 0));
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(x, max - 1, 0));
uvs2[vertex] = new Vector2(0f, 2 * hexOffset);
uvs2[vertex + 1] = new Vector2(0f, 2 * hexOffset + drawTotal);
vertex += 2;
}
// Draw Diagonals
for (int y = min; y < max; y++)
{
float drawDiagOffset = ((y + 1) % 3) * hexOffset;
var cellOffSet = Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0f, y * cellStrideY + cellOffsetY, 0.0f));
// Slope Up
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min), min, 0)) + cellOffSet;
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max), max, 0)) + cellOffSet;
uvs2[vertex] = new Vector2(0f, drawDiagOffset);
uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
vertex += 2;
// Slope Down
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max), min, 0)) + cellOffSet;
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min), max, 0)) + cellOffSet;
uvs2[vertex] = new Vector2(0f, drawDiagOffset);
uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
vertex += 2;
// Alternate Row Offset
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min) + 1, min, 0)) + cellOffSet;
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max) + 1, max, 0)) + cellOffSet;
uvs2[vertex] = new Vector2(0f, drawDiagOffset);
uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
vertex += 2;
vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max) + 1, min, 0)) + cellOffSet;
vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min) + 1, max, 0)) + cellOffSet;
uvs2[vertex] = new Vector2(0f, drawDiagOffset);
uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
vertex += 2;
}
var uv0 = new Vector2(k_GridGizmoDistanceFalloff, 0f);
var indices = new int[totalVertices];
var uvs = new Vector2[totalVertices];
var colors = new Color[totalVertices];
var normals = new Vector3[totalVertices]; // Normal channel stores the position of the other end point of the line.
var uvs3 = new Vector2[totalVertices]; // UV3 channel stores the UV2 value of the other end point of the line.
for (int i = 0; i < totalVertices; i++)
{
uvs[i] = uv0;
indices[i] = i;
colors[i] = color;
var alternate = i + ((i % 2) == 0 ? 1 : -1);
normals[i] = vertices[alternate];
uvs3[i] = uvs2[alternate];
}
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.uv2 = uvs2;
mesh.uv3 = uvs3;
mesh.colors = colors;
mesh.normals = normals;
mesh.SetIndices(indices, MeshTopology.Lines, 0);
return mesh;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dbeb7e810b463742b937ae39fe73c12
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+194
View File
@@ -0,0 +1,194 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public enum EVertexAttribute
{
Position = 0x0001,
Normal = 0x0002,
Tangent = 0x0004,
Color = 0x0008,
UV1 = 0x0010,
UV2 = 0x0020,
UV3 = 0x0040,
UV4 = 0x0080,
BoneWeight = 0x0100,
}
public class Vertex
{
public Vector3 pos;
public Vector3 normal;
public Vector4 tangent;
public Color color;
public Vector2 uv1;
public Vector2 uv2;
public Vector2 uv3;
public Vector2 uv4;
public BoneWeight bWeight;
public Vertex(Vector3 aPos)
{
pos = aPos;
}
}
public class MeshWelder
{
Vertex[] vertices;
List<Vertex> newVerts;
int[] map;
EVertexAttribute m_Attributes;
Mesh m_Mesh;
public float MaxUVDelta = 0.0001f;
public float MaxPositionDelta = 0.001f;
public float MaxAngleDelta = 0.01f;
public float MaxColorDelta = 1f / 255f;
public float MaxBWeightDelta = 0.01f;
public MeshWelder(Mesh aMesh)
{
m_Mesh = aMesh;
}
private bool HasAttr(EVertexAttribute aAttr)
{
return (m_Attributes & aAttr) != 0;
}
private bool CompareColor(Color c1, Color c2)
{
return
(Mathf.Abs(c1.r - c2.r) <= MaxColorDelta) &&
(Mathf.Abs(c1.g - c2.g) <= MaxColorDelta) &&
(Mathf.Abs(c1.b - c2.b) <= MaxColorDelta) &&
(Mathf.Abs(c1.a - c2.a) <= MaxColorDelta);
}
private bool CompareBoneWeight(BoneWeight v1, BoneWeight v2)
{
if (v1.boneIndex0 != v2.boneIndex0 || v1.boneIndex1 != v2.boneIndex1 ||
v1.boneIndex2 != v2.boneIndex2 || v1.boneIndex3 != v2.boneIndex3) return false;
if (Mathf.Abs(v1.weight0 - v2.weight0) > MaxBWeightDelta) return false;
if (Mathf.Abs(v1.weight1 - v2.weight1) > MaxBWeightDelta) return false;
if (Mathf.Abs(v1.weight2 - v2.weight2) > MaxBWeightDelta) return false;
if (Mathf.Abs(v1.weight3 - v2.weight3) > MaxBWeightDelta) return false;
return true;
}
private bool Compare(Vertex v1, Vertex v2)
{
if ((v1.pos - v2.pos).sqrMagnitude > MaxPositionDelta) return false;
if (HasAttr(EVertexAttribute.Normal) && Vector3.Angle(v1.normal, v2.normal) > MaxAngleDelta) return false;
if (HasAttr(EVertexAttribute.Tangent) && Vector3.Angle(v1.tangent, v2.tangent) > MaxAngleDelta || v1.tangent.w != v2.tangent.w) return false;
if (HasAttr(EVertexAttribute.Color) && !CompareColor(v1.color, v2.color)) return false;
if (HasAttr(EVertexAttribute.UV1) && (v1.uv1 - v2.uv1).sqrMagnitude > MaxUVDelta) return false;
if (HasAttr(EVertexAttribute.UV2) && (v1.uv2 - v2.uv2).sqrMagnitude > MaxUVDelta) return false;
if (HasAttr(EVertexAttribute.UV3) && (v1.uv3 - v2.uv3).sqrMagnitude > MaxUVDelta) return false;
if (HasAttr(EVertexAttribute.UV4) && (v1.uv4 - v2.uv4).sqrMagnitude > MaxUVDelta) return false;
if (HasAttr(EVertexAttribute.BoneWeight) && !CompareBoneWeight(v1.bWeight, v2.bWeight)) return false;
return true;
}
private void CreateVertexList()
{
var Positions = m_Mesh.vertices;
var Normals = m_Mesh.normals;
var Tangents = m_Mesh.tangents;
var Colors = m_Mesh.colors;
var Uv1 = m_Mesh.uv;
var Uv2 = m_Mesh.uv2;
var Uv3 = m_Mesh.uv3;
var Uv4 = m_Mesh.uv4;
var BWeights = m_Mesh.boneWeights;
m_Attributes = EVertexAttribute.Position;
if (Normals != null && Normals.Length > 0) m_Attributes |= EVertexAttribute.Normal;
if (Tangents != null && Tangents.Length > 0) m_Attributes |= EVertexAttribute.Tangent;
if (Colors != null && Colors.Length > 0) m_Attributes |= EVertexAttribute.Color;
if (Uv1 != null && Uv1.Length > 0) m_Attributes |= EVertexAttribute.UV1;
if (Uv2 != null && Uv2.Length > 0) m_Attributes |= EVertexAttribute.UV2;
if (Uv3 != null && Uv3.Length > 0) m_Attributes |= EVertexAttribute.UV3;
if (Uv4 != null && Uv4.Length > 0) m_Attributes |= EVertexAttribute.UV4;
if (BWeights != null && BWeights.Length > 0) m_Attributes |= EVertexAttribute.BoneWeight;
vertices = new Vertex[Positions.Length];
for (int i = 0; i < Positions.Length; i++)
{
var v = new Vertex(Positions[i]);
if (HasAttr(EVertexAttribute.Normal)) v.normal = Normals[i];
if (HasAttr(EVertexAttribute.Tangent)) v.tangent = Tangents[i];
if (HasAttr(EVertexAttribute.Color)) v.color = Colors[i];
if (HasAttr(EVertexAttribute.UV1)) v.uv1 = Uv1[i];
if (HasAttr(EVertexAttribute.UV2)) v.uv2 = Uv2[i];
if (HasAttr(EVertexAttribute.UV3)) v.uv3 = Uv3[i];
if (HasAttr(EVertexAttribute.UV4)) v.uv4 = Uv4[i];
if (HasAttr(EVertexAttribute.BoneWeight)) v.bWeight = BWeights[i];
vertices[i] = v;
}
}
private void RemoveDuplicates()
{
map = new int[vertices.Length];
newVerts = new List<Vertex>();
for (int i = 0; i < vertices.Length; i++)
{
var v = vertices[i];
bool dup = false;
for (int i2 = 0; i2 < newVerts.Count; i2++)
{
if (Compare(v, newVerts[i2]))
{
map[i] = i2;
dup = true;
break;
}
}
if (!dup)
{
map[i] = newVerts.Count;
newVerts.Add(v);
}
}
}
private void AssignNewVertexArrays()
{
m_Mesh.vertices = newVerts.Select(v => v.pos).ToArray();
if (HasAttr(EVertexAttribute.Normal))
m_Mesh.normals = newVerts.Select(v => v.normal).ToArray();
if (HasAttr(EVertexAttribute.Tangent))
m_Mesh.tangents = newVerts.Select(v => v.tangent).ToArray();
if (HasAttr(EVertexAttribute.Color))
m_Mesh.colors = newVerts.Select(v => v.color).ToArray();
if (HasAttr(EVertexAttribute.UV1))
m_Mesh.uv = newVerts.Select(v => v.uv1).ToArray();
if (HasAttr(EVertexAttribute.UV2))
m_Mesh.uv2 = newVerts.Select(v => v.uv2).ToArray();
if (HasAttr(EVertexAttribute.UV3))
m_Mesh.uv3 = newVerts.Select(v => v.uv3).ToArray();
if (HasAttr(EVertexAttribute.UV4))
m_Mesh.uv4 = newVerts.Select(v => v.uv4).ToArray();
if (HasAttr(EVertexAttribute.BoneWeight))
m_Mesh.boneWeights = newVerts.Select(v => v.bWeight).ToArray();
}
private void RemapTriangles()
{
for (int n = 0; n < m_Mesh.subMeshCount; n++)
{
var tris = m_Mesh.GetTriangles(n);
for (int i = 0; i < tris.Length; i++)
{
tris[i] = map[tris[i]];
}
m_Mesh.SetTriangles(tris, n);
}
}
public void Weld()
{
CreateVertexList();
RemoveDuplicates();
RemapTriangles();
AssignNewVertexArrays();
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a067ff12ca6ed39469eda7ab2c4b00df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
{
"name": "com.alexismorin.floorplan.static",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c4df6f69b1bd3d542a0bd5e003678751
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: