Unity + ZXing + 螢幕旋轉自動自適應 + 自定義掃碼介面
由於使用 ZXing 在unity進行二維碼識別功能的人較多,這邊我也試著使用了一下ZXing。發現如下幾個問題:
- ZXing僅僅只提供了二維碼和條形碼等的解碼,並沒有提供在unity中的預製件(也就是prefab)。這樣就會導致很多第一次使用zxing的盆友,需要自己寫一個自適應螢幕大小和根據螢幕旋轉自動縮放的攝像機。
- 需要自行編寫一個能夠自適應螢幕大小和根據螢幕旋轉自動縮放的攝像機,以保證渲染出來的WebCamTexture(就是攝像頭獲得過來的影象)不會拉伸。
- Zxing的解碼操作並不能放在update裡進行操作,不然會計算量過大導致嚴重卡頓甚至卡死。
- 也是由於zxing的解碼操作計算容易導致卡頓,從攝像頭獲得過來的texture(也就是WebCamTexture),不能使用高解析度,不然也會卡死。
因此,我這邊放出我的解決方案,供廣大unity碼農使用。下載包裡面提供了預製件和使用示例。至於自定義掃碼介面,因為我這邊是unity的實現方式,並不是android或者ios等其他平臺的原生掃碼實現方式,所以直接在我的prefab的基礎上加介面就可以了。
主要原始碼如下:
using UnityEngine;
using System.Collections;
using ZXing;
using System;
using System.Runtime.InteropServices;
public class ScanQRCoder : MonoBehaviour
{
public static event Action<string> OnDecoderMessage;
private Camera renderCam;
private MeshRenderer meshRender;
private WebCamTexture webCamTexture;
private DeviceOrientation lastDeviceOrientation;
public void ReInitRect()
{
StopCoroutine(DecodeQR());
webCamTexture.Stop();
Start();
}
private void Start()
{
lastDeviceOrientation = Input.deviceOrientation;
Init();
meshRender.material.mainTexture = webCamTexture;
webCamTexture.Play();
StartCoroutine(DecodeQR());
}
private void Init()
{
renderCam = GetComponentInChildren<Camera>();
int webCamDeviceIndex = -1;
for (int i = 0; i < WebCamTexture.devices.Length; i++)
{
if (!WebCamTexture.devices[i].isFrontFacing)
{
webCamDeviceIndex = i;
break;
}
}
if (webCamDeviceIndex == -1 && WebCamTexture.devices.Length > 0) webCamDeviceIndex = 0;
Vector3[] camfov = GetCameraFovPositionByDistance(renderCam, renderCam.transform.localPosition.y);
float w = Vector3.Distance(camfov[1], camfov[0]);
float h = Vector3.Distance(camfov[2], camfov[0]);
if(Screen.width >= Screen.height)
{
h = w;
}
else
{
w = h;
}
meshRender = GetComponentInChildren<MeshRenderer>();
meshRender.transform.localScale = new Vector3(w / 10, 1, h / 10);
webCamTexture = new WebCamTexture(WebCamTexture.devices[webCamDeviceIndex].name, 200, 200);//這裡的第二第三個引數可以根據機子的效能而調高,也就是解析度越高
}
void onDecoderMessage(string code)
{
if (OnDecoderMessage != null)
{
OnDecoderMessage(code);
Debug.Log("code:" + code);
}
}
private IEnumerator DecodeQR()
{
yield return new WaitForSeconds(1f);
try
{
var barcodeReader = new BarcodeReader { AutoRotate = true, TryHarder = true };
Result result = barcodeReader.Decode(webCamTexture.GetPixels32(), webCamTexture.width, webCamTexture.height);
//Debug.Log("QR Code w h: " + webCamTexture.width + " " + webCamTexture.height);
if (result != null)
{
onDecoderMessage(result.Text);
//Debug.Log("QR Code: " + result.Text);
}
}
catch { }
if (Input.deviceOrientation != lastDeviceOrientation)
{
ReInitRect();
}
else
{
if (webCamTexture.isPlaying)
StartCoroutine(DecodeQR());
}
}
private static byte[] ColorArrayToByteArray(Color[] colors)
{
if (colors == null || colors.Length == 0)
return null;
int lengthOfColor32 = Marshal.SizeOf(typeof(Color));
int length = lengthOfColor32 * colors.Length;
byte[] bytes = new byte[length];
GCHandle handle = default(GCHandle);
try
{
handle = GCHandle.Alloc(colors, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
Marshal.Copy(ptr, bytes, 0, length);
}
finally
{
if (handle != default(GCHandle))
handle.Free();
}
return bytes;
}
/// <summary>
/// 獲取指定距離下相機視口四個角的座標
/// </summary>
private Vector3[] GetCameraFovPositionByDistance(Camera cam, float distance)
{
Vector3[] corners = new Vector3[4];
Array.Resize(ref corners, 4);
// Top left
corners[0] = cam.ViewportToWorldPoint(new Vector3(0, 1, distance));
// Top right
corners[1] = cam.ViewportToWorldPoint(new Vector3(1, 1, distance));
// Bottom left
corners[2] = cam.ViewportToWorldPoint(new Vector3(0, 0, distance));
// Bottom right
corners[3] = cam.ViewportToWorldPoint(new Vector3(1, 0, distance));
return corners;
}
}
使用示例:
using UnityEngine;
using System.Collections;
public class ScanQRCoderDemo : MonoBehaviour
{
public ScanQRCoder scanner;
private void OnEnable()
{
ScanQRCoder.OnDecoderMessage += OnDecoderMessage;
}
private void OnDisable()
{
ScanQRCoder.OnDecoderMessage -= OnDecoderMessage;
}
public void OnDecoderMessage(string msg)
{
Debug.Log("二維碼資訊:" + msg);
}
}
2017.04.05更新
現發現了新的實現方式,幀率和解析度都非常滿意!強烈推薦使用。
裡面有示例場景。
下載地址:ScanQRCoder2
【個人廣告】
希望大家可以支援我的個人微訊號“小遊戲情報局”
相關文章
- Android 螢幕自適應Android
- Unity3D結合NGUI的螢幕自適應程式碼分享Unity3DNGUI
- Swift橫豎屏切換、自動旋轉螢幕、手動旋轉螢幕、鎖定當前螢幕禁止轉屏、橫豎屏頁面跳轉過度、橫豎屏UI適配SwiftUI
- win10平板不能自動旋轉螢幕如何解決Win10
- 網站如何自適應手機螢幕?網站
- ubuntu螢幕旋轉Ubuntu
- Qt:Qt自適應高解析度螢幕QT
- 學習筆記:自適應佈局,多螢幕適配筆記
- Android 禁止螢幕旋轉Android
- orientationchange 螢幕旋轉事件事件
- 怎麼讓body高度自適應螢幕?為什麼?
- mui 控制旋轉螢幕方向UI
- ios一句程式碼搞定螢幕旋轉iOS
- iOS螢幕旋轉解決方案iOS
- 自適應介面設計
- Web移動端 自適應縮放介面Web
- uni-app實戰:自定義掃碼介面APP
- android 螢幕適配一:通過自定義View的方式實現適配AndroidView
- 記windows自定義bat指令碼自啟動WindowsBAT指令碼
- 自定義Mybatis自動生成程式碼規則MyBatis
- JMeter 介面自動化測試(手工轉自動化指令碼)JMeter指令碼
- Android SeekBar 自定義thumb,thumb旋轉動畫效果Android動畫
- 瞭解Android核心元件活動生命週期————旋轉螢幕Android元件
- WPF控制元件介面自適應控制元件
- 平板Win8電腦升級Win10系統後螢幕不能自動旋轉怎麼解決Win10
- 自定義 SAP 採購訂單螢幕
- Unity觸控式螢幕觸控事件定義Unity事件
- springboot+redis+Interceptor+自定義annotation實現介面自動冪等Spring BootRedis
- SpringBoot自動裝配-自定義StartSpring Boot
- 自動載入的iframe高度自適應
- java 企業 網站原始碼 模版 螢幕自適應 有前後臺 springmvc SSM 生成靜態化Java網站原始碼SpringMVCSSM
- win10螢幕亮度自動變暗怎麼辦_win10螢幕亮度自動變暗的解決方法Win10
- [教程文件]html5實現圖片自適應手機螢幕頁面的cssHTMLCSS
- @media 移動端螢幕適配
- gridview自動適應列寬View
- 螢幕適配
- 新型掩碼自編碼器 AdaMAE,自適應取樣
- Oracle RAC的自定義service自啟動Oracle
- Win10系統下怎麼禁止螢幕旋轉Win10