欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Unity使用LineRender实现签名效果

程序员文章站 2022-03-23 10:41:20
本文为大家分享了unity制作签名功能的具体代码,供大家参考,具体内容如下前言:项目中需要做一个签名的功能,同时需要两个两个屏幕进行显示,但是都是在ui上,从网上查了大量资料。找到两种方法:1、修改图...

本文为大家分享了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实现签名效果

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