標籤:
剛接觸Unity不久,正處於用什麼學什麼的狀態,遇到這個問題著實研究了一陣子,得到了一個比較笨的方法。
想要完成的功能有兩個,一是攝像機繞著整個情境中的所有模型旋轉,旋轉的中心點是全局座標的原點;二是不管攝像機旋轉到什麼位置,模型都能跟隨滑鼠進行移動。
單獨的讓攝像機繞全局座標原點旋轉可以使用transform.RotateAround(Vector3.zero, Vector3.down, mouseMovex * Time.deltaTime)。但是問題來了,如果只是進行水平方向或是垂直方向上的單方向的旋轉,簡單的使用transform.RotateAround(Vector3.zero, Vector3.down, mouseMovex * Time.deltaTime)是可以的;如果需要水平方向和垂直方向的混合旋轉,就會出現問題,而這個問題就出在Vector3.down上。對於使用者來說,在滑鼠拖拽旋轉的過程中,是以螢幕座標為準的。也就是說這個Vector3.down對於使用者來說是螢幕座標的y軸,只有第一次旋轉的時候螢幕座標的x、y軸與全局座標的x、y軸是重合的,只要攝像機進行過一次旋轉,螢幕座標與全局座標就不再重合。所以當多次旋轉時,就會出現混亂。不只是旋轉,滑鼠對模型的拖拽也會出現嚴重的偏差。這就需要在每一次旋轉前對旋轉軸進行修正。我的方法是在攝像機x方向加一和y方向加一各添加一個Empty GameObject與攝像機進行同步旋轉,作為方向標誌物。在每一次旋轉前,擷取攝像機與兩個方向標誌物的全局座標,進而計算出螢幕座標軸在全局座標中的方向向量,來確定攝像機的旋轉軸。代碼如下:
1 using UnityEngine; 2 using System.Collections; 3 4 public class scencerotate : MonoBehaviour { 5 6 Vector2 mousePositionBefore, mousePositionAfter; //用來記錄滑鼠的位置,以便計算旋轉幅度 7 private GameObject camera; //儲存攝像機資訊 8 private GameObject xflagGameObject; //儲存x方向標誌物的資訊 9 private GameObject yflagGameObject; //儲存y方向標誌物的資訊10 private Vector3 xdirVector; //螢幕座標x方向在全局座標中的方向向量11 private Vector3 ydirVector; //螢幕座標y方向在全局座標中的方向向量12 13 // Use this for initialization14 void Start () 15 { 16 }17 18 // Update is called once per frame19 void Update () 20 {21 if (Input.GetMouseButtonDown(1)) //檢測滑鼠右鍵是否被按下22 {23 xflagGameObject = GameObject.Find("xFlag(Clone)");24 yflagGameObject = GameObject.Find("yFlag(Clone)");25 camera = GameObject.Find("Main Camera");26 xdirVector = xflagGameObject.transform.position - camera.transform.position; //得到螢幕座標的x方向在全局座標系下的方向向量27 ydirVector = yflagGameObject.transform.position - camera.transform.position; //得到螢幕座標的y方向在全局座標系下的方向向量28 mousePositionBefore = new Vector2(Input.mousePosition.x, Input.mousePosition.y); //滑鼠右鍵按下時記錄滑鼠位置mousePositionBefore29 }30 if (Input.GetMouseButton(1)) //檢測滑鼠右鍵是否被按著31 {32 mousePositionAfter = new Vector2(Input.mousePosition.x, Input.mousePosition.y); //滑鼠右鍵拖動時記錄滑鼠位置mousePositionAfter33 //下面開始旋轉34 float mouseMovex = (mousePositionAfter.x - mousePositionBefore.x) * 0.1f;35 float mouseMovey = (mousePositionAfter.y - mousePositionBefore.y) * 0.1f;36 transform.RotateAround(Vector3.zero, ydirVector, mouseMovex * Time.deltaTime); //在螢幕座標系水平方向上進行旋轉37 transform.RotateAround(Vector3.zero, -xdirVector, mouseMovey) * Time.deltaTime); //在螢幕座標系垂直方向上進行旋轉38 }39 }40 }
把以上指令碼放到攝像機上即可。模型移動是一樣的方法
1 using UnityEngine; 2 using System.Collections; 3 4 public class move : MonoBehaviour 5 { 6 private GameObject camera; //儲存攝像機資訊 7 private GameObject xflagGameObject; //儲存x方向標誌物的資訊 8 private GameObject yflagGameObject; //儲存y方向標誌物的資訊 9 private Vector3 xdirVector; //螢幕座標x方向在全局座標中的方向向量10 private Vector3 ydirVector; //螢幕座標y方向在全局座標中的方向向量11 private Vector3 moveModel; //模型在全局座標中的移動向量12 13 // Use this for initialization14 15 void Start()16 {17 18 }19 20 // Update is called once per frame21 22 void Update()23 {24 25 }26 27 //下面的函數是當滑鼠觸碰到碰撞體或者剛體時調用,我的碰撞體設定是mesh collider,然後別忘了,給這個collider添加物理材質28 //值得注意的是全局座標系轉化為螢幕座標系,Z軸是不變的29 IEnumerator OnMouseDown()30 {31 Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position); //將物體由全局座標系轉化為螢幕座標系 ,由vector3 結構體變數ScreenSpace儲存,以用來明確螢幕座標系Z軸的位置32 Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z)); //完成了兩個步驟,1由於滑鼠的座標系是2維的,需要轉化成3維的全局座標系,2隻有三維的情況下才能來計算滑鼠位置與物體的距離,offset即是距離33 34 //當滑鼠左鍵按下時35 while (Input.GetMouseButton(0))36 {37 Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z); //得到現在滑鼠的2維座標系位置38 Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace); //將當前滑鼠的2維位置轉化成三維的位置39 40 //判斷移動方向41 xflagGameObject = GameObject.Find("xFlag(Clone)");42 yflagGameObject = GameObject.Find("yFlag(Clone)");43 camera = GameObject.Find("Main Camera");44 xdirVector = xflagGameObject.transform.position - camera.transform.position;45 ydirVector = yflagGameObject.transform.position - camera.transform.position;46 moveModel.x = xdirVector.x * offset.x + ydirVector.x * offset.x;47 moveModel.y = xdirVector.y * offset.y + ydirVector.y * offset.y;48 moveModel.z = xdirVector.z * offset.z + ydirVector.z * offset.z;49 transform.position = new Vector3(curPosition.x + moveModel.x, curPosition.y + moveModel.y, curPosition.z + moveModel.z);50 51 //這個很重要52 yield return new WaitForFixedUpdate();53 }54 }55 }
以上只是一個初學者自己想出來的解決方案,應該還會有更好的方法,使用座標轉換或許能行且簡單些(我沒有弄出來)。
camera旋轉+模型移動