千家信息网

在Unity中如何使用LineRender实现签名效果

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容主要讲解"在Unity中如何使用LineRender实现签名效果",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"在Unity中如何使用LineRen
千家信息网最后更新 2025年01月19日在Unity中如何使用LineRender实现签名效果

本篇内容主要讲解"在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().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()    {     }     ///     /// 显示    ///     ///     public virtual void Show(object parameter = null)    {               gameObject.SetActive(true);    }     ///     /// 隐藏    ///     ///     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();        }        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));             }      ///       /// 对相机截图。       ///       /// The screenshot2.      /// Camera.要被截屏的相机      /// Rect.截屏的区域      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();            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 points = new List();    public  LineRenderer line;    private void Awake()    {        line = GetComponent();    }    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实现签名效果"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0