您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

601 行
19 KiB

using UnityEngine;
using System;
using UnityEngine.Experimental.Rendering.HDPipeline;
using UnityEngine.Rendering;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class DebugOverlay : MonoBehaviour
{
[Header("Overlay size")]
[SerializeField]
int width = 80;
[SerializeField]
int height = 25;
[Header("Font material info")]
public Material instanceMaterialProc;
[Tooltip("Number of columns of glyphs on texture")]
public int charCols = 30;
[Tooltip("Number of rows of glyphs on texture")]
public int charRows = 16;
[Tooltip("Width in pixels of each glyph")]
public int cellWidth = 32;
[Tooltip("Height in pixels of each glyph")]
public int cellHeight = 32;
public Shader lineShaderProc;
public static DebugOverlay instance;
public static int Width { get { return instance.width; } }
public static int Height { get { return instance.height; } }
void Awake()
{
m_LineMaterial = new Material(lineShaderProc);
m_line3DBuffer = new Line3DBuffer();
#if UNITY_EDITOR
Camera[] sceneCameras = UnityEditor.SceneView.GetAllSceneCameras();
foreach(var camera in sceneCameras)
{
camera.gameObject.AddComponent<DebugOverlayCamera>();
}
#endif
}
public void Init()
{
instance = this;
}
public void Shutdown()
{
if (m_QuadInstanceBuffer != null)
m_QuadInstanceBuffer.Release();
m_QuadInstanceBuffer = null;
m_QuadInstanceData = null;
if (m_LineInstanceBuffer != null)
m_LineInstanceBuffer.Release();
m_LineInstanceBuffer = null;
m_LineInstanceData = null;
m_line3DBuffer.Shutdown();
m_line3DBuffer = null;
instance = null;
}
public void TickLateUpdate()
{
// Recreate compute buffer if needed.
if (m_QuadInstanceBuffer == null || m_QuadInstanceBuffer.count != m_QuadInstanceData.Length)
{
if (m_QuadInstanceBuffer != null)
{
m_QuadInstanceBuffer.Release();
m_QuadInstanceBuffer = null;
}
m_QuadInstanceBuffer = new ComputeBuffer(m_QuadInstanceData.Length, 16 + 16 + 16);
instanceMaterialProc.SetBuffer("positionBuffer", m_QuadInstanceBuffer);
}
if (m_LineInstanceBuffer == null || m_LineInstanceBuffer.count != m_LineInstanceData.Length)
{
if (m_LineInstanceBuffer != null)
{
m_LineInstanceBuffer.Release();
m_LineInstanceBuffer = null;
}
m_LineInstanceBuffer = new ComputeBuffer(m_LineInstanceData.Length, 16 + 16);
m_LineMaterial.SetBuffer("positionBuffer", m_LineInstanceBuffer);
}
m_line3DBuffer.PrepareBuffer();
m_QuadInstanceBuffer.SetData(m_QuadInstanceData, 0, 0, m_NumQuadsUsed);
m_NumQuadsToDraw = m_NumQuadsUsed;
m_LineInstanceBuffer.SetData(m_LineInstanceData, 0, 0, m_NumLinesUsed);
m_NumLinesToDraw = m_NumLinesUsed;
instanceMaterialProc.SetVector("scales", new Vector4(
1.0f / width,
1.0f / height,
(float)cellWidth / instanceMaterialProc.mainTexture.width,
(float)cellHeight / instanceMaterialProc.mainTexture.height));
m_LineMaterial.SetVector("scales", new Vector4(1.0f / width, 1.0f / height, 1.0f / 1280.0f, 1.0f / 720.0f));
_Clear();
}
/// <summary>
/// Set color of text.
/// </summary>
/// <param name="col"></param>
public static void SetColor(Color col)
{
if (instance == null)
return;
instance.m_CurrentColor = col;
}
public static void SetOrigin(float x, float y)
{
if (instance == null)
return;
instance.m_OriginX = x;
instance.m_OriginY = y;
}
// TODO (petera) Reconsider decision to go 'virtual character' coordinate system
// Write in raw pixel
public static void WriteAbsolute(float x, float y, float size, char[] buf, int count)
{
if (instance == null)
return;
float scalex = (float)instance.width / Screen.width;
float scaley = (float)instance.height / Screen.height;
x *= scalex;
y *= scaley;
float sizex = scalex * size;
float sizey = scaley * size * 1.5f;
//instance.width
for (var i = 0; i < count; i++)
instance.AddQuad(x + i*sizex, y, sizex, sizey, buf[i], instance.m_CurrentColor);
}
public static void AddQuadAbsolute(float x, float y, float width, float height, char c, Vector4 col)
{
if (instance == null)
return;
float scalex = (float)instance.width / Screen.width;
float scaley = (float)instance.height / Screen.height;
x *= scalex;
y *= scaley;
width *= scalex;
height *= scaley;
instance.AddQuad(x, y, width, height, c, col);
}
public static void Write(float x, float y, string format)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T>(float x, float y, string format, T arg)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write(Color col, float x, float y, string format)
{
if (instance == null)
return;
Color c = instance.m_CurrentColor;
instance.m_CurrentColor = col;
var l = StringFormatter.Write(ref _buf, 0, format);
instance._DrawText(x, y, ref _buf, l);
instance.m_CurrentColor = c;
}
public static void Write<T>(Color col, float x, float y, string format, T arg)
{
if (instance == null)
return;
Color c = instance.m_CurrentColor;
instance.m_CurrentColor = col;
var l = StringFormatter.Write(ref _buf, 0, format, arg);
instance._DrawText(x, y, ref _buf, l);
instance.m_CurrentColor = c;
}
public static void Write<T0,T1>(Color col, float x, float y, string format, T0 arg0, T1 arg1)
{
if (instance == null)
return;
Color c = instance.m_CurrentColor;
instance.m_CurrentColor = col;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1);
instance._DrawText(x, y, ref _buf, l);
instance.m_CurrentColor = c;
}
public static void Write<T0, T1>(float x, float y, string format, T0 arg0, T1 arg1)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T0, T1, T2>(float x, float y, string format, T0 arg0, T1 arg1, T2 arg2)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T0,T1,T2>(Color col, float x, float y, string format, T0 arg0, T1 arg1, T2 arg2)
{
if (instance == null)
return;
Color c = instance.m_CurrentColor;
instance.m_CurrentColor = col;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2);
instance._DrawText(x, y, ref _buf, l);
instance.m_CurrentColor = c;
}
public static void Write<T0, T1, T2, T3>(float x, float y, string format, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2, arg3);
instance._DrawText(x, y, ref _buf, l);
}
public static void Write<T0, T1, T2, T3, T4>(float x, float y, string format, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
if (instance == null)
return;
var l = StringFormatter.Write(ref _buf, 0, format, arg0, arg1, arg2, arg3, arg4);
instance._DrawText(x, y, ref _buf, l);
}
// Draw a histogram of one set of data. Data must contain non-negative datapoints.
public static void DrawHist(float x, float y, float w, float h, float[] data, int startSample, Color color, float maxRange = -1.0f)
{
if (instance == null)
return;
s_TempData[0] = data;
s_TempColors[0] = color;
instance._DrawHist(x, y, w, h, s_TempData, startSample, s_TempColors, maxRange);
s_TempData[0] = null;
}
static float[][] s_TempData = new float[1][];
static Color[] s_TempColors = new Color[1];
// Draw a stacked histogram multiple sets of data. Data must contain non-negative datapoints.
public static void DrawHist(float x, float y, float w, float h, float[][] data, int startSample, Color[] color, float maxRange = -1.0f)
{
if (instance == null)
return;
instance._DrawHist(x, y, w, h, data, startSample, color, maxRange);
}
public static void DrawGraph(float x, float y, float w, float h, float[] data, int startSample, Color color, float maxRange = -1.0f)
{
if (instance == null)
return;
s_TempData[0] = data;
s_TempColors[0] = color;
instance._DrawGraph(x, y, w, h, s_TempData, startSample, s_TempColors, maxRange);
}
public static void DrawGraph(float x, float y, float w, float h, float[][] data, int startSample, Color[] color, float maxRange = -1.0f)
{
if (instance == null)
return;
instance._DrawGraph(x, y, w, h, data, startSample, color, maxRange);
}
public static void DrawRect(float x, float y, float w, float h, Color col)
{
if (instance == null)
return;
instance._DrawRect(x, y, w, h, col);
}
public static void DrawLine(float x1, float y1, float x2, float y2, Color col)
{
if (instance == null)
return;
instance.AddLine(x1, y1, x2, y2, col);
}
public static void DrawLine3D(Vector3 start, Vector3 end, Color col)
{
if (instance == null)
return;
instance.m_line3DBuffer.AddLine3D(start, end, col);
}
public static Line3DBuffer GetLine3DBuffer()
{
if (instance == null)
return null;
return instance.m_line3DBuffer;
}
void _DrawText(float x, float y, ref char[] text, int length)
{
const string hexes = "0123456789ABCDEF";
Vector4 col = m_CurrentColor;
int xpos = 0;
if (x < 0) x += Width;
if (y < 0) y += Height;
for (var i = 0; i < length; i++)
{
if (text[i] == '^' && i < length - 3)
{
var r = hexes.IndexOf(text[i + 1]);
var g = hexes.IndexOf(text[i + 2]);
var b = hexes.IndexOf(text[i + 3]);
col.x = (float)(r * 16 + r) / 255.0f;
col.y = (float)(g * 16 + g) / 255.0f;
col.z = (float)(b * 16 + b) / 255.0f;
i += 3;
continue;
}
AddQuad(m_OriginX + x + xpos, m_OriginY + y, 1, 1, text[i], col);
xpos++;
}
}
void _DrawGraph(float x, float y, float w, float h, float[][] data, int startSample, Color[] color, float maxRange = -1.0f)
{
if(data == null || data.Length == 0 || data[0] == null)
throw new System.ArgumentException("Invalid data argument (data must contain at least one non null array");
var numSamples = data[0].Length;
for(int i = 1; i < data.Length; ++i)
{
if(data[i] == null || data[i].Length != numSamples)
throw new System.ArgumentException("Length of data of all arrays must be the same");
}
if (color.Length != data.Length)
throw new System.ArgumentException("Length of colors must match number of datasets");
float maxData = float.MinValue;
foreach (var dataset in data)
{
for (var i = 0; i < numSamples; i++)
{
if (dataset[i] > maxData)
maxData = dataset[i];
}
}
if (maxData > maxRange)
maxRange = maxData;
float dx = w / numSamples;
float scale = maxRange > 0 ? h / maxRange : 1.0f;
for (var j = 0; j < data.Length; j++)
{
float old_pos_x = 0;
float old_pos_y = 0;
Vector4 col = color[j];
for (var i = 0; i < numSamples; i++)
{
float d = data[j][(i + startSample) % numSamples];
var pos_x = m_OriginX + x + dx * i;
var pos_y = m_OriginY + y + h - d * scale;
if (i > 0)
AddLine(old_pos_x, old_pos_y, pos_x, pos_y, col);
old_pos_x = pos_x;
old_pos_y = pos_y;
}
}
AddLine(x, y + h, x + w, y + h, color[0]);
AddLine(x, y, x, y + h, color[0]);
}
void _DrawHist(float x, float y, float w, float h, float[][] data, int startSample, Color[] color, float maxRange = -1.0f)
{
if (data == null || data.Length == 0 || data[0] == null)
throw new System.ArgumentException("Invalid data argument (data must contain at least one non null array");
if (x < 0) x += Width;
if (y < 0) y += Height;
var numSamples = data[0].Length;
for (int i = 1; i < data.Length; ++i)
{
if (data[i] == null || data[i].Length != numSamples)
throw new System.ArgumentException("Length of data of all arrays must be the same");
}
if (color.Length != data.Length)
throw new System.ArgumentException("Length of colors must match number of datasets");
var dataLength = data.Length;
float maxData = float.MinValue;
// Find tallest stack of values
for (var i = 0; i < numSamples; i++)
{
float sum = 0;
foreach(var dataset in data)
sum += dataset[i];
if (sum > maxData)
maxData = sum;
}
if (maxData > maxRange)
maxRange = maxData;
float dx = w / numSamples;
float scale = maxRange > 0 ? h / maxRange : 1.0f;
float stackOffset = 0;
for (var i = 0; i < numSamples; i++)
{
stackOffset = 0;
for (var j = 0; j < data.Length; j++)
{
var c = color[j];
float d = data[j][(i + startSample) % numSamples];
float barHeight = d * scale; // now in [0, h]
var pos_x = m_OriginX + x + dx * i;
var pos_y = m_OriginY + y + h - barHeight - stackOffset;
var width = dx;
var height = barHeight;
stackOffset += barHeight;
AddQuad(pos_x, pos_y, width, height, '\0', new Vector4(c.r, c.g, c.b, c.a));
}
}
}
void _DrawRect(float x, float y, float w, float h, Color col)
{
AddQuad(m_OriginX + x, m_OriginY + y, w, h, '\0', col);
}
void _Clear()
{
m_NumQuadsUsed = 0;
m_NumLinesUsed = 0;
SetOrigin(0, 0);
}
static char[] _buf = new char[1024];
void OnPostRender()
{
m_LineMaterial.SetPass(0);
Graphics.DrawProcedural(MeshTopology.Triangles, m_NumLinesToDraw * 6, 1);
instanceMaterialProc.SetPass(0);
Graphics.DrawProcedural(MeshTopology.Triangles, m_NumQuadsToDraw * 6, 1);
}
public static void Render(HDCamera hdCamera, CommandBuffer cmd)
{
if (!instance)
return;
instance._Render(hdCamera, cmd);
}
public static void Render3D(HDCamera hdCamera, CommandBuffer cmd)
{
if (!instance)
return;
instance._Render3D(hdCamera, cmd);
}
void _Render(HDCamera hdCamera, CommandBuffer cmd)
{
if (hdCamera.camera.cameraType != CameraType.Game)
return;
cmd.DrawProcedural(Matrix4x4.identity, m_LineMaterial, 0, MeshTopology.Triangles, m_NumLinesToDraw * 6, 1);
cmd.DrawProcedural(Matrix4x4.identity, instanceMaterialProc, 0, MeshTopology.Triangles, m_NumQuadsToDraw * 6, 1);
}
void _Render3D(HDCamera hdCamera, CommandBuffer cmd)
{
if(m_line3DBuffer != null)
{
m_line3DBuffer.HDDraw(cmd);
}
}
unsafe void AddLine(float x1, float y1, float x2, float y2, Vector4 col)
{
if (m_NumLinesUsed >= m_LineInstanceData.Length)
{
// Resize
var newBuf = new LineInstanceData[m_LineInstanceData.Length + 128];
System.Array.Copy(m_LineInstanceData, newBuf, m_LineInstanceData.Length);
m_LineInstanceData = newBuf;
}
fixed (LineInstanceData* d = &m_LineInstanceData[m_NumLinesUsed])
{
d->color = col;
d->position.x = x1;
d->position.y = y1;
d->position.z = x2;
d->position.w = y2;
}
m_NumLinesUsed++;
}
public unsafe void AddQuad(float x, float y, float w, float h, char c, Vector4 col)
{
if (m_NumQuadsUsed >= m_QuadInstanceData.Length)
{
// Resize
var newBuf = new QuadInstanceData[m_QuadInstanceData.Length + 128];
System.Array.Copy(m_QuadInstanceData, newBuf, m_QuadInstanceData.Length);
m_QuadInstanceData = newBuf;
}
fixed (QuadInstanceData* d = &m_QuadInstanceData[m_NumQuadsUsed])
{
if (c != '\0')
{
d->positionAndUV.z = (c - 32) % charCols;
d->positionAndUV.w = (c - 32) / charCols;
col.w = 0.0f;
}
else
{
d->positionAndUV.z = 0;
d->positionAndUV.w = 0;
}
d->color = col;
d->positionAndUV.x = x;
d->positionAndUV.y = y;
d->size.x = w;
d->size.y = h;
d->size.z = 0;
d->size.w = 0;
}
m_NumQuadsUsed++;
}
float m_OriginX;
float m_OriginY;
Color m_CurrentColor = Color.white;
struct QuadInstanceData
{
public Vector4 positionAndUV; // if UV are zero, dont sample
public Vector4 size; // zw unused
public Vector4 color;
}
struct LineInstanceData
{
public Vector4 position; // segment from (x,y) to (z,w)
public Vector4 color;
}
Line3DBuffer m_line3DBuffer;
int m_NumQuadsUsed = 0;
int m_NumLinesUsed = 0;
ComputeBuffer m_QuadInstanceBuffer;
ComputeBuffer m_LineInstanceBuffer;
int m_NumQuadsToDraw = 0;
int m_NumLinesToDraw = 0;
QuadInstanceData[] m_QuadInstanceData = new QuadInstanceData[128];
LineInstanceData[] m_LineInstanceData = new LineInstanceData[128];
Material m_LineMaterial;
}