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上色方法...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM