服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - Unity使用LineRender实现签名效果

Unity使用LineRender实现签名效果

2022-12-06 11:34吸血鬼1124 C#

这篇文章主要为大家详细介绍了Unity使用LineRender实现签名效果,制作签名功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文为大家分享了Unity制作签名功能的具体代码,供大家参考,具体内容如下:

前言:项目中需要做一个签名的功能,同时需要两个两个屏幕进行显示,但是都是在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窗口设置:

Unity使用LineRender实现签名效果

项目需求:使用了两个画布,MainCamera照射Quad,两个UI相机分别照射两个画布,画布的Render Mode设置为Screen Space -Camera格式。GameObject挂载脚本,Quad用来修改其上的图片的像素点。

效果图:

Unity使用LineRender实现签名效果

使用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中加入自己创建的材质球

Unity使用LineRender实现签名效果

项目需求:Hierarchy窗口设置

和上面一种方法一样,也是两个画布,两个UI相机,同时需要一个MainCamera

Unity使用LineRender实现签名效果

parent为空物体,用来作为根节点,将签名时实时生成的预制体放在其下面,作为子节点,方便后面进行销毁,重新签名。

重点:

第二种方法使用的是特定相机照射画面进行截图,Test5中的CaptureCamera方法就是截取主相机照射到的画面。由于签名不能进行全屏进行截图,只能部分截图,类似相面的画面

Unity使用LineRender实现签名效果

下面会有一些常规的功能按钮,重新签名,保存签名等等操作,这些操作就是在UI上进行签名。

所以,通过修改MainCamera的Viewport Rect窗口来进行截图,同时能够实现正常的签名操作。

MainCamera的Viewport Rect设置:

运行刚开始:

Unity使用LineRender实现签名效果

通过设置这个属性,可以使签名界面呈现上一个图的效果,前面是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实际签名过程中

Unity使用LineRender实现签名效果

中间的白色部分,通过设置MainCamera中的Camera组件中的Background(设置为白色)以及天空盒(Windows->Lighting->Settings->Scene->Skybox Material设置为空),设置为需要的颜色。UI制作的时候需要签名的部分制作成透明的即可。

效果图:

Unity使用LineRender实现签名效果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_37608784/article/details/82835865

延伸 · 阅读

精彩推荐
  • C#C#开发简易winform计算器程序

    C#开发简易winform计算器程序

    这篇文章主要为大家详细介绍了C#开发简易winform计算器程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    WarrenHome7382022-02-20
  • C#C#中ManualResetEvent用法总结

    C#中ManualResetEvent用法总结

    这篇文章主要介绍了C#中ManualResetEvent用法总结,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...

    旷野风筝少年4222022-10-31
  • C#C#简单读取主机上所有进程的方法

    C#简单读取主机上所有进程的方法

    这篇文章主要介绍了C#简单读取主机上所有进程的方法,涉及C#进程的遍历读取操作相关实现技巧,需要的朋友可以参考下...

    Quber6152021-12-02
  • C#同时兼容JS和C#的RSA加密解密算法详解(对web提交的数据加密传输)

    同时兼容JS和C#的RSA加密解密算法详解(对web提交的数据加密传输

    这篇文章主要给大家介绍了关于同时兼容JS和C#的RSA加密解密算法,通过该算法可以对web提交的数据进行加密传输,文中通过图文及示例代码介绍的非常详细...

    JackWang-CUMT9012022-01-19
  • C#c#批量抓取免费代理并且验证有效性的实战教程

    c#批量抓取免费代理并且验证有效性的实战教程

    突破反爬虫限制的方法之一就是多用几个代理IP,下面这篇文章主要给大家介绍了关于利用c#批量抓取免费代理并且验证有效性的相关资料,文中通过示例代...

    张林-布莱恩特11412022-02-25
  • C#C#动态创建button的方法

    C#动态创建button的方法

    这篇文章主要介绍了C#动态创建button的方法,涉及C#按钮属性动态设置的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...

    我心依旧10672021-10-22
  • C#C#获取客户端相关信息实例总结

    C#获取客户端相关信息实例总结

    这篇文章主要介绍了C#获取客户端相关信息的方法,以实例形式总结了C#获取客户端IP地址、网络连接、硬件信息等相关技巧,具有一定参考借鉴价值,需要的朋...

    C#教程网9632021-10-27
  • C#C#控制台实现简单飞行棋游戏

    C#控制台实现简单飞行棋游戏

    这篇文章主要为大家详细介绍了C#控制台实现简单飞行棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    梳碧湖-砍柴人5132022-11-27