最近一直很多人私信问去年写的一篇:Unity中实现360°预览模型的文章,回看了一下去年写的文章,简直惨不忍睹,结构和思路都不太清晰,鉴于问的小伙伴有点多,这里重新写一下这篇文章,希望可以帮到大家。
一、实现方式
要实现模型的360°预览,主要有两种方式:
1. 旋转模型本身,通过改变模型在世界空间的欧拉角或者自身的旋转角来实现。
(将脚本挂载到需要旋转的物体上)
void Update () {
//transform.Rotate(0,30*Time.deltaTime,0);
if (Input.GetMouseButton (0)) {
//将屏幕坐标转化为世界坐标
var pos = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x,
Input.mousePosition.y, Camera.main.farClipPlane));
//求弧度
var radian = Mathf.Atan2 (-pos.y, pos.x);
//将弧度转化为角度
var angle = Mathf.Rad2Deg * radian;
//改变当前对象在世界空间中的旋转角度
transform.localEulerAngles = new Vector3 (0, angle, 0);
}
}
这种实现方式有很大的局限性,而且对于不规则的模型,比如人物,建筑物,这种实现方式看起来特别别扭,本文不在这里对这种实现方式做过多研究。
2.通过控制摄像机的旋转角度来达到模型旋转的目的,其原理就和我们用手机对一个物体进行360°拍照一样,使手机摄像头始终注视着物体,人拿着手机围绕着物体进行旋转,其呈现效果就好像模型自身在旋转一样。
其实要实现这样的效果很简单,Unity官方已经为我们提供了一个强大的相机插件包了,我们只需要将Unity自带的Cameras包导入到场景中,稍加按照我们的需求修改官方的源码,就能很轻易的实现。
1.导入资源包

2.从Asset中找到FreeLookCameraRig 预制体,放入场景中。


3.在使用前首先阅读以下Cameras下的CameraGuidelines使用说明书。
Camera Rig <- position will move towards target.
Pivot <- adjust Y position for height, X position for horizontal offset
Camera <- adjust Z position for distance away from target
Camera Rig 相机操控,移动相机的目标位置上,即将这个GameObject的position移动到
需要旋转查看的目标对象上,使二者的世界左边重合。
Pivot 锚点 改变Pivot的GameObject的Y最表调节高度,改变X坐标调节水平偏移
(最终效果是,物体在视窗中呈现的位置,如果X和Y均为0,则物体在视窗中居中显示,否则根据X和Y的值调整距离屏幕的距离)
Camera 主摄相机 调整这个对象的坐标的Z值来该表物体距离相机的远近程度,这里一般用来实现缩放效果
实现方式和插件的使用注意项大致到这里,下面开始代码部分。
二、实现过程
首先分析一下,我们需要通过手指滑动屏幕(或者是鼠标移动,或者是键盘输入的方式)来控制模型的旋转,当滑动手指时,模型旋转,当手指移开屏幕时,模型旋转速度逐渐变慢,直至速度变为0(停止),由于Unity官方已经封装了一个跨平台输入的插件,我们直接导入(CrossPlatformInput)使用就可以了。
1. 首先创建一个Image,用于接收用户输入,并附加一个TouchPad脚本。

在TouchPad.cs中声明两个变量,如下:
//水平输入值
public float XValue = 0;
//垂直输入值
public float YValue = 0;
修改UpdateVirtualAxes函数如下:
void UpdateVirtualAxes(Vector3 value)
{
value = value.normalized;
if (m_UseX)
{
m_HorizontalVirtualAxis.Update(value.x);
XValue = value.x;
}
if (m_UseY)
{
m_VerticalVirtualAxis.Update(value.y);
YValue = value.y;
}
}
修改Update()函数如下:
void Update()
{
if (!m_Dragging)
{
return;
}
if (Input.touchCount >= m_Id)
{
Vector2 pointerDelta;
pointerDelta.x = Input.mousePosition.x - m_PreviousMouse.x;
pointerDelta.y = Input.mousePosition.y - m_PreviousMouse.y;
m_PreviousMouse = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f);
UpdateVirtualAxes(new Vector3(pointerDelta.x, pointerDelta.y, 0));
}
}
以上函数尽量保持和我的一致,并将宏定义注释掉。如果不注释宏定义,导出真机测试时会达不到预想的效果。读者有时间的话也可以仔细读一下这个插件包的源代码,当时项目比较急,没有空做深入研究,用了这种暴力的方式,其实是不太好的。
2.在场景中找到FreeLookCameraRig对象,修改挂载的FreeLookCam.cs的脚本,增加以下代码:
//获取用户的输入值
public TouchPad touchPad;
//添加这个脚本目的是:有时需要禁用用户控制模型旋转,
//可以通过设置组件enabled=false的方式禁用组件,再次通过enabled=true的方式启用组件时,
//不会出现相机跳动的情况
private void OnEnable()
{
m_LookAngle = transform.localEulerAngles.y;
m_TiltAngle = transform.localEulerAngles.x;
}
接下来修改HandleRotationMovement()函数中的代码如下:
private void HandleRotationMovement()
{
if(Time.timeScale < float.Epsilon)
return;
// Read the user input
var x = touchPad.XValue;
var y = touchPad.YValue;
// Adjust the look angle by an amount proportional to the turn speed and horizontal input.
m_LookAngle += x*m_TurnSpeed;
// Rotate the rig (the root object) around Y axis only:
m_TransformTargetRot = Quaternion.Euler(0f, m_LookAngle, 0f);
if (m_VerticalAutoReturn)
{
// For tilt input, we need to behave differently depending on whether we're using mouse or touch input:
// on mobile, vertical input is directly mapped to tilt value, so it springs back automatically when the look input is released
// we have to test whether above or below zero because we want to auto-return to zero even if min and max are not symmetrical.
m_TiltAngle = y > 0 ? Mathf.Lerp(0, -m_TiltMin, y) : Mathf.Lerp(0, m_TiltMax, -y);
}
else
{
// on platforms with a mouse, we adjust the current angle based on Y mouse input and turn speed
m_TiltAngle -= y*m_TurnSpeed;
// and make sure the new value is within the tilt range
m_TiltAngle = Mathf.Clamp(m_TiltAngle, -m_TiltMin, m_TiltMax);
}
// Tilt input around X is applied to the pivot (the child of this object)
m_PivotTargetRot = Quaternion.Euler(m_TiltAngle, m_PivotEulers.y , m_PivotEulers.z);
if (m_TurnSmoothing > 0)
{
m_Pivot.localRotation = Quaternion.Slerp(m_Pivot.localRotation, m_PivotTargetRot, m_TurnSmoothing * Time.deltaTime);
transform.localRotation = Quaternion.Slerp(transform.localRotation, m_TransformTargetRot, m_TurnSmoothing * Time.deltaTime);
}
else
{
m_Pivot.localRotation = m_PivotTargetRot;
transform.localRotation = m_TransformTargetRot;
}
}
为FreeLookCam的Touchpad变量赋值,将之前创建的Image拖入到对应位置:

预览一下最终效果:

具体的大家可以下载工程文件研究一下,这里我就不坐过多的说明了,说的再多还不如看源码。强烈建议看源码,你会收获一些关于欧拉角、线性插值等等一些开发中常用的数学知识。如果有什么问题,可以在公众号私信我互相交流。
欢迎关注公众号: