最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Unity實現(xiàn)VR中在黑板上寫字效果

 更新時間:2019年07月16日 11:12:04   作者:Marsir  
這篇文章主要為大家詳細介紹了Unity實現(xiàn)VR中在黑板上寫字效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Unity實現(xiàn)VR中在黑板上寫字的具體代碼,供大家參考,具體內(nèi)容如下

一、工具

1.開發(fā)用的是Unity 5.6.2版本

2.VR中的物理交互用的是VRTK插件,這個插件集成了比較好的物理交互功能;

3.HTC Vive

二、概述

實現(xiàn)的功能: 在一個白板上,用不同顏色的筆,在白板畫出任何想要的圖形;

因為只是一個初級篇所以只是用兩個腳本簡單的實現(xiàn),而且并沒有黑板擦等功能 ,也不能兩個筆同時畫畫,這些功能將會在未來的升級篇中寫出;

三、知識點

其實這個功能很簡單,只是簡單的運用Unity Texure2D類中的兩個函數(shù):

public void SetPixels32(int x, int y, int blockWidth, int blockHeight, Color32[] colors, int miplevel = 0);

前面4個參數(shù)相當于一個矩形,x和y就是矩形的左下角的那個點,blockWidth和blockHeight分別是矩形的寬和高,這個矩形所代表的范圍就是blockWidth*blockHeight個像素所在的位置,不妨稱這個矩形范圍為一個色塊;

colors這個參數(shù)的大小必須等于blockWidth*blockHeight,因為這個方法就是給坐標(x,y)開始,從左到右,從下到上,一行一行的對矩形范圍內(nèi)的每個像素賦值;

也就是把colors[0]~colors[blockWidth - 1]分別賦值到坐標為(x,y)~(x + blockWidth,y)的像素,以此類推;

最后一個參數(shù),因為我們用的圖片把Generate Min Maps這個選項關(guān)閉了,所以用默認的可選參數(shù)0;

public void Apply(bool updateMipmaps = true, bool makeNoLongerReadable = false);

當對圖片改動完成以后,需要調(diào)用這個方法,才能讓改動真正的應(yīng)用在圖片上;

四、場景搭建

1.畫板

在場景中建一個Quad,把它的x和y方向的Scale分別設(shè)置為1.92和1.08(或者其它尺寸);注意這個Quad一定要用Mesh Collider作為碰撞體,不然到時候射線獲取的紋理坐標有誤,并為它設(shè)置一個Tag為Board;

2.筆

建一個尺寸合適的筆,創(chuàng)建一個空的子物體,命名為SnapPoint,并設(shè)置SnapPoint的Z方向指向筆尖方向,這個子物體就是,手柄拿筆的位置就是,并且保證筆的姿態(tài)是相當于人正常拿筆的樣子;

3.其它

創(chuàng)建一個放筆的物體,讓筆處于比較好拿的位置;

我的場景中代表畫板的是WhiteBoard下的Board物體;

五、代碼實現(xiàn)功能

這個腳本是掛在代表畫板的物體上的:

using System.Linq;
using UnityEngine;

/// <summary>
/// 畫板
/// </summary>
public class Board : MonoBehaviour
{
 //當畫筆移動速度很快時,為了不出現(xiàn)斷斷續(xù)續(xù)的點,所以需要對兩個點之間進行插值,lerp就是插值系數(shù)
 [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

 //設(shè)置當前圖片
 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);
  //如果快速移動畫筆的話,會出現(xiàn)斷續(xù)的現(xiàn)象,所以要插值
  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>
 /// 設(shè)置當前畫筆所在的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;//設(shè)置成類型的成員,而不是類型實例的成員,因為所有畫筆都是用的同一個board

 private void Start()
 {
 //將畫筆部件設(shè)置為畫筆的顏色,用于識別這個畫筆的顏色
 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")
  {
  //設(shè)置畫筆所在位置對應(yīng)畫板圖片的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;
 }
 }

}

六、等待完善的地方

1.畫筆所能畫的最小點是有大小的,也就是SetPixels參數(shù)中的blockWidth*blockHeight的大小,當這個畫筆在畫板的邊緣的時候,那么這個畫筆所能畫的色塊的矩形范圍就到圖片之外去了,這會引起未處理異常;

2.同時只有一個筆能在畫板上畫畫;

3.沒有黑板擦功能;

4.沒有顏色混合功能;

5.畫筆是純粹的顏色,其實可以用一個圖片設(shè)置畫筆的形狀;

6.筆可以穿透畫板

這些問題都將在升級篇中完善;

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于C#編寫獲取硬件信息的工具類

    基于C#編寫獲取硬件信息的工具類

    這篇文章主要為大家詳細介紹了如何利用C#編寫一個獲取硬件信息的簡單工具類,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-11-11
  • C#泛型編程介紹

    C#泛型編程介紹

    泛型:通過參數(shù)化類型來實現(xiàn)在同一份代碼上操作多種數(shù)據(jù)類型。利用“參數(shù)化類型”將類型抽象化,從而實現(xiàn)靈活的復用
    2013-09-09
  • C#設(shè)計模式之Builder生成器模式解決帶老婆配置電腦問題實例

    C#設(shè)計模式之Builder生成器模式解決帶老婆配置電腦問題實例

    這篇文章主要介紹了C#設(shè)計模式之Builder生成器模式解決帶老婆配置電腦問題,簡單介紹了生成器模式的概念、功能并結(jié)合具體實例形式分析了C#生成器模式解決配電腦問題的步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2017-09-09
  • C# 設(shè)計模式系列教程-策略模式

    C# 設(shè)計模式系列教程-策略模式

    策略模式是一種定義一系列算法的方法,從概念上來看,所有算法完成的都是相同的工作,只是實現(xiàn)不同,它可以以相同的方式調(diào)用所有的算法,減少了各種算法類與使用算法類之間的耦合。
    2016-06-06
  • C# 表達式目錄樹Expression的實現(xiàn)

    C# 表達式目錄樹Expression的實現(xiàn)

    本文主要介紹了C# 表達式目錄樹Expression的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C#實現(xiàn)多線程編程的簡單案例

    C#實現(xiàn)多線程編程的簡單案例

    這篇文章介紹了C#實現(xiàn)多線程編程的簡單案例,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • c# 實現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的簡單實例

    c# 實現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的簡單實例

    下面小編就為大家?guī)硪黄猚# 實現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • c#不使用windows api函數(shù)打開我的電腦和獲取電腦驅(qū)動器信息

    c#不使用windows api函數(shù)打開我的電腦和獲取電腦驅(qū)動器信息

    這篇文章主要介紹了c#不使用windows api函數(shù)打開我的電腦和電腦驅(qū)動器信息的方法,大家參考使用
    2013-12-12
  • C# 可空類型的具體使用

    C# 可空類型的具體使用

    這篇文章主要介紹了C# 可空類型的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • 微信小程序支付C#后端源碼

    微信小程序支付C#后端源碼

    這篇文章主要為大家詳細介紹了微信小程序支付C#后端源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08

最新評論

岳阳市| 新巴尔虎右旗| 二连浩特市| 紫云| 施甸县| 玛纳斯县| 浠水县| 汕尾市| 中山市| 孝昌县| 广丰县| 阿拉善盟| 北票市| 赤峰市| 栖霞市| 松原市| 宁河县| 扶风县| 邹平县| 武强县| 宜君县| 开原市| 美姑县| 沁水县| 阆中市| 乌海市| 扶沟县| 阿瓦提县| 厦门市| 汉源县| 巴彦淖尔市| 布尔津县| 常山县| 柳州市| 嘉义县| 建湖县| 论坛| 休宁县| 台南县| 鄱阳县| 临邑县|