本篇內容主要講解“在Unity中如何使用LineRender實現簽名效果”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“在Unity中如何使用LineRender實現簽名效果”吧!
前言:項目中需要做一個簽名的功能,同時需要兩個兩個屏幕進行顯示,但是都是在UI上
找到兩種方法:
1、修改圖片像素點 但是是馬賽克效果,不滿足需求
2、使用LineRenderer 的3D簽名制作出2D效果
改像素點:
先上代碼
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紋理坐標。
Vector2 pixelUV = hit.textureCoord;
//以像素為單位的紋理寬度
pixelUV.x *= m_tex.width;
pixelUV.y *= m_tex.height;
//貼圖UV坐標以右上角為原點
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();
}
//在處理鼠標按下的記錄下位置,抬起的時候記錄下位置,取2個位置中間的位置發射射線
//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腳本是用來修改像素點的,ObjBase只是一個根父類,控制顯示和隱藏。
測試場景用的Quad,通過讀取他的mainTexture對應的像素,進行修改,UI中的話就是將一張圖片轉成Texture2D形式,通過讀取像素點,進行修改即可,同時還可以實現同步效果。
項目中的Hierarchy窗口設置:

項目需求:使用了兩個畫布,MainCamera照射Quad,兩個UI相機分別照射兩個畫布,畫布的Render Mode設置為Screen Space -Camera格式。GameObject掛載腳本,Quad用來修改其上的圖片的像素點。
效果圖:

使用LineRenderer 3D劃線方法實現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;//主相機和UI相機共同照射到的地方進行截圖
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>
/// 對相機截圖。
/// </summary>
/// <returns>The screenshot2.</returns>
/// <param name="camera">Camera.要被截屏的相機</param>
/// <param name="rect">Rect.截屏的區域</param>
Texture2D CaptureCamera(Camera camera,Rect rect)
{
// 創建一個RenderTexture對象
RenderTexture rt = new RenderTexture((int)rect.width, (int)rect.height, 0);
// 臨時設置相關相機的targetTexture為rt, 并手動渲染相關相機
camera.targetTexture = rt;
camera.Render();
//ps: --- 如果這樣加上第二個相機,可以實現只截圖某幾個指定的相機一起看到的圖像。
//camera2.targetTexture = rt;
// camera2.Render();
//ps: -------------------------------------------------------------------
// 激活這個rt, 并從中中讀取像素。
RenderTexture.active = rt;
Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
screenShot.ReadPixels(rect, 0, 0);// 注:這個時候,它是從RenderTexture.active中讀取像素
screenShot.Apply();
// 重置相關參數,以使用camera繼續在屏幕上顯示
camera.targetTexture = null;
// camera2.targetTexture = null;
//ps: camera2.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
GameObject.Destroy(rt);
// 最后將這些紋理數據,成一個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函數綁定在按鈕上
Line:制作簽名預制體
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腳本掛在預制體Line上,Line 添加LineRenderer組件,同時Material中加入自己創建的材質球

項目需求:Hierarchy窗口設置
和上面一種方法一樣,也是兩個畫布,兩個UI相機,同時需要一個MainCamera

parent為空物體,用來作為根節點,將簽名時實時生成的預制體放在其下面,作為子節點,方便后面進行銷毀,重新簽名。
重點:
第二種方法使用的是特定相機照射畫面進行截圖,Test5中的CaptureCamera方法就是截取主相機照射到的畫面。由于簽名不能進行全屏進行截圖,只能部分截圖,類似相面的畫面

下面會有一些常規的功能按鈕,重新簽名,保存簽名等等操作,這些操作就是在UI上進行簽名。
所以,通過修改MainCamera的Viewport Rect窗口來進行截圖,同時能夠實現正常的簽名操作。
MainCamera的Viewport Rect設置:
運行剛開始:

通過設置這個屬性,可以使簽名界面呈現上一個圖的效果,前面是UI層,后面是3D層。
然而在截屏圖的時候如果始終保持Viewport Rect是上面的設置,則截圖的時候仍把周圍的黑色部分也截取出來,剛開始以為特定相機照射截圖只截取Viewport Rect中的圖像,后來測試是周圍的所有黑色部分也截取了,這樣就不滿足要求。
所以,在代碼中簽字 的時候保持上面的設置,截圖之前main.rect = new Rect(0, 0, 1, 1);設置成全屏,截好之后重新回復成原來的設置 main.rect = new Rect(0.25f, 0.35f, 0.5f, 0.5f);,截圖完成之后將簽名圖片賦值給第二個屏幕畫布中的RawImage進行展示。
達到效果。結合UI實際簽名過程中

中間的白色部分,通過設置MainCamera中的Camera組件中的Background(設置為白色)以及天空盒(Windows->Lighting->Settings->Scene->Skybox Material設置為空),設置為需要的顏色。UI制作的時候需要簽名的部分制作成透明的即可。
效果圖:

到此,相信大家對“在Unity中如何使用LineRender實現簽名效果”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。