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
- 360奇酷手機自動旋轉螢幕怎麼關閉 360奇酷手機自動旋轉螢幕關閉教程
- 樂1s自動旋轉螢幕怎麼關閉 樂視超級手機1s自動旋轉螢幕關閉教程
- win10平板不能自動旋轉螢幕如何解決Win10
- Swift橫豎屏切換、自動旋轉螢幕、手動旋轉螢幕、鎖定當前螢幕禁止轉屏、橫豎屏頁面跳轉過度、橫豎屏UI適配SwiftUI
- 根據螢幕高度自適應元素高度
- android自適應螢幕方向和大小Android
- 網站如何自適應手機螢幕?網站
- 圖片大小自適應手機螢幕程式碼例項
- android系統如何自適應螢幕大小Android
- Qt:Qt自適應高解析度螢幕QT
- iOS 自定義tableView Cell、高度自適應iOSView
- 學習筆記:自適應佈局,多螢幕適配筆記
- ubuntu螢幕旋轉Ubuntu
- 怎麼讓body高度自適應螢幕?為什麼?
- orientationchange 螢幕旋轉事件事件
- HTML5 移動頁面自適應手機螢幕四類方法HTML
- android自適應滑動鍵盤產生的螢幕尺寸變化Android
- 判斷螢幕旋轉的事件程式碼事件
- Android 禁止螢幕旋轉Android
- mui 控制旋轉螢幕方向UI
- 自適應介面設計
- Web移動端 自適應縮放介面Web
- ios一句程式碼搞定螢幕旋轉iOS
- iOS螢幕旋轉解決方案iOS
- 自定義輸入框--超出限制動畫提示及自動轉行適配(待更新程式碼)動畫
- autorandr:自動調整螢幕佈局
- VMware ubuntu 自適應螢幕和檔案共享不顯示 解決Ubuntu
- PostgreSQL自定義自動型別轉換(CAST)SQL型別AST
- js判斷螢幕是否旋轉程式碼例項JS
- iOS 手勢操作:拖動、捏合、旋轉、點按、長按、輕掃、自定義iOS
- 自定義Mybatis自動生成程式碼規則MyBatis
- 記windows自定義bat指令碼自啟動WindowsBAT指令碼
- uni-app實戰:自定義掃碼介面APP
- 在自定義Screen上利用標準選擇螢幕的兩個方法 --- 轉自老白的部落格
- WPF控制元件介面自適應控制元件
- 螢幕旋轉的適配問題以及遇到的一些坑