Unity實現3D書寫功能
阿新 • • 發佈:2020-12-09
Unity實現3D書寫功能
利用LineRender實現書寫功能
利用LineRender的點位功能實現畫線功能
畫板的預製排版
畫板的指令碼放置與Board上並新增BoxCollider
UICanvasTemp為臨時畫板層
UICanvasSave為最終畫板層
UICanvasTemp與UICanvasSave中的Comtent採用RawImage
UICamera與UICanvasTemp中的Comtent使用RenderTexture進行關聯,使UICanvasTemp
UICanvasSave中的Comtent的圖片為LineRender的儲存圖片
畫板的缺陷
- 需要保證UICanvasTemp和UICanvasSave的大小全部佔滿UICamera的區間,否則會出現BUG
- UICanvasTemp的Layer層需要為Default
- UICanvasTemp的Layer層需要為DrawUI
- UICamera為畫板的專用相機,只看畫板層DrawUI
- 場景中的主相機不可場景DrawUI層
- 畫布Canvas的RenderMode的型別必須為WorldSpace否則主相機無法檢視
畫板的優化
- UICanvasSave的作用為避免LineRender
- 畫布Canvas的RenderMode的型別可以用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,
}
}