在VR虚拟场景的物理实验室模块中,我想做一个切割磁感线发电机的模拟装置;为了让用户更加真实的操作设备,让用户通过手柄的旋转手势,实现转盘的同步转动。
(之后补gif图)
原理,获取到需要转动的物体中心的位置,记录鼠标按下的瞬间的位置,按下后计算每帧的鼠标移动的位置,通过这三个位置,计算角度,(即鼠标按下时与物体中心的连线 和 每一帧鼠标位置与物体中心的连线的夹角)。
通过四元数判断旋转的方向的,通过 transform.localEluerAngles方法,控制物体旋转。
modelPos = ca.WorldToScreenPoint(target1.transform.position);
坐标系转换,从世界坐标系到屏幕位置转换(屏幕位置以像素定义,左下为0,0;z的位置是以世界坐标系衡量的到相机的距离)。括号里加三维向量。
详见Unity3D中Camera类的方法。
static function Angle (from : Vector3, to : Vector3) : float
RotateAngle = Vector3.Angle (preMousePos - modelPos, mousePos - modelPos);
由from和to两者返回一个角度;即,他们的夹角。初始鼠标位置与中心,当前鼠标位置与中心的夹角。
q = Quaternion.FromToRotation (preMousePos - modelPos,mousePos - modelPos); float k = q.z > 0 ? 1 : -1;
四元数,根据q的z值,判断旋转方向是顺时针还是逆时针。z为正逆时针,为负顺时针。
大于0返回1小于0返回-1。条件运算符?:
target1.transform.localEulerAngles = localEluer;
localEulerAngles,自身欧拉角,用于读取和设置角度。等号右边是三维向量。
即transform.localEulerAngles = new Vector3(0,0,0);物体的旋转方向是默认方向。
transform.localEulerAngles = new Vector3(90,0,0);沿x轴指向,逆时针旋转90度。
transform.localEulerAngles = new Vector3(0,90,0);沿y轴指向,逆时针旋转90度。
如果将上述角度改成负数,沿着改变轴的方向,变为顺时针。
angle = localEluer.z = Mathf.Clamp (localEluer.z,-36000,36000);
static function Clamp (value : float, min : float, max : float) : float
Mathf.Clamp限制。限制value的值在min和max之间,以满足某些功能的需要。如果value小于min,返回min;如果value大于max,返回max,否则返回value。
//圣典案例 // Set the position of the transform to be that of the time // but never less than 1 or more than 3 //随着时间设置变换位置 //但是不会小于1或大于3 function Update () { transform.position = Vector3(Mathf.Clamp(Time.time, 1.0, 3.0), 0, 0); }
参数可以为float也可以为int。
源码
public Camera ca; private Quaternion q; private Vector3 mousePos; private Vector3 preMousePos; private Vector3 modelPos; private Vector3 localEluer; private bool IsSelect = false; private float RotateAngle; private float angle; public Transform target1; // Use this for initialization void Start () { modelPos = ca.WorldToScreenPoint(target1.transform.position); angle = localEluer.z; target1.transform.localEulerAngles = localEluer; } // Update is called once per frame void Update () { if(Input.GetMouseButtonDown (0)){ IsSelect = true; preMousePos = mousePos = Input.mousePosition; } if (Input.GetMouseButton (0) && IsSelect) { IsSelect = true; mousePos = Input.mousePosition; RotateAngle = Vector3.Angle (preMousePos - modelPos, mousePos - modelPos); //print (RotateAngle); if (RotateAngle == 0) { preMousePos = mousePos; } else { q = Quaternion.FromToRotation (preMousePos - modelPos,mousePos - modelPos); float k = q.z > 0 ? 1 : -1; localEluer.z += k * RotateAngle; Debug.Log (localEluer.x); angle = localEluer.z = Mathf.Clamp (localEluer.z,-36000,36000); target1.transform.localEulerAngles = localEluer; preMousePos = mousePos; } } if(Input.GetMouseButtonUp(0)){ IsSelect = false; } }