Unity Shader 之 GL Mesh Shader 实现物体模型的线框效果(也适用于移动端)
目录
Unity Shader 之 GL Mesh Shader 实现物体模型的线框效果(也适用于移动端)
扫描二维码关注公众号,回复:
11566387 查看本文章
一、简单介绍
Shader Language的发展方向是设计出在便携性方面可以和C++、Java等相比的高级语言,“赋予程序员灵活而方便的编程方式”,并“尽可能的控制渲染过程”同时“利用图形硬件的并行性,提高算法效率”。
之前我们说了使用 Geometry Shader 实现物体线框效果,由于 Geometry Shader 在移动端收到限制,所以本节介绍使用 GL 实现在移动端也可以的线框效果。
二、实现原理
1、MeshFilter / SkinnedMeshRenderer 获取 mesh 数据
2、在通过 mesh 获取点数据
3、GL 把点数据绘制出来
三、使用说明
1、把脚本挂载到需要绘制的模型上
2、右键脚本,可以在编辑模式下自动获取meshes 和 lines 数据,可以节约一些性能
四、效果预览
五、实现步骤
1、打开Unity ,新建一个工程
2、在工程中,新建脚本和shader,shader 主要是控制 GL 线段的颜色,MeshWireframe 主要实现绘制模型线框
3、场景添加一个模型,把绘制线框脚本挂在上去
4、选中模型,鼠标放在脚本名称上,右键 获取模型的mesh 数据,生成 lines 数据
5、在 Test 的物体上添加 Test 脚本,并赋值
6、运行场景,效果如上
六、关键代码
1、MeshWireframe.cs
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary>
/// 获取模型mesh数据,使用GL绘制模型线框
/// </summary>
[ExecuteInEditMode]
public class MeshWireframe : MonoBehaviour
{
// 设置线框颜色
public Color lineColor = Color.white;
public Material lineMat;
[ReadOnly]
[Tooltip("(放在脚本名字上右键)根据当前模型自动获取mesh")]
public List<Mesh> meshs;
[ReadOnly]
[Tooltip("(放在脚本名字上右键)根据当前模型自动算计line")]
public List<Vector3> lines;
private void Start()
{
}
/// <summary>
/// GL 绘制线框
/// </summary>
private void OnRenderObject()
{
// 设置 GL 线的颜色
lineMat.SetColor("_LineColor", lineColor);
lineMat.SetPass(0);
GL.PushMatrix();
//转换到世界坐标
GL.MultMatrix(transform.localToWorldMatrix);
GL.Begin(GL.LINES);
for (int i = 0; i < lines.Count / 3; i++)
{
// 画三角形的方法
GL.Vertex(lines[i * 3]);
GL.Vertex(lines[i * 3 + 1]);
GL.Vertex(lines[i * 3 + 1]);
GL.Vertex(lines[i * 3 + 2]);
GL.Vertex(lines[i * 3 + 2]);
GL.Vertex(lines[i * 3]);
}
GL.End();
GL.PopMatrix();
}
/// <summary>
/// 获取模型的 mesh数据
/// </summary>
private void GenerateLines()
{
// 清空线数据。获取线数据
if (lines != null)
lines.Clear();
else
lines = new List<Vector3>();
// 从 mesh 获取顶点数据
foreach (var mesh in meshs)
{
var vertices = mesh.vertices;
var triangles = mesh.triangles;
for (int i = 0; i < triangles.Length / 3; i++)
{
// 从 三角形的数据点添加点数据
lines.Add(vertices[triangles[i * 3]]);
lines.Add(vertices[triangles[i * 3 + 1]]);
lines.Add(vertices[triangles[i * 3 + 2]]);
}
}
}
/// <summary>
/// 编辑状态下就获取到 Mesh 相关数据
/// </summary>
[ContextMenu("根据MeshFilter组件生成Line数据")]
private void GetMeshesData()
{
#if UNITY_EDITOR // 编辑状态下执行
GameObject o = UnityEditor.Selection.activeGameObject;
if (o == null)
return;
// 获取 mesh 数据
if (meshs != null)
meshs.Clear();
else
meshs = new List<Mesh>();
// 从 MeshFilter 获取 mesh
MeshFilter[] meshFilters = o.GetComponentsInChildren<MeshFilter>(true);
if (meshFilters != null && meshFilters.Length > 0)
{
foreach (var mf in meshFilters)
{
meshs.Add(mf.sharedMesh);
}
GenerateLines();
}
else
{
Debug.LogError("选中物体及子物体没有MeshFilter组件,请添加");
}
// 从 SkinnedMeshRenderer 获取 mesh
SkinnedMeshRenderer[] skinnedMeshRenderers = o.GetComponentsInChildren<SkinnedMeshRenderer>(true);
if (skinnedMeshRenderers != null && skinnedMeshRenderers.Length > 0)
{
foreach (var sr in skinnedMeshRenderers)
{
meshs.Add(sr.sharedMesh);
}
GenerateLines();
}
else
{
Debug.LogError("选中物体及子物体没有SkinnedMeshRenderer组件,请添加");
}
#endif
}
}
2、GL_LineColor.shader
Shader "Custom/GL_LineColor"
{
Properties{
_LineColor("Line Color", Color) = (1.0, 1.0, 1.0, 1.0)
}
SubShader{
Pass {
Tags { "RenderType" = "Opaque"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
half4 pos : SV_POSITION;
};
fixed4 _LineColor;
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : COLOR
{
return _LineColor;
}
ENDCG
}
}
}