163 lines
5.0 KiB
C#
163 lines
5.0 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.ProBuilder;
|
|
using PMath = UnityEngine.ProBuilder.Math;
|
|
|
|
namespace ProBuilder.Examples
|
|
{
|
|
class MeshEditor : MonoBehaviour
|
|
{
|
|
Camera m_SceneCamera;
|
|
CameraMotion m_CameraMotion;
|
|
MeshAndFace m_Selection;
|
|
|
|
class MeshState
|
|
{
|
|
public ProBuilderMesh mesh;
|
|
public Vector3[] vertices;
|
|
public Vector3[] origins;
|
|
public List<int> indices;
|
|
|
|
public MeshState(ProBuilderMesh mesh, IList<int> selectedIndices)
|
|
{
|
|
this.mesh = mesh;
|
|
vertices = mesh.positions.ToArray();
|
|
indices = mesh.GetCoincidentVertices(selectedIndices);
|
|
origins = new Vector3[indices.Count];
|
|
|
|
for (int i = 0, c = indices.Count; i < c; i++)
|
|
origins[i] = vertices[indices[i]];
|
|
}
|
|
}
|
|
|
|
class DragState
|
|
{
|
|
public bool active;
|
|
public Ray constraint;
|
|
public float offset;
|
|
public MeshState meshState;
|
|
}
|
|
|
|
DragState m_DragState = new DragState();
|
|
|
|
void Awake()
|
|
{
|
|
m_SceneCamera = Camera.main;
|
|
m_CameraMotion = m_SceneCamera.GetComponent<CameraMotion>();
|
|
Camera.onPostRender += DrawSelection;
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
m_CameraMotion.Focus(Vector3.zero, 10f);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if(!m_DragState.active)
|
|
m_Selection = Utility.PickFace(m_SceneCamera, Input.mousePosition);
|
|
|
|
HandleInput();
|
|
}
|
|
|
|
void DrawSelection(Camera cam)
|
|
{
|
|
if (m_CameraMotion.active)
|
|
return;
|
|
|
|
Handles.Draw(m_Selection.mesh, m_Selection.face, Color.cyan);
|
|
|
|
if (m_DragState.active)
|
|
{
|
|
var o = m_DragState.constraint.origin;
|
|
var d = m_DragState.constraint.direction;
|
|
Handles.DrawLine(o - d * 100f, o + d * 1000f, Color.green);
|
|
}
|
|
}
|
|
|
|
void LateUpdate()
|
|
{
|
|
if (!m_DragState.active)
|
|
m_CameraMotion.DoLateUpdate();
|
|
}
|
|
|
|
void HandleInput()
|
|
{
|
|
if (m_CameraMotion.active)
|
|
return;
|
|
|
|
if (Input.GetMouseButtonDown(0) && m_Selection.face != null)
|
|
{
|
|
BeginDrag();
|
|
}
|
|
else if (Input.GetMouseButtonUp(0))
|
|
{
|
|
EndDrag();
|
|
}
|
|
else if (m_DragState.active && Input.GetMouseButton(0))
|
|
{
|
|
UpdateDrag();
|
|
}
|
|
else if (Input.GetKeyUp(KeyCode.F))
|
|
{
|
|
if (m_Selection.mesh != null)
|
|
m_CameraMotion.Focus(m_Selection.mesh.gameObject);
|
|
else
|
|
m_CameraMotion.Focus(Vector3.zero, 10f);
|
|
}
|
|
}
|
|
|
|
void BeginDrag()
|
|
{
|
|
if (m_DragState.active || m_Selection.mesh == null || m_Selection.face == null)
|
|
return;
|
|
|
|
m_DragState.active = true;
|
|
|
|
var trs = m_Selection.mesh.transform;
|
|
|
|
// The constraint ray is stored in world space
|
|
var origin = trs.TransformPoint(PMath.Average(m_Selection.mesh.positions, m_Selection.face.indexes));
|
|
var direction = trs.TransformDirection(PMath.Normal(m_Selection.mesh, m_Selection.face));
|
|
|
|
m_DragState.constraint = new Ray(origin, direction);
|
|
m_DragState.meshState = new MeshState(m_Selection.mesh, m_Selection.face.distinctIndexes);
|
|
m_DragState.offset = GetDragDistance();
|
|
}
|
|
|
|
void EndDrag()
|
|
{
|
|
m_DragState.active = false;
|
|
}
|
|
|
|
void UpdateDrag()
|
|
{
|
|
var distance = GetDragDistance() - m_DragState.offset;
|
|
|
|
var mesh = m_Selection.mesh;
|
|
var indices = m_DragState.meshState.indices;
|
|
var vertices = m_DragState.meshState.vertices;
|
|
var origins = m_DragState.meshState.origins;
|
|
// Constraint is in world coordinates, but we need model space when applying changes to mesh values.
|
|
var direction = mesh.transform.InverseTransformDirection(m_DragState.constraint.direction);
|
|
|
|
for (int i = 0, c = indices.Count; i < c; i++)
|
|
vertices[indices[i]] = origins[i] + direction * distance;
|
|
|
|
mesh.positions = vertices;
|
|
mesh.ToMesh();
|
|
mesh.Refresh();
|
|
}
|
|
|
|
float GetDragDistance()
|
|
{
|
|
Ray constraint = m_DragState.constraint;
|
|
Ray mouse = m_SceneCamera.ScreenPointToRay(Input.mousePosition);
|
|
Vector3 nearestPoint = PMath.GetNearestPointRayRay(constraint, mouse);
|
|
float sign = System.Math.Sign(Vector3.Dot(nearestPoint - constraint.origin, constraint.direction));
|
|
return Vector3.Distance(constraint.origin, nearestPoint) * sign;
|
|
}
|
|
}
|
|
}
|