【Unity3D】3D物體擺放、場景優化案例Demo

目錄

PlaceManager.cs(放置管理類)

Ground.cs(地板類)?和?GroundData.cs(地板數據類)

額外知識點說明

1、MeshFilter和MeshRenderer的Bounds區別

?2、Gizmos 繪制一個平行于斜面的立方體


通過網盤分享的文件:PlaceGameDemo2.unitypackage
鏈接: https://pan.baidu.com/s/1Jobzy8JaDqnBmRofNk2-Mw?pwd=fpfm 提取碼: fpfm

PlaceManager.cs(放置管理類)

1、負責加載建筑數據表(BUILD_CONFIG_JSON_STR)json內容
? ? ? ? id:1,Build_A(立方體)、id:2,Build_B(球體)

2、構建世界World類對象(1000*1000*1000大小)以100*100*100的立方體為房間Room填充World空間。
? ? ? ? World由若干個Room組成,Room下可存放若干個處于Room范圍內的物體(Unit封裝)
? ? ? ? 每個Unit均是動態創建并放入相關的Room對象內,Unit會持有1個所屬Room列表(belongRoomList)。
? ? ? ? 每個Unit創建時會存入<unitId, Unit>字典(unitDict)方便獲取以及序列化使用

3、Update方法
? ? ? ? 3.1 控制物體交互(點擊物體開始拖拽、拖拽中、放下物體)
? ? ? ? 3.2?可視處理,從<unitId, Unit>字典遍歷所有已存在Unit,遍歷Unit的belongRoomList房間是否位于攝像機視椎體內(是否可見),若可見則顯示Unit持有的物體,否則隱藏。(可優化)
? ? ? ? 3.3 按下鍵盤空格鍵,動態創建建筑配表的A或B物體并存放于默認地板defaultGround(應動態獲取地板)(可優化 僅創建Unit對象放入World相應的Room對象內,由【可視處理】動態創建或顯示物體)
? ? ? ? 3.4 按下鍵盤D鍵,清空場景物體,加載場景序列化文件,反序列化構建World對象(globalWorld),之后會由【可視處理】動態創建或顯示物體。
? ? ? ? 3.5 按下鍵盤S鍵,序列化World對象(globalWorld)保存為(world_json.json)序列化<unitId, Unit>字典(unitDict)保存為(unit_json.json),反序列化會使用到unit_json.json去輔助生成Unit對象填入相應的Room對象的Unit列表。

4、可搜索#region 世界 房間 單元 實體 找到World、Room、Unit類。
????????注意使用了[JsonIgnore]忽略某些字段序列化,以及使用[JsonConstructor]強制使用默認類去反序列化時的構造方法。個人認為反序列化時不應該依賴構造方法,而是手動組裝所有類成員,曾試過會出問題,特別是有參構造方法,參數傳入會是空的。

5、MoveGo方法,檢測到地板物體后會拿到地板物體身上的Ground類對象,判斷ground.IsCanPlaceBuild(movingGo)是否可放置在地板上,若可放置就調用ground.PlaceBuild(movingGo)放到地板,地板類會記錄這個物體相關的信息用于判定是否可放置,若不可放置,那么會回到movingStartPos移動開始位置。

Ground.cs(地板類)?和?GroundData.cs(地板數據類)

Ground.cs持有1個GroundData.cs類構建一個以地板為中心的特殊空間。這個類沒有太多作用,基本是與GroundData類對象溝通,用它只是用了一個Gizmos繪制地板的已占據格子。

案例中使用了一個Plane(灰色)地板以及一個Cube(綠色)地板,它們都掛載了Ground類。
每個Ground類是依據地板網格Mesh的Bounds.size和地板自身LocalScale大小相乘得到真實大小去構建GroundData的,并且以SlotSize切割出若干個格子Slot。


如上圖,由于Plane網格是(10,1,10)大小,乘上Scale(100,1,100)得到(1000,1,1000)大小的GroundData,計算出的地板左下角,右上角坐標如上圖(-500,-500), (500,500),總共會有1000*1000個Slot格子,注意Slot格子是動態創建的。

那么此時HGround物體的GroundData為(1000x1000)的平面,內有1000000個Slot。
為了支持Slot是動態創建的,GroundData存儲Slot是使用Dictionary<int, SlotData> map字典,字典Key是由(y*width+x)構成。

重點分析方法:
1、IsCanPlaceBuild(GameObject go, Action<SlotData> action = null)是否可放置物體,action委托方法是處理一個將可放置Slot對象的方法,PlaceBuild方法會使用到這個。

????????將go物體的世界坐標點轉為地板局部坐標,會得到一個[-5,5]范圍內的坐標,但我們需要的是一個[-500,500]的以上面的HGround大小為例,所以需要【局部坐標】乘以地板的LocalScale,得到一個【相對Ground平面的物體坐標】,之后會使用這個坐標和根據移動物體大小計算出【相對Ground平米的物體MinX,MaxX,MinY,MaxY邊界值】,用這4個邊界值分別處于SlotSize取整才能得到GroundData的下標邊界值【left, right, bottom, top】,遍歷這個邊界值范圍動態獲取或創建SlotData,判斷SlotData有物體hasGo且物體的unitId不等于當前移動物體的unitId時,會立刻退出循環遍歷,返回false不可放置,否則是可放置的,會執行action方法將SlotData傳遞出去處理,返回true可放置。(這里有好幾個坐標系 下標概念?要好好理解下)

? ? ? ? 創建SlotData時,其中的center格子中心點是世界坐標系的,主要用途是用于繪制Gizmos使用,它是通過將【相對Ground平面的坐標除以地板的LocalScale得到【局部坐標】再轉世界坐標,具體代碼說明:

float localPosY = groundSize.y / 2f + slotSize / 2f;
Vector3 localPos = new Vector3((x + 0.5f) * slotSize / localScale.x, 
localPosY / localScale.y, (y + 0.5f) * slotSize / localScale.z);
data.center = ground.TransformPoint(localPos);

localPosY是相對Ground坐標的格子Y軸偏移值,等于地板深度/2加上格子高度/2,因為地板是有深度的,例如使用Cube作為地板網格時,深度是Bounds.size.y*LocalScale.y,如果不偏移這個深度其格子會埋沒在地板內。【localPosY是相對Ground平面的格子坐標Y值】
x,y坐標是GroundData的map下標,它是格子的左下角下標,需要+0.5偏移到中心點再乘以slotSize得到【相對Ground平面的格子坐標】,之后則是除以LocalScale得到【局部坐標】再轉世界坐標。

2、PlaceBuild(GameObject go) 放置物體

????????這個方法使用到了IsCanPlaceBuild方法判定是否可放置,且傳了action委托方法,將所有物體相關的可放入SlotData存儲如List<SlotData>?tempSlotDataList,確定是可放置后會遍歷tempSlotDataList列表將所有SlotData的hasGo設置為True,unitId設置為當前物體unitId。
放置后會將<當前物體,tempSlotDataList>存儲入字典cacheGoSlotDataDict,用于Gizmos繪制紅色方框代表已放置的格子。

3、OnDrawGizmos方法 繪制所占據格子的紅色方框

//通過rotationMatrix4矩陣將空間轉到以繪制物體點為中心并且旋轉角度保持與Ground一致的空間 直接進行原點繪制格子
Matrix4x4 oldMatrix4 = Handles.matrix;
Transform groundTrans = slotData.groundData.ground.transform;
Matrix4x4 rotationMatrix4 = Matrix4x4.TRS(slotData.center, Quaternion.FromToRotation(Vector3.up, groundTrans.up.normalized), Vector3.one);
Gizmos.matrix = rotationMatrix4; //轉移矩陣
Gizmos.DrawWireCube(Vector3.zero, new Vector3(slotSize, slotSize, slotSize));
Gizmos.matrix = oldMatrix4; //復原矩陣

可優化Room也可以使用動態形式場景,類似SlotData一樣的方式即可。

額外知識點說明

1、MeshFilter和MeshRenderer的Bounds區別

MeshFilter.mesh.bounds是網格的AABB盒,其大小和位置均是網格實際大小位置。
MeshRenderer.bounds是場景物體的AABB盒,其大小和位置會隨受物體的TRS矩陣影響,即位移、旋轉、縮放影響。

如上圖,立方體(1,1,1)大小,MeshFilter是前三行數據,MeshRenderer是后三行數據,所以當你想獲取物體的真實大小時,你應該用MeshFilter的形式獲取Mesh.bounds知道它的大小,再乘上它的LocalScale得到,上面的代碼如下

Debug.Log(GetComponent<MeshFilter>().mesh.bounds);
Debug.Log(GetComponent<MeshFilter>().mesh.bounds.center);
Debug.Log(GetComponent<MeshFilter>().mesh.bounds.size);Debug.Log("  ");
Debug.Log(GetComponent<MeshRenderer>().bounds);
Debug.Log(GetComponent<MeshRenderer>().bounds.center);
Debug.Log(GetComponent<MeshRenderer>().bounds.size);

?2、Gizmos 繪制一個平行于斜面的立方體

例如這個小方塊的位置畫一個和它一樣重疊的紅色線框方框,你會發現沒有旋轉。

你必須使用Gizmos.matrix去將空間轉以這個繪制方塊為中心的空間,再進行繪制

using UnityEditor;
using UnityEngine;public class Test : MonoBehaviour
{public Transform ground;private void OnDrawGizmos(){Gizmos.color = Color.red;//Gizmos.DrawWireCube(transform.position, transform.localScale);Matrix4x4 oldMatrix4 = Gizmos.matrix;Matrix4x4 rotationMatrix4 = Matrix4x4.TRS(transform.position,Quaternion.FromToRotation(Vector3.up, ground.up.normalized), Vector3.one);Gizmos.matrix = rotationMatrix4; //轉移矩陣Gizmos.DrawWireCube(Vector3.zero, transform.localScale);Gizmos.matrix = oldMatrix4; //復原矩陣}
}

可能會有一些Bug,例如銷毀物體時,MarkPlaceLight物體需要移出去,還有銷毀物體時要將相關聯的Unit、SlotData移除之類的操作沒有做的,所以這方面的代碼請自行修復吧...

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66536.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66536.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66536.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenEuler學習感悟

在初次接觸 OpenEuler 時&#xff0c;我深感其學習難度較大。它與我之前熟悉的操作系統存在諸多差異&#xff0c;學習過程中&#xff0c;需要理解復雜的內核機制、掌握獨特的系統配置方法。但正是這種挑戰&#xff0c;激發了我深入探索的熱情。 從理論學習入手&#xff0c;我發…

C# OpenCvSharp 部署文檔矯正,包括文檔扭曲/模糊/陰影等情況

目錄 說明 效果 模型 項目 代碼 下載 參考 C# OpenCvSharp 部署文檔矯正&#xff0c;包括文檔扭曲/模糊/陰影等情況 說明 地址&#xff1a;https://github.com/RapidAI/RapidUnDistort 修正文檔扭曲/模糊/陰影等情況&#xff0c;使用onnx模型簡單輕量部署&#xff0c…

CSS 溢出問題及解決方案:實用案例與技巧

在網頁開發中&#xff0c;CSS 的布局和樣式起著至關重要的作用&#xff0c;但經常會遇到一個棘手的問題——溢出問題。溢出是指元素內的內容超出了其設定的容器大小&#xff0c;這不僅會影響頁面的美觀&#xff0c;還可能干擾用戶體驗。本文將詳細探討 CSS 溢出問題的案例&…

生成樹機制實驗

1 實驗內容 1、基于已有代碼,實現生成樹運行機制,對于給定拓撲(four_node_ring.py),計算輸出相應狀態下的生成樹拓撲 2、構造一個不少于7個節點,冗余鏈路不少于2條的拓撲,節點和端口的命名規則可參考four_node_ring.py,使用stp程序計算輸出生成樹拓撲 2 實驗原理 一、…

數據結構詳解——堆與二叉樹

? 目錄 樹的概念樹的表示方法二叉樹的概念特殊的二叉樹二叉樹的性質二叉樹的存儲結構順序存儲鏈式存儲 堆的概念與結構堆的性質堆的實現堆的初始化入堆堆的擴容向上調整算法出堆&#xff08;最頂端元素&#xff09;向下調整算法 二叉樹的實現二叉樹的創建二叉樹的銷毀二叉樹的…

【藍橋杯】43694.正則問題

題目描述 考慮一種簡單的正則表達式&#xff1a; 只由 x ( ) | 組成的正則表達式。 小明想求出這個正則表達式能接受的最長字符串的長度。 例如 ((xx|xxx)x|(x|xx))xx 能接受的最長字符串是&#xff1a; xxxxxx&#xff0c;長度是 6。 輸入描述 一個由 x()| 組成的正則表達式。…

mac m1下載maven安裝并配置環境變量

下載地址&#xff1a;Download Apache Maven – Maven 解壓到一個沒有中文和空格的文件夾 輸入pwd查看安裝路徑 輸入cd返回根目錄再輸入 code .zshrc 若顯示 command not found: code你可以通過以下步驟來安裝和配置 code 命令&#xff1a; 1. 確保你已經安裝了 Visual Studio…

【自己動手開發Webpack插件:開啟前端構建工具的個性化定制之旅】

在前端開發的世界里&#xff0c;Webpack無疑是構建工具中的“明星”。它強大的功能可以幫助我們高效地打包和管理前端資源。然而&#xff0c;有時候默認的Webpack功能可能無法完全滿足我們的特定需求&#xff0c;這時候就需要自定義Webpack插件來大展身手啦&#xff01;今天&am…

移遠通信多模衛星通信模組BG95-S5獲得Skylo網絡認證,進一步拓展全球衛星物聯網市場

近日&#xff0c;全球領先的物聯網整體解決方案供應商移遠通信正式宣布&#xff0c;其支持“衛星蜂窩”多模式的高集成度NTN衛星通信模組BG95-S5已成功獲得NTN網絡運營商Skylo的網絡認證。BG95-S5也成為了獲得該認證的最新款移遠衛星通信模組。 BG95-S5模組順利獲得Skylo認證&a…

1.3.淺層神經網絡

目錄 1.3.淺層神經網絡 1.3.1 淺層神經網絡表示 1.3.2 單個樣本的向量化表示 1.3.4 激活函數的選擇 1.3.5 修改激活函數 1.3.5 練習??????? 1.3.淺層神經網絡 1.3.1 淺層神經網絡表示 之前已經說過神經網絡的結構了&#xff0c;在這不重復敘述。假設我們有如下…

StarRocks強大的實時數據分析

代碼倉庫&#xff1a;https://github.com/StarRocks/starrocks?tabreadme-ov-file StarRocks | A High-Performance Analytical Database 快速開始&#xff1a;StarRocks | StarRocks StarRocks 是一款高性能分析型數據倉庫&#xff0c;使用向量化、MPP 架構、CBO、智能物化…

2024年博客之星主題創作|貓頭虎分享AI技術洞察:2025年AI發展趨勢前瞻與展望

2025年AI發展趨勢前瞻&#xff1a;貓頭虎深度解析未來科技與商業機遇 摘要 2024年&#xff0c;AI技術迎來爆發式增長&#xff0c;AIGC、智能體、AIRPA、AI搜索、推理模型等技術不斷突破&#xff0c;AI應用場景持續擴展。2025年&#xff0c;AI將進入全新發展階段&#xff0c;W…

PG vs MySQL mvcc機制實現的異同

MVCC實現方法比較 MySQL 寫新數據時&#xff0c;把舊數據寫入回滾段中&#xff0c;其他人讀數據時&#xff0c;從回滾段中把舊的數據讀出來 PostgreSQL 寫新數據時&#xff0c;舊數據不刪除&#xff0c;直接插入新數據。 MVCC實現的原理 PG的MVCC實現原理 定義多版本的數據…

Android SystemUI——CarSystemBar視圖解析(十一)

前面文章我們已經把 CarSystemBar 從啟動到構建視圖,再到將視圖添加到 Window 的流程分析完畢,我們知道默認情況下在車載系統中只顯示頂部欄和底部欄視圖的。這里我們在前面文章的基礎上以頂部欄為例具體解析其視圖的結構。 一、頂部欄解析 通過《CarSystemBar車載狀態欄》這…

51c~ONNX~合集1

我自己的原文哦~ https://blog.51cto.com/whaosoft/11608027 一、使用Pytorch進行簡單的自定義圖像分類 ~ONNX 推理 圖像分類是計算機視覺中的一項基本任務&#xff0c;涉及訓練模型將圖像分類為預定義類別。本文中&#xff0c;我們將探討如何使用 PyTorch 構建一個簡單的自定…

每打開一個chrome頁面都會【自動打開F12開發者模式】,原因是 使用HBuilderX會影響谷歌瀏覽器的瀏覽模式

打開 HBuilderX&#xff0c;點擊 運行 -> 運行到瀏覽器 -> 設置web服務器 -> 添加chrome瀏覽器安裝路徑 chrome谷歌瀏覽器插件 B站視頻下載助手插件&#xff1a; 參考地址&#xff1a;Chrome插件 - B站下載助手&#xff08;輕松下載bilibili嗶哩嗶哩視頻&#xff09…

go語言之OOP特性和演示

一、OOP特性 Go語言中的OOP特性 結構體&#xff1a;在Go中&#xff0c;結構體用于定義復合類型&#xff0c;類似于其他語言中的類。它可以包含字段&#xff08;屬性&#xff09;和方法&#xff08;行為&#xff09;。方法&#xff1a;Go允許為任何自定義類型&#xff08;包括…

USB3020任意波形發生器4路16位同步模擬量輸出卡1MS/s頻率 阿爾泰科技

信息社會的發展&#xff0c;在很大程度上取決于信息與信號處理技術的先進性。數字信號處理技術的出現改變了信息 與信號處理技術的整個面貌&#xff0c;而數據采集作為數字信號處理的必不可少的前期工作在整個數字系統中起到關鍵 性、乃至決定性的作用&#xff0c;其應用已經深…

ChatGPT大模型極簡應用開發-目錄

引言 要理解 ChatGPT&#xff0c;了解其背后的 Transformer 架構和 GPT 技術一路的演進則變得非常必要。 ChatGPT 背后的 LLM 技術使普通人能夠通過自然語言完成過去只能由程序員通過編程語言實現的任務&#xff0c;這是一場巨大的變革。然而&#xff0c;人類通常容易高估技術…

C++入門基礎篇:域、C++的輸入輸出、缺省參數、函數重載、引用、inline、nullptr

本篇文章是對C學習前期的一些基礎部分的學習分享&#xff0c;希望也能夠對你有所幫助。 那咱們廢話不多說&#xff0c;直接開始吧&#xff01; 目錄 1.第一個C程序 2. 域 3. namespace 3.1 namespace的作用 3.2 namespace的定義 3.3 namespace使用說明 4.C的輸入和輸出…