zoukankan      html  css  js  c++  java
  • unity3D AR涂涂乐制作浅谈

    unity3D AR涂涂乐制作浅谈

       AR为现在是虚拟现实较为火爆的一个技术,其中有个比较炫酷的就是AR涂涂乐的玩法,这个技术可以把扫描到的图片上的纹理 粘贴到模型上实现为模型上色的功能,但是我们需要怎么才能实现其功能呢?大体的方法是将扫描到图片保存成纹理,在将纹理保存到模型的材质球上然后实现上色的功能。

       那么有什么方式可以实现这个功能呢?我在参考的EsayAR的Demo以及在网上查找的方法基本都是采用通过Shader进行图片的处理,因此在这样的条件下,若有多个模型的UV张开图就要写不同的Shader进行进行图片的处理,这样的方式并不方便。那么有没有方法可以不写Shader来实现图片上UV展开图的颜色准确粘贴到模型上呢?于是我想为什么不可以在屏幕上设置一个扫描对准框,然后将扫描框的的内容保存成纹理呢?

      那么我先配置好AR的环境,这里我用EsayAR来制作AR涂涂乐的效果,这里为了方便我直接用EsayAR Coloring3D的例子来做这个效果吧!我们先去创建一个空的Gameobject将EsayAR例子中的EasyImageTargetBehaviour类拖入空的GameObject里然后我们将其改名为ImageTargetNamecard,设置好我们的识别图片红色框是图片名字,黄色框是图片放置的位置,记得要Storage属性要设置成Assets,如下图所示:

       然后将模型拖入到刚刚创建的ImageTargetNamecard下这样我们就做好了识别图以及模型,摆放的模型要注意的是这个模型必须是要有纹理展开图的模型,然后作为模型的识别图的图片必须对是对应着其纹理的展开的图片,例子里面我是使用一个展开过纹理的Cube模型,其中色块的位置正是UV展开的位置,展开的纹理图片如图下图所示:

       现在弄好了AR环境了,那么我们开始做扫描用的对准框吧,这里我用的是UGUI来制作对准框,这里我给对焦框设定好大小,因为我使用的识别图片是1024*1024的所以我们的对焦框也要弄成正方形的520*520就可以了,然后在弄一个按钮在对准后帮模型“上色”!做好的效果大体就如下图所示一样:

       那么开始写代码吧!这里我们在模型上添加一个InterceptTexture脚本,脚本内容如下:

    using System;
    using UnityEngine;
    using System.Collections;
    using System.IO;
    using EasyAR;
    using Image = UnityEngine.UI.Image;
    
    public class InterceptTexture : MonoBehaviour {
    
        public Image scanTexture;
        public bool isrealRender = false;
        private Camera scanCamera;
        private RenderTexture renderTexture;
        private string pipingID;
        private string scanPath;
        private Rect scanRect;
        private bool isScanTexture = false;//是否开启实时渲染
        //ImageTargetBaseBehaviour targetBehaviour;
    
    
        // Use this for initialization
        void Start()
        {
            scanPath = Application.dataPath + "/StreamingAssets/Drwaing/";
            scanRect = new Rect(scanTexture.rectTransform.position.x - scanTexture.rectTransform.rect.width / 2, scanTexture.rectTransform.position.y - scanTexture.rectTransform.rect.height / 2,
               (int)scanTexture.rectTransform.rect.width, (int)scanTexture.rectTransform.rect.height);
            //targetBehaviour = GetComponentInParent<ImageTargetBaseBehaviour>();
            gameObject.layer = 31;
            
        }
    
        void Renderprepare()
        {
            if (!scanCamera)
            {
                GameObject obj = new GameObject("ScanCamera");
                scanCamera = obj.AddComponent<Camera>();
                obj.transform.parent = transform.parent;
                scanCamera.hideFlags = HideFlags.HideAndDontSave;
            }
            scanCamera.CopyFrom(Camera.main);
            scanCamera.depth = 0;
            scanCamera.cullingMask = 31;
            if (!renderTexture)
            {
                renderTexture = new RenderTexture(Screen.width, Screen.height, -50);
            }
            if (!isScanTexture)
            {
                scanCamera.targetTexture = renderTexture;
                scanCamera.Render();
            }
            if(isrealRender)
                GetComponent<Renderer>().material.SetTexture("_MainTex", renderTexture);
            //RenderTexture.active = renderTexture;
            //StartCoroutine(ImageCreate());
           
        }
    
        void OnWillRenderObject()
        {
            Renderprepare();
        }
    
        void OnDestroy()
        {
            if (renderTexture)
                DestroyImmediate(renderTexture);
            if (scanCamera)
                DestroyImmediate(scanCamera.gameObject);
        }
    
        public void ScanTextureClick()
        {
            StartCoroutine(ImageCreate());
        }
    
        IEnumerator ImageCreate()
        {
            isScanTexture = true;
            if (isScanTexture)
            {
                scanCamera.targetTexture = renderTexture;
                scanCamera.Render();
            }
            RenderTexture.active = renderTexture;
            Texture2D scantTexture2D = new Texture2D((int)scanRect.width, (int)scanRect.height, TextureFormat.RGB24, false);
            yield return new WaitForEndOfFrame();
            scantTexture2D.ReadPixels(scanRect, 0, 0, false);
            scantTexture2D.Apply();
    
            scanCamera.targetTexture = null;
            RenderTexture.active = null;
            GameObject.Destroy(renderTexture);
    
            byte[] bytes = scantTexture2D.EncodeToPNG();
            string savePath = scanPath + gameObject.name + ".png";
            File.WriteAllBytes(savePath,bytes);
            isScanTexture = false;
            isrealRender = false;        ///关闭实时渲染
            this.gameObject.GetComponent<Renderer>().material.SetTexture("_MainTex", scantTexture2D);
            Debug.Log("截图完成!");
        }
    }
      这里使用的UGUI来制作的扫描框,因此如果用NGUI的同学要自己改一下代码哟!因为公司极却摄像头,我就不做实时演示的截图了

      通过对准框截图下来的图片如下:

       然后看看我们的模型没贴纹理之前的样子,如下图所示:

       然后是先附上贴非裁剪的正常纹理图,第二张是我们截图下来的做纹理的图片:

       因为测试的时候用手机打开识别图,导致颜色有点变了,但是大体上位置都没有错!好了测试成功了~~~运行测试的时候千万被手抖哟!不如就没办法完美的对好UV位置!~~

      因为是刚刚开始接触AR不久,所以可能做的不好望大家可以多多交流~第一次在公司写技术文章,写的不好请多多包含~

                                                                                                                                                                                                                                                                                                --Bě9oniǎ     

    这里还有现在普遍的shader上色方法...

  • 相关阅读:
    Oracle-函数-split 和 splitstr 的创建
    git merge方法
    查看Android 设备进程id
    内存泄漏
    Mac显示隐藏文件快捷键
    gradle版本
    commit单一文件
    21不下发信号
    FileInputStream read函数何时返回-1
    maven turbonet目录
  • 原文地址:https://www.cnblogs.com/czaoth/p/5530459.html
Copyright © 2011-2022 走看看