Unity Shader 之 GL Mesh Shader 實現物體模型的線框效果(也適用於移動端)

 

 

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
		}
	}
	
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章