Unity + ZXing + 屏幕旋转自动自适应 + 自定义扫码界面
2017-03-28 17:25
2471 查看
由于使用 ZXing 在unity进行二维码识别功能的人较多,这边我也试着使用了一下ZXing。发现如下几个问题:
ZXing仅仅只提供了二维码和条形码等的解码,并没有提供在unity中的预制件(也就是prefab)。这样就会导致很多第一次使用zxing的盆友,需要自己写一个自适应屏幕大小和根据屏幕旋转自动缩放的摄像机。
需要自行编写一个能够自适应屏幕大小和根据屏幕旋转自动缩放的摄像机,以保证渲染出来的WebCamTexture(就是摄像头获得过来的图像)不会拉伸。
Zxing的解码操作并不能放在update里进行操作,不然会计算量过大导致严重卡顿甚至卡死。
也是由于zxing的解码操作计算容易导致卡顿,从摄像头获得过来的texture(也就是WebCamTexture),不能使用高分辨率,不然也会卡死。
因此,我这边放出我的解决方案,供广大unity码农使用。下载包里面提供了预制件和使用示例。至于自定义扫码界面,因为我这边是unity的实现方式,并不是android或者ios等其他平台的原生扫码实现方式,所以直接在我的prefab的基础上加界面就可以了。
下载地址:ScanQRCoder.unitypackage
主要源码如下:
使用示例:
2017.04.05更新
现发现了新的实现方式,帧率和分辨率都非常满意!强烈推荐使用。
里面有示例场景。
下载地址:ScanQRCoder2
【个人广告】
希望大家可以支持我的个人微信号“小游戏情报局”
ZXing仅仅只提供了二维码和条形码等的解码,并没有提供在unity中的预制件(也就是prefab)。这样就会导致很多第一次使用zxing的盆友,需要自己写一个自适应屏幕大小和根据屏幕旋转自动缩放的摄像机。
需要自行编写一个能够自适应屏幕大小和根据屏幕旋转自动缩放的摄像机,以保证渲染出来的WebCamTexture(就是摄像头获得过来的图像)不会拉伸。
Zxing的解码操作并不能放在update里进行操作,不然会计算量过大导致严重卡顿甚至卡死。
也是由于zxing的解码操作计算容易导致卡顿,从摄像头获得过来的texture(也就是WebCamTexture),不能使用高分辨率,不然也会卡死。
因此,我这边放出我的解决方案,供广大unity码农使用。下载包里面提供了预制件和使用示例。至于自定义扫码界面,因为我这边是unity的实现方式,并不是android或者ios等其他平台的原生扫码实现方式,所以直接在我的prefab的基础上加界面就可以了。
下载地址:ScanQRCoder.unitypackage
主要源码如下:
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
【个人广告】
希望大家可以支持我的个人微信号“小游戏情报局”
相关文章推荐
- iphone应用程序中禁止屏幕自动旋转 自定义屏幕旋转
- android 界面自适应屏幕尺寸相关
- Cocos2d – 禁止屏幕自动旋转
- android自动屏幕旋转流程分析
- 【iOS】ios6.0 UINavigationController支持屏幕自动旋转
- android-自定义Camera竖屏时,摄像头自动旋转90度的解决方案
- android 界面自适应屏幕尺寸相关
- android怎样实现关闭系统自动旋转屏幕时能够自动横竖屏
- 屏幕旋转自动问题
- Unity--GUI 的旋转和自适应屏幕分辨率
- 关于设备屏幕自动旋转一些问题
- 屏幕自动旋转和调节大小
- 【iOS-cocos2d-X 游戏开发之十六】Cocos2dx编译后的Android自动使用(-hd)高清图&设置自适应屏幕
- Android 屏幕自动旋转-Sensor属性
- android自动屏幕旋转流程分析
- 屏幕自动旋转和调节大小
- Android屏幕自动旋转-Sensor属性
- UIView设置为自动适配屏幕时,当用户旋转设备的时候,会调用layoutSubviews方法,我们只需重写 这个方法,然后判断用户屏幕的方向。在调整每个空间的位置即可。
- 屏幕自动旋转和调节大小
- android的自定义camera竖屏时,摄像头自动旋转90度的解决方案