2016年,公司让开发google cardboard VR,下载google cardboard sdk并研究了一下,下面把自己的感受写出来,牢记一下过去的知识,也算共享。首先,请大家上网上下载google VR SDK,过去叫cardbord,现在叫GVR。sdk的下载请上https://developers.google.cn/vr/下载。现在google 已经将VR 发展为DayDream了,VR会越来越火啦。
Unity3d 的版本一定要用5.3.3f1版本,不然,发布出来的app会一直增长内存。
公司让我研究google VR 相机围绕目标点旋转,以鸟瞰俯视的角度来观看场景,点击 按钮,相机会平滑移动到某一位置观察场景。经过研究,google VR 是不能够改变角度位置的,不能修改GVRHead.cs脚本中的 GvrViewer.Instance.HeadPose.Orientation,为了实现围绕 中心点 旋转,我特意找到了类似 魔兽、仙剑奇侠传的相机功能的脚本WowMainCamera.cs。下面将WowMainCamera.csde 代码贴上
using UnityEngine;
using System.Collections;
public class WowMainCamera : MonoBehaviour
{
public bool HideAndShowCursor = true;
public bool LockRotationWhenRightClick = false;
public bool UseBlurEffect = true;
public bool UseFogEffect = true;
public Transform target;
public float targetHeight = 1.0f;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public float xSpeed = 250.0f;
public float ySpeed = 120.0f;
public int yMinLimit = -80;
public int yMaxLimit = 80;
public int zoomRate = 40;
public float rotationDampening = 3.0f;
public float zoomDampening = 10.0f;
private float x = 0.0f;
private float y = 0.0f;
private float currentDistance;
private float desiredDistance;
private float correctedDistance;
private bool grounded = false;
/// <summary>
/// 控制相机状态切换
/// </summary>
bool State;
/// <summary>
/// 外部调用
/// </summary>
public bool _State
{
get { return State; }
set { State = value; }
}
void Start ()
{
Vector3 angles = transform.eulerAngles;
x = angles.x;
y = angles.y;
currentDistance = distance;
desiredDistance = distance;
correctedDistance = distance - 0.2f;
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate ()
{
if(HideAndShowCursor)
{
if (Input.GetMouseButton(1) || Input.GetMouseButton(2))
{
Screen.lockCursor = true;
}
else
{
Screen.lockCursor = false;
}
}
// Don't do anything if target is not defined
if (!target)
{
GameObject go = GameObject.Find("Player");
target = go.transform;
transform.LookAt(target);
return;
}
// If either mouse buttons are down, let the mouse govern camera position
if (Input.GetMouseButton(1) || Input.GetMouseButton(2))
{
if (LockRotationWhenRightClick == false)
{
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
//控制一直摁住鼠标右键,镜头向前推进
if (!State)
{
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
}
}
}
// otherwise, ease behind the target if any of the directional keys are pressed
else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
{
float targetRotationAngle = target.eulerAngles.y;
float currentRotationAngle = transform.eulerAngles.y;
x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
}
y = ClampAngle(y, yMinLimit, yMaxLimit);
// set camera rotation
Quaternion rotation = Quaternion.Euler(y, x, 0);
#region 反方向控制角色的方向
/*
* 2013.3.11新增代码 反方向控制角色(Charactor)与第三人称相机旋转方向一致,可以使相机、角色方向始终超前
*/
Quaternion TargetRotation = Quaternion.Euler(0, x, 0);
if (target != null)
{
target.rotation = TargetRotation;
}
#endregion
desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
correctedDistance = desiredDistance;
// calculate desired camera position
Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
// check for collision using the true target's desired registration point as set by user using height
RaycastHit collisionHit;
Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
// if there was a collision, correct the camera position and calculate the corrected distance
bool isCorrected = false;
if (Physics.Linecast(trueTargetPosition, position, out collisionHit))
{
position = collisionHit.point;
correctedDistance = Vector3.Distance(trueTargetPosition, position);
isCorrected = true;
}
// For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
// recalculate position based on the new currentDistance
position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight - 0.05f, 0));
transform.rotation = rotation;
transform.position = position;
}
private static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
我将GVRHead.cs修改了一下,实现了围绕中心点旋转又能通过点击VR UI 中的按钮,实现 相机的旋转、相机的拉近拉远,下面将代码贴上
using UnityEngine;
[AddComponentMenu("GoogleVR/GvrHead")]
public class GvrHead : MonoBehaviour
{
public bool trackRotation = true;
public bool trackPosition = false;
public Transform target;
public AngleData angleData;
public bool updateEarly = false;
/// Returns a ray based on the heads position and forward direction, after making
/// sure the transform is up to date. Use to raycast into the scene to determine
/// objects that the user is looking at.
public Ray Gaze
{
get
{
UpdateHead();
return new Ray(transform.position, transform.forward);
}
}
public delegate void HeadUpdatedDelegate(GameObject head);
/// Called after the head pose has been updated with the latest sensor data.
public event HeadUpdatedDelegate OnHeadUpdated;
private static GvrHead instance;
public static GvrHead Instance
{
get { return instance; }
}
public bool isOverrideOribit = true;
private bool updated;
Quaternion rot=Quaternion.identity;
public float rotLimitTime = 1.0f;
public float targetHeight = 1.0f;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public int yMinLimit = -80;
public int yMaxLimit = 80;
private float x = 0.0f;
private float y = 0.0f;
public float zoomRate = 40;
public float zoomDampening = 10.0f;
[SerializeField]
private float currentDistance;
public float desiredDistance;
[SerializeField]
private float correctedDistance;
private bool grounded = false;
private float scrollWheel;
public ScrollWheelDatas scrollWheelDatas;
private bool isMove;
public float moveTime = 1.5f;
private CamMoveDatas middlePoint;
private bool desiredDistanceMove;
private float desiredMoveTime;
public float lastDesiredDistance;
void Awake()
{
GvrViewer.Create();
if (!instance)
{
instance = this;
}
}
private void Start()
{
if (this.enabled)
{
currentDistance = distance;
desiredDistance = distance;
correctedDistance = distance - 0.2f;
if (GetComponent<Rigidbody>())
{
GetComponent<Rigidbody>().freezeRotation = true;
}
scrollWheelDatas.scrollWheelAdd = scrollWheelDatas.scrollWheelMax;
}
}
private void Update()
{
updated = false; // OK to recompute head pose.
if (updateEarly)
{
UpdateHead();
}
}
// Normally, update head pose now.
private void LateUpdate()
{
UpdateHead();
}
// Compute new head pose.
private void UpdateHead()
{
// Don't do anything if target is not defined
if (!target&& updated)
{
return;
}
updated = true;
GvrViewer.Instance.UpdateState();
if (trackRotation)
{
if (isMove)
{
if (middlePoint != null)
{
angleData.x = Mathf.Lerp(angleData.x, middlePoint.x, moveTime * Time.deltaTime);
angleData.y = Mathf.Lerp(angleData.y, middlePoint.y, moveTime * Time.deltaTime);
desiredDistance = Mathf.Lerp(desiredDistance, middlePoint.desiredDistance, moveTime * Time.deltaTime);
if ((Mathf.Abs(angleData.x - middlePoint.x) <= 0.01f) && (Mathf.Abs(angleData.y - middlePoint.y) <= 0.01f) && (Mathf.Abs(desiredDistance - middlePoint.desiredDistance) <= 0.01f))
{
angleData.x = middlePoint.x;
angleData.y = middlePoint.y;
desiredDistance = middlePoint.desiredDistance;
isMove = false;
}
}
}
if (desiredDistanceMove)
{
lastDesiredDistance = Mathf.Clamp(lastDesiredDistance, minDistance, maxDistance);
desiredDistance = Mathf.Lerp(desiredDistance, lastDesiredDistance, desiredMoveTime * Time.deltaTime);
if ((Mathf.Abs(desiredDistance - lastDesiredDistance) <= 0.01f))
{
desiredDistance = lastDesiredDistance;
desiredDistanceMove = false;
}
}
Quaternion limitRotation = GvrViewer.Instance.HeadPose.Orientation*Quaternion.Euler(angleData.x, angleData.y, 0);
rot = Quaternion.Slerp(rot, limitRotation, rotLimitTime);
if (isOverrideOribit)
{
x = rot.eulerAngles.y;
y = rot.eulerAngles.x;
y = ClampAngleX(y, yMinLimit, yMaxLimit);
Quaternion rotation = Quaternion.Euler(y, x, 0);
#region 反方向控制角色的方向
/*
* 2013.3.11新增代码 反方向控制角色(Charactor)与第三人称相机旋转方向一致,可以使相机、角色方向始终超前
*/
Quaternion TargetRotation = Quaternion.Euler(0, x, 0);
if (target != null)
{
target.rotation = TargetRotation;
}
#endregion
#region 限制鼠标中轮向前推进
desiredDistance -= scrollWheel * Time.deltaTime * zoomRate;
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
#endregion
correctedDistance = desiredDistance;
Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
#region 当相机遇到碰撞后,相机收缩
RaycastHit collisionHit;
Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
bool isCorrected = false;
if (Physics.Linecast(trueTargetPosition, position, out collisionHit))
{
position = collisionHit.point;
correctedDistance = Vector3.Distance(trueTargetPosition, position);
isCorrected = true;
}
#endregion
currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight - 0.05f, 0));
transform.rotation = rotation;
transform.position = position;
}
else
{
transform.rotation = Quaternion.Euler(rot.eulerAngles.x, rot.eulerAngles.y, 0);
}
}
if (OnHeadUpdated != null)
{
OnHeadUpdated(gameObject);
}
}
public void VRCameraMoveForward()
{
scrollWheelDatas.isForward = true;
scrollWheelDatas.isReverse = false;
scrollWheel = 0;
scrollWheel += scrollWheelDatas.scrollWheelAdd;
}
public void VRCameraMoveReverse()
{
scrollWheelDatas.isForward = false;
scrollWheelDatas.isReverse = true;
scrollWheel = 0;
scrollWheel -= scrollWheelDatas.scrollWheelAdd;
}
public void CameraMove(CamMoveDatas camMoveDatas)
{
isMove = true;
middlePoint = camMoveDatas;
}
public void CameraDesiredMove(float targetDistance,float time=1.5f)
{
desiredDistanceMove = true;
lastDesiredDistance = targetDistance;
desiredMoveTime = time;
}
public void SetDistances(float value)
{
currentDistance = desiredDistance = correctedDistance = value;
}
private float ClampAngleX(float angle, float min, float max)
{
if (angle < 0)
angle -= angle * 2;
if (angle > 90)
angle -= ((angle - 90) * 2);
return Mathf.Clamp(angle, min, max);
}
}
[System.Serializable]
public class ScrollWheelDatas
{
public bool isForward;
public bool isReverse;
public float scrollWheelMax;
public float scrollWheelMin;
public float scrollWheelAdd;
}
[System.Serializable]
public class AngleData
{
public float x;
public float y;
}
[System.Serializable]
public class CamMoveDatas
{
public float x;
public float y;
public float desiredDistance;
}
测试调用代码 CameraJump.cs
using UnityEngine;
using System.Collections;
public class CameraJump : MonoBehaviour
{
public GvrHead gvrhead;
public CamMoveDatas original;
public CamMoveDatas point;
private void Start()
{
}
void OnGUI()
{
if (GUILayout.Button("位置1", GUILayout.MinWidth(200), GUILayout.MinHeight(80)))
{
gvrhead.CameraMove(point);
}
if (GUILayout.Button("Original", GUILayout.MinWidth(200), GUILayout.MinHeight(80)))
{
gvrhead.CameraMove(original);
}
if (GUILayout.Button("扩大", GUILayout.MinWidth(200), GUILayout.MinHeight(80)))
{
gvrhead.CameraDesiredMove(400, 5.0f);
}
if (GUILayout.Button("缩小", GUILayout.MinWidth(200), GUILayout.MinHeight(80)))
{
gvrhead.CameraDesiredMove(150,5.0f);
}
}
}
下面给几个cardboard的学习网址
http://www.chinaar.com/unity/2212.html
http://www.taidous.com/thread-43648-1-1.html
http://www.taidous.com/thread-44054-1-1.html
http://www.taidous.com/thread-50872-1-1.html
http://www.taidous.com/thread-50876-1-1.html
学习如果遇到问题,请google 查看 API 或 github 上找到google 开源 GVR 上面的 https://github.com/googlevr/gvr-unity-sdk/issues
下面上传demo地址http://download.csdn.net/detail/yuyingwin/9757218