csharp 多网

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 多网相关的知识,希望对你有一定的参考价值。

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Reflection;

[CustomEditor(typeof(PolyMesh))]
public class PolyMeshEditor : Editor
{
	/// <summary>
	/// Sceneビュー上でのステータスを示す構造体
	/// </summary>
	enum State { Hover, Drag, BoxSelect, DragSelected, RotateSelected, ScaleSelected, Extrude }

	/// <summary>
	/// クリック判定領域
	/// </summary>
	const float clickRadius = 0.12f;

	/// <summary>
	/// ???
	/// </summary>
	FieldInfo undoCallback;
	/// <summary>
	/// Editモードかどうか
	/// </summary>
	bool editing;
	/// <summary>
	/// ???
	/// </summary>
	bool tabDown;
	/// <summary>
	/// ???
	/// </summary>
	State state;

	/// <summary>
	/// 直線パス
	/// </summary>
	List<Vector3> keyPoints;
	/// <summary>
	/// 曲線パス
	/// </summary>
	List<Vector3> curvePoints;
	/// <summary>
	/// カーブするかどうか???
	/// </summary>
	List<bool> isCurve;

	/// <summary>
	/// global座標をlocal座標で持つ???
	/// </summary>
	Matrix4x4 worldToLocal;
	/// <summary>
	/// 回転角度 Quaternionでもつの???
	/// </summary>
	Quaternion inverseRotation;
	
	/// <summary>
	/// マウス座標
	/// </sumamry>
	Vector3 mousePosition;
	/// <summary>
	/// クリック座標
	/// </summary>
	Vector3 clickPosition;
	/// <summary>
	/// スクリーン上でのマウスの座標
	/// </summary>
	Vector3 screenMousePosition;
	/// <summary>
	/// マウスカーソルの状態をArrowに指定
	/// </summary>
	MouseCursor mouseCursor = MouseCursor.Arrow;
	/// <summary>
	/// スナップ???
	/// </summary>
	float snap;

	/// <summary>
	/// ???
	/// </summary>
	int dragIndex;
	/// <summary>
	/// ???
	/// </summary>
	List<int> selectedIndices = new List<int>();
	/// <summary>
	/// ???
	/// </summary>
	int nearestLine;
	/// <summary>
	/// ???
	/// </summary>
	Vector3 splitPosition;
	/// <summary>
	/// ???
	/// </summary>
	bool extrudeKeyDown;
	/// <summary>
	/// ???
	/// </summary>
	bool doExtrudeUpdate;
	/// <summary>
	/// ???
	/// </summary>
	bool draggingCurve;

	#region Inspector GUI
	public override void OnInspectorGUI() {
		if (target == null) {
			return;
		}

		if (polyMesh.keyPoints.Count == 0) {
			CreateSquare(polyMesh, 0.5f);
		}

		// Editモードに入るかどうか
		if (editing) {
			if (GUILayout.Button("Stop Editing"))
			{
				editing = false;
				HideWireframe(false);
			}
		}
		else if (GUILayout.Button("Edit PolyMesh")) {
			editing = true;
			HideWireframe(hideWireframe);
		}

		// UV設定
		if (uvSettings = EditorGUILayout.Foldout(uvSettings, "UVs")) {
			var uvPosition = EditorGUILayout.Vector2Field("Position", polyMesh.uvPosition);
			var uvScale = EditorGUILayout.FloatField("Scale", polyMesh.uvScale);
			var uvRotation = EditorGUILayout.Slider("Rotation", polyMesh.uvRotation, -180, 180) % 360;
			if (uvRotation < -180)
				uvRotation += 360;
			if (GUI.changed) {
				RecordUndo();
				polyMesh.uvPosition = uvPosition;
				polyMesh.uvScale = uvScale;
				polyMesh.uvRotation = uvRotation;
			}
			if (GUILayout.Button("Reset UVs")) {
				polyMesh.uvPosition = Vector3.zero;
				polyMesh.uvScale = 1;
				polyMesh.uvRotation = 0;
			}
		}

		// Mesh設定
		if (meshSettings = EditorGUILayout.Foldout(meshSettings, "Mesh")) {
			var curveDetail = EditorGUILayout.Slider("Curve Detail", polyMesh.curveDetail, 0.01f, 1f);
			curveDetail = Mathf.Clamp(curveDetail, 0.01f, 1f);
			if (GUI.changed) {
				RecordUndo();
				polyMesh.curveDetail = curveDetail;
			}

			//Buttons
			EditorGUILayout.BeginHorizontal();
			if (GUILayout.Button("Build Mesh")) {
				polyMesh.BuildMesh();				
			}
			if (GUILayout.Button("Make Mesh Unique")) {
				RecordUndo();
				polyMesh.GetComponent<MeshFilter>().mesh = null;
				polyMesh.BuildMesh();
			}
			EditorGUILayout.EndHorizontal();
		}

		// Colliderの生成
		if (colliderSettings = EditorGUILayout.Foldout(colliderSettings, "Collider")) {
			// Colliderの深さ設定(z軸の長さ)
			var colliderDepth = EditorGUILayout.FloatField("Depth", polyMesh.colliderDepth);
			colliderDepth = Mathf.Max(colliderDepth, 0.01f);
			var buildColliderEdges = EditorGUILayout.Toggle("Build Edges", polyMesh.buildColliderEdges);
			var buildColliderFront = EditorGUILayout.Toggle("Build Font", polyMesh.buildColliderFront);
			if (GUI.changed) {
				RecordUndo();
				polyMesh.colliderDepth = colliderDepth;
				polyMesh.buildColliderEdges = buildColliderEdges;
				polyMesh.buildColliderFront = buildColliderFront;
			}

			// Colliderの破壊
			if (polyMesh.meshCollider == null) {
				if (GUILayout.Button("Create Collider")) {
					RecordDeepUndo();
					var obj = new GameObject("Collider", typeof(MeshCollider));
					polyMesh.meshCollider = obj.GetComponent<MeshCollider>();
					obj.transform.parent = polyMesh.transform;
					obj.transform.localPosition = Vector3.zero;
				}
			} else if (GUILayout.Button("Destroy Collider")) {
				RecordDeepUndo();
				DestroyImmediate(polyMesh.meshCollider.gameObject);
			}
		}

		//Update mesh
		if (GUI.changed) {
			polyMesh.BuildMesh();
		}

		//Editor settings
		if (editorSettings = EditorGUILayout.Foldout(editorSettings, "Editor")) {
			gridSnap = EditorGUILayout.FloatField("Grid Snap", gridSnap);
			autoSnap = EditorGUILayout.Toggle("Auto Snap", autoSnap);
			globalSnap = EditorGUILayout.Toggle("Global Snap", globalSnap);
			EditorGUI.BeginChangeCheck();
			hideWireframe = EditorGUILayout.Toggle("Hide Wireframe", hideWireframe);
			if (EditorGUI.EndChangeCheck()) {
				HideWireframe(hideWireframe);
			}

			editKey = (KeyCode)EditorGUILayout.EnumPopup("[Toggle Edit] Key", editKey);
			selectAllKey = (KeyCode)EditorGUILayout.EnumPopup("[Select All] Key", selectAllKey);
			splitKey = (KeyCode)EditorGUILayout.EnumPopup("[Split] Key", splitKey);
			extrudeKey = (KeyCode)EditorGUILayout.EnumPopup("[Extrude] Key", extrudeKey);
		}
	}
	#endregion

	#region Scene GUI
	void OnSceneGUI() {
		if (target == null) {
			return;
		}

		if (KeyPressed(editKey)) {
			editing = !editing;
		}

		if (editing) {
			// 各種パスを取得
			if (keyPoints == null) {
				keyPoints = new List<Vector3>(polyMesh.keyPoints);
				curvePoints = new List<Vector3>(polyMesh.curvePoints);
				isCurve = new List<bool>(polyMesh.isCurve);
			}

			// Undo時の動作を設定
			if (undoCallback == null) {
				undoCallback = typeof(EditorApplication).GetField("undoRedoPerformed", BindingFlags.NonPublic | BindingFlags.Static);
				if (undoCallback != null) {
					undoCallback.SetValue(null, new EditorApplication.CallbackFunction(OnUndoRedo));
				}
			}

			// ハンドルの座標を読み込む
			Handles.matrix = polyMesh.transform.localToWorldMatrix;

			// パスと線の描画
			DrawAxis();
			Handles.color = Color.white;
			for (int i = 0; i < keyPoints.Count; i++) {
				// PolyMeshの外枠を描画
				Handles.color = nearestLine == i ? Color.green : Color.white;
				DrawSegment(i);
				// 選択中のパスの描画
				if (selectedIndices.Contains(i)) {
					Handles.color = Color.green;
					DrawCircle(keyPoints[i], 0.08f);
				} else {
					Handles.color = Color.white;
				}
				DrawKeyPoint(i);
				// 曲線パスについての描画???
				if (isCurve[i]) {
					Handles.color = (draggingCurve && dragIndex == i) ? Color.white : Color.blue;
					DrawCurvePoint(i);
				}
			}

			// ツール切り替え時はキャンセル
			if (e.type == EventType.KeyDown) {
				switch (e.keyCode) {
				case KeyCode.Q:
				case KeyCode.W:
				case KeyCode.E:
				case KeyCode.R:
					return;
				}
			}

			//パニング中、もしくはカメラがシーン中にない場合はキャンセル
			if (Tools.current == Tool.View || (e.isMouse && e.button > 0) || Camera.current == null || e.type == EventType.ScrollWheel) {
				return;
			}
			//レイアウトの更新時はキャンセル
			if (e.type == EventType.Layout) {
				HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
				return;
			}

			//Cursor rectangle
			EditorGUIUtility.AddCursorRect(new Rect(0, 0, Camera.current.pixelWidth, Camera.current.pixelHeight), mouseCursor);
			mouseCursor = MouseCursor.Arrow;

			//Extrude key state
			if (e.keyCode == extrudeKey) {
				if (extrudeKeyDown) {
					if (e.type == EventType.KeyUp)
						extrudeKeyDown = false;
				} else if (e.type == EventType.KeyDown) {
					extrudeKeyDown = true;
				}
			}

			//Update matrices and snap
			worldToLocal = polyMesh.transform.worldToLocalMatrix;
			inverseRotation = Quaternion.Inverse(polyMesh.transform.rotation) * Camera.current.transform.rotation;
			snap = gridSnap;
			
			//Update mouse position
			screenMousePosition = new Vector3(e.mousePosition.x, Camera.current.pixelHeight - e.mousePosition.y);
			var plane = new Plane(-polyMesh.transform.forward, polyMesh.transform.position);
			var ray = Camera.current.ScreenPointToRay(screenMousePosition);
			float hit;
			if (plane.Raycast(ray, out hit)) {
				mousePosition = worldToLocal.MultiplyPoint(ray.GetPoint(hit));
			} else {
				return;
			}

			//Update nearest line and split position
			nearestLine = NearestLine(out splitPosition);
			
			//Update the state and repaint
			var newState = UpdateState();
			if (state != newState)
				SetState(newState);
			HandleUtility.Repaint();
			e.Use();
		}
	}

	void HideWireframe(bool hide)
	{
        Renderer renderer = polyMesh.GetComponent<Renderer>();
		if (renderer != null) {
			EditorUtility.SetSelectedWireframeHidden(renderer, hide);
		}
	}

	void RecordUndo() {
		Undo.RecordObject(target, "PolyMesh Changed");
	}

	void RecordDeepUndo() {
		Undo.RegisterFullObjectHierarchyUndo(target, "PolyMesh Changed");
	}

	#endregion

	#region State Control

	//Initialize state
	void SetState(State newState) {
		state = newState;
		switch (state) {
		case State.Hover:
			break;
		}
	}

	//Update state
	State UpdateState() {
		switch (state) {
			//Hovering
		case State.Hover:
			DrawNearestLineAndSplit();

			if (Tools.current == Tool.Move && TryDragSelected())
				return State.DragSelected;
			if (Tools.current == Tool.Rotate && TryRotateSelected())
				return State.RotateSelected;
			if (Tools.current == Tool.Scale && TryScaleSelected())
				return State.ScaleSelected;
			if (Tools.current == Tool.Move && TryExtrude())
				return State.Extrude;

			if (TrySelectAll())
				return State.Hover;
			if (TrySplitLine())
				return State.Hover;
			if (TryDeleteSelected())
				return State.Hover;

			if (TryHoverCurvePoint(out dragIndex) && TryDragCurvePoint(dragIndex))
				return State.Drag;
			if (TryHoverKeyPoint(out dragIndex) && TryDragKeyPoint(dragIndex))
				return State.Drag;
			if (TryBoxSelect())
				return State.BoxSelect;

			break;

			//Dragging
		case State.Drag:
			mouseCursor = MouseCursor.MoveArrow;
			DrawCircle(keyPoints[dragIndex], clickRadius);
			if (draggingCurve)
				MoveCurvePoint(dragIndex, mousePosition - clickPosition);
			else
				MoveKeyPoint(dragIndex, mousePosition - clickPosition);
			if (TryStopDrag())
				return State.Hover;
			break;

			//Box Selecting
		case State.BoxSelect:
			if (TryBoxSelectEnd())
				return State.Hover;
			break;

			//Dragging selected
		case State.DragSelected:
			mouseCursor = MouseCursor.MoveArrow;
			MoveSelected(mousePosition - clickPosition);
			if (TryStopDrag())
				return State.Hover;
			break;

			//Rotating selected
		case State.RotateSelected:
			mouseCursor = MouseCursor.RotateArrow;
			RotateSelected();
			if (TryStopDrag())
				return State.Hover;
			break;

			//Scaling selected
		case State.ScaleSelected:
			mouseCursor = MouseCursor.ScaleArrow;
			ScaleSelected();
			if (TryStopDrag())
				return State.Hover;
			break;

			//Extruding
		case State.Extrude:
			mouseCursor = MouseCursor.MoveArrow;
			MoveSelected(mousePosition - clickPosition);
			if (doExtrudeUpdate && mousePosition != clickPosition)
			{
				UpdatePoly(false, false);
				doExtrudeUpdate = false;
			}
			if (TryStopDrag())
				return State.Hover;
			break;
		}
		return state;
	}

	//Update the mesh on undo/redo
	void OnUndoRedo() {
		keyPoints = new List<Vector3>(polyMesh.keyPoints);
		curvePoints = new List<Vector3>(polyMesh.curvePoints);
		isCurve = new List<bool>(polyMesh.isCurve);
		polyMesh.BuildMesh();
	}
	
	void LoadPoly() {
		for (int i = 0; i < keyPoints.Count; i++) {
			keyPoints[i] = polyMesh.keyPoints[i];
			curvePoints[i] = polyMesh.curvePoints[i];
			isCurve[i] = polyMesh.isCurve[i];
		}
	}
	
	void TransformPoly(Matrix4x4 matrix) {
		for (int i = 0; i < keyPoints.Count; i++) {
			keyPoints[i] = matrix.MultiplyPoint(polyMesh.keyPoints[i]);
			curvePoints[i] = matrix.MultiplyPoint(polyMesh.curvePoints[i]);
		}
	}
	
	void UpdatePoly(bool sizeChanged, bool recordUndo) {
		if (recordUndo) {
			RecordUndo();
		}
		if (sizeChanged) {
			polyMesh.keyPoints = new List<Vector3>(keyPoints);
			polyMesh.curvePoints = new List<Vector3>(curvePoints);
			polyMesh.isCurve = new List<bool>(isCurve);
		} else {
			for (int i = 0; i < keyPoints.Count; i++) {
				polyMesh.keyPoints[i] = keyPoints[i];
				polyMesh.curvePoints[i] = curvePoints[i];
				polyMesh.isCurve[i] = isCurve[i];
			}
		}
		for (int i = 0; i < keyPoints.Count; i++){ 
			if (!isCurve[i]) {
				polyMesh.curvePoints[i] = curvePoints[i] = Vector3.Lerp(keyPoints[i], keyPoints[(i + 1) % keyPoints.Count], 0.5f);
			}
		}
		polyMesh.BuildMesh();
	}

	void MoveKeyPoint(int index, Vector3 amount) {
		var moveCurve = selectedIndices.Contains((index + 1) % keyPoints.Count);
		if (doSnap) {
			if (globalSnap) {
				keyPoints[index] = Snap(polyMesh.keyPoints[index] + amount);
				if (moveCurve){
					curvePoints[index] = Snap(polyMesh.curvePoints[index] + amount);
				}
			} else {
				amount = Snap(amount);
				keyPoints[index] = polyMesh.keyPoints[index] + amount;
				if (moveCurve) {
					curvePoints[index] = polyMesh.curvePoints[index] + amount;
				}
			}
		} else {
			keyPoints[index] = polyMesh.keyPoints[index] + amount;
			if (moveCurve) {
				curvePoints[index] = polyMesh.curvePoints[index] + amount;
			}
		}
	}

	void MoveCurvePoint(int index, Vector3 amount) {
		isCurve[index] = true;
		if (doSnap) {
			if (globalSnap){
				curvePoints[index] = Snap(polyMesh.curvePoints[index] + amount);
			} else {
				curvePoints[index] = polyMesh.curvePoints[index] + amount;
			}
		} else {
			curvePoints[index] = polyMesh.curvePoints[index] + amount;
		}
	}

	void MoveSelected(Vector3 amount) {
		foreach (var i in selectedIndices) {
			MoveKeyPoint(i, amount);
		}
	}

	void RotateSelected() {
		var center = GetSelectionCenter();

		Handles.color = Color.white;
		Handles.DrawLine(center, clickPosition);
		Handles.color = Color.green;
		Handles.DrawLine(center, mousePosition);

		var clickOffset = clickPosition - center;
		var mouseOffset = mousePosition - center;
		var clickAngle = Mathf.Atan2(clickOffset.y, clickOffset.x);
		var mouseAngle = Mathf.Atan2(mouseOffset.y, mouseOffset.x);
		var angleOffset = mouseAngle - clickAngle;

		foreach (var i in selectedIndices) {
			var point = polyMesh.keyPoints[i];
			var pointOffset = point - center;
			var a = Mathf.Atan2(pointOffset.y, pointOffset.x) + angleOffset;
			var d = pointOffset.magnitude;
			keyPoints[i] = center + new Vector3(Mathf.Cos(a) * d, Mathf.Sin(a) * d);
		}
	}

	void ScaleSelected() {
		Handles.color = Color.green;
		Handles.DrawLine(clickPosition, mousePosition);

		var center = GetSelectionCenter();
		var scale = mousePosition - clickPosition;

		//Uniform scaling if shift pressed
		if (e.shift) {
			if (Mathf.Abs(scale.x) > Mathf.Abs(scale.y)) {
				scale.y = scale.x;
			} else {
				scale.x = scale.y;
			}
		}

		//Determine direction of scaling
		if (scale.x < 0) {
			scale.x = 1 / (-scale.x + 1);
		}else {
			scale.x = 1 + scale.x;
		}
		if (scale.y < 0) {
			scale.y = 1 / (-scale.y + 1);
		}else {
			scale.y = 1 + scale.y;
		}

		foreach (var i in selectedIndices) {
			var point = polyMesh.keyPoints[i];
			var offset = point - center;
			offset.x *= scale.x;
			offset.y *= scale.y;
			keyPoints[i] = center + offset;
		}
	}

	#endregion

	#region Drawing

	void DrawAxis() {
		Handles.color = Color.red;
		var size = HandleUtility.GetHandleSize(Vector3.zero) * 0.1f;
		Handles.DrawLine(new Vector3(-size, 0), new Vector3(size, 0));
		Handles.DrawLine(new Vector3(0, -size), new Vector2(0, size));
	}

	void DrawKeyPoint(int index) {
		Handles.DotCap(0, keyPoints[index], Quaternion.identity, HandleUtility.GetHandleSize(keyPoints[index]) * 0.03f);
	}

	void DrawCurvePoint(int index) {
		Handles.DotCap(0, curvePoints[index], Quaternion.identity, HandleUtility.GetHandleSize(keyPoints[index]) * 0.03f);
	}

	void DrawSegment(int index) {
		var from = keyPoints[index];
		var to = keyPoints[(index + 1) % keyPoints.Count];
		if (isCurve[index]) {
			var control = Bezier.Control(from, to, curvePoints[index]);
			var count = Mathf.Ceil(1 / polyMesh.curveDetail);
			for (int i = 0; i < count; i++) {
				Handles.DrawLine(Bezier.Curve(from, control, to, i / count), Bezier.Curve(from, control, to, (i + 1) / count));
			}
		} else {
			Handles.DrawLine(from, to);
		}
	}

	void DrawCircle(Vector3 position, float size) {
		Handles.CircleCap(0, position, inverseRotation, HandleUtility.GetHandleSize(position) * size);
	}

	void DrawNearestLineAndSplit() {
		if (nearestLine >= 0) {
			Handles.color = Color.green;
			DrawSegment(nearestLine);
			Handles.color = Color.red;
			Handles.DotCap(0, splitPosition, Quaternion.identity, HandleUtility.GetHandleSize(splitPosition) * 0.03f);
		}
	}

	#endregion

	#region State Checking

	bool TryHoverKeyPoint(out int index) {
		if (TryHover(keyPoints, Color.white, out index)) {
			mouseCursor = MouseCursor.MoveArrow;
			return true;
		}
		return false;
	}

	bool TryHoverCurvePoint(out int index) {
		if (TryHover(curvePoints, Color.white, out index)) {
			mouseCursor = MouseCursor.MoveArrow;
			return true;
		}
		return false;
	}

	bool TryDragKeyPoint(int index) {
		if (TryDrag(keyPoints, index)) {
			draggingCurve = false;
			return true;
		}
		return false;
	}

	bool TryDragCurvePoint(int index) {
		if (TryDrag(curvePoints, index)) {
			draggingCurve = true;
			return true;
		}
		return false;
	}

	bool TryHover(List<Vector3> points, Color color, out int index) {
		if (Tools.current == Tool.Move) {
			index = NearestPoint(points);
			if (index >= 0 && IsHovering(points[index])) {
				Handles.color = color;
				DrawCircle(points[index], clickRadius);
				return true;
			}
		}
		index = -1;
		return false;
	}

	bool TryDrag(List<Vector3> points, int index) {
		if (e.type == EventType.MouseDown && IsHovering(points[index])) {
			clickPosition = mousePosition;
			return true;
		}
		return false;
	}

	bool TryStopDrag() {
		if (e.type == EventType.MouseUp) {
			dragIndex = -1;
			UpdatePoly(false, state != State.Extrude);
			return true;
		}
		return false;
	}

	bool TryBoxSelect() {
		if (e.type == EventType.MouseDown) {
			clickPosition = mousePosition;
			return true;
		}
		return false;
	}

	bool TryBoxSelectEnd() {
		var min = new Vector3(Mathf.Min(clickPosition.x, mousePosition.x), Mathf.Min(clickPosition.y, mousePosition.y));
		var max = new Vector3(Mathf.Max(clickPosition.x, mousePosition.x), Mathf.Max(clickPosition.y, mousePosition.y));
		Handles.color = Color.white;
		Handles.DrawLine(new Vector3(min.x, min.y), new Vector3(max.x, min.y));
		Handles.DrawLine(new Vector3(min.x, max.y), new Vector3(max.x, max.y));
		Handles.DrawLine(new Vector3(min.x, min.y), new Vector3(min.x, max.y));
		Handles.DrawLine(new Vector3(max.x, min.y), new Vector3(max.x, max.y));

		if (e.type == EventType.MouseUp) {
			var rect = new Rect(min.x, min.y, max.x - min.x, max.y - min.y);

			if (!control) { 
				selectedIndices.Clear();
			}
			for (int i = 0; i < keyPoints.Count; i++){
				if (rect.Contains(keyPoints[i])) {
					selectedIndices.Add(i);
				}
			}
			return true;
		}
		return false;
	}

	bool TryDragSelected() {
		if (selectedIndices.Count > 0 && TryDragButton(GetSelectionCenter(), 0.2f)) {
			clickPosition = mousePosition;
			return true;
		}
		return false;
	}

	bool TryRotateSelected() {
		if (selectedIndices.Count > 0 && TryRotateButton(GetSelectionCenter(), 0.3f)) {
			clickPosition = mousePosition;
			return true;
		}
		return false;
	}

	bool TryScaleSelected() {
		if (selectedIndices.Count > 0 && TryScaleButton(GetSelectionCenter(), 0.3f)) {
			clickPosition = mousePosition;
			return true;
		}
		return false;
	}

	bool TryDragButton(Vector3 position, float size) {
		size *= HandleUtility.GetHandleSize(position);
		if (Vector3.Distance(mousePosition, position) < size) {
			if (e.type == EventType.MouseDown) {
				return true;
			} else {
				mouseCursor = MouseCursor.MoveArrow;
				Handles.color = Color.green;
			}
		} else {
			Handles.color = Color.white;
		}
		var buffer = size / 2;
		Handles.DrawLine(new Vector3(position.x - buffer, position.y), new Vector3(position.x + buffer, position.y));
		Handles.DrawLine(new Vector3(position.x, position.y - buffer), new Vector3(position.x, position.y + buffer));
		Handles.RectangleCap(0, position, Quaternion.identity, size);
		return false;
	}

	bool TryRotateButton(Vector3 position, float size) {
		size *= HandleUtility.GetHandleSize(position);
		var dist = Vector3.Distance(mousePosition, position);
		var buffer = size / 4;
		if (dist < size + buffer && dist > size - buffer) {
			if (e.type == EventType.MouseDown) {
				return true;
			}else {
				mouseCursor = MouseCursor.RotateArrow;
				Handles.color = Color.green;
			}
		} else {
			Handles.color = Color.white;
		}
		Handles.CircleCap(0, position, inverseRotation, size - buffer / 2);
		Handles.CircleCap(0, position, inverseRotation, size + buffer / 2);
		return false;
	}

	bool TryScaleButton(Vector3 position, float size) {
		size *= HandleUtility.GetHandleSize(position);
		if (Vector3.Distance(mousePosition, position) < size) {
			if (e.type == EventType.MouseDown) {
				return true;
			}else {
				mouseCursor = MouseCursor.ScaleArrow;
				Handles.color = Color.green;
			}
		}
		else
			Handles.color = Color.white;
		var buffer = size / 4;
		Handles.DrawLine(new Vector3(position.x - size - buffer, position.y), new Vector3(position.x - size + buffer, position.y));
		Handles.DrawLine(new Vector3(position.x + size - buffer, position.y), new Vector3(position.x + size + buffer, position.y));
		Handles.DrawLine(new Vector3(position.x, position.y - size - buffer), new Vector3(position.x, position.y - size + buffer));
		Handles.DrawLine(new Vector3(position.x, position.y + size - buffer), new Vector3(position.x, position.y + size + buffer));
		Handles.RectangleCap(0, position, Quaternion.identity, size);
		return false;
	}

	bool TrySelectAll(){
		if (KeyPressed(selectAllKey)) {
			selectedIndices.Clear();
			for (int i = 0; i < keyPoints.Count; i++){
				selectedIndices.Add(i);
			}
			return true;
		}
		return false;
	}

	bool TrySplitLine() {
		if (nearestLine >= 0 && KeyPressed(splitKey)) {
			if (nearestLine == keyPoints.Count - 1) {
				keyPoints.Add(splitPosition);
				curvePoints.Add(Vector3.zero);
				isCurve.Add(false);
			} else {
				keyPoints.Insert(nearestLine + 1, splitPosition);
				curvePoints.Insert(nearestLine + 1, Vector3.zero);
				isCurve.Insert(nearestLine + 1, false);
			}
			isCurve[nearestLine] = false;
			UpdatePoly(true, true);
			return true;
		}
		return false;
	}

	bool TryExtrude() {
		if (nearestLine >= 0 && extrudeKeyDown && e.type == EventType.MouseDown) {
			var a = nearestLine;
			var b = (nearestLine + 1) % keyPoints.Count;
			if (b == 0 && a == keyPoints.Count - 1) {
				//Extrude between the first and last points
				keyPoints.Add(polyMesh.keyPoints[a]);
				keyPoints.Add(polyMesh.keyPoints[b]);
				curvePoints.Add(Vector3.zero);
				curvePoints.Add(Vector3.zero);
				isCurve.Add(false);
				isCurve.Add(false);
				
				selectedIndices.Clear();
				selectedIndices.Add(keyPoints.Count - 2);
				selectedIndices.Add(keyPoints.Count - 1);
			} else {
				//Extrude between two inner points
				var pointA = keyPoints[a];
				var pointB = keyPoints[b];
				keyPoints.Insert(a + 1, pointA);
				keyPoints.Insert(a + 2, pointB);
				curvePoints.Insert(a + 1, Vector3.zero);
				curvePoints.Insert(a + 2, Vector3.zero);
				isCurve.Insert(a + 1, false);
				isCurve.Insert(a + 2, false);
				
				selectedIndices.Clear();
				selectedIndices.Add(a + 1);
				selectedIndices.Add(a + 2);
			}
			isCurve[nearestLine] = false;

			clickPosition = mousePosition;
			doExtrudeUpdate = true;
			UpdatePoly(true, true);
			return true;
		}
		return false;
	}

	bool TryDeleteSelected() {
		if (KeyPressed(KeyCode.Backspace) || KeyPressed(KeyCode.Delete)) {
			if (selectedIndices.Count > 0) {
				if (keyPoints.Count - selectedIndices.Count >= 3) {
					for (int i = selectedIndices.Count - 1; i >= 0; i--) {
						var index = selectedIndices[i];
						keyPoints.RemoveAt(index);
						curvePoints.RemoveAt(index);
						isCurve.RemoveAt(index);
					}
					selectedIndices.Clear();
					UpdatePoly(true, true);
					return true;
				}
			} else if (IsHovering(curvePoints[nearestLine])) {
				isCurve[nearestLine] = false;
				UpdatePoly(false, true);
			}
		}
		return false;
	}

	bool IsHovering(Vector3 point) {
		return Vector3.Distance(mousePosition, point) < HandleUtility.GetHandleSize(point) * clickRadius;
	}
	
	int NearestPoint(List<Vector3> points) {
		var near = -1;
		var nearDist = float.MaxValue;
		for (int i = 0; i < points.Count; i++) {
			var dist = Vector3.Distance(points[i], mousePosition);
			if (dist < nearDist) {
				nearDist = dist;
				near = i;
			}
		}
		return near;
	}
	
	int NearestLine(out Vector3 position) {
		var near = -1;
		var nearDist = float.MaxValue;
		position = keyPoints[0];
		var linePos = Vector3.zero;
		for (int i = 0; i < keyPoints.Count; i++) {
			var j = (i + 1) % keyPoints.Count;
			var line = keyPoints[j] - keyPoints[i];
			var offset = mousePosition - keyPoints[i];
			var dot = Vector3.Dot(line.normalized, offset);
			if (dot >= 0 && dot <= line.magnitude) {
				if (isCurve[i]) {
					linePos = Bezier.Curve(keyPoints[i], Bezier.Control(keyPoints[i], keyPoints[j], curvePoints[i]), keyPoints[j], dot / line.magnitude);
				} else {
					linePos = keyPoints[i] + line.normalized * dot;
				}
				var dist = Vector3.Distance(linePos, mousePosition);
				if (dist < nearDist) {
					nearDist = dist;
					position = linePos;
					near = i;
				}
			}
		}
		return near;
	}

	bool KeyPressed(KeyCode key) {
		return e.type == EventType.KeyDown && e.keyCode == key;
	}

	bool KeyReleased(KeyCode key) {
		return e.type == EventType.KeyUp && e.keyCode == key;
	}
	
	Vector3 Snap(Vector3 value) {
		value.x = Mathf.Round(value.x / snap) * snap;
		value.y = Mathf.Round(value.y / snap) * snap;
		return value;
	}

	Vector3 GetSelectionCenter() {
		var center = Vector3.zero;
		foreach (var i in selectedIndices)
			center += polyMesh.keyPoints[i];
		return center / selectedIndices.Count;
	}

	#endregion

	#region Properties

	PolyMesh polyMesh {
		get { return (PolyMesh)target; }
	}

	Event e {
		get { return Event.current; }
	}

	bool control {
		get { return Application.platform == RuntimePlatform.OSXEditor ? e.command : e.control; }
	}

	bool doSnap {
		get { return autoSnap ? !control : control; }
	}

	static bool meshSettings {
		get { return EditorPrefs.GetBool("PolyMeshEditor_meshSettings", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_meshSettings", value); }
	}

	static bool colliderSettings {
		get { return EditorPrefs.GetBool("PolyMeshEditor_colliderSettings", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_colliderSettings", value); }
	}

	static bool uvSettings {
		get { return EditorPrefs.GetBool("PolyMeshEditor_uvSettings", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_uvSettings", value); }
	}

	static bool editorSettings {
		get { return EditorPrefs.GetBool("PolyMeshEditor_editorSettings", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_editorSettings", value); }
	}

	static bool autoSnap {
		get { return EditorPrefs.GetBool("PolyMeshEditor_autoSnap", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_autoSnap", value); }
	}

	static bool globalSnap {
		get { return EditorPrefs.GetBool("PolyMeshEditor_globalSnap", false); }
		set { EditorPrefs.SetBool("PolyMeshEditor_globalSnap", value); }
	}

	static float gridSnap {
		get { return EditorPrefs.GetFloat("PolyMeshEditor_gridSnap", 1); }
		set { EditorPrefs.SetFloat("PolyMeshEditor_gridSnap", value); }
	}

	static bool hideWireframe {
		get { return EditorPrefs.GetBool("PolyMeshEditor_hideWireframe", true); }
		set { EditorPrefs.SetBool("PolyMeshEditor_hideWireframe", value); }
	}

	public KeyCode editKey {
		get { return (KeyCode)EditorPrefs.GetInt("PolyMeshEditor_editKey", (int)KeyCode.Tab); }
		set { EditorPrefs.SetInt("PolyMeshEditor_editKey", (int)value); }
	}

	public KeyCode selectAllKey {
		get { return (KeyCode)EditorPrefs.GetInt("PolyMeshEditor_selectAllKey", (int)KeyCode.A); }
		set { EditorPrefs.SetInt("PolyMeshEditor_selectAllKey", (int)value); }
	}

	public KeyCode splitKey {
		get { return (KeyCode)EditorPrefs.GetInt("PolyMeshEditor_splitKey", (int)KeyCode.S); }
		set { EditorPrefs.SetInt("PolyMeshEditor_splitKey", (int)value); }
	}

	public KeyCode extrudeKey {
		get { return (KeyCode)EditorPrefs.GetInt("PolyMeshEditor_extrudeKey", (int)KeyCode.D); }
		set { EditorPrefs.SetInt("PolyMeshEditor_extrudeKey", (int)value); }
	}

	#endregion

	#region Menu Items

	[MenuItem("GameObject/Create Other/PolyMesh", false, 1000)]
	static void CreatePolyMesh() {
		var obj = new GameObject("PolyMesh", typeof(MeshFilter), typeof(MeshRenderer));
		var polyMesh = obj.AddComponent<PolyMesh>();
		CreateSquare(polyMesh, 0.5f);
	}

	static void CreateSquare(PolyMesh polyMesh, float size) {
		polyMesh.keyPoints.AddRange(new Vector3[] { new Vector3(size, size), new Vector3(size, -size), new Vector3(-size, -size), new Vector3(-size, size)} );
		polyMesh.curvePoints.AddRange(new Vector3[] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero } );
		polyMesh.isCurve.AddRange(new bool[] { false, false, false, false } );
		polyMesh.BuildMesh();
	}

	#endregion
}
using UnityEngine;
using System.Collections.Generic;

//コンポーネントを自動的に追加
[RequireComponent(typeof(MeshFilter))]
public class PolyMesh : MonoBehaviour
{
	/// <summary>
	/// 
	/// </summary>
	public List<Vector3> keyPoints = new List<Vector3>();
	
	/// <summary>
	/// 
	/// </summary>
	public List<Vector3> curvePoints = new List<Vector3>();
	
	/// <summary>
	/// 
	/// </summary>
	public List<bool> isCurve = new List<bool>();
	
	/// <summary>
	/// 
	/// </summary>
	public MeshCollider meshCollider;
	
	/// <summary>
	/// 
	/// </summary>
	[Range(0.01f, 1)] public float curveDetail = 0.1f;
	
	/// <summary>
	/// 
	/// </summary>
	public float colliderDepth = 1;
	
	/// <summary>
	/// 
	/// </summary>
	public bool buildColliderEdges = true;
	
	/// <summary>
	/// 
	/// </summary>
	public bool buildColliderFront;
	
	/// <summary>
	/// 
	/// </summary>
	public Vector2 uvPosition;
	
	/// <summary>
	/// 
	/// </summary>
	public float uvScale = 1;
	
	/// <summary>
	/// 
	/// </summary>
	public float uvRotation;
	
	public List<Vector3> GetEdgePoints()
	{
		//Build the point list and calculate curves
		var points = new List<Vector3>();
		for (int i = 0; i < keyPoints.Count; i++)
		{
			if (isCurve[i])
			{
				//Get the curve control point
				var a = keyPoints[i];
				var c = keyPoints[(i + 1) % keyPoints.Count];
				var b = Bezier.Control(a, c, curvePoints[i]);
				
				//Build the curve
				var count = Mathf.Ceil(1 / curveDetail);
				for (int j = 0; j < count; j++)
				{
					var t = (float)j / count;
					points.Add(Bezier.Curve(a, b, c, t));
				}
			}
			else
				points.Add(keyPoints[i]);
		}
		return points;
	}
	
	public void BuildMesh()
	{
		var points = GetEdgePoints();
		var vertices = points.ToArray();
		
		//Build the index array
		var indices = new List<int>();
		while (indices.Count < points.Count)
			indices.Add(indices.Count);

		//Build the triangle array
		var triangles = Triangulate.Points(points);
		
		//Build the uv array
		var scale = uvScale != 0 ? (1 / uvScale) : 0;
		var matrix = Matrix4x4.TRS(-uvPosition, Quaternion.Euler(0, 0, uvRotation), new Vector3(scale, scale, 1));
		var uv = new Vector2[points.Count];
		for (int i = 0; i < uv.Length; i++)
		{
			var p = matrix.MultiplyPoint(points[i]);
			uv[i] = new Vector2(p.x, p.y);
		}
		
		//Find the mesh (create it if it doesn't exist)
		var meshFilter = GetComponent<MeshFilter>();
		var mesh = meshFilter.sharedMesh;
		if (mesh == null)
		{
			mesh = new Mesh();
			mesh.name = "PolySprite_Mesh";
			meshFilter.mesh = mesh;
		}
		
		//Update the mesh
		mesh.Clear();
		mesh.vertices = vertices;
		mesh.uv = uv;
		mesh.triangles = triangles;
		mesh.RecalculateNormals();
		mesh.Optimize();
		
		//Update collider after the mesh is updated
		UpdateCollider(points, triangles);
	}
	
	void UpdateCollider(List<Vector3> points, int[] tris)
	{
		//Update the mesh collider if there is one
		if (meshCollider != null)
		{
			var vertices = new List<Vector3>();
			var triangles = new List<int>();
			
			if (buildColliderEdges)
			{
				//Build vertices array
				var offset = new Vector3(0, 0, colliderDepth / 2);
				for (int i = 0; i < points.Count; i++)
				{
					vertices.Add(points[i] + offset);
					vertices.Add(points[i] - offset);
				}
				
				//Build triangles array
				for (int a = 0; a < vertices.Count; a += 2)
				{
					var b = (a + 1) % vertices.Count;
					var c = (a + 2) % vertices.Count;
					var d = (a + 3) % vertices.Count;
					triangles.Add(a);
					triangles.Add(c);
					triangles.Add(b);
					triangles.Add(c);
					triangles.Add(d);
					triangles.Add(b);
				}
			}
			
			if (buildColliderFront)
			{
				for (int i = 0; i < tris.Length; i++)
					tris[i] += vertices.Count;
				vertices.AddRange(points);
				triangles.AddRange(tris);
			}
			
			//Find the mesh (create it if it doesn't exist)
			var mesh = meshCollider.sharedMesh;
			if (mesh == null)
			{
				mesh = new Mesh();
				mesh.name = "PolySprite_Collider";
			}
			
			//Update the mesh
			mesh.Clear();
			mesh.vertices = vertices.ToArray();
			mesh.triangles = triangles.ToArray();
			mesh.RecalculateNormals();
			mesh.Optimize();
			meshCollider.sharedMesh = null;
			meshCollider.sharedMesh = mesh;
		}
	}
	
	bool IsRightTurn(List<Vector3> points, int a, int b, int c)
	{
		var ab = points[b] - points[a];
		var bc = points[c] - points[b];
		return (ab.x * bc.y - ab.y * bc.x) < 0;
	}
	
	bool IntersectsExistingLines(List<Vector3> points, Vector3 a, Vector3 b)
	{
		for (int i = 0; i < points.Count; i++)
			if (LinesIntersect(points, a, b, points[i], points[(i + 1) % points.Count]))
				return true;
		return false;
	}
	
	bool LinesIntersect(List<Vector3> points, Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4)
	{
		if (point1 == point3 || point1 == point4 || point2 == point3 || point2 == point4)
			return false;
		
		float ua = (point4.x - point3.x) * (point1.y - point3.y) - (point4.y - point3.y) * (point1.x - point3.x);
		float ub = (point2.x - point1.x) * (point1.y - point3.y) - (point2.y - point1.y) * (point1.x - point3.x);
		float denominator = (point4.y - point3.y) * (point2.x - point1.x) - (point4.x - point3.x) * (point2.y - point1.y);
		
		if (Mathf.Abs(denominator) <= 0.00001f)
		{
			if (Mathf.Abs(ua) <= 0.00001f && Mathf.Abs(ub) <= 0.00001f)
				return true;
		}
		else
		{
			ua /= denominator;
			ub /= denominator;
			
			if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
				return true;
		}
		
		return false;
	}
}

public static class Bezier
{
	public static float Curve(float from, float control, float to, float t)
	{
		return from * (1 - t) * (1 - t) + control * 2 * (1 - t) * t + to * t * t;
	}
	public static Vector3 Curve(Vector3 from, Vector3 control, Vector3 to, float t)
	{
		from.x = Curve(from.x, control.x, to.x, t);
		from.y = Curve(from.y, control.y, to.y, t);
		from.z = Curve(from.z, control.z, to.z, t);
		return from;
	}
	
	public static Vector3 Control(Vector3 from, Vector3 to, Vector3 curve)
	{
		//var center = Vector3.Lerp(from, to, 0.5f);
		//return center + (curve - center) * 2;
		var axis = Vector3.Normalize(to - from);
		var dot = Vector3.Dot(axis, curve - from);
		var linePoint = from + axis * dot;
		return linePoint + (curve - linePoint) * 2;
	}
}

public static class Triangulate
{
	public static int[] Points(List<Vector3> points)
	{
		var indices = new List<int>();
		
		int n = points.Count;
		if (n < 3)
			return indices.ToArray();
		
		int[] V = new int[n];
		if (Area(points) > 0)
		{
			for (int v = 0; v < n; v++)
				V[v] = v;
		}
		else
		{
			for (int v = 0; v < n; v++)
				V[v] = (n - 1) - v;
		}
		
		int nv = n;
		int count = 2 * nv;
		for (int m = 0, v = nv - 1; nv > 2; )
		{
			if ((count--) <= 0)
				return indices.ToArray();
			
			int u = v;
			if (nv <= u)
				u = 0;
			v = u + 1;
			if (nv <= v)
				v = 0;
			int w = v + 1;
			if (nv <= w)
				w = 0;
			
			if (Snip(points, u, v, w, nv, V))
			{
				int a, b, c, s, t;
				a = V[u];
				b = V[v];
				c = V[w];
				indices.Add(a);
				indices.Add(b);
				indices.Add(c);
				m++;
				for (s = v, t = v + 1; t < nv; s++, t++)
					V[s] = V[t];
				nv--;
				count = 2 * nv;
			}
		}
		
		indices.Reverse();
		return indices.ToArray();
	}
	
	static float Area(List<Vector3> points)
	{
		int n = points.Count;
		float A = 0.0f;
		for (int p = n - 1, q = 0; q < n; p = q++)
		{
			Vector3 pval = points[p];
			Vector3 qval = points[q];
			A += pval.x * qval.y - qval.x * pval.y;
		}
		return (A * 0.5f);
	}
	
	static bool Snip(List<Vector3> points, int u, int v, int w, int n, int[] V)
    {
		int p;
		Vector3 A = points[V[u]];
		Vector3 B = points[V[v]];
		Vector3 C = points[V[w]];
		if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))))
			return false;
		for (p = 0; p < n; p++)
		{
			if ((p == u) || (p == v) || (p == w))
				continue;
			Vector3 P = points[V[p]];
			if (InsideTriangle(A, B, C, P))
				return false;
		}
		return true;
	}
	
	static bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
	{
		float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
		float cCROSSap, bCROSScp, aCROSSbp;
		
		ax = C.x - B.x; ay = C.y - B.y;
		bx = A.x - C.x; by = A.y - C.y;
		cx = B.x - A.x; cy = B.y - A.y;
		apx = P.x - A.x; apy = P.y - A.y;
		bpx = P.x - B.x; bpy = P.y - B.y;
		cpx = P.x - C.x; cpy = P.y - C.y;
		
		aCROSSbp = ax * bpy - ay * bpx;
		cCROSSap = cx * apy - cy * apx;
		bCROSScp = bx * cpy - by * cpx;
		
		return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
	}
}
using UnityEngine;
using System.Collections.Generic;

[ExecuteInEditMode]
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class GenerateMesh : MonoBehaviour
{
	/// <summary>
	/// パス座標
	/// </summary>
	public List<Vector3> keyPoints = new List<Vector3>();
	/// <summary>
	/// 頂点パス座標
	/// </summary>
	public List<Vector3> curvePoints = new List<Vector3>();
	/// <summary>
	/// 各頂点間が曲線を持つかどうか
	/// </summary>
	public List<bool> isCurve = new List<bool>();
	/// <summary>
	/// Mesh Collider
	/// </summary>
	public MeshCollider meshCollider;
	[Range(0.01f, 1)] public float curveDetail = 0.1f;
	public float colliderDepth = 1;
	public bool buildColliderEdges = true;
	public bool buildColliderFront;
	/// <summary>
	/// テクスチャの描画位置
	/// </summary>
	public Vector2 uvPosition;
	/// <summary>
	/// UVの拡大率
	/// </summary>
	public float uvScale = 1;
	/// <summary>
	/// UVの回転率
	/// </summary>
	public float uvRotation;
	
	public List<Vector3> GetEdgePoints() {
		//Build the point list and calculate curves
		var points = new List<Vector3>();
		for (int i = 0; i < keyPoints.Count; i++) {
			if (isCurve[i]) {
				//Get the curve control point
				var a = keyPoints[i];
				var c = keyPoints[(i + 1) % keyPoints.Count];
				var b = Bezier.Control(a, c, curvePoints[i]);
				
				//Build the curve
				var count = Mathf.Ceil(1 / curveDetail);
				for (int j = 0; j < count; j++)
				{
					var t = (float)j / count;
					points.Add(Bezier.Curve(a, b, c, t));
				}
			}
			else
				points.Add(keyPoints[i]);
		}
		return points;
	}
	
	public void BuildMesh()
	{
		var points = GetEdgePoints();
		var vertices = points.ToArray();
		
		//Build the index array
		var indices = new List<int>();
		while (indices.Count < points.Count)
			indices.Add(indices.Count);

		//Build the triangle array
		var triangles = Triangulate.Points(points);
		
		//Build the uv array
		var scale = uvScale != 0 ? (1 / uvScale) : 0;
		var matrix = Matrix4x4.TRS(-uvPosition, Quaternion.Euler(0, 0, uvRotation), new Vector3(scale, scale, 1));
		var uv = new Vector2[points.Count];
		for (int i = 0; i < uv.Length; i++)
		{
			var p = matrix.MultiplyPoint(points[i]);
			uv[i] = new Vector2(p.x, p.y);
		}
		
		//Find the mesh (create it if it doesn't exist)
		var meshFilter = GetComponent<MeshFilter>();
		var mesh = meshFilter.sharedMesh;
		if (mesh == null)
		{
			mesh = new Mesh();
			mesh.name = "PolySprite_Mesh";
			meshFilter.mesh = mesh;
		}
		
		//Update the mesh
		mesh.Clear();
		mesh.vertices = vertices;
		mesh.uv = uv;
		mesh.triangles = triangles;
		mesh.RecalculateNormals();
		mesh.Optimize();
		
		//Update collider after the mesh is updated
		UpdateCollider(points, triangles);
	}
	
	void UpdateCollider(List<Vector3> points, int[] tris)
	{
		//Update the mesh collider if there is one
		if (meshCollider != null)
		{
			var vertices = new List<Vector3>();
			var triangles = new List<int>();
			
			if (buildColliderEdges)
			{
				//Build vertices array
				var offset = new Vector3(0, 0, colliderDepth / 2);
				for (int i = 0; i < points.Count; i++)
				{
					vertices.Add(points[i] + offset);
					vertices.Add(points[i] - offset);
				}
				
				//Build triangles array
				for (int a = 0; a < vertices.Count; a += 2)
				{
					var b = (a + 1) % vertices.Count;
					var c = (a + 2) % vertices.Count;
					var d = (a + 3) % vertices.Count;
					triangles.Add(a);
					triangles.Add(c);
					triangles.Add(b);
					triangles.Add(c);
					triangles.Add(d);
					triangles.Add(b);
				}
			}
			
			if (buildColliderFront)
			{
				for (int i = 0; i < tris.Length; i++)
					tris[i] += vertices.Count;
				vertices.AddRange(points);
				triangles.AddRange(tris);
			}
			
			//Find the mesh (create it if it doesn't exist)
			var mesh = meshCollider.sharedMesh;
			if (mesh == null)
			{
				mesh = new Mesh();
				mesh.name = "PolySprite_Collider";
			}
			
			//Update the mesh
			mesh.Clear();
			mesh.vertices = vertices.ToArray();
			mesh.triangles = triangles.ToArray();
			mesh.RecalculateNormals();
			mesh.Optimize();
			meshCollider.sharedMesh = null;
			meshCollider.sharedMesh = mesh;
		}
	}
	
	bool IsRightTurn(List<Vector3> points, int a, int b, int c)
	{
		var ab = points[b] - points[a];
		var bc = points[c] - points[b];
		return (ab.x * bc.y - ab.y * bc.x) < 0;
	}
	
	bool IntersectsExistingLines(List<Vector3> points, Vector3 a, Vector3 b)
	{
		for (int i = 0; i < points.Count; i++)
			if (LinesIntersect(points, a, b, points[i], points[(i + 1) % points.Count]))
				return true;
		return false;
	}
	
	bool LinesIntersect(List<Vector3> points, Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4)
	{
		if (point1 == point3 || point1 == point4 || point2 == point3 || point2 == point4)
			return false;
		
		float ua = (point4.x - point3.x) * (point1.y - point3.y) - (point4.y - point3.y) * (point1.x - point3.x);
		float ub = (point2.x - point1.x) * (point1.y - point3.y) - (point2.y - point1.y) * (point1.x - point3.x);
		float denominator = (point4.y - point3.y) * (point2.x - point1.x) - (point4.x - point3.x) * (point2.y - point1.y);
		
		if (Mathf.Abs(denominator) <= 0.00001f)
		{
			if (Mathf.Abs(ua) <= 0.00001f && Mathf.Abs(ub) <= 0.00001f)
				return true;
		}
		else
		{
			ua /= denominator;
			ub /= denominator;
			
			if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
				return true;
		}
		
		return false;
	}
}

public static class Bezier
{
	public static float Curve(float from, float control, float to, float t)
	{
		return from * (1 - t) * (1 - t) + control * 2 * (1 - t) * t + to * t * t;
	}
	public static Vector3 Curve(Vector3 from, Vector3 control, Vector3 to, float t)
	{
		from.x = Curve(from.x, control.x, to.x, t);
		from.y = Curve(from.y, control.y, to.y, t);
		from.z = Curve(from.z, control.z, to.z, t);
		return from;
	}
	
	public static Vector3 Control(Vector3 from, Vector3 to, Vector3 curve)
	{
		//var center = Vector3.Lerp(from, to, 0.5f);
		//return center + (curve - center) * 2;
		var axis = Vector3.Normalize(to - from);
		var dot = Vector3.Dot(axis, curve - from);
		var linePoint = from + axis * dot;
		return linePoint + (curve - linePoint) * 2;
	}
}

public static class Triangulate
{
	public static int[] Points(List<Vector3> points)
	{
		var indices = new List<int>();
		
		int n = points.Count;
		if (n < 3)
			return indices.ToArray();
		
		int[] V = new int[n];
		if (Area(points) > 0)
		{
			for (int v = 0; v < n; v++)
				V[v] = v;
		}
		else
		{
			for (int v = 0; v < n; v++)
				V[v] = (n - 1) - v;
		}
		
		int nv = n;
		int count = 2 * nv;
		for (int m = 0, v = nv - 1; nv > 2; )
		{
			if ((count--) <= 0)
				return indices.ToArray();
			
			int u = v;
			if (nv <= u)
				u = 0;
			v = u + 1;
			if (nv <= v)
				v = 0;
			int w = v + 1;
			if (nv <= w)
				w = 0;
			
			if (Snip(points, u, v, w, nv, V))
			{
				int a, b, c, s, t;
				a = V[u];
				b = V[v];
				c = V[w];
				indices.Add(a);
				indices.Add(b);
				indices.Add(c);
				m++;
				for (s = v, t = v + 1; t < nv; s++, t++)
					V[s] = V[t];
				nv--;
				count = 2 * nv;
			}
		}
		
		indices.Reverse();
		return indices.ToArray();
	}
	
	static float Area(List<Vector3> points)
	{
		int n = points.Count;
		float A = 0.0f;
		for (int p = n - 1, q = 0; q < n; p = q++)
		{
			Vector3 pval = points[p];
			Vector3 qval = points[q];
			A += pval.x * qval.y - qval.x * pval.y;
		}
		return (A * 0.5f);
	}
	
	static bool Snip(List<Vector3> points, int u, int v, int w, int n, int[] V)
	{
		int p;
		Vector3 A = points[V[u]];
		Vector3 B = points[V[v]];
		Vector3 C = points[V[w]];
		if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))))
			return false;
		for (p = 0; p < n; p++)
		{
			if ((p == u) || (p == v) || (p == w))
				continue;
			Vector3 P = points[V[p]];
			if (InsideTriangle(A, B, C, P))
				return false;
		}
		return true;
	}
	
	static bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
	{
		float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
		float cCROSSap, bCROSScp, aCROSSbp;
		
		ax = C.x - B.x; ay = C.y - B.y;
		bx = A.x - C.x; by = A.y - C.y;
		cx = B.x - A.x; cy = B.y - A.y;
		apx = P.x - A.x; apy = P.y - A.y;
		bpx = P.x - B.x; bpy = P.y - B.y;
		cpx = P.x - C.x; cpy = P.y - C.y;
		
		aCROSSbp = ax * bpy - ay * bpx;
		cCROSSap = cx * apy - cy * apx;
		bCROSScp = bx * cpy - by * cpx;
		
		return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
	}
}

以上是关于csharp 多网的主要内容,如果未能解决你的问题,请参考以下文章

思科模拟器怎么实现多网互通?

R语言ggplot2多子图(facet grid)绘制注释实战:无子图注释有子图注释自定义每个子图注释的位置多网面子图注释

双网隔离

有哪些名气不大却非常实用的软件呢?

多网卡网速叠加

第一章 计算机网络概述