功能本身为测试用例,所以写的并不是很严谨,三角线使用的是缩放后的圆柱Mesh,黄色使用Box的Mesh,绿色使用Sphere的Mesh。
box和sphere也可以同时生成多个,但需要修改VrGizmos.cs中的两个方法DrawSphere、DrawBox,逻辑类似三角线的方法DrawSegments
放上VrGizmos.cs的源码:
using System.Collections.Generic;
using UnityEngine;
///
/// Calling any VrGizmo static function will add this to Camera.main.
/// Or attach to a VR camera to manually enable VR gizmo drawing.
///
[RequireComponent(typeof(Camera))]
public class VrGizmos : MonoBehaviour
{
#region Consts and types
const string SHADER = "Unlit/Color";
public class DrawCommand
{
Mesh[] _mesh;
Matrix4x4[] _matrix;
Color[] _color;
public DrawCommand(Mesh[] mesh, Color[] color, Matrix4x4[] matrix)
{
_mesh = mesh;
_matrix = matrix;
_color = color;
}
public void Draw(Material m)
{
for (int i = 0; i < _mesh.Length; i++)
{
_color[i].a *= alpha;
m.color = _color[i];
m.SetPass(0);
Graphics.DrawMeshNow(_mesh[i], _matrix[i]);
}
}
}
#endregion
#region Static
static List<VrGizmos> _drawers = new List<VrGizmos>();
public static Dictionary<PrimitiveType, Mesh> _meshes;
static bool _initd = false;
static void Init()
{
if (_initd) return;
alpha = 1;
_meshes = new Dictionary<PrimitiveType, Mesh>();
foreach (PrimitiveType pt in (PrimitiveType[]) System.Enum.GetValues(typeof(PrimitiveType)))
{
GameObject go = GameObject.CreatePrimitive(pt);
Mesh m = go.GetComponent<MeshFilter>().sharedMesh;
Object.DestroyImmediate(go);
_meshes.Add(pt, m);
}
_initd = true;
}
static bool AddDrawer(Camera cam)
{
if (cam == null) return false;
if (cam.stereoTargetEye != StereoTargetEyeMask.None)
{
cam.gameObject.AddComponent<VrGizmos>();
Debug.LogWarningFormat("Automatically added VrGizmo component to camera {0}", cam.name);
return true;
}
return false;
}
public static void AddDraw(DrawCommand drawCommand)
{
if (!active || !Application.isPlaying) return;
if (_drawers.Count == 0)
{
bool added = AddDrawer(Camera.main);
if (!added)
{
foreach (var cam in Camera.allCameras)
{
added = AddDrawer(cam);
if (added) break;
}
}
if (!added)
{
Debug.LogWarning(
"No VrGizmo components detected on cameras and no valid VR cameras found - nothing will be drawn");
}
}
foreach (var d in _drawers)
{
if (!d._cmds.Contains(drawCommand))
{
d._cmds.Add(drawCommand);
}
}
}
public static void RemoveDraw(DrawCommand drawCommand)
{
foreach (var d in _drawers)
{
if (d._cmds.Contains(drawCommand))
{
d._cmds.Remove(drawCommand);
}
}
}
#region API
public static float alpha;
public static bool active = true;
public struct Segment
{
public Vector3 _start;
public Vector3 _end;
public Color _color;
public Segment(Vector3 start, Vector3 end, Color color)
{
_start = start;
_end = end;
_color = color;
}
}
public static DrawCommand DrawSegments(Segment[] segments, float thickness)
{
Mesh[] meshes = new Mesh[segments.Length];
Color[] colors = new Color[segments.Length];
Matrix4x4[] matrixs = new Matrix4x4[segments.Length];
for (int i = 0; i < segments.Length; i++)
{
var start = segments[i]._start;
var end = segments[i]._end;
var position = (start + end) / 2f;
var rotation = Quaternion.FromToRotation(Vector3.up, end - start);
var length = Vector3.Distance(start, end) / 2f;
meshes[i] = _meshes[PrimitiveType.Cylinder];
matrixs[i] = Matrix4x4.TRS(position, rotation, new Vector3(thickness, length, thickness));
colors[i] = segments[i]._color;
}
return new DrawCommand(meshes, colors, matrixs);
}
public static DrawCommand DrawSphere(Vector3 position, float radius, Color color)
{
Mesh[] meshes = new[] {_meshes[PrimitiveType.Sphere]};
Color[] colors = new[] {color};
Matrix4x4[] matrixs = new[] {Matrix4x4.TRS(position, Quaternion.identity, Vector3.one * radius)};
return new DrawCommand(meshes, colors, matrixs);
}
public static DrawCommand DrawBox(Vector3 position, Quaternion rotation, Vector3 size, Color color)
{
Mesh[] meshes = new[] {_meshes[PrimitiveType.Cube]};
Color[] colors = new[] {color};
Matrix4x4[] matrixs = new[] {Matrix4x4.TRS(position, rotation, size)};
return new DrawCommand(meshes, colors, matrixs);
}
#endregion
#endregion
#region Instance
public Material _mat;
List<DrawCommand> _cmds = new List<DrawCommand>();
void Awake()
{
Init();
_drawers.Add(this);
_mat = new Material(Shader.Find(SHADER));
_mat.hideFlags = HideFlags.HideAndDontSave;
}
void OnDestroy()
{
_drawers.Remove(this);
Destroy(_mat);
_cmds.Clear();
}
void OnPostRender()
{
foreach (var c in _cmds)
{
c.Draw(_mat);
}
}
#endregion
}
以及测试使用的代码:
using UnityEngine;
public class TestVrGizmos : MonoBehaviour
{
private VrGizmos.DrawCommand _cmdSphere;
private VrGizmos.DrawCommand _cmdBox;
private VrGizmos.DrawCommand _cmdLines;
private Vector3 currPos;
private Vector3 lastPos;
// Start is called before the first frame update
void Start()
{
VrGizmos.alpha = 0.2f;
lastPos = currPos = transform.position;
_cmdSphere = VrGizmos.DrawSphere(currPos, 1f, Color.green);
_cmdBox = VrGizmos.DrawBox(currPos + Vector3.up, Quaternion.identity, Vector3.one, Color.yellow);
VrGizmos.Segment[] segments = new[]
{
new VrGizmos.Segment(new Vector3(0, 0, 0), new Vector3(1, 1, 1), Color.cyan),
new VrGizmos.Segment(new Vector3(1, 1, 1), new Vector3(1, 0, 1), Color.green),
new VrGizmos.Segment(new Vector3(1, 0, 1), new Vector3(0, 0, 0), Color.red)
};
_cmdLines = VrGizmos.DrawSegments(segments, 0.01f);
}
// Update is called once per frame
void Update()
{
currPos = transform.position;
if (!lastPos.Equals(currPos))
{
lastPos = currPos;
VrGizmos.RemoveDraw(_cmdSphere);
VrGizmos.RemoveDraw(_cmdBox);
_cmdSphere = VrGizmos.DrawSphere(currPos, 1f, Color.green);
_cmdBox = VrGizmos.DrawBox(currPos + Vector3.up, Quaternion.identity, Vector3.one, Color.yellow);
}
VrGizmos.AddDraw(_cmdSphere);
VrGizmos.AddDraw(_cmdBox);
VrGizmos.AddDraw(_cmdLines);
}
}
使用方式:
1.导入SteamVR插件,并在场景中拖入[CameraRig]预制体
2.将脚本VrGizmos.cs挂在[CameraRig]下面的Camera上
3.新建空白对象,挂上脚本TestVrGizmos.cs,运行即可
感谢Dr Luke Thompson的项目源码https://github.com/SixWays/VrGizmos
2020-08-25更新:
经过进一步的使用发现项目升级到HDRP后,Graphics.DrawMeshNow绘制的网格显示不出来,原因未知。
只能更换绘制API为Graphics.DrawMesh。
转载注明出处,感谢。