Unity使用LineRender實(shí)現(xiàn)簽名效果
本文為大家分享了Unity制作簽名功能的具體代碼,供大家參考,具體內(nèi)容如下
前言:項(xiàng)目中需要做一個(gè)簽名的功能,同時(shí)需要兩個(gè)兩個(gè)屏幕進(jìn)行顯示,但是都是在UI上,從網(wǎng)上查了大量資料。
找到兩種方法:
1、修改圖片像素點(diǎn) 但是是馬賽克效果,不滿足需求
2、使用LineRenderer 的3D簽名制作出2D效果
改像素點(diǎn):
先上代碼
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Test : ObjBase { public GameObject m_obj; private Texture2D m_tex; public Color m_color; public int size = 3; private Color[] m_textureColorsStart; public RawImage showImg; void Start() { if (Display.displays.Length > 1) Display.displays[1].Activate(); if (Display.displays.Length > 2) Display.displays[2].Activate(); m_tex = m_obj.GetComponent<MeshRenderer>().material.mainTexture as Texture2D; //從紋理中獲取像素顏色 m_textureColorsStart = m_tex.GetPixels(); Debug.Log(m_tex.name); } void Update() { //Vector3 oldPos=Vector3.zero; //oldPos = Input.mousePosition; //Ray ray = uiCam.ScreenPointToRay(Input.mousePosition); Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Input.GetMouseButton(0)) { // float m_magnitude = (Input.mousePosition - oldPos).magnitude; // Vector3 dir = Input.mousePosition - oldPos; if (Physics.Raycast(ray, out hit)) { //在碰撞位置處的UV紋理坐標(biāo)。 Vector2 pixelUV = hit.textureCoord; //以像素為單位的紋理寬度 pixelUV.x *= m_tex.width; pixelUV.y *= m_tex.height; //貼圖UV坐標(biāo)以右上角為原點(diǎn) for (float i = pixelUV.x - 1; i < pixelUV.x + size; i++) { for (float j = pixelUV.y - 1; j < pixelUV.y + size; j++) { m_tex.SetPixel((int)i, (int)j, m_color); } } Debug.Log(pixelUV); m_tex.Apply(); showImg.texture = m_tex; } } if (Input.GetKeyDown(KeyCode.Space)) { //還原 m_tex.SetPixels(m_textureColorsStart); m_tex.Apply(); } //在處理鼠標(biāo)按下的記錄下位置,抬起的時(shí)候記錄下位置,取2個(gè)位置中間的位置發(fā)射射線 //if (Input.GetMouseButtonDown(0)) //{ //} //if (Input.GetMouseButtonUp(0)) //{ //} } public void OnClick() { showImg.texture = m_tex; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ObjBase : MonoBehaviour { public bool IsShow { get { return gameObject.activeSelf; } } // Use this for initialization void Start() { } /// <summary> /// 顯示 /// </summary> /// <param name="parameter"></param> public virtual void Show(object parameter = null) { gameObject.SetActive(true); } /// <summary> /// 隱藏 /// </summary> /// <param name="parameter"></param> public virtual void Hide(object parameter = null) { gameObject.SetActive(false); } }
Test腳本是用來修改像素點(diǎn)的,ObjBase只是一個(gè)根父類,控制顯示和隱藏。
測(cè)試場(chǎng)景用的Quad,通過讀取他的mainTexture對(duì)應(yīng)的像素,進(jìn)行修改,UI中的話就是將一張圖片轉(zhuǎn)成Texture2D形式,通過讀取像素點(diǎn),進(jìn)行修改即可,同時(shí)還可以實(shí)現(xiàn)同步效果。
項(xiàng)目中的Hierarchy窗口設(shè)置:
項(xiàng)目需求:使用了兩個(gè)畫布,MainCamera照射Quad,兩個(gè)UI相機(jī)分別照射兩個(gè)畫布,畫布的Render Mode設(shè)置為Screen Space -Camera格式。GameObject掛載腳本,Quad用來修改其上的圖片的像素點(diǎn)。
效果圖:
使用LineRenderer 3D劃線方法實(shí)現(xiàn)2D簽名效果:
先上代碼:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.Text; using System.IO; using UnityEngine.EventSystems; public class Test5 : MonoBehaviour { public GameObject drawObj; private bool beginDraw; private GameObject obj; public Transform parent; public RawImage rawImg; public Camera UICam; public Camera main;//主相機(jī)和UI相機(jī)共同照射到的地方進(jìn)行截圖 Color[] colors; Texture2D myTexture2D; public RawImage photo; public RawImage showImg; [SerializeField] private string _name; public RectTransform canvas1; public void SaveFile() { Camera mainCam; GameObject cam = Camera.main.gameObject; if (cam) { mainCam = cam.GetComponent<Camera>(); } else { return; } RenderTexture renderTex; renderTex = new RenderTexture(Screen.width, Screen.height, 24); mainCam.targetTexture = renderTex; mainCam.Render(); myTexture2D = new Texture2D(renderTex.width, renderTex.height); RenderTexture.active = renderTex; myTexture2D.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0); myTexture2D.Apply(); byte[] bytes = myTexture2D.EncodeToJPG(); myTexture2D.Compress(true); myTexture2D.Apply(); RenderTexture.active = null; File.WriteAllBytes(Application.dataPath + "/StreamingAssets/TextureTemp.png", bytes); mainCam.targetTexture = null; GameObject.Destroy(renderTex); } public void OnClick() { main.rect = new Rect(0, 0, 1, 1); CaptureCamera( main,new Rect(Screen.width * 0f, Screen.height * 0f, Screen.width * 1f, Screen.height * 1f)); } /// <summary> /// 對(duì)相機(jī)截圖。 /// </summary> /// <returns>The screenshot2.</returns> /// <param name="camera">Camera.要被截屏的相機(jī)</param> /// <param name="rect">Rect.截屏的區(qū)域</param> Texture2D CaptureCamera(Camera camera,Rect rect) { // 創(chuàng)建一個(gè)RenderTexture對(duì)象 RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0); // 臨時(shí)設(shè)置相關(guān)相機(jī)的targetTexture為rt, 并手動(dòng)渲染相關(guān)相機(jī) camera.targetTexture = rt; camera.Render(); //ps: --- 如果這樣加上第二個(gè)相機(jī),可以實(shí)現(xiàn)只截圖某幾個(gè)指定的相機(jī)一起看到的圖像。 //camera2.targetTexture = rt; // camera2.Render(); //ps: ------------------------------------------------------------------- // 激活這個(gè)rt, 并從中中讀取像素。 RenderTexture.active = rt; Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false); screenShot.ReadPixels(rect, 0, 0);// 注:這個(gè)時(shí)候,它是從RenderTexture.active中讀取像素 screenShot.Apply(); // 重置相關(guān)參數(shù),以使用camera繼續(xù)在屏幕上顯示 camera.targetTexture = null; // camera2.targetTexture = null; //ps: camera2.targetTexture = null; RenderTexture.active = null; // JC: added to avoid errors GameObject.Destroy(rt); // 最后將這些紋理數(shù)據(jù),成一個(gè)png圖片文件 byte[] bytes = screenShot.EncodeToPNG(); string filename = Application.dataPath + string.Format("/Screenshot_{0}.png", _name); System.IO.File.WriteAllBytes(filename, bytes); Debug.Log(string.Format("截屏了一張照片: {0}", filename)); showImg.texture = screenShot; main.rect = new Rect(0.25f, 0.35f, 0.5f, 0.5f); return screenShot; } void Start () { if (Display.displays.Length > 1) Display.displays[1].Activate(); if (Display.displays.Length > 2) Display.displays[2].Activate(); } // Update is called once per frame void Update () { if (Input.GetMouseButtonDown(0)) { beginDraw = true; obj = Instantiate(drawObj) as GameObject; obj.transform.parent = parent; } if (Input.GetMouseButtonUp(0)) { beginDraw = false; } if (beginDraw) { Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10f); position = Camera.main.ScreenToWorldPoint(position); //Vector3 localPoint; //if(RectTransformUtility.ScreenPointToWorldPointInRectangle(canvas1, position, null, out localPoint)) //{ // position = localPoint; //} DrawText dt = obj.GetComponent<DrawText>(); dt.points.Add(position); dt.Draw(); dt.line.startColor = Color.yellow; dt.line.endColor = Color.yellow; dt.line.startWidth = 0.03f; dt.line.endWidth = 0.03f; } } }
Test5是劃線和截取簽名的操作,綁定在空物體上,OnClick函數(shù)綁定在按鈕上
Line:制作簽名預(yù)制體
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DrawText : MonoBehaviour { public List<Vector3> points = new List<Vector3>(); public LineRenderer line; private void Awake() { line = GetComponent<LineRenderer>(); } public void Draw() { line.positionCount = points.Count; for (int i = 0; i < points.Count; i++) { line.SetPosition(i, points[i]); line.startWidth =2f; line.endWidth =2f; } } // Use this for initialization void Start () { } // Update is called once per frame void Update () { } }
Draw Text腳本掛在預(yù)制體Line上,Line 添加LineRenderer組件,同時(shí)Material中加入自己創(chuàng)建的材質(zhì)球
項(xiàng)目需求:Hierarchy窗口設(shè)置
和上面一種方法一樣,也是兩個(gè)畫布,兩個(gè)UI相機(jī),同時(shí)需要一個(gè)MainCamera
parent為空物體,用來作為根節(jié)點(diǎn),將簽名時(shí)實(shí)時(shí)生成的預(yù)制體放在其下面,作為子節(jié)點(diǎn),方便后面進(jìn)行銷毀,重新簽名。
重點(diǎn):
第二種方法使用的是特定相機(jī)照射畫面進(jìn)行截圖,Test5中的CaptureCamera方法就是截取主相機(jī)照射到的畫面。由于簽名不能進(jìn)行全屏進(jìn)行截圖,只能部分截圖,類似相面的畫面
下面會(huì)有一些常規(guī)的功能按鈕,重新簽名,保存簽名等等操作,這些操作就是在UI上進(jìn)行簽名。
所以,通過修改MainCamera的Viewport Rect窗口來進(jìn)行截圖,同時(shí)能夠?qū)崿F(xiàn)正常的簽名操作。
MainCamera的Viewport Rect設(shè)置:
運(yùn)行剛開始:
通過設(shè)置這個(gè)屬性,可以使簽名界面呈現(xiàn)上一個(gè)圖的效果,前面是UI層,后面是3D層。
然而在截屏圖的時(shí)候如果始終保持Viewport Rect是上面的設(shè)置,則截圖的時(shí)候仍把周圍的黑色部分也截取出來,剛開始以為特定相機(jī)照射截圖只截取Viewport Rect中的圖像,后來測(cè)試是周圍的所有黑色部分也截取了,這樣就不滿足要求。
所以,在代碼中簽字 的時(shí)候保持上面的設(shè)置,截圖之前main.rect = new Rect(0, 0, 1, 1);設(shè)置成全屏,截好之后重新回復(fù)成原來的設(shè)置 main.rect = new Rect(0.25f, 0.35f, 0.5f, 0.5f);,截圖完成之后將簽名圖片賦值給第二個(gè)屏幕畫布中的RawImage進(jìn)行展示。
達(dá)到效果。結(jié)合UI實(shí)際簽名過程中
中間的白色部分,通過設(shè)置MainCamera中的Camera組件中的Background(設(shè)置為白色)以及天空盒(Windows->Lighting->Settings->Scene->Skybox Material設(shè)置為空),設(shè)置為需要的顏色。UI制作的時(shí)候需要簽名的部分制作成透明的即可。
效果圖:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
DevExpress之餅狀圖突出(Explode)設(shè)置實(shí)例
這篇文章主要介紹了DevExpress之餅狀圖突出(Explode)設(shè)置方法,以實(shí)例形式展示了餅狀圖突出設(shè)置的具體實(shí)現(xiàn)過程,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法
c#使用process.start啟動(dòng)程序報(bào)錯(cuò)解決方法,大家參考使用吧2013-12-12C#訪問C++動(dòng)態(tài)分配的數(shù)組指針(實(shí)例講解)
下面小編就為大家分享一篇C#訪問C++動(dòng)態(tài)分配的數(shù)組指針(實(shí)例講解),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12C#中#define后面只加一個(gè)參數(shù)的解釋
今天小編就為大家分享一篇關(guān)于C#中#define后面只加一個(gè)參數(shù)的解釋,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-04-04c# socket心跳超時(shí)檢測(cè)的思路(適用于超大量TCP連接情況下)
這篇文章主要介紹了c# socket心跳超時(shí)檢測(cè)的思路(適用于超大量TCP連接情況下),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03