1. 程式人生 > 其它 >Unity實現3D書寫功能

Unity實現3D書寫功能

技術標籤:Unityunity前端

Unity實現3D書寫功能

利用LineRender實現書寫功能

利用LineRender的點位功能實現畫線功能

畫板的預製排版

在這裡插入圖片描述

畫板的指令碼放置與Board上並新增BoxCollider
UICanvasTemp為臨時畫板層
UICanvasSave為最終畫板層
UICanvasTempUICanvasSave中的Comtent採用RawImage
UICameraUICanvasTemp中的Comtent使用RenderTexture進行關聯,使UICanvasTemp

中的Comtent的圖片始終為UICamera的圖片
UICanvasSave中的Comtent的圖片為LineRender的儲存圖片

畫板的缺陷

  • 需要保證UICanvasTempUICanvasSave的大小全部佔滿UICamera的區間,否則會出現BUG
  • UICanvasTempLayer層需要為Default
  • UICanvasTempLayer層需要為DrawUI
  • UICamera為畫板的專用相機,只看畫板層DrawUI
  • 場景中的主相機不可場景DrawUI
  • 畫布CanvasRenderMode的型別必須為WorldSpace否則主相機無法檢視

畫板的優化

  • UICanvasSave的作用為避免LineRender
    中的點位過多導致程式卡死,所有每一筆畫完都需要對LineRender的內容進行儲存.或當LineRender的點位達到一定的數量進行臨時儲存.或當相鄰點位的距離較小時忽略點位的寫入
  • 畫布CanvasRenderMode的型別可以用ScreenSpace-Camera來確保畫布的大小佔滿UICamera的區間

畫板功能程式碼


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.
UI; public class DrawBoard : MonoBehaviour { public Transform mRoot; public Camera mUICamera; public Canvas mUICanvasSave; public Canvas mUICanvasTemp; public RawImage mSaveDrawCanvas; public RawImage mTempDrawCanvas; Dictionary<uint, LineRenderer> mAllLine = new Dictionary<uint, LineRenderer>(); List<LineRenderer> mLastLine = new List<LineRenderer>(); /// <summary> /// 開始繪畫引數準備 /// </summary> /// <param name="varPenID">筆的ID,方便與多筆同時進行作畫</param> /// <param name="size">筆的粗細</param> /// <param name="color">筆的顏色</param> public void StartDraw(uint varPenID, float size, Color color, Vector3 pos) { if (mAllLine.ContainsKey(varPenID)) { return; } LineRenderer Line; if (mLastLine.Count != 0) { Line = mLastLine[0]; mLastLine.RemoveAt(0); } else { Line = NewGameobject<LineRenderer>("Line", mRoot); Line.gameObject.layer = LayerMask.NameToLayer("DrawUI"); Line.material = new Material(Shader.Find("Unlit/Color")); Line.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } Line.material.SetColor("_Color", color); Line.widthMultiplier = size; Line.positionCount = 2; Line.SetPosition(0, pos); Line.SetPosition(1, pos); Line.gameObject.SetActive(true); mAllLine.Add(varPenID, Line); } /// <summary> /// 進行繪畫 /// </summary> /// <param name="varPen">筆的ID,方便與多筆同時進行作畫</param> /// <param name="pos">繪畫的點位</param> public void Drawing(uint varPenID, Vector3 pos) { if (!mAllLine.ContainsKey(varPenID)) { return; } LineRenderer Line = mAllLine[varPenID]; Line.positionCount += 1; Line.SetPosition(Line.positionCount - 1, pos); } /// <summary> /// 結束繪畫 /// </summary> /// <param name="varPen">筆的ID,方便與多筆同時進行作畫</param> public void EndDraw(uint varPenID) { if (!mAllLine.ContainsKey(varPenID)) { return; } LineRenderer varLine = mAllLine[varPenID]; mAllLine.Remove(varPenID); //進行圖畫儲存 SaveDraw(); varLine.gameObject.SetActive(false); mLastLine.Add(varLine); } /// <summary> /// 對相機渲染的圖片進行儲存進指定的圖片中 /// </summary> private void SaveDraw() { if (mSaveDrawCanvas == null || mTempDrawCanvas == null) return; foreach (var item in mAllLine) { item.Value.gameObject.SetActive(false); } Texture2D screenShot = CaptureScreen(mUICamera); mSaveDrawCanvas.texture = screenShot; mSaveDrawCanvas.color = Color.white; foreach (var item in mAllLine) { item.Value.gameObject.SetActive(true); } } /// <summary> /// 將相機看到的畫面轉換成Texture2D /// </summary> /// <param name="came"></param> /// <param name="r"></param> /// <returns></returns> public Texture2D CaptureScreen(Camera camera) { camera.Render(); RenderTexture.active = camera.targetTexture; Rect r = new Rect(Vector2.zero, new Vector2(camera.activeTexture.width, camera.targetTexture.height)); #if UNITY_2017 Texture2D screenShot = new Texture2D((int)r.width, (int)r.height, TextureFormat.RGBA32, false); #elif UNITY_2019 Texture2D screenShot = new Texture2D((int)r.width, (int)r.height, GraphicsFormat.R32G32B32A32_SFloat, TextureCreationFlags.None); #endif screenShot.ReadPixels(r, 0, 0); screenShot.Apply(); RenderTexture.active = null; return screenShot; } private T NewGameobject<T>(string varContent,Transform varParent) where T:Component { GameObject TempGame = new GameObject(varContent); TempGame.transform.SetParent(varParent); TempGame.transform.localPosition = Vector3.zero; TempGame.transform.localEulerAngles = Vector3.zero; TempGame.transform.localScale = Vector3.one; T TempT = TempGame.AddComponent<T>(); return TempT; } }

畫筆的功能實現


using UnityEngine;

public class DrawPen : MonoBehaviour
{
    /// <summary>
    /// 筆的ID
    /// </summary>
    public uint mID;
    /// <summary>
    /// 筆的輸入大小
    /// </summary>
    public float mSize = 0.01f;
    /// <summary>
    /// 筆的輸入顏色
    /// </summary>
    public Color mPenColor = Color.white;
    /// <summary>
    /// 筆的輸入型別
    /// </summary>
    public PenType mPenType = PenType.Collider;


    private void Awake()
    {
        ColliderDrawInit();
    }

    #region ColliderDraw//使用碰撞實現畫筆的輸入功能

    private void ColliderDrawInit()
    {
        if (mPenType != PenType.Collider)
            return;
        BoxCollider box = this.GetComponent<BoxCollider>();
        if (box == null)
        {
            box = this.gameObject.AddComponent<BoxCollider>();
        }
        box.isTrigger = true;

        Rigidbody Rig = this.GetComponent<Rigidbody>();
        if (Rig == null)
        {
            Rig = this.gameObject.AddComponent<Rigidbody>();
        }
        Rig.isKinematic = true;
        Rig.useGravity = false;
    }
    private void OnTriggerEnter(Collider other)
    {
        if (mPenType != PenType.Collider)
            return;
        DrawBoard board = other.GetComponent<DrawBoard>();
        if (board == null)
            return;
        Vector3 pos = other.ClosestPoint(this.transform.position);
        board.StartDraw(mID, mSize, mPenColor, pos);
    }
    private void OnTriggerStay(Collider other)
    {
        if (mPenType != PenType.Collider)
            return;
        DrawBoard board = other.GetComponent<DrawBoard>();
        if (board == null)
            return;
        Vector3 pos = other.ClosestPoint(this.transform.position);
        board.Drawing(mID, pos);
    }
    private void OnTriggerExit(Collider other)
    {
        if (mPenType != PenType.Collider)
            return;
        DrawBoard board = other.GetComponent<DrawBoard>();
        if (board == null)
            return;
        board.EndDraw(mID);
    }
    
    #endregion
    
    #region RayDraw//使用射線實現畫筆的輸入功能



    #endregion

    public enum PenType
    {
        Collider,
        Ray,
    }
}