您的位置:首页 > 编程语言 > Go语言

让我们克隆PokémonGO一样的游戏 - 1、AR模式

2016-12-05 16:59 417 查看
PokémonGO中的AR效果相对简单,用一个章节简单介绍。当然也可以用第三方SDK实现AR效果,如kudan、wikitude等都是自带SLAM功能的。

LZ的实际项目稍微复杂,用了真实的经纬度信息,在后台可以管理每个小精灵的刷新信息。相关内容还没有写到,暂时不作介绍。

资源来自于PokemonGO.apk,提取完发现没有Assets里没有一只小精灵,恐怕是做了AB,于是去国外网站找了一只没有动作的皮神。有兴趣的同学可以在这里下载更多。



如上图所示,我们要在一个场景中制作平面模式与AR模式的切换。确保层级遮挡关系正确,然后从最底层开始依次编辑每个层。



平面背景层 切分好的背景和树木用image组件拼好效果,填满画布。



AR背景层

新建RawImage,编辑脚本CameraAsBackground.cs,再挂上自带的组件AspectRatioFitter,控制画布比例。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class CameraAsBackground : MonoBehaviour
{
private RawImage image;
private WebCamTexture cam;
private AspectRatioFitter arf;

void Start ()
{
arf = GetComponent<AspectRatioFitter>();

image = GetComponent<RawImage>();
cam = new WebCamTexture(Screen.width,Screen.height);
image.texture = cam;
image.enabled = false;
}

void Update ()
{
if (cam.width < 100)
{
return;
}

float cwNeeded = -cam.videoRotationAngle;
if (cam.videoVerticallyMirrored)
{
cwNeeded += 180f;
}

image.rectTransform.localEulerAngles = new Vector3(0f,0f,cwNeeded);

float videoRatio = (float)cam.width / (float) cam.height;
arf.aspectRatio = videoRatio;

if (cam.videoVerticallyMirrored)
{
image.uvRect = new Rect(1, 0, -1, 1);
}
else
{
image.uvRect = new Rect(0,0,1,1);
}
}

public void videoTexture(bool isOpen)
{
if (isOpen)
{
image.enabled = true;
cam.Play();
}
else
{
cam.Stop();
image.enabled = false;
}
}
}
模型层

把皮神模型拖放到摄像机前合适的位置。Game面板中把比例调到Portrait方向预览。
UI层

新建CatchManager.cs。因为 “AR背景层” 是叠在 “平面背景层” 上面的,所以用AR切换开关控制该层显示与隐藏。ARMode挂上AR On/Off 两张状态图。

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class CatchManager : MonoBehaviour
{
private bool isARMode = false;
public Sprite[] ARMode;
public Image ARModeImage;
private GyroController gyroController;
private CameraAsBackground cameraAsBackground;

void Start ()
{
gyroController = GameObject.FindObjectOfType<GyroController>();
cameraAsBackground = GameObject.FindObjectOfType<CameraAsBackground>();
}

public void SwitchARMode ()
{
isARMode = !isARMode;
if (!isARMode)
{
ARModeImage.sprite = ARMode[0];
gyroController.DetachGyro();
cameraAsBackground.videoTexture(false);
}
else
{
ARModeImage.sprite = ARMode[1];
gyroController.AttachGyro();
cameraAsBackground.videoTexture(true);
}
}
}
摄像机层

在MainCamera挂上新建脚本GyroController.cs。这是一个调用陀螺仪,并平滑处理抖动的脚本。
using UnityEngine;

public class GyroController : MonoBehaviour
{
#region [Private fields]

private bool gyroEnabled = true;
private const float lowPassFilterFactor = 0.2f;

private readonly Quaternion baseIdentity = Quaternion.Euler(90, 0, 0);
private readonly Quaternion landscapeRight = Quaternion.Euler(0, 0, 90);
private readonly Quaternion landscapeLeft = Quaternion.Euler(0, 0, -90);
private readonly Quaternion upsideDown = Quaternion.Euler(0, 0, 180);

private Quaternion cameraBase = Quaternion.identity;
private Quaternion calibration = Quaternion.identity;
private Quaternion baseOrientation = Quaternion.Euler(90, 0, 0);
private Quaternion baseOrientationRotationFix = Quaternion.identity;

private Quaternion referanceRotation = Quaternion.identity;

#endregion

#region [Unity events]

void Start ()
{
DetachGyro();
}

void Update()
{
if (!gyroEnabled)
return;
transform.rotation = Quaternion.Slerp(transform.rotation, cameraBase * ( ConvertRotation(referanceRotation * Input.gyro.attitude) * GetRotFix()), lowPassFilterFactor);
}

#endregion

#region [Public methods]

// Attaches gyro controller to the transform.
public void AttachGyro()
{
Input.gyro.enabled = true;
gyroEnabled = true;
ResetBaseOrientation();
UpdateCalibration(true);
UpdateCameraBaseRotation(true);
RecalculateReferenceRotation();
}

// Detaches gyro controller from the transform
public void DetachGyro()
{
transform.rotation = Quaternion.identity;
gyroEnabled = false;
Input.gyro.enabled = false;
}

#endregion

#region [Private methods]

/// Update the gyro calibration.
private void UpdateCalibration(bool onlyHorizontal)
{
if (onlyHorizontal)
{
var fw = (Input.gyro.attitude) * (-Vector3.forward);
fw.z = 0;
if (fw == Vector3.zero)
{
calibration = Quaternion.identity;
}
else
{
calibration = (Quaternion.FromToRotation(baseOrientationRotationFix * Vector3.up, fw));
}
}
else
{
calibration = Input.gyro.attitude;
}
}

/// Update the camera base rotation.
/// Only y rotation.
private void UpdateCameraBaseRotation(bool onlyHorizontal)
{
if (onlyHorizontal)
{
var fw = transform.forward;
fw.y = 0;
if (fw == Vector3.zero)
{
cameraBase = Quaternion.identity;
}
else
{
cameraBase = Quaternion.FromToRotation(Vector3.forward, fw);
}
}
else
{
cameraBase = transform.rotation;
}
}

// Converts the rotation from right handed to left handed.
// The result rotation.
// The rotation to convert.
private static Quaternion ConvertRotation(Quaternion q)
{
return new Quaternion(q.x, q.y, -q.z, -q.w);
}

// Gets the rot fix for different orientations.
// The rot fix.
private Quaternion GetRotFix()
{
return Quaternion.identity;
}

// Recalculates reference system.
private void ResetBaseOrientation()
{
baseOrientationRotationFix = GetRotFix();
baseOrientation = baseOrientationRotationFix * baseIdentity;
}

// Recalculates reference rotation.
private void RecalculateReferenceRotation()
{
referanceRotation = Quaternion.Inverse(baseOrientation)*Quaternion.Inverse(calibration);
}

#endregion
}


附上本节完整Demo下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity pokemon AR