下面代码演示了Gizmos.matrix的用法,分别在第74行和第188行。通过这两行代码来理解Gizmos.matrix设置的作用就是为其后面的绘制设定基准。(本代码来自HongLiu的DigitalTwin项目中设置全局视角功能)
using UnityEngine;
public class SetGlobalViewCtrl : MonoBehaviour
{
[SerializeField]
[Range(0, 360)]
[Header("水平起点")]
float rotHStart = 0;
[SerializeField]
[Header("水平范围")]
[Range(0, 360)]
float rotHRang = 90;
[SerializeField]
[Range(0, 1)]
[Header("水平插值")]
float processH = 0.5f;
[SerializeField]
[Header("垂直起点")]
[Range(-90, 90)]
float rotVStart = 0;
[SerializeField]
[Range(0, 180)]
[Header("垂直范围")]
float rotVRang = 75;
[SerializeField]
[Range(0, 1)]
[Header("垂直插值")]
float processV = 0.5f;
[SerializeField]
[Range(1, 100)]
[Header("推拉起始")]
float zoomStart = 15;
[SerializeField]
[Range(5, 200)]
[Header("推拉范围")]
float zoomRange = 20;
[SerializeField]
[Range(0,1)]
[Header("推拉插值")]
float zoomProcess = 0.3f;
[SerializeField]
[Header("预览")]
bool preview = true;
void Start()
{
GlobalViewCtrl.instance.Set(transform.position, rotHStart, rotHRang, processH, rotVStart, rotVRang, processV, zoomStart, zoomRange);
}
Transform trCam;
void OnDrawGizmos()
{
if (!preview) return;
//
rotHStart = Mathf.Clamp(rotHStart, 0, 360);
rotHRang = Mathf.Clamp(rotHRang, 0, 360);
processH = Mathf.Clamp01(processH);
rotVStart = Mathf.Clamp(rotVStart, -90, 90);
rotVRang = Mathf.Clamp(rotVRang, 0, 180);
processV = Mathf.Clamp01(processV);
zoomStart = Mathf.Clamp(zoomStart, 1, 100);
zoomRange = Mathf.Clamp(zoomRange, 5, 200);
transform.rotation = Quaternion.identity;
//
Gizmos.matrix = transform.localToWorldMatrix;
Vector3 vHStartVStart = Quaternion.Euler(-rotVStart, -rotHStart, 0) * Vector3.forward;
Vector3 vHEndVStart = Quaternion.Euler(-rotVStart, -rotHStart - rotHRang, 0) * Vector3.forward;
Vector3 vHStartVEnd = Quaternion.Euler(-rotVStart - rotVRang, -rotHStart, 0) * Vector3.forward;
Vector3 vHEndVEnd = Quaternion.Euler(-rotVStart - rotVRang, -rotHStart - rotHRang, 0) * Vector3.forward;
//
Gizmos.color = new Color(0, 0, 1, 0.2f);
Gizmos.DrawLine(Vector3.zero, vHStartVStart * zoomStart);
Gizmos.DrawLine(Vector3.zero, vHEndVStart * zoomStart);
Gizmos.DrawLine(Vector3.zero, vHStartVEnd * zoomStart);
Gizmos.DrawLine(Vector3.zero, vHEndVEnd * zoomStart);
Gizmos.color = new Color(0, 1, 0, 0.3f);
float zoomEnd = zoomStart + zoomRange;
Gizmos.DrawLine(vHStartVStart * zoomStart, vHStartVStart * zoomEnd);
Gizmos.DrawLine(vHEndVStart * zoomStart, vHEndVStart * zoomEnd);
Gizmos.DrawLine(vHStartVEnd * zoomStart, vHStartVEnd * zoomEnd);
Gizmos.DrawLine(vHEndVEnd * zoomStart, vHEndVEnd * zoomEnd);
//------------------------------------------------------------------------------------------------------------------------
int countSegment = (int)(rotHRang / 10) + 1;
Vector3[] rangePoints = new Vector3[countSegment + 1];
float deltaAngle = rotHRang / countSegment;
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart, -rotHStart - deltaAngle * i, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart - rotVRang, -rotHStart - deltaAngle * i, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
//------------------------------------------------------------------------------------------------------------------------
countSegment = (int)(rotVRang / 10) + 1;
rangePoints = new Vector3[countSegment + 1];
deltaAngle = rotVRang / countSegment;
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart - deltaAngle * i, -rotHStart, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart - deltaAngle * i, -rotHStart - rotHRang, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
//------------------------------------------------------------------------------------------------------------------------
Gizmos.color = Color.cyan;
Vector3 vHProcess = Quaternion.Euler(-rotVStart - rotVRang * processV, -rotHStart - rotHRang * processH, 0) * Vector3.forward;
Gizmos.DrawLine(vHProcess * zoomStart, vHProcess * zoomEnd);
//
Gizmos.color = new Color(0, 1, 1, 0.2f);
Vector3 vHL = Quaternion.Euler(-rotVStart - rotVRang * processV, -rotHStart, 0) * Vector3.forward;
Vector3 vHR = Quaternion.Euler(-rotVStart - rotVRang * processV, -rotHStart - rotHRang, 0) * Vector3.forward;
Vector3 vVB = Quaternion.Euler(-rotVStart, -rotHStart - rotHRang * processH, 0) * Vector3.forward;
Vector3 vVT = Quaternion.Euler(-rotVStart - rotVRang, -rotHStart - rotHRang * processH, 0) * Vector3.forward;
Gizmos.DrawLine(vHL * zoomStart, vHL * zoomEnd);
Gizmos.DrawLine(vHR * zoomStart, vHR * zoomEnd);
Gizmos.DrawLine(vVB * zoomStart, vVB * zoomEnd);
Gizmos.DrawLine(vVT * zoomStart, vVT * zoomEnd);
countSegment = (int)(rotHRang / 10) + 1;
rangePoints = new Vector3[countSegment + 1];
deltaAngle = rotHRang / countSegment;
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart - rotVRang * processV, -rotHStart - deltaAngle * i, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
countSegment = (int)(rotVRang / 10) + 1;
rangePoints = new Vector3[countSegment + 1];
deltaAngle = rotVRang / countSegment;
for (int i = 0; i <= countSegment; i++)
{
rangePoints[i] = Quaternion.Euler(-rotVStart - deltaAngle * i, -rotHStart - rotHRang * processH, 0) * Vector3.forward;
}
for (int i = 0; i < rangePoints.Length - 1; i++)
{
Gizmos.DrawLine(rangePoints[i] * zoomStart, rangePoints[i + 1] * zoomStart);
Gizmos.DrawLine(rangePoints[i] * zoomEnd, rangePoints[i + 1] * zoomEnd);
}
//
Vector3 position = vHProcess * (zoomStart +zoomRange* zoomProcess);
Quaternion rotation = Quaternion.LookRotation(-vHProcess);
Gizmos.matrix = Matrix4x4.TRS(position, rotation, Vector3.one);
Gizmos.color = Color.blue;
Gizmos.DrawFrustum(Vector3.zero, 60, 5, 0.1f, 1.77f);
}
}
Camera.current为当前视图正在渲染的摄像机,对于Scene视图来说,这个摄像机的名字是"SceneCamera",当然这个摄像机是看不到的,不过可以依据这个摄像机的朝向构建Maxtrix来绘制Gizmos,实现始终朝向视图摄像机的图形,参考代码如下:
using UnityEngine;
using UnityEngine.Events;
public class SelectableObject : MonoBehaviour
{
[SerializeField]
[Header("编号")]
int _id = -1;
public int id { get { return _id; } }
[SerializeField]
[Header("显示名称")]
string _showName;
public string showName { get { return _showName; } }
[SerializeField]
[Header("注视焦点偏移")]
Vector3 focusOffset;
[SerializeField]
[Header("注视初始距离")]
float focusDist = 1;
[SerializeField]
[Header("注视水平角度")]
float focusRotH = 30;
[SerializeField]
[Header("注视垂直角度")]
float focusRotV = 45;
void Start()
{
}
bool _selected = false;
public bool selected { get { return _selected; } }
UnityAction onSelected;
public void AddActSelected(UnityAction act) { onSelected -= act; onSelected += act; }
public void RemoveActSelected(UnityAction act) { onSelected -= act; }
public void Selected(bool selected)
{
_selected = selected;
onSelected?.Invoke(_selected);
}
public void SetID(int id) { _id = id; }
public void SetShowName(string showName) { _showName = showName; }
bool _inCamera;
public bool inCamera { get { return _inCamera; } }
void OnBecameVisible() { _inCamera = true; }
void OnBecameInvisible() { _inCamera = false; }
void OnDrawGizmosSelected()
{
//-------------------------------------------------------------------------------------------------------------------
float size = 1;
MeshRenderer[] renders = GetComponentsInChildren();
if (renders == null || renders.Length == 0)
{
size = (Camera.current.transform.position - transform.TransformPoint(focusOffset)).magnitude * 0.1f;
Debug.Log(size);
}
else
{
float sum = 0;
foreach (MeshRenderer render in renders)
{
sum += render.bounds.size.x;
sum += render.bounds.size.y;
sum += render.bounds.size.z;
}
size = sum / renders.Length * 0.2f;
}
Collider[] cols = GetComponentsInChildren();
if (cols == null || cols.Length == 0)
{
Gizmos.matrix = Matrix4x4.TRS(transform.position, Camera.current.transform.rotation, Vector3.one);
Gizmos.color = Color.red;
//
Vector3 p0 = new Vector3(-size, size, 0);
Vector3 p1 = new Vector3(size, size, 0);
Vector3 p2 = new Vector3(size, -size, 0);
Vector3 p3 = new Vector3(-size, -size, 0);
Gizmos.DrawLine(p0, p1);
Gizmos.DrawLine(p1, p2);
Gizmos.DrawLine(p2, p3);
Gizmos.DrawLine(p3, p0);
Gizmos.DrawLine(p0, p2);
Gizmos.DrawLine(p1, p3);
}
//-------------------------------------------------------------------------------------------------------------------
focusDist = Mathf.Clamp(focusDist, 0.1f, 10000);
focusRotH = Mathf.Clamp(focusRotH, 0, 360);
focusRotV = Mathf.Clamp(focusRotV, 0, 90);
//-------------------------------------------------------------------------------------------------------------------
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = Color.green;
Vector3 vector = Quaternion.Euler(-focusRotV, -focusRotH, 0) * Vector3.forward;
Vector3 posCam = vector * focusDist + focusOffset;
float radius = focusDist * 0.02f;
if (radius > size * 0.2f) radius = size * 0.2f;
Gizmos.DrawWireSphere(focusOffset, radius);
Gizmos.DrawLine(focusOffset, posCam);
Vector3 pos = transform.TransformPoint(posCam);
Quaternion rot = Quaternion.LookRotation(-vector);
//-------------------------------------------------------------------------------------------------------------------
Gizmos.matrix = Matrix4x4.TRS(pos, rot, Vector3.one);
Gizmos.color = Color.white;
Gizmos.DrawFrustum(Vector3.zero, 60, focusDist * 0.3f, 0.01f, 1.78f);
}
}