添加插件
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class ObiActorEditorSelectionHandler
|
||||
{
|
||||
private static HashSet<ObiSolver> solvers = new HashSet<ObiSolver>();
|
||||
private static ObiSolver clickedSolver;
|
||||
private static int particleIndex;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal static void SolverInitialized(ObiSolver solver)
|
||||
{
|
||||
if (solver != null)
|
||||
{
|
||||
if (solvers.Count == 0)
|
||||
Init();
|
||||
|
||||
if (solver != null)
|
||||
solvers.Add(solver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static void SolverTeardown(ObiSolver solver)
|
||||
{
|
||||
if (solver != null)
|
||||
{
|
||||
solvers.Remove(solver);
|
||||
|
||||
if (solvers.Count == 0)
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
SceneView.duringSceneGui += SceneGui;
|
||||
}
|
||||
|
||||
internal static void Dispose()
|
||||
{
|
||||
SceneView.duringSceneGui -= SceneGui;
|
||||
}
|
||||
|
||||
private static bool RaycastAgainstSolver(ObiSolver solver, Ray ray, float thickness, out int pIndex, out float distance)
|
||||
{
|
||||
float closestDistanceToRay = float.MaxValue;
|
||||
pIndex = -1;
|
||||
distance = float.MaxValue;
|
||||
|
||||
Matrix4x4 solver2World = solver.transform.localToWorldMatrix;
|
||||
|
||||
// Find the closest particle hit by the ray:
|
||||
for (int i = 0; i < solver.activeParticleCount; ++i)
|
||||
{
|
||||
int p = solver.activeParticles[i];
|
||||
|
||||
Vector3 worldPos = solver2World.MultiplyPoint3x4(solver.positions[p]);
|
||||
Vector3 projected = ObiUtils.ProjectPointLine(ray.origin, ray.origin + ray.direction, worldPos, out float mu, false);
|
||||
|
||||
// Disregard particles behind the camera:
|
||||
if (mu < 0)
|
||||
continue;
|
||||
|
||||
float radius = solver.principalRadii[p][0] + thickness;
|
||||
float distanceToRay = Vector3.SqrMagnitude(worldPos - projected);
|
||||
|
||||
if (distanceToRay <= radius * radius &&
|
||||
distanceToRay < closestDistanceToRay &&
|
||||
mu < closestDistanceToRay)
|
||||
{
|
||||
distance = mu;
|
||||
closestDistanceToRay = distanceToRay;
|
||||
pIndex = p;
|
||||
}
|
||||
}
|
||||
|
||||
return pIndex >= 0;
|
||||
}
|
||||
|
||||
private static ObiSolver RaycastAllSolvers(Ray ray, out int pIndex, out float distance)
|
||||
{
|
||||
distance = float.MaxValue;
|
||||
pIndex = -1;
|
||||
|
||||
ObiSolver hitSolver = null;
|
||||
|
||||
foreach (ObiSolver s in solvers)
|
||||
{
|
||||
if (s == null || !s.bounds.IntersectRay(ray))
|
||||
continue;
|
||||
|
||||
if (RaycastAgainstSolver(s, ray, 0, out int p, out float d))
|
||||
{
|
||||
if (d < distance)
|
||||
{
|
||||
distance = d;
|
||||
hitSolver = s;
|
||||
pIndex = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hitSolver;
|
||||
}
|
||||
|
||||
private static void SceneGui(SceneView sceneView)
|
||||
{
|
||||
if (EditorApplication.isPaused || !ObiEditorSettings.GetOrCreateSettings().sceneViewParticlePicking)
|
||||
return;
|
||||
|
||||
// only do this in the main stage or prefab stage, if we're in any other stage don't raycast against particles.
|
||||
// This will prevent selecting stuff when in the blueprint editor, avatar editor, or other stages.
|
||||
var stage = StageUtility.GetCurrentStage();
|
||||
if (!(stage is MainStage) && !(stage is PrefabStage))
|
||||
return;
|
||||
|
||||
var evt = Event.current;
|
||||
|
||||
if (evt.alt)
|
||||
return;
|
||||
|
||||
float ppp = EditorGUIUtility.pixelsPerPoint;
|
||||
int mouseScreenX = (int)(evt.mousePosition.x * ppp);
|
||||
int mouseScreenY = (int)(evt.mousePosition.y * ppp);
|
||||
|
||||
if (mouseScreenX < 0 || mouseScreenX >= sceneView.camera.pixelWidth ||
|
||||
mouseScreenY < 0 || mouseScreenY >= sceneView.camera.pixelHeight)
|
||||
return;
|
||||
|
||||
int controlID = GUIUtility.GetControlID(FocusType.Passive);
|
||||
|
||||
switch (evt.type)
|
||||
{
|
||||
case EventType.Layout:
|
||||
case EventType.MouseMove:
|
||||
|
||||
if (!Tools.viewToolActive)
|
||||
{
|
||||
// Raycast against all solvers:
|
||||
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
clickedSolver = RaycastAllSolvers(ray, out particleIndex, out float closest);
|
||||
|
||||
// check whether we hit a collider before the closest particle in the solver:
|
||||
RaycastHit hit;
|
||||
ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);
|
||||
if (Physics.Raycast(ray, out hit, closest) && hit.collider != null)
|
||||
clickedSolver = null;
|
||||
|
||||
// If we hit something, register our control ID and the distance to the particle:
|
||||
if (clickedSolver != null && Camera.current != null)
|
||||
{
|
||||
var worldPos = clickedSolver.transform.TransformPoint(clickedSolver.positions[particleIndex]);
|
||||
var screenCenter = HandleUtility.WorldToGUIPoint(worldPos);
|
||||
|
||||
var distance = (Event.current.mousePosition - screenCenter).magnitude;
|
||||
|
||||
HandleUtility.AddControl(controlID, distance);
|
||||
|
||||
// AddDefaultControl means that if no other control is selected, this will be chosen as the fallback.
|
||||
// This allows things like the translate handle and buttons to function.
|
||||
HandleUtility.AddDefaultControl(controlID);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EventType.MouseDown:
|
||||
|
||||
if (evt.button == 0 && HandleUtility.nearestControl == controlID && clickedSolver != null)
|
||||
{
|
||||
// Setting the hotControl tells the Scene View that this mouse down/up event cannot be considered
|
||||
// a picking action because the event is in use.
|
||||
GUIUtility.hotControl = controlID;
|
||||
evt.Use();
|
||||
}
|
||||
break;
|
||||
|
||||
case EventType.MouseUp:
|
||||
|
||||
if (!Tools.viewToolActive && GUIUtility.hotControl == controlID)
|
||||
{
|
||||
// In case we hit some actor, select the actor it belongs to:
|
||||
if (clickedSolver != null)
|
||||
{
|
||||
var clickedActor = clickedSolver.particleToActor[particleIndex].actor;
|
||||
if (clickedActor != null)
|
||||
{
|
||||
var selection = Selection.objects.ToList();
|
||||
|
||||
if (evt.shift || evt.control)
|
||||
{
|
||||
if (selection.Contains(clickedActor.gameObject))
|
||||
selection.Remove(clickedActor.gameObject);
|
||||
else
|
||||
selection.Add(clickedActor.gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
selection.Clear();
|
||||
selection.Add(clickedActor.gameObject);
|
||||
}
|
||||
|
||||
Selection.objects = selection.ToArray();
|
||||
}
|
||||
|
||||
GUIUtility.hotControl = 0;
|
||||
evt.Use();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user