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)绘制注释实战:无子图注释有子图注释自定义每个子图注释的位置多网面子图注释