DressingRoom
簡 介 DressingRoom 是 利 用 Unity 所 內 建 的 壓 縮 技 術 AssetBundle 將 現 有 的 模 型 材 質 骨 架 貼 圖 動 作 分 開 匯 出 成 檔 案, 放 置 於 網 路 或 本 機 資 料 夾 中, 在 遊 戲 中 達 到 紙 娃 娃 的 功 能
Editor 簡 介 & 功 能 簡 介 如 何 讓 Class 出 現 在 Editor 面 板 上? FBXPostprocessor Generate Materials Create Assetbundles Update Character Element Database
如 何 讓 Class 出 現 在 Editor 面 板 上? 只 需 在 該 script 腳 本 中 加 入 下 面 這 段 語 法 即 可 [MenuItem( 路 徑 / 名 稱 ")] [MenuItem("Character Generator/Create Assetbundles")]
FBXPostprocessor FBXPostprocessor 繼 承 AssetPostprocessor Class, AssetPostprocessor 是 Unity 的 Editor Class, 當 匯 入 asset 時 會 被 呼 叫, 必 須 在 Editor 下 才 能 使 用, 只 能 使 用 於 C#, 使 用 前 要 加 上 using UnityEditor; OnPreprocessModel 匯 入 FBX 之 前 呼 叫 OnPostprocessModel 匯 入 FBX 之 後 呼 叫
FBXPostprocessor.OnPreprocessModel() 所 有 的 FBX ( 包 含 動 作 檔 ) 透 過 ModelImporter 修 改 所 有 的 FBX 的 globalscale 為 1 過 濾 掉 characters 資 料 夾 以 外 的 檔 案 設 定 FBX 上 animationcompression = ModelImporterAnimationCompression.Off, 並 移 除 模 型 上 的 材 質 球
FBX Animation 子 物 件 SkinnedMeshRender Material Bone FBX Animation SkinnedMeshRender Bone * 此 FBX 指 的 characters 資 料 夾 內 所 有 的 FBX( 包 含 動 作 檔 )
FBXPostprocessor. OnPostprocessModel() 過 濾 掉 characters 資 料 夾 以 外 的 檔 案 抓 取 動 作 檔 把 動 作 檔 裡 面 的 所 有 子 物 件 上 的 SkinnedMeshRenderers 和 meshes 移 除 移 除 所 有 動 作 檔 裡 面 的 bone
FBX@ Animation SkinnedMeshRender FBX@ Bone Animation * 此 FBX@ 指 的 characters 資 料 夾 內 所 有 的 動 作 檔
Assetbundle 拆 出 來 的 檔 案 人 物 最 外 層 的 殼 - 人 物 _characterbase.assetbundle_assetbundle 檔 檔 案 裡 面 包 含 的 資 訊 : [CreateAssetbundles 所 產 出 ] Animation SkinnedMeshRender Bone ---------------------------------------------------------------------------------- 人 物 材 質 球 - 貼 圖 名 稱.mat( 貼 圖 名 稱 上 會 代 有 貼 圖 要 使 用 到 的 材 質 球 shader) [GenerateMaterials 所 產 出 ] ---------------------------------------------------------------------------------- 人 物 部 位 - 人 物 _ 部 位. Assetbundle 檔 案 裡 面 包 含 的 資 訊 :[CreateAssetbundles 所 產 出 ] SkinnedMeshRender Bone -------------------------------------------------------------------------- 比 對 檔 - CharacterElementDatabase.assetbundle 人 物 assetbundle 檔 和 材 質 球 檔 名 稱 相 對 應 存 入 資 料 : [UpdateCharacterElementDatabase 所 產 出 ] 人 物 assetbundle 檔 ( 無 副 檔 名 ) 材 質 球 檔 ( 無 副 檔 名 ) 人 物 assetbundle 檔 1( 無 副 檔 名 ) 材 質 球 檔 1( 無 副 檔 名 )...
List<Texture2D> textures GenerateMaterials 透 過 EditorHelpers 收 集 characterfbx 使 用 到 的 貼 圖 檢 查 characterfbx 子 物 件 上 FBX 子 物 件 使 用 到 的 貼 圖 無 normal 有 normal Material 使 用 Specular 的 Shader Material 使 用 Bumped Specular 的 Shader 建 立 檔 案 ( 檔 名 : 貼 圖 名 稱.mat) * 此 作 法 是 將 貼 圖 名 稱 都 已 事 先 命 名 好 相 對 應 的 人 物 _ 部 位 並 加 上 顏 色 以 及 是 否 使 用 normal 在 貼 圖 名 稱 上
CreateAssetbundles FBX Animation SkinnedMeshRender Bone
過 濾 檔 案, 抓 出 Female.FBX Male.FBX characterclone Animation SkinnedMeshRender Bone characterclone Animation SkinnedMeshRender Bone 建 立 assetbundle 檔 ( 檔 名 : 人 物 _characterbase.assetbundle) male _characterbase.assetbundle female_characterbase.assetbundle characterbaseprefab Animation SkinnedMeshRender Bone 經 過 GetPrefab(): 複 製 一 個 空 的 Prefab 將 GameObject 存 入 並 取 代 Prefab
FBX Animation SkinnedMeshRender Bone rendererparent(fbx 父 物 件 ) Animation rendererclone(fbx 子 物 件 ) (eyes face hair..) 角 色 名 稱 male 元 素 face-1 face-2 eyes hair-1 List<Object> toinclude rendererprefab rendererparent Animation rendererprefab rendererclone (eyes face hair..) 經 過 GetPrefab() rendererclone (eyes face hair..)
List<Material> materials 用 EditorHelpers 收 集 GenerateMaterials 所 建 立 出 來 的 材 質 球 檔 EditorHelpers 是 一 個 自 定 義 的 Class, 裡 面 是 一 個 泛 型, 將 要 找 的 檔 案 的 資 料 型 態 給 它, 它 就 會 把 你 要 找 的 檔 案 存 入 List< 資 料 型 態 > 後 回 傳 toinclude 材 質 球 檔 對 應 characterfbx 子 物 件 名 稱 的 檔 案 (.mat) List<string> bonenames 找 出 characterfbx 子 物 件 的 bone.name 將 hold 建 檔 ( 檔 名 :bonenames.asset) toinclude holder holder 把 bonenames 轉 成 Array holder 是 經 過 StringHolder Class 建 立 出 來 的 字 串 陣 列, 而 StringHolder 是 一 個 ScriptableObject, ScriptableObject 是 一 個 Class 讓 你 建 立 物 件 不 必 把 Script 加 到 Gameobject 上, 常 用 來 存 資 料
toinclude rendererprefab 材 質 球 檔 (.mat) holder toinclude.toarray() 建 立 成 assetbundle 檔 案 ( 檔 名 : 人 物 _ 部 位. assetbundle) 刪 除 用 來 存 資 料 的 asset 檔 建 立 assetbundle 檔 案 時 需 在 unity asset 資 料 夾 內 有 實 體 物 件 才 能 建 立 成 assetbundle, 所 以 當 資 料 存 在 ScriptableObject 時, 它 並 不 存 在 unity asset, 必 須 先 存 成 asset 檔 才 能 建 立 成 assetbundle 檔
UpdateCharacterElementDatabase string[] assetbundles assetbundle 檔 剔 除 assetbundle 檔 案 的 副 檔 名 string bundlename assetbundle string[] materials 材 質 球 檔 (.mat) 比 對 assetbundle 和 材 質 球 檔 前 面 的 名 稱 一 樣 List<CharacterElement> characterelements CharacterElement() 方 法 將 對 應 的 資 料 ( 材 質 球 檔 名 稱 去 掉.mat, assetbundle 檔 名 ) 存 入 characterelement 中 的 CharacterElement() 方 法
t characterelements 建 立 asset 檔 ( 檔 名 :CharacterElementDatabase.asset) t 是 透 過 CharacterElementHolder ( 意 義 同 於 StringHolder) 建 立 的 一 個 ScriptableObject 建 立 成 assetbundle 檔 ( 檔 名 :CharacterElementDatabase.assetbundle)
CharacterElement 用 於 處 理 角 色 的 部 位 元 素, 裡 面 含 有 其 材 質 名 稱 對 應 的 assetbundle 名 稱 可 以 取 得 骨 架 的 名 稱 的 方 法.. 等 等
CharacterElement_ 方 法 GetSkinnedMeshRenderer() 生 成 一 個 Object 再 將 materialrequest 賦 予 給 他 回 傳 Object 上 的 smr(renderer) GetBoneNames() 取 得 對 應 的 骨 架 名 稱
CharacterElement_ 變 數 P1 Name 材 質 名 稱 bundlename 對 應 的 assetbundle 名 稱 Wwws 紀 錄 assetbundle 對 應 的 WWW gameobjectrequest 對 應 的 mesh materialrequest 對 應 的 材 質 球
CharacterElement_ 變 數 P2 bonenamerequest 對 應 的 骨 架 名 稱 WWW 包 含 對 應 的 assetbundle IsLoaded 判 斷 是 否 已 經 下 載 完 成 且 是 否 賦 予 在 gameobjectrequest materialrequest bonenamerequest
DressingRoom 執 行 流 程 Part1 Main.Start() F 確 認 資 源 是 否 已 取 出 T T 確 認 是 否 已 有 角 色 資 訊 F 使 用 Female 創 立 新 角 色 使 用 舊 有 資 訊 創 角
DressingRoom 執 行 流 程 Part2 Main.Update() F T 確 認 CharacterGenerator 是 否 存 在 T 確 認 是 否 正 在 創 角 或 換 裝 F F 確 認 資 源 是 否 皆 已 載 入 T 確 認 是 否 為 新 角 色 或 換 角
DressingRoom 執 行 流 程 Part3 T 確 認 是 否 為 新 角 色 或 換 角 F 刪 除 舊 有 角 色 新 增 新 角 色 更 換 指 定 部 位 F 是 否 為 第 一 次 建 立 的 角 色 確 認 是 否 有 動 作 要 播 放 F T T 角 色 從 場 景 外 走 入 播 放 對 應 動 作 角 色 直 接 出 現 在 場 景 內 跳 出
Script 解 析 Main CharacterGenerator
Main 這 個 MonoBehaviour 是 用 來 控 制 CharacterGenerator 類 別 人 物 的 動 畫 還 有 使 用 者 介 面 當 使 用 者 更 換 了 不 同 的 角 色 配 置 時, CharacterGenerator 則 需 準 備 好 需 要 的 物 件 元 素
Main_Start() 此 場 景 程 式 中 的 進 入 點 等 待 CharacterElementDatabase 解 析 完 後 初 始 角 色 使 用 PlayerPrefs.HasKey 確 認 是 否 有 儲 存 的 角 色 資 訊
Main_Other Update() : 用 來 判 斷 是 否 為 第 一 次 創 角 是 否 有 更 換 角 色 或 更 換 部 位 動 作 判 斷 與 播 放 OnGUI() : 繪 製 使 用 者 介 面 AddCategory() : 除 了 Character 按 鈕 需 要 換 腳 色 以 外, 其 他 的 六 顆 按 鈕 則 是 用 來 更 換 某 個 部 位, 主 要 目 的 是 為 了 減 少 code 量 ChangeCharacter() : 更 換 角 色 ChangeElement() : 替 換 部 位
Config 的 存 取 刪 除 範 例 中 Config 的 存 取 是 利 用 unity 內 建 的 api PlayerPrefs 存 : Playerprefs.SetInt ( KeyName,Value) 取 : Playerprefs.GetInt ( KeyName ) 刪 除 : Playerprefs.DeleteKey( KeyName ) 確 認 : Playerprefs.HasKey( KeyName )
PlayerPrefs 的 儲 存 位 置 PlayerPrefs 在 Windows 運 行 環 境 下 將 資 料 存 於 HKCU\Software\[company name]\[product name] PlayerPrefs 在 Windows Web 檔 案 存 於 %APPDATA%\Unity\WebPlayerPrefs 在 Web 運 行 環 境 下 儲 存 的 檔 案 大 小 不 得 大 於 1MB, 不 然 之 後 所 有 的 儲 存 將 會 跳 出 錯 誤
CharacterGenerator 這 個 類 別 裡 包 含 了 許 多 的 方 法 與 變 數, 負 責 資 源 的 處 理 與 角 色 的 combining 存 取 角 色 資 訊 還 有 人 物 的 建 置 與 部 位 的 更 換, 都 是 在 此 類 別 下 做 處 理
CharacterGenerator_ 變 數 P1 Database 用 於 載 入 CharacterElementDatabase. assetbundle sortedelements ( 右 圖 ) 用 於 管 理 所 有 可 用 的 角 色 名 稱 與 部 位 角 色 名 稱 部 位 元 素 Male Face Face-1 Face-2 Eyes Eyes-1 Eyes-2 availablecharacters 儲 存 可 用 角 色 ( 字 串 ) Female Face Face-1 Face-2 Eyes Eyes-1 Eyes-2 characterbasewwws 儲 存 角 色 名 稱 與 對 應 的 Name_characterbase.assetbundle
CharacterGenerator_ 變 數 P2 characterbaserequests 儲 存 所 有 角 色 的 Prefab, 不 含 Mesh 材 質 currentcharacter 目 前 使 用 的 角 色 名 稱 ( 字 串 ) currentconfiguration 目 前 角 色 身 上 的 部 位 資 訊 assetbundlesalreadydownloaded 讀 取 的 進 度 ( 百 分 比 )
CharacterGenerator_ 變 數 P3 ReadyToUse 確 認 sortedelements 是 否 已 解 析 完 成 CurrentConfigProgress 目 前 部 位 的 載 入 進 度 ( 百 分 比 ) ConfigReady 目 前 角 色 的 所 有 部 位 是 否 都 已 載 入 完 成 AssetbundleBaseURL Assetbundle 的 儲 存 路 徑
CharacterGenerator_ 方 法 P1 CreateWithRandomConfig() 呼 叫 PrepareRandomConfig() 隨 機 創 角 ( 含 性 別 ) CreateWithRandomConfig(string character) 呼 叫 PrepareRandomConfig(string character) 隨 機 創 角 ( 指 定 性 別 ) CreateWithConfig(string config) 呼 叫 PrepareConfig(string config) 使 用 已 儲 存 的 Config 創 立 角 色
CharacterGenerator_ 方 法 P2 PrepareRandomConfig() 與 直 接 呼 叫 下 一 個 方 法 的 差 異 在 於 多 了 一 個 Random 角 色 PrepareRandomConfig(string character) 先 將 currentconfiguration 清 空 > 取 得 目 前 使 用 的 角 色 名 稱 > 依 照 取 得 的 角 色 名 稱 填 入 對 應 的 身 體 部 位 ( 隨 機 ) > 偵 測 有 多 少 assetbundle 已 被 下 載
CharacterGenerator_ 方 法 P3 PrepareConfig(string config) 解 析 收 到 的 config 並 將 其 存 入 settings 陣 列 裡 ( 下 圖 ) > 使 用 的 角 色 為 陣 列 的 第 0 格 > 初 始 化 一 個 currentconfiguration 來 儲 存 部 位 資 訊 > 依 序 比 對 settings 陣 列 內 容 是 否 為 可 用 元 素 > 將 部 位 資 訊 存 入 currentconfiguration > 偵 測 有 多 少 assetbundle 已 被 下 載 Settings[0] Settings[1] Settings[2] Settings[3] Settings[4] Settings[5] Settings[6]. Name Category Name Element Name Category Name Element Name Category Name Element Name
CharacterGenerator_ 方 法 P4 GetConfig() 取 得 目 前 的 角 色 部 位 資 訊 並 以 String 回 傳 Ex : Name Face Face-1 Eyes Eyes-2 ChangeCharacter(bool next) 呼 叫 PrepareRandomConfig(string character) 更 換 角 色 ChangeElement(string catagory, bool next) 使 用 currentconfiguration[catagory] = element;. 來 實 做 更 換 特 定 部 位
CharacterGenerator_ 方 法 P5 Generate() 初 始 化 一 個 角 色 根 目 錄 Generate(GameObject root) 紀 錄 所 有 子 物 件 的 transform > foreach (CharacterElement element in currentconfiguration.values) SkinnedMeshRenderer smr = element.getskinnedmeshrenderer(); 取 得 smr 裡 所 有 的 materials > 取 得 smr 裡 所 有 的 mesh > 取 得 smr 裡 所 有 的 bones > 刪 除 smr > 取 得 root 身 上 的 smr > 使 用 CombineMeshes 將 剛 才 取 得 的 所 有 mesh 整 合 > 最 後 將 bones & materials 都 賦 予 在 root.smr 上, 回 傳
人 物 生 成 示 意 圖 CurrentConfiguration. Value female_eyes_brown female_face-2 female_hair-1_red female_pants-2_orange female_shoes-2_yellow female_top-2_purple 初 使 化 角 色 取 得 所 有 子 物 件 的 Transform 資 訊 從 currentconfiguration 裡 取 得 所 有 的 SMR 從 SMR 裡 取 得 Mesh 從 SMR 裡 取 得 materials 從 currentconfiguration 裡 比 對 並 取 得 Bones SMR = SkinnedMeshRenderer 將 materials Bones Combine 後 的 Mesh 賦 予 到 root 身 上 的 SMR 回 傳
Q & A