您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Unity如何實現VR中在黑板上寫字效果,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
具體內容如下
一、工具
1.開發用的是Unity 5.6.2版本
2.VR中的物理交互用的是VRTK插件,這個插件集成了比較好的物理交互功能;
3.HTC Vive
二、概述
實現的功能: 在一個白板上,用不同顏色的筆,在白板畫出任何想要的圖形;
因為只是一個初級篇所以只是用兩個腳本簡單的實現,而且并沒有黑板擦等功能 ,也不能兩個筆同時畫畫,這些功能將會在未來的升級篇中寫出;
三、知識點
其實這個功能很簡單,只是簡單的運用Unity Texure2D類中的兩個函數:
public void SetPixels32(int x, int y, int blockWidth, int blockHeight, Color32[] colors, int miplevel = 0);
前面4個參數相當于一個矩形,x和y就是矩形的左下角的那個點,blockWidth和blockHeight分別是矩形的寬和高,這個矩形所代表的范圍就是blockWidth*blockHeight個像素所在的位置,不妨稱這個矩形范圍為一個色塊;
colors這個參數的大小必須等于blockWidth*blockHeight,因為這個方法就是給坐標(x,y)開始,從左到右,從下到上,一行一行的對矩形范圍內的每個像素賦值;
也就是把colors[0]~colors[blockWidth - 1]分別賦值到坐標為(x,y)~(x + blockWidth,y)的像素,以此類推;
最后一個參數,因為我們用的圖片把Generate Min Maps這個選項關閉了,所以用默認的可選參數0;
public void Apply(bool updateMipmaps = true, bool makeNoLongerReadable = false);
當對圖片改動完成以后,需要調用這個方法,才能讓改動真正的應用在圖片上;
四、場景搭建
1.畫板
在場景中建一個Quad,把它的x和y方向的Scale分別設置為1.92和1.08(或者其它尺寸);注意這個Quad一定要用Mesh Collider作為碰撞體,不然到時候射線獲取的紋理坐標有誤,并為它設置一個Tag為Board;
2.筆
建一個尺寸合適的筆,創建一個空的子物體,命名為SnapPoint,并設置SnapPoint的Z方向指向筆尖方向,這個子物體就是,手柄拿筆的位置就是,并且保證筆的姿態是相當于人正常拿筆的樣子;
3.其它
創建一個放筆的物體,讓筆處于比較好拿的位置;
我的場景中代表畫板的是WhiteBoard下的Board物體;
五、代碼實現功能
這個腳本是掛在代表畫板的物體上的:
using System.Linq; using UnityEngine; /// <summary> /// 畫板 /// </summary> public class Board : MonoBehaviour { //當畫筆移動速度很快時,為了不出現斷斷續續的點,所以需要對兩個點之間進行插值,lerp就是插值系數 [Range(0, 1)] public float lerp = 0.05f; //初始化背景的圖片 public Texture2D initailizeTexture; //當前背景的圖片 private Texture2D currentTexture; //畫筆所在位置映射到畫板圖片的UV坐標 private Vector2 paintPos; private bool isDrawing = false;//當前畫筆是不是正在畫板上 //離開時畫筆所在的位置 private int lastPaintX; private int lastPaintY; //畫筆所代表的色塊的大小 private int painterTipsWidth = 30; private int painterTipsHeight = 15; //當前畫板的背景圖片的尺寸 private int textureWidth; private int textureHeight; //畫筆的顏色 private Color32[] painterColor; private Color32[] currentColor; private Color32[] originColor; private void Start() { //獲取原始圖片的大小 Texture2D originTexture = GetComponent<MeshRenderer>().material.mainTexture as Texture2D; textureWidth = originTexture.width;//1920 textureHeight = originTexture.height;//1080 //設置當前圖片 currentTexture = new Texture2D(textureWidth, textureHeight, TextureFormat.RGBA32, false, true); currentTexture.SetPixels32(originTexture.GetPixels32()); currentTexture.Apply(); //賦值給黑板 GetComponent<MeshRenderer>().material.mainTexture = currentTexture; //初始化畫筆的顏色 painterColor = Enumerable.Repeat<Color32>(new Color32(255, 0, 0, 255), painterTipsWidth * painterTipsHeight).ToArray<Color32>(); } private void LateUpdate() { //計算當前畫筆,所代表的色塊的一個起始點 int texPosX = (int)(paintPos.x * (float)textureWidth - (float)(painterTipsWidth / 2)); int texPosY = (int)(paintPos.y * (float)textureHeight - (float)(painterTipsHeight / 2)); if (isDrawing) { //改變畫筆所在的塊的像素值 currentTexture.SetPixels32(texPosX, texPosY, painterTipsWidth, painterTipsHeight, painterColor); //如果快速移動畫筆的話,會出現斷續的現象,所以要插值 if (lastPaintX != 0 && lastPaintY != 0) { int lerpCount = (int)(1 / lerp); for (int i = 0; i <= lerpCount; i++) { int x = (int)Mathf.Lerp((float)lastPaintX, (float)texPosX, lerp); int y = (int)Mathf.Lerp((float)lastPaintY, (float)texPosY, lerp); currentTexture.SetPixels32(x, y, painterTipsWidth, painterTipsHeight, painterColor); } } currentTexture.Apply(); lastPaintX = texPosX; lastPaintY = texPosY; } else { lastPaintX = lastPaintY = 0; } } /// <summary> /// 設置當前畫筆所在的UV位置 /// </summary> /// <param name="x"></param> /// <param name="y"></param> public void SetPainterPositon(float x, float y) { paintPos.Set(x, y); } /// <summary> /// 畫筆當前是不是在畫畫 /// </summary> public bool IsDrawing { get { return isDrawing; } set { isDrawing = value; } } /// <summary> /// 使用當前正在畫板上的畫筆的顏色 /// </summary> /// <param name="color"></param> public void SetPainterColor(Color32 color) { if (!painterColor[0].IsEqual(color)) { for (int i = 0; i < painterColor.Length; i++) { painterColor[i] = color; } } } } public static class MethodExtention { /// <summary> /// 用于比較兩個Color32類型是不是同種顏色 /// </summary> /// <param name="origin"></param> /// <param name="compare"></param> /// <returns></returns> public static bool IsEqual(this Color32 origin, Color32 compare) { if (origin.g == compare.g && origin.r == compare.r) { if (origin.a == compare.a && origin.b == compare.b) { return true; } } return false; } }
下面這個腳本是掛在畫筆上的:
using UnityEngine; public class Painter : MonoBehaviour { /// <summary> /// 畫筆的顏色 /// </summary> public Color32 penColor; public Transform rayOrigin; private RaycastHit hitInfo; //這個畫筆是不是正在被手柄抓著 private bool IsGrabbing; private static Board board;//設置成類型的成員,而不是類型實例的成員,因為所有畫筆都是用的同一個board private void Start() { //將畫筆部件設置為畫筆的顏色,用于識別這個畫筆的顏色 foreach (var renderer in GetComponentsInChildren<MeshRenderer>()) { if (renderer.transform == transform) { continue; } renderer.material.color = penColor; } if (!board) { board = FindObjectOfType<Board>(); } } private void Update() { Ray r = new Ray(rayOrigin.position, rayOrigin.forward); if (Physics.Raycast(r, out hitInfo, 0.1f)) { if (hitInfo.collider.tag == "Board") { //設置畫筆所在位置對應畫板圖片的UV坐標 board.SetPainterPositon(hitInfo.textureCoord.x, hitInfo.textureCoord.y); //當前筆的顏色 board.SetPainterColor(penColor); board.IsDrawing = true; IsGrabbing = true; } } else if(IsGrabbing) { board.IsDrawing = false; IsGrabbing = false; } } }
關于“Unity如何實現VR中在黑板上寫字效果”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。