(轉載)[海莉zhe] 【每日一記】Unity3D 實戰練習-實現物體的映象 (十四)
阿新 • • 發佈:2018-12-25
http://www.manew.com/thread-140831-1-1.html
最近在學習如何實現物體的映象,練習了一個簡單的例子,然後和大家一起探討一下哈!物體映象的操作實際上是通過一個模型的MeshFilter 和 MeshRenderer 來獲取模型的頂點和網格的資訊,按指定的軸向、指定的距離來克隆一個新物件,簡單來講,就是克隆了一個含有MeshRenderer的物件。
好吧!廢話不多講,我們直接進入實戰吧!
1. 需要新建一個含有Mesh Filter元件和Mesh Renderer 元件的物件;
2. 直接增加 MeshMirrorManager.cs 元件類,並且附加物件上;
具體程式碼如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 映象方向 /// </summary> public enum MeshMirrorDir { X, Y, Z } /// <summary> /// 顯示的模式 /// </summary> public enum MeshRendererMode { Opaque,//不透明 Cutout,//鏤空 Fade,//淡入淡出 Transparent,//透明 } /// <summary> /// 物件映象管理類 /// </summary> public class MeshMirrorManager : MonoBehaviour { /// <summary> /// 映象方向 /// </summary> public MeshMirrorDir m_mirrorDir; /// <summary> /// 映象與物件距離 /// </summary> public float m_mirrorDistance=2.0f; /// <summary> /// 映象材質透明度 /// </summary> [Range(0.1f, 1.0f)] public float m_mirrorMaterialAlpha = 0.5f; /// <summary> /// 映象材質顏色 /// </summary> public Color m_mirrorMaterialColor = Color.white; MeshFilter _meshFilter; MeshRenderer _meshRenderer; void Start () { _meshFilter = GetComponent<MeshFilter> (); _meshRenderer = GetComponent<MeshRenderer> (); GenerateMirror(); } private void GenerateMirror() { if ( _meshFilter== null && _meshRenderer== null) { Debug.Log("請確認物件已附加MeshFilter或MeshRenderer元件"); } GameObject mirror = new GameObject("Mirror"); mirror.transform.position = this.transform.position; mirror.transform.rotation = this.transform.rotation; mirror.transform.localScale = this.transform.localScale; mirror.transform.SetParent(this.transform); mirror.AddComponent<MeshFilter>(); mirror.AddComponent<MeshRenderer>(); //映象的網格 Mesh mesh = new Mesh(); mesh.Clear(); mesh.vertices = GenerateVertices(_meshFilter.mesh.vertices); mesh.triangles = GenerateTriangles(_meshFilter.mesh.triangles); mesh.uv=GetComponent<MeshFilter>().mesh.uv; mesh.name = "mirror"; //重新計算髮現(重新整理顯示) mesh.RecalculateNormals(); mirror.GetComponent<MeshFilter>().mesh = mesh; mirror.GetComponent<MeshRenderer>().material = GenerateMaterial(_meshRenderer.material); } /// <summary> /// 生成映象頂點 /// </summary> /// <param name="backVertices">原遊戲物件的頂點</param> /// <returns></returns> private Vector3[] GenerateVertices(Vector3[] backVertices) { Vector3[] newVertices = backVertices; switch(m_mirrorDir) { case MeshMirrorDir.X: for (int i = 0; i <= newVertices.Length - 1;i++ ) { newVertices[i].x = newVertices[i].x * -1 + m_mirrorDistance; } break; case MeshMirrorDir.Y: for (int i = 0; i <= newVertices.Length - 1; i++) { newVertices[i].y = newVertices[i].y * -1 + m_mirrorDistance; } break; case MeshMirrorDir.Z: for (int i = 0; i <= newVertices.Length - 1; i++) { newVertices[i].z = newVertices[i].z * -1 + m_mirrorDistance; } break; default: break; } return newVertices; } /// <summary> /// 生成映象三角面 /// </summary> /// <param name="backTriangles">各個頂點的渲染順序</param> /// <returns></returns> int[] GenerateTriangles(int[] backTriangles) { int[] newTriangles = new int[backTriangles.Length]; //將所有面的頂點渲染順序顛倒 for (int i = 0; i < newTriangles.Length; i++) { newTriangles[newTriangles.Length - i - 1] = backTriangles[i]; } return newTriangles; } /// <summary> /// 生成材質球 /// </summary> /// <returns>原材質球</returns> /// <param name="backMeterial">複製後的材質球</param> private Material GenerateMaterial(Material backMeterial) { Material newMaterial = new Material(backMeterial); //不透明 if (m_mirrorMaterialAlpha >= 1.0f) { SetMaterialRenderingMode(newMaterial, MeshRendererMode.Opaque); if (newMaterial.HasProperty("_Color")) { newMaterial.SetColor("_Color", m_mirrorMaterialColor); } } //透明 else { SetMaterialRenderingMode(newMaterial, MeshRendererMode.Fade); if (newMaterial.HasProperty("_Color")) { m_mirrorMaterialColor.a = m_mirrorMaterialAlpha; newMaterial.SetColor("_Color", m_mirrorMaterialColor); } } return newMaterial; } /// <summary> /// 設定紋理渲染模式 /// </summary> /// <param name="material"></param> /// <param name="renderingMode"></param> private void SetMaterialRenderingMode(Material material, MeshRendererMode renderingMode) { switch (renderingMode) { case MeshRendererMode.Opaque: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = -1; break; case MeshRendererMode.Cutout: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.EnableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 2450; break; case MeshRendererMode.Fade: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.SetInt("_ZWrite", 0); material.DisableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; break; case MeshRendererMode.Transparent: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.SetInt("_ZWrite", 0); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.EnableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; break; } } }
3.執行專案看效果哈!