国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Unity3D】縮放、平移、旋轉(zhuǎn)場景

這篇具有很好參考價值的文章主要介紹了【Unity3D】縮放、平移、旋轉(zhuǎn)場景。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1 前言

? ? ? ? 場景縮放、平移、旋轉(zhuǎn)有兩種實現(xiàn)方案,一種是對場景中所有物體進行同步變換,另一種方案是對相機的位置和姿態(tài)進行變換。

? ? ? ? 對于方案一,如果所有物體都在同一個根對象下(其子對象或?qū)O子對象),那么只需要對根對象施加變換就可以實現(xiàn)場景變換;如果有多個根對象,那就需要對所有根對象施加變換。該方案實現(xiàn)簡單,但是會破壞場景中對象的尺寸、位置、姿態(tài),不符合現(xiàn)實世界的規(guī)則。如:對場景施加縮放變換后,又新增了一個對象,但是該對象不是放在同一個根目錄下,就會讓用戶感覺新增對象的尺寸超出意外;如果有多個根對象,就會存在多個參考系(每個根對象一個參考系),增加場景中對象的控制難度。

? ? ? ? 對于方案二,通過變換相機的位置和姿態(tài),讓用戶感覺場景中所有對象在同步縮放、平移、旋轉(zhuǎn)。該方案實現(xiàn)較困難,但是不會破環(huán)場景中對象的尺寸、位置、姿態(tài),更貼近真實世界的規(guī)則,也不需要將所有對象都放在同一個根對象下。

? ? ? ? 方案二明顯優(yōu)于方案一,本文將詳細介紹其原理和實現(xiàn)。原理如下:

? ? ? ? 1)場景縮放原理

? ? ? ? 利用相機的透視原理(詳見→透視變換原理),即相機拍攝到的圖片呈現(xiàn)近大遠小的效果,將相機靠近和遠離場景,從而實現(xiàn)放大和縮小場景的效果。

? ? ? ? 2)場景平移原理

? ? ? ? 相機成像是在近平面上,如果擴展近平面的范圍,相機拍攝的范圍也就越大,將近平面平移到相機位置上,記為平面 S,將相機在 S 平面上平移,就會實現(xiàn)場景平移效果。

? ? ? ? 3)場景旋轉(zhuǎn)原理

? ? ? ? 在 Unity3D Scene 窗口,通過按 Alt 鍵 + 鼠標拖拽,可以旋轉(zhuǎn)場景。場景旋轉(zhuǎn)包含兩種情況,鼠標沿水平方向拖拽、鼠標沿豎直方向拖拽。

? ? ? ? 當鼠標沿水平方向拖拽時,筆者通過多次實驗觀察,發(fā)現(xiàn)如下規(guī)律:當場景縮放到某個值時,旋轉(zhuǎn)場景時,屏幕中心位置的物體(在相機的正前方)在場景旋轉(zhuǎn)過程中始終處在屏幕中心,并且旋轉(zhuǎn)軸的方向始終是 Y 軸方向。因此可以得出結(jié)論:旋轉(zhuǎn)中心在相機正前方(forward),旋轉(zhuǎn)軸沿 Y 軸方向。

? ? ? ? 旋轉(zhuǎn)中心的 y 值最好與地圖的 y 值相等,如果場景中沒有地圖,可以取旋轉(zhuǎn)中心為:cam.position + cam.forward * (nearPlan + 1 / nearPlan),當然,用戶也可以取其他值。已知旋轉(zhuǎn)中心的 y 值,可以按照以下公式推導(dǎo)出 x、z 值:

【Unity3D】縮放、平移、旋轉(zhuǎn)場景

? ? ? ? 當鼠標沿豎直方向拖拽時,旋轉(zhuǎn)中心在相機位置,旋轉(zhuǎn)軸沿相機的左邊(-right)。

? ? ? ? 本文代碼資源見→縮放、平移、旋轉(zhuǎn)場景。

2 代碼實現(xiàn)

????????SceneController.cs

using UnityEngine;
 
public class SceneController : MonoBehaviour {
    private Texture2D[] cursorTextures; // 鼠標樣式: 箭頭、小手、眼睛
    private Transform cam; // 相機
    private float nearPlan; // 近平面
    private Vector3 preMousePos; // 上一幀的鼠標坐標
    private int cursorStatus = 0; // 鼠標樣式狀態(tài)
    private bool isDraging = false; // 是否在拖拽中
 
    private void Awake() {
        string[] mouseIconPath = new string[]{"MouseIcon/0_arrow", "MouseIcon/1_hand", "MouseIcon/2_eye"};
        cursorTextures = new Texture2D[mouseIconPath.Length];
        for(int i = 0; i < mouseIconPath.Length; i++) {
            cursorTextures[i] = Resources.Load<Texture2D>(mouseIconPath[i]);
        }
        cam = Camera.main.transform;
        Vector3 angle = cam.eulerAngles;
        cam.eulerAngles = new Vector3(angle.x, angle.y, 0); // 使camp.right指向水平方向
        nearPlan = Camera.main.nearClipPlane;
    }
 
    private void Update() {
        cursorStatus = GetCursorStatus();
        // 更新鼠標樣式, 第二個參數(shù)表示鼠標點擊位置在圖標中的位置, zero表示左上角
        Cursor.SetCursor(cursorTextures[cursorStatus], Vector2.zero, CursorMode.Auto);
        UpdateScene(); // 更新場景(Ctrl+Scroll: 縮放場景, Ctrl+Drag: 平移場景, Alt+Drag: 旋轉(zhuǎn)場景)
    }
 
    private int GetCursorStatus() { // 獲取鼠標狀態(tài)(0: 箭頭, 1: 小手, 2: 眼睛)
        if (isDraging) {
            return cursorStatus;
        }
        if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftControl)) {
            return 1;
        }
        if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.LeftAlt)) {
            return 2;
        }
        return 0;
    }
 
    private void UpdateScene() { // 更新場景(Ctrl+Scroll: 縮放場景, Ctrl+Drag: 平移場景, Alt+Drag: 旋轉(zhuǎn)場景)
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        if (!isDraging && cursorStatus == 1 && Mathf.Abs(scroll) > 0) { // 縮放場景
            ScaleScene(scroll);
        } else if (Input.GetMouseButtonDown(0)) {
            preMousePos = Input.mousePosition;
            isDraging = true;
        } else if (Input.GetMouseButtonUp(0)) {
            isDraging = false;
        } else if (Input.GetMouseButton(0)) {
            Vector3 offset = Input.mousePosition - preMousePos;
            if (cursorStatus == 1) { // 移動場景
                MoveScene(offset);
            } else if (cursorStatus == 2) { // 旋轉(zhuǎn)場景
                RotateScene(offset);
            }
            preMousePos = Input.mousePosition;
        }
    }
 
    private void ScaleScene(float scroll) { // 縮放場景
        cam.position += cam.forward * scroll;
    }
 
    private void MoveScene(Vector3 offset) { // 平移場景
        cam.position -= (cam.right * offset.x / 100 + cam.up * offset.y / 100);
    }
 
    private void RotateScene(Vector3 offset) { // 旋轉(zhuǎn)場景
        Vector3 rotateCenter = GetRotateCenter(0);
        cam.RotateAround(rotateCenter, Vector3.up, offset.x / 3); // 水平拖拽分量
        cam.LookAt(rotateCenter);
        cam.RotateAround(rotateCenter, -cam.right, offset.y / 5); // 豎直拖拽分量
    }
 
    private Vector3 GetRotateCenter(float planeY) { // 獲取旋轉(zhuǎn)中心
        if (Mathf.Abs(cam.forward.y) < float.Epsilon || Mathf.Abs(cam.position.y) < float.Epsilon) {
            return cam.position + cam.forward * (nearPlan + 1 / nearPlan);
        }
        float t = (planeY - cam.position.y) / cam.forward.y;
        float x = cam.position.x + t * cam.forward.x;
        float z = cam.position.z + t * cam.forward.z;
        return new Vector3(x, planeY, z);
    }
}

? ? ? ? 說明:SceneController 腳本組件掛在相機下,鼠標圖標如下,需要放在 Resouses/MouseIcon 目錄下, 并且需要在 Inspector 窗口將其 Texture Type 屬性調(diào)整為 Cursor。

【Unity3D】縮放、平移、旋轉(zhuǎn)場景

3 運行效果

?????????通過 Ctrl+Scroll 縮放場景,Ctrl+Drag 平移場景,Alt+Drag 旋轉(zhuǎn)場景 ,效果如下:

【Unity3D】縮放、平移、旋轉(zhuǎn)場景

4 優(yōu)化

? ? ? ? 第 2 節(jié)中場景變換存在以下問題,本節(jié)將對這些問題進行優(yōu)化。

  • 豎直方向平移場景時,會抬高或降低相機高度;
  • 豎直方向旋轉(zhuǎn)場景時,如果相機垂直朝向地面,就會出現(xiàn)窗口急速晃動問題,因為旋轉(zhuǎn)中心出現(xiàn)了跳變。

? ? ? ? 針對問題一,將相機的上方向量(camera.up)投影到水平面上,再用投影向量計算相機前后平移的偏移量。

? ? ? ? 針對問題二,使用一個全局變量實時保存并更新旋轉(zhuǎn)中心的位置,并通過相機周轉(zhuǎn)和自傳(兩者旋轉(zhuǎn)角度和方向相等)實現(xiàn)水平和豎直方向旋轉(zhuǎn)場景,避免使用 LookAt,因為相機不一定一直朝向旋轉(zhuǎn)中心(如:相機焦點不在地圖里)。

????????SceneController.cs文章來源地址http://www.zghlxwxcb.cn/news/detail-421192.html

using UnityEngine;

public class SceneController : MonoBehaviour {
    private const float MAX_HALF_EDGE_X = 5f; // 地圖x軸方向半邊長
    private const float MAX_HALF_EDGE_Z = 5f; // 地圖z軸方向半邊長
    private Texture2D[] cursorTextures; // 鼠標樣式: 箭頭、小手、眼睛
    private Transform cam; // 相機
    private float planeY = 0f; // 地面高度
    private Vector3 rotateCenter; // 旋轉(zhuǎn)中心
    private Vector3 focusCenter; // 相機在地面上的焦點中心
    private bool isFocusInMap; // 相機焦點是否在地圖里
    private Vector3 preMousePos; // 上一幀的鼠標坐標
    private int cursorStatus = 0; // 鼠標樣式狀態(tài)
    private bool isDraging = false; // 是否在拖拽中

    private void Awake() {
        string[] mouseIconPath = new string[] { "MouseIcon/0_arrow", "MouseIcon/1_hand", "MouseIcon/2_eye" };
        cursorTextures = new Texture2D[mouseIconPath.Length];
        for (int i = 0; i < mouseIconPath.Length; i++) {
            cursorTextures[i] = Resources.Load<Texture2D>(mouseIconPath[i]);
        }
        cam = Camera.main.transform;
        Vector3 angle = cam.eulerAngles;
        cam.eulerAngles = new Vector3(angle.x, angle.y, 0); // 使camp.right指向水平方向
        rotateCenter = new Vector3(0, planeY, 0);
        focusCenter = new Vector3(0, planeY, 0);
    }

    private void Update() {
        cursorStatus = GetCursorStatus();
        // 更新鼠標樣式, 第二個參數(shù)表示鼠標點擊位置在圖標中的位置, zero表示左上角
        Cursor.SetCursor(cursorTextures[cursorStatus], Vector2.zero, CursorMode.Auto);
        UpdateScene(); // 更新場景(Ctrl+Scroll: 縮放場景, Ctrl+Drag: 平移場景, Alt+Drag: 旋轉(zhuǎn)場景)
    }

    private int GetCursorStatus() { // 獲取鼠標狀態(tài)(0: 箭頭, 1: 小手, 2: 眼睛)
        if (isDraging)
        {
            return cursorStatus;
        }
        if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftControl))
        {
            return 1;
        }
        if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.LeftAlt))
        {
            return 2;
        }
        return 0;
    }

    private void UpdateScene() { // 更新場景(Ctrl+Scroll: 縮放場景, Ctrl+Drag: 平移場景, Alt+Drag: 旋轉(zhuǎn)場景)
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        if (!isDraging && cursorStatus == 1 && Mathf.Abs(scroll) > 0) { // 縮放場景
            ScaleScene(scroll);
        }
        else if (Input.GetMouseButtonDown(0)) {
            preMousePos = Input.mousePosition;
            UpdateRotateCenter();
            isDraging = true;
        }
        else if (Input.GetMouseButtonUp(0)) {
            isDraging = false;
        }
        else if (Input.GetMouseButton(0)) {
            Vector3 offset = Input.mousePosition - preMousePos;
            if (cursorStatus == 1) { // 移動場景
                MoveScene(offset);
            }
            else if (cursorStatus == 2) { // 旋轉(zhuǎn)場景
                RotateScene(offset);
            }
            preMousePos = Input.mousePosition;
        }
    }

    private void ScaleScene(float scroll) { // 縮放場景
        cam.position += cam.forward * scroll;
    }

    private void MoveScene(Vector3 offset) { // 平移場景
        Vector3 horVec = Vector3.ProjectOnPlane(cam.right, Vector3.up).normalized;
        Vector3 verVec = Vector3.ProjectOnPlane(cam.up, Vector3.up).normalized;
        cam.position -= (horVec * offset.x / 100 + verVec * offset.y / 100);
    }

    private void RotateScene(Vector3 offset) { // 旋轉(zhuǎn)場景
        float hor = offset.x / 3;
        float ver = -offset.y / 5;
        cam.RotateAround(rotateCenter, Vector3.up, hor); // 相機繞旋轉(zhuǎn)中心水平旋轉(zhuǎn)
        cam.RotateAround(rotateCenter, cam.right, ver); // 相機繞旋轉(zhuǎn)中心豎直旋轉(zhuǎn)
        // 由于transform.RotateAround方法中已經(jīng)進行了物體姿態(tài)調(diào)整, 因此以下語句是多余的
        // cam.RotateAround(cam.position, Vector3.up, hor); // 相機自轉(zhuǎn), 使其朝向旋轉(zhuǎn)中心
        // cam.RotateAround(cam.position, cam.right, ver); // 相機自轉(zhuǎn), 使其朝向旋轉(zhuǎn)中心
    }

    private void UpdateRotateCenter() { // 更新旋轉(zhuǎn)中心
        UpdateFocusStatus();
        if (!isFocusInMap) {
            return;
        }
        rotateCenter.x = Mathf.Clamp(focusCenter.x, -MAX_HALF_EDGE_X, MAX_HALF_EDGE_X);
        rotateCenter.z = Mathf.Clamp(focusCenter.z, -MAX_HALF_EDGE_Z, MAX_HALF_EDGE_Z);
    }

    private void UpdateFocusStatus() { // 更新焦點狀態(tài)
        isFocusInMap = true;
        Vector3 vec1 = new Vector3(0, planeY - cam.position.y, 0);
        Vector3 vec2 = cam.forward;
        if (Mathf.Abs(vec1.y) < float.Epsilon || Mathf.Abs(vec2.y) < float.Epsilon) {
            isFocusInMap = false;
            return;
        }
        float angle = Vector3.Angle(vec1, vec2);
        if (angle >= 90) { // 相機在地面以上并且朝天, 或在地面以下并且朝下
            isFocusInMap = false;
            return;
        }
        float t = (planeY - cam.position.y) / vec2.y;
        focusCenter.x = cam.position.x + t * vec2.x;
        focusCenter.z = cam.position.z + t * vec2.z;
        if (Mathf.Abs(focusCenter.x) > MAX_HALF_EDGE_X || Mathf.Abs(focusCenter.z) > MAX_HALF_EDGE_Z) { // 相機焦點不在地圖區(qū)域內(nèi)
            isFocusInMap = false;
        }
    }
}

到了這里,關(guān)于【Unity3D】縮放、平移、旋轉(zhuǎn)場景的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Unity3D 腳本3(旋轉(zhuǎn))

    Unity3D 腳本3(旋轉(zhuǎn))

    一、物體的旋轉(zhuǎn) 給物體調(diào)轉(zhuǎn)一個旋轉(zhuǎn)角度。 1、Quaternion四元組(x,y,z,w) transfrom.rotation()=... 不方便操作,官方不建議用 2、Euler Angle 歐拉角 transfrom.eulerAngles = new Vector(0,45,0); transfrom.LocalE ulerAngles = new Vector(0,45,0); 這樣就可以讓物體旋轉(zhuǎn)45度。 在Update 中修改角度持續(xù)旋轉(zhuǎn) Vecto

    2023年04月16日
    瀏覽(96)
  • unity3D 鼠標滾輪實現(xiàn)物體的大小縮放

    鼠標滾輪響應(yīng)函數(shù)是Input.GetAxis(\\\"Mouse ScrollWheel\\\"),函數(shù)返回值類型是float,向前滾是返回正數(shù),向后滾是返回負數(shù),且鼠標滾輪滑動單次函數(shù)返回值為0.1 利用返回值修改模型transform.localscale,實現(xiàn)模型縮放 鼠標滾輪一直向后滾,會看見模型逐漸變小,當變到很小到消失的時候,

    2024年02月08日
    瀏覽(96)
  • Unity3D相機圍繞物體自由旋轉(zhuǎn)

    Unity3D相機圍繞物體自由旋轉(zhuǎn)

    寫了一個相機圍繞物體360°自由旋轉(zhuǎn)的腳本,比較實用,分享出來給大家使用,配置如下: Hierarchy界面 ?LookPovit:為物體Auto Aircraft的中心空對象; AroundPovit:用于相機的空對象,作為父類,主要作用是為了保持與被觀察物體的位置一致,可防止Auto Aircraft出現(xiàn)抖動而影響相機

    2024年02月11日
    瀏覽(100)
  • Unity3D 控制物體移動且自動旋轉(zhuǎn)

    Unity3D 控制物體移動且自動旋轉(zhuǎn)

    直接上代碼(改腳本掛載到游戲物體上) 第三人稱攝像機移動

    2024年02月15日
    瀏覽(97)
  • Unity3D實現(xiàn)鍵盤控制小車左右方向旋轉(zhuǎn)

    Unity3D實現(xiàn)鍵盤控制小車左右方向旋轉(zhuǎn)

    注:本文章是在已學(xué)課程的基礎(chǔ)上實現(xiàn)的標題效果! 以下是學(xué)習(xí)控制物體旋轉(zhuǎn)的簡單方法: 代碼在updata()函數(shù)中實現(xiàn); ?transform:指本腳所掛載的物體的位置信息,包含Position(位置)、Rotation(旋轉(zhuǎn))、Scale(縮放),此處通過\\\".\\\"來調(diào)用Rotate方法; Rotate:unity手冊中描述如下,參數(shù)一:

    2024年01月18日
    瀏覽(32)
  • Unity3D-場景中3D物體添加點擊事件

    Unity3D-場景中3D物體添加點擊事件

    Unity3D - 場景中3D物體添加鼠標點擊事件 鼠標點擊3D物體觸發(fā),Unity從本質(zhì)上來說有兩種:一種是通過事件(event)觸發(fā),一種是通過射線(ray)判斷穿過的物體觸發(fā)。這兩種觸發(fā)的原理是不同的,不論哪種觸發(fā)都必須滿足觸發(fā)的要求才可以,既然原理不同,觸發(fā)的要求也不一樣

    2024年02月08日
    瀏覽(101)
  • unity3d場景怎么添加天空盒子?

    unity3d場景怎么添加天空盒子?

    unity3d場景中想要添加天空盒子,該怎么添加呢?下面我們就來看看詳細的教程。 1、先下載組成天空盒子的天空圖片 2、把天空圖片拖進 unity3d 中創(chuàng)建的文件夾 3、新建一個 材質(zhì)球 4、把材質(zhì)球的 shader修改成天空盒選項 5、在天空盒的六個方向(前,后,左,右,上,下)添加

    2024年02月11日
    瀏覽(101)
  • Unity3D:提升場景畫面品質(zhì)&平衡性能優(yōu)化

    Unity3D:提升場景畫面品質(zhì)&平衡性能優(yōu)化

    在日常開發(fā)中,提升場景畫面品質(zhì)的同時平衡性能優(yōu)化一直是很重要且頭疼的一部分,尤其是當場景類型不同及效果需求不一樣時。 所以怎么同時提升場景畫面品質(zhì)和平衡性能優(yōu)化呢,下面介紹一些適用度高且實用性好的設(shè)置。 介紹之前先說一下結(jié)論:怎么樣才能說的上是

    2024年02月08日
    瀏覽(95)
  • Unity3D學(xué)習(xí)記錄02——PloyBrush場景搭建

    Unity3D學(xué)習(xí)記錄02——PloyBrush場景搭建

    首先在Window-Package Manager里面搜索Poly Brush,下載后將URP的Shader樣例導(dǎo)入 ?導(dǎo)入后Asset文件夾下會有Sample的文件夾,在菜單欄 Tools-PolyBrush-PolyBrush Window 打開窗口 這個窗口最上面的五個,第一個是用來調(diào)整地形高低的,第二個是進行柔化場景的,第三個是調(diào)整顏色的, 第四個可以

    2024年02月08日
    瀏覽(96)
  • Unity3D攝像機,鍵盤控制前后左右上下移動,鼠標控制旋轉(zhuǎn)、放縮

    Unity3D中運行場景時,實現(xiàn)攝像機的前、后、左、右、上、下,以及鼠標滾輪的放縮,鼠標右鍵的旋轉(zhuǎn)操作。親測有效,可供參考。 按鍵功能介紹:W——前;S——后;A——左;D——右;Q——下降;E——上升;鼠標右鍵——旋轉(zhuǎn);鼠標滾輪——放縮。 Tourcamera腳本需要掛在攝

    2024年02月11日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包