Unity Shader 之 GL Mesh Shader 實現物體模型的線框效果(也適用於移動端)
目錄
Unity Shader 之 GL Mesh Shader 實現物體模型的線框效果(也適用於移動端)
一、簡單介紹
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
}
}
}