2020-08-21 利用Graphics.DrawMeshNow绘制运行时Gizmos,VR可用,HDRP可用

先放效果图:
2020-08-21 利用Graphics.DrawMeshNow绘制运行时Gizmos,VR可用,HDRP可用_第1张图片

功能本身为测试用例,所以写的并不是很严谨,三角线使用的是缩放后的圆柱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。

转载注明出处,感谢。

你可能感兴趣的:(Unity3D,笔记,unity,vr)