You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

159 lines
6.8 KiB

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Rendering;
namespace UnityEditor.Rendering
{
class VolumeGizmoDrawer
{
#region GizmoCallbacks
static readonly Dictionary<Type, IVolumeAdditionalGizmo> s_AdditionalGizmoCallbacks = new();
[InitializeOnLoadMethod]
static void InitVolumeGizmoCallbacks()
{
foreach (var additionalGizmoCallback in TypeCache.GetTypesDerivedFrom<IVolumeAdditionalGizmo>())
{
if (additionalGizmoCallback.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null) == null)
continue;
var instance = Activator.CreateInstance(additionalGizmoCallback) as IVolumeAdditionalGizmo;
s_AdditionalGizmoCallbacks.Add(instance.type, instance);
}
}
#endregion
[DrawGizmo(GizmoType.Active | GizmoType.Selected | GizmoType.NonSelected)]
static void OnDrawGizmos(IVolume scr, GizmoType gizmoType)
{
if (scr is not MonoBehaviour monoBehaviour)
return;
if (!monoBehaviour.enabled)
return;
if (scr.isGlobal || scr.colliders == null)
return;
// Store the computation of the lossyScale
var lossyScale = monoBehaviour.transform.lossyScale;
Gizmos.matrix = Matrix4x4.TRS(monoBehaviour.transform.position, monoBehaviour.transform.rotation, lossyScale);
var gizmoColor = VolumesPreferences.volumeGizmoColor;
var gizmoColorWhenBlendRegionEnabled = new Color(gizmoColor.r, gizmoColor.g, gizmoColor.b, 0.5f * gizmoColor.a);
s_AdditionalGizmoCallbacks.TryGetValue(scr.GetType(), out var callback);
// Draw a separate gizmo for each collider
foreach (var collider in scr.colliders)
{
if (!collider || !collider.enabled)
continue;
float blendDistance = 0f;
if (scr is Volume volume)
blendDistance = volume.blendDistance;
bool blendDistanceEnabled = blendDistance > 0f;
// Reduce gizmo opacity when blend region is enabled because there are two of them
Gizmos.color = blendDistanceEnabled && VolumesPreferences.drawSolid ? gizmoColorWhenBlendRegionEnabled : gizmoColor;
// We'll just use scaling as an approximation for volume skin. It's far from being
// correct (and is completely wrong in some cases). Ultimately we'd use a distance
// field or at least a tesselate + push modifier on the collider's mesh to get a
// better approximation, but the current Gizmo system is a bit limited and because
// everything is dynamic in Unity and can be changed at anytime, it's hard to keep
// track of changes in an elegant way (which we'd need to implement a nice cache
// system for generated volume meshes).
switch (collider)
{
case BoxCollider c: DrawBoxCollider(c); break;
case SphereCollider c: DrawSphereCollider(c); break;
case MeshCollider c: DrawMeshCollider(c); break;
default:
// Nothing for capsule (DrawCapsule isn't exposed in Gizmo), terrain, wheel and
// other m_Colliders...
break;
}
void DrawBoxCollider(BoxCollider boxCollider)
{
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireCube(boxCollider.center, boxCollider.size);
if (VolumesPreferences.drawSolid)
Gizmos.DrawCube(boxCollider.center, boxCollider.size);
if (blendDistanceEnabled)
DrawBlendDistanceBox(boxCollider, blendDistance);
callback?.OnBoxColliderDraw(scr, boxCollider);
}
void DrawSphereCollider(SphereCollider c)
{
Matrix4x4 oldMatrix = Gizmos.matrix;
// For sphere the only scale that is used is the transform.x
Gizmos.matrix = Matrix4x4.TRS(monoBehaviour.transform.position, monoBehaviour.transform.rotation,
Vector3.one * lossyScale.x);
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireSphere(c.center, c.radius);
if (VolumesPreferences.drawSolid)
Gizmos.DrawSphere(c.center, c.radius);
if (blendDistanceEnabled)
DrawBlendDistanceSphere(c, blendDistance);
callback?.OnSphereColliderDraw(scr, c);
Gizmos.matrix = oldMatrix;
}
void DrawMeshCollider(MeshCollider c)
{
// Only convex mesh m_Colliders are allowed
if (!c.convex)
c.convex = true;
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireMesh(c.sharedMesh);
if (VolumesPreferences.drawSolid)
// Mesh pivot should be centered or this won't work
Gizmos.DrawMesh(c.sharedMesh);
callback?.OnMeshColliderDraw(scr, c);
}
}
}
static void DrawBlendDistanceBox(BoxCollider c, float blendDistance)
{
var twiceFadeRadius = blendDistance * 2;
var transformScale = c.transform.localScale;
// Divide by scale because blendDistance is absolute units and we don't want transform scale to affect it
Vector3 size = c.size + new Vector3(
twiceFadeRadius / transformScale.x,
twiceFadeRadius / transformScale.y,
twiceFadeRadius / transformScale.z
);
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireCube(c.center, size);
if (VolumesPreferences.drawSolid)
Gizmos.DrawCube(c.center, size);
}
static void DrawBlendDistanceSphere(SphereCollider c, float blendDistance)
{
// Divide by scale because blendDistance is absolute units and we don't want transform scale to affect it
var blendSphereSize = c.radius + blendDistance / c.transform.lossyScale.x;
if (VolumesPreferences.drawWireFrame)
Gizmos.DrawWireSphere(c.center, blendSphereSize);
if (VolumesPreferences.drawSolid)
Gizmos.DrawSphere(c.center, blendSphereSize);
}
}
}