diff --git a/Assets/Effekseer/package.json b/Assets/Effekseer/package.json index 428a3aa..d09d52e 100644 --- a/Assets/Effekseer/package.json +++ b/Assets/Effekseer/package.json @@ -2,7 +2,7 @@ "name": "com.thirdparty.effekseer", "displayName": "Effekseer", "version": "0.0.1", - "unity": "2019.4", + "unity": "2019.3", "description": "", "dependencies": { } } \ No newline at end of file diff --git a/Assets/Effekseer/package.json.meta b/Assets/Effekseer/package.json.meta index 94c6d9c..cd46074 100644 --- a/Assets/Effekseer/package.json.meta +++ b/Assets/Effekseer/package.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d06b5da1e348e4945abf14c2a51dc63a +guid: 80ca51d8500b55a46ba57f883a5813e1 TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/VCI-Official-Samples/CameraApiSample/CameraApiSample.unity b/Assets/VCI-Official-Samples/CameraApiSample/CameraApiSample.unity index d929afb..cc1a2b6 100644 --- a/Assets/VCI-Official-Samples/CameraApiSample/CameraApiSample.unity +++ b/Assets/VCI-Official-Samples/CameraApiSample/CameraApiSample.unity @@ -424,7 +424,7 @@ MonoBehaviour: contactInformation: reference: thumbnail: {fileID: 0} - version: 1.0 + version: 1.1 description: exporterVersion: 0.33 specVersion: @@ -456,14 +456,11 @@ MonoBehaviour: false\r\n\r\nlocal teleButtonName = \"ButtonTele\"\r\nlocal teleButtonTransform = vci.assets.GetTransform(teleButtonName)\r\nlocal teleButtonAnchorTransform = vci.assets.GetTransform(\"ButtonTeleAnchor\")\r\nlocal isTeleButtonUsed = - false\r\n\r\nlocal fovStateName = \"FOV\"\r\nlocal minFov = 10\r\nlocal maxFov - = 170\r\nlocal fovStep = 2\r\n\r\nlocal nearClipStateName = \"NEAR_CLIP\"\r\n\r\nlocal - takePhotoMessageName = \"message_take_photo\"\r\n\r\nlocal previewMaterialName - = \"Display\"\r\nlocal photoMaterialName = \"Photo\"\r\n\r\nlocal isInitialized - = false\r\nlocal photographyCamera = nil\r\n\r\n-- \u30A2\u30A4\u30C6\u30E0\u5185\u540C\u671F\u5909\u6570\u3092\u521D\u671F\u5316\r\n-- - * \u81EA\u8EAB\u304C\u3053\u306EVCI\u306E\u6240\u6709\u6A29\u3092\u6301\u3063\u3066\u3044\u308B\u3068\u304D\u306E\u307F\u5B9F\u884C\u3057\u307E\u3059\u3002\r\nif - vci.assets.IsMine then\r\n vci.state.Set(fovStateName, 60)\r\n vci.state.Set(nearClipStateName, - 0.01)\r\nend\r\n\r\n-- \u5199\u771F\u64AE\u5F71\u6642\u306E\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\r\n-- + false\r\n\r\nlocal fovStateName = \"FOV\"\r\nlocal initialFov = 60\r\nlocal + minFov = 10\r\nlocal maxFov = 170\r\nlocal fovStep = 2\r\n\r\nlocal takePhotoMessageName + = \"message_take_photo\"\r\n\r\nlocal previewMaterialName = \"Display\"\r\nlocal + photoMaterialName = \"Photo\"\r\n\r\nlocal isInitialized = false\r\nlocal photographyCamera + = nil\r\n\r\n-- \u5199\u771F\u64AE\u5F71\u6642\u306E\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\r\n-- * ExportPhotographyCamera.SetOnTakePhotoCallback\u306B\u3053\u306E\u95A2\u6570\u3092\u6E21\u3059\u3053\u3068\u3067\u3001 \r\n-- ExportPhotographyCamera.TakePhotograph\u5B9F\u884C\u6642\u306B\u3053\u306E\u95A2\u6570\u304C\u547C\u3070\u308C\u307E\u3059\u3002\r\n-- * \u5F15\u6570\u306EphotoMetadata\u306E\u4E2D\u306B\u3001\u64AE\u5F71\u3057\u305F\u30C6\u30AF\u30B9\u30C1\u30E3\u3092\u793A\u3059ID\u304C\u5165\u3063\u3066\u3044\u307E\u3059\u3002\r\n-- @@ -473,34 +470,29 @@ MonoBehaviour: vci.assets.material.SetTexture(photoMaterialName, photoTextureId)\r\nend\r\n\r\n-- \u5199\u771F\u64AE\u5F71\u306E message \u53D7\u3051\u53D6\u308A\u6642\u306B\u5B9F\u884C\u3055\u308C\u308B\u95A2\u6570\r\n-- * \u30EA\u30E2\u30FC\u30C8\u5074\u3067\u3053\u306EVCI\u304CUse\u3055\u308C\u305F\u3068\u304D\u306B\u5B9F\u884C\u3055\u308C\u307E\u3059\r\nfunction - onTakePhotoMessageReceived(sender, name, messnilge)\r\n photographyCamera.TakePhotograph()\r\nend\r\n\r\nlocal - initCameraCoroutine = coroutine.create(\r\n function()\r\n -- \u30A2\u30A4\u30C6\u30E0\u5185\u540C\u671F\u5909\u6570\u306E\u521D\u671F\u5316\u3092\u5F85\u3064\r\n - while true do\r\n local isFovInitialized = vci.state.Get(fovStateName) - ~= nil\r\n local isNearClipInitialized = vci.state.Get(nearClipStateName) - ~= nil\r\n if isFovInitialized and isNearClipInitialized then\r\n - print(\"state initialized.\")\r\n break\r\n end\r\n - print(\"waiting for state init...\")\r\n coroutine.yield()\r\n - end\r\n\r\n -- \u5199\u771F\u64AE\u5F71\u7528\u30AB\u30E1\u30E9\u751F\u6210\r\n - -- * \u5199\u771F\u64AE\u5F71\u7528\u30AB\u30E1\u30E9\u304C\u751F\u6210\u3055\u308C\u3001\"LensAnchor\"\u306ETransform\u306B\u8FFD\u5F93\u3059\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002\r\n - local lensTransform = vci.assets.GetTransform(cameraLensAnchorName)\r\n - photographyCamera = vci.cameraSystem.CreatePhotographyCamera(lensTransform)\r\n\r\n - -- \u30D7\u30EC\u30D3\u30E5\u30FC\u63CF\u753B\r\n -- * GetCameraPreviewTextureId\u3067\u30AB\u30E1\u30E9\u306E\u30D7\u30EC\u30D3\u30E5\u30FC\u306E\u30C6\u30AF\u30B9\u30C1\u30E3\u3092\u793A\u3059ID\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\r\n - -- * \u3053\u306E\u30C6\u30AF\u30B9\u30C1\u30E3ID\u3092vci.assets.material.SetTexture\u306B\u6E21\u3059\u3053\u3068\u3067\u30D7\u30EC\u30D3\u30E5\u30FC\u3092\u8868\u793A\u3057\u307E\u3059\u3002\r\n - local previewTextureId = photographyCamera.GetCameraPreviewTextureId()\r\n - vci.assets.material.SetTexture(previewMaterialName, previewTextureId)\r\n\r\n - -- \u5199\u771F\u64AE\u5F71\u6642\u306E\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u3092\u30BB\u30C3\u30C8\r\n - -- * ExportPhotographyCamera.TakePhotograph\u5B9F\u884C\u6642\u306B\u3001\u3053\u3053\u3067\u6E21\u3057\u305F\u95A2\u6570\u304C\u5B9F\u884C\u3055\u308C\u307E\u3059\u3002\r\n - photographyCamera.SetOnTakePhotoCallback(onTakePhotoCallback)\r\n\r\n - -- \u30AB\u30E1\u30E9\u306ENear Clip Plane\u3068\u5782\u76F4FOV\u306E\u521D\u671F\u5024\u3092\u30BB\u30C3\u30C8\r\n - initialFov = vci.state.Get(fovStateName)\r\n photographyCamera.SetVerticalFieldOfView(initialFov)\r\n - initialNearClip = vci.state.Get(nearClipStateName)\r\n photographyCamera.SetNearClipPlane(initialNearClip)\r\n\r\n - -- \u5199\u771F\u64AE\u5F71\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u308B\r\n - -- * \u30EA\u30E2\u30FC\u30C8\u5074\u304B\u3089\u9001\u4FE1\u3055\u308C\u305F\u3001\"message_take_photo\"\u3068\u3044\u3046\u540D\u524D\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u4FE1\u3057\u305F\u3068\u304D\u306B\u3001\r\n - -- \u3053\u3053\u3067\u6E21\u3057\u305F\u95A2\u6570\u304C\u5B9F\u884C\u3055\u308C\u307E\u3059\u3002\r\n - vci.message.On(takePhotoMessageName, onTakePhotoMessageReceived)\r\n\r\n - -- \u30AB\u30E1\u30E9\u306E\u521D\u671F\u5316\u5B8C\u4E86\r\n isInitialized - = true\r\n end\r\n)\r\n\r\nvci.StartCoroutine(initCameraCoroutine)\r\n\r\nfunction - updateAll()\r\n -- \u30BA\u30FC\u30E0\u30A2\u30A6\u30C8\u306E\u30DC\u30BF\u30F3\u3092\u30AB\u30E1\u30E9\u672C\u4F53\u306B\u8FFD\u5F93\u3055\u305B\u308B\r\n + onTakePhotoMessageReceived(sender, name, messnilge)\r\n photographyCamera.TakePhotograph()\r\nend\r\n\r\n-- + \u5199\u771F\u64AE\u5F71\u7528\u30AB\u30E1\u30E9\u751F\u6210\r\n-- * \u5199\u771F\u64AE\u5F71\u7528\u30AB\u30E1\u30E9\u304C\u751F\u6210\u3055\u308C\u3001\"LensAnchor\"\u306ETransform\u306B\u8FFD\u5F93\u3059\u308B\u3088\u3046\u306B\u306A\u308A\u307E\u3059\u3002\r\nlocal + lensTransform = vci.assets.GetTransform(cameraLensAnchorName)\r\nphotographyCamera + = vci.cameraSystem.CreatePhotographyCamera(lensTransform)\r\n\r\n-- \u30D7\u30EC\u30D3\u30E5\u30FC\u63CF\u753B\r\n-- + * GetCameraPreviewTextureId\u3067\u30AB\u30E1\u30E9\u306E\u30D7\u30EC\u30D3\u30E5\u30FC\u306E\u30C6\u30AF\u30B9\u30C1\u30E3\u3092\u793A\u3059ID\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\r\n-- + * \u3053\u306E\u30C6\u30AF\u30B9\u30C1\u30E3ID\u3092vci.assets.material.SetTexture\u306B\u6E21\u3059\u3053\u3068\u3067\u30D7\u30EC\u30D3\u30E5\u30FC\u3092\u8868\u793A\u3057\u307E\u3059\u3002\r\nlocal + previewTextureId = photographyCamera.GetCameraPreviewTextureId()\r\nvci.assets.material.SetTexture(previewMaterialName, + previewTextureId)\r\n\r\n-- \u5199\u771F\u64AE\u5F71\u6642\u306E\u30B3\u30FC\u30EB\u30D0\u30C3\u30AF\u3092\u30BB\u30C3\u30C8\r\n-- + * ExportPhotographyCamera.TakePhotograph\u5B9F\u884C\u6642\u306B\u3001\u3053\u3053\u3067\u6E21\u3057\u305F\u95A2\u6570\u304C\u5B9F\u884C\u3055\u308C\u307E\u3059\u3002\r\nphotographyCamera.SetOnTakePhotoCallback(onTakePhotoCallback)\r\n\r\n-- + \u30A2\u30A4\u30C6\u30E0\u5185\u540C\u671F\u5909\u6570\u3092\u521D\u671F\u5316\r\n-- + * \u81EA\u8EAB\u304C\u3053\u306EVCI\u306E\u6240\u6709\u6A29\u3092\u6301\u3063\u3066\u3044\u308B\u3068\u304D\u306E\u307F\u5B9F\u884C\u3057\u307E\u3059\u3002\r\nif + vci.assets.IsMine then\r\n local isFovInitialized = vci.state.Get(fovStateName) + ~= nil\r\n-- \u30AB\u30E1\u30E9\u306E fov \u304C\u521D\u671F\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u5834\u5408\u3001\u521D\u671F\u5316\u51E6\u7406\u3092\u5B9F\u884C\u3059\u308B\r\n + if not isFovInitialized then\r\n print(\"initialize fov...\")\r\n + vci.state.Set(fovStateName, initialFov)\r\n end\r\nend\r\nl\r\n\r\n-- \u30AB\u30E1\u30E9\u306ENear + Clip Plane\u3068\u5782\u76F4FOV\u306E\u521D\u671F\u5024\u3092\u30BB\u30C3\u30C8\r\ninitialFov + = vci.state.Get(fovStateName)\r\nphotographyCamera.SetVerticalFieldOfView(initialFov)\r\n-- + \u5FC5\u8981\u306A\u3089\u3070\u3001near clip plane \u3092\u4EFB\u610F\u306E\u5024\u306B\u30BB\u30C3\u30C8\u3059\u308B\r\n-- + photographyCamera.SetNearClipPlane(initialNearClip)\r\n\r\n-- \u5199\u771F\u64AE\u5F71\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u3051\u53D6\u308B\r\n-- + * \u30EA\u30E2\u30FC\u30C8\u5074\u304B\u3089\u9001\u4FE1\u3055\u308C\u305F\u3001\"message_take_photo\"\u3068\u3044\u3046\u540D\u524D\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D7\u4FE1\u3057\u305F\u3068\u304D\u306B\u3001\r\n-- + \u3053\u3053\u3067\u6E21\u3057\u305F\u95A2\u6570\u304C\u5B9F\u884C\u3055\u308C\u307E\u3059\u3002\r\nvci.message.On(takePhotoMessageName, + onTakePhotoMessageReceived)\r\n\r\n-- \u30AB\u30E1\u30E9\u306E\u521D\u671F\u5316\u5B8C\u4E86\r\nisInitialized + = true\r\n\r\nfunction updateAll()\r\n -- \u30BA\u30FC\u30E0\u30A2\u30A6\u30C8\u306E\u30DC\u30BF\u30F3\u3092\u30AB\u30E1\u30E9\u672C\u4F53\u306B\u8FFD\u5F93\u3055\u305B\u308B\r\n -- * \u8FFD\u5F93\u51E6\u7406\u306F\u3001\u30BA\u30FC\u30E0\u30A2\u30A6\u30C8\u30DC\u30BF\u30F3\u306E\u6240\u6709\u6A29\u3092\u6301\u3063\u3066\u3044\u308B\u30E6\u30FC\u30B6\u30FC\u306E\u74B0\u5883\u4E0A\u3067\u306E\u307F\u884C\u308F\u308C\u307E\u3059\u3002\r\n if wideButtonTransform.IsMine then\r\n wideButtonAnchorPos = wideButtonAnchorTransform.GetPosition()\r\n wideButtonTransform.SetPosition(wideButtonAnchorPos)\r\n wideButtonAnchorRot diff --git a/Assets/VCI-Official-Samples/CameraApiSample/Scripts/main.lua b/Assets/VCI-Official-Samples/CameraApiSample/Scripts/main.lua index 3c141d0..4a5b64d 100644 --- a/Assets/VCI-Official-Samples/CameraApiSample/Scripts/main.lua +++ b/Assets/VCI-Official-Samples/CameraApiSample/Scripts/main.lua @@ -27,12 +27,11 @@ local teleButtonAnchorTransform = vci.assets.GetTransform("ButtonTeleAnchor") local isTeleButtonUsed = false local fovStateName = "FOV" +local initialFov = 60 local minFov = 10 local maxFov = 170 local fovStep = 2 -local nearClipStateName = "NEAR_CLIP" - local takePhotoMessageName = "message_take_photo" local previewMaterialName = "Display" @@ -41,13 +40,6 @@ local photoMaterialName = "Photo" local isInitialized = false local photographyCamera = nil --- アイテム内同期変数を初期化 --- * 自身がこのVCIの所有権を持っているときのみ実行します。 -if vci.assets.IsMine then - vci.state.Set(fovStateName, 60) - vci.state.Set(nearClipStateName, 0.01) -end - -- 写真撮影時のコールバック -- * ExportPhotographyCamera.SetOnTakePhotoCallbackにこの関数を渡すことで、 -- ExportPhotographyCamera.TakePhotograph実行時にこの関数が呼ばれます。 @@ -65,52 +57,46 @@ function onTakePhotoMessageReceived(sender, name, messnilge) photographyCamera.TakePhotograph() end -local initCameraCoroutine = coroutine.create( - function() - -- アイテム内同期変数の初期化を待つ - while true do - local isFovInitialized = vci.state.Get(fovStateName) ~= nil - local isNearClipInitialized = vci.state.Get(nearClipStateName) ~= nil - if isFovInitialized and isNearClipInitialized then - print("state initialized.") - break - end - print("waiting for state init...") - coroutine.yield() - end - - -- 写真撮影用カメラ生成 - -- * 写真撮影用カメラが生成され、"LensAnchor"のTransformに追従するようになります。 - local lensTransform = vci.assets.GetTransform(cameraLensAnchorName) - photographyCamera = vci.cameraSystem.CreatePhotographyCamera(lensTransform) - - -- プレビュー描画 - -- * GetCameraPreviewTextureIdでカメラのプレビューのテクスチャを示すIDを取得します。 - -- * このテクスチャIDをvci.assets.material.SetTextureに渡すことでプレビューを表示します。 - local previewTextureId = photographyCamera.GetCameraPreviewTextureId() - vci.assets.material.SetTexture(previewMaterialName, previewTextureId) - - -- 写真撮影時のコールバックをセット - -- * ExportPhotographyCamera.TakePhotograph実行時に、ここで渡した関数が実行されます。 - photographyCamera.SetOnTakePhotoCallback(onTakePhotoCallback) - - -- カメラのNear Clip Planeと垂直FOVの初期値をセット - initialFov = vci.state.Get(fovStateName) - photographyCamera.SetVerticalFieldOfView(initialFov) - initialNearClip = vci.state.Get(nearClipStateName) - photographyCamera.SetNearClipPlane(initialNearClip) - - -- 写真撮影のメッセージを受け取る - -- * リモート側から送信された、"message_take_photo"という名前のメッセージを受信したときに、 - -- ここで渡した関数が実行されます。 - vci.message.On(takePhotoMessageName, onTakePhotoMessageReceived) - - -- カメラの初期化完了 - isInitialized = true +-- 写真撮影用カメラ生成 +-- * 写真撮影用カメラが生成され、"LensAnchor"のTransformに追従するようになります。 +local lensTransform = vci.assets.GetTransform(cameraLensAnchorName) +photographyCamera = vci.cameraSystem.CreatePhotographyCamera(lensTransform) + +-- プレビュー描画 +-- * GetCameraPreviewTextureIdでカメラのプレビューのテクスチャを示すIDを取得します。 +-- * このテクスチャIDをvci.assets.material.SetTextureに渡すことでプレビューを表示します。 +local previewTextureId = photographyCamera.GetCameraPreviewTextureId() +vci.assets.material.SetTexture(previewMaterialName, previewTextureId) + +-- 写真撮影時のコールバックをセット +-- * ExportPhotographyCamera.TakePhotograph実行時に、ここで渡した関数が実行されます。 +photographyCamera.SetOnTakePhotoCallback(onTakePhotoCallback) + +-- アイテム内同期変数を初期化 +-- * 自身がこのVCIの所有権を持っているときのみ実行します。 +if vci.assets.IsMine then + local isFovInitialized = vci.state.Get(fovStateName) ~= nil +-- カメラの fov が初期化されていない場合、初期化処理を実行する + if not isFovInitialized then + print("initialize fov...") + vci.state.Set(fovStateName, initialFov) end -) +end + + +-- カメラのNear Clip Planeと垂直FOVの初期値をセット +initialFov = vci.state.Get(fovStateName) +photographyCamera.SetVerticalFieldOfView(initialFov) +-- 必要ならば、near clip plane を任意の値にセットする +-- photographyCamera.SetNearClipPlane(initialNearClip) + +-- 写真撮影のメッセージを受け取る +-- * リモート側から送信された、"message_take_photo"という名前のメッセージを受信したときに、 +-- ここで渡した関数が実行されます。 +vci.message.On(takePhotoMessageName, onTakePhotoMessageReceived) -vci.StartCoroutine(initCameraCoroutine) +-- カメラの初期化完了 +isInitialized = true function updateAll() -- ズームアウトのボタンをカメラ本体に追従させる diff --git a/Assets/VCI-Official-Samples/StateApiSample/Scripts/main.lua b/Assets/VCI-Official-Samples/StateApiSample/Scripts/main.lua index 0add633..7b81d52 100644 --- a/Assets/VCI-Official-Samples/StateApiSample/Scripts/main.lua +++ b/Assets/VCI-Official-Samples/StateApiSample/Scripts/main.lua @@ -55,7 +55,9 @@ end function update() syncTransform() +end +function updateAll() -- state値を監視して更新があれば表示を更新 local upstreamMyState = vci.state.Get(myStateName) if upstreamMyState ~= localMyState then diff --git a/Assets/VCI-Official-Samples/StateApiSample/StateApiSample.unity b/Assets/VCI-Official-Samples/StateApiSample/StateApiSample.unity index f6481f0..ec77f6b 100644 --- a/Assets/VCI-Official-Samples/StateApiSample/StateApiSample.unity +++ b/Assets/VCI-Official-Samples/StateApiSample/StateApiSample.unity @@ -818,7 +818,7 @@ MonoBehaviour: contactInformation: reference: thumbnail: {fileID: 0} - version: 1.0 + version: 1.1 description: exporterVersion: 0.33 specVersion: @@ -854,8 +854,8 @@ MonoBehaviour: \u30DC\u30BF\u30F3\u3092\u89E6\u308B\u3068state\u3092\u5909\u66F4\u3059\u308B\r\nfunction onUse(name)\r\n if name == button1Name then\r\n vci.state.Set(myStateName, 1)\r\n elseif name == button2Name then\r\n vci.state.Set(myStateName, - 2)\r\n end\r\nend\r\n\r\nfunction update()\r\n syncTransform()\r\n\r\n - -- state\u5024\u3092\u76E3\u8996\u3057\u3066\u66F4\u65B0\u304C\u3042\u308C\u3070\u8868\u793A\u3092\u66F4\u65B0\r\n + 2)\r\n end\r\nend\r\n\r\nfunction update()\r\n syncTransform()\r\nend\r\n\r\nfunction + updateAll()\r\n -- state\u5024\u3092\u76E3\u8996\u3057\u3066\u66F4\u65B0\u304C\u3042\u308C\u3070\u8868\u793A\u3092\u66F4\u65B0\r\n local upstreamMyState = vci.state.Get(myStateName)\r\n if upstreamMyState ~= localMyState then\r\n showState(upstreamMyState)\r\n localMyState = upstreamMyState\r\n end\r\nend\r\n\r\n-- \u30B5\u30FC\u30D0\u30FC\u4E0A\u306Estate\u5024\u3067\u8868\u793A\u3092\u521D\u671F\u5316\r\n-- diff --git a/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs b/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs new file mode 100644 index 0000000..67fceb1 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs @@ -0,0 +1,53 @@ +using UniGLTF; +using UnityEngine; + +namespace VCI +{ + public sealed class EditorPhysicsColliderImporter + { + private readonly VciData _data; + private readonly VCIImporter _context; + private readonly UnityPath _prefabFilePath; + + private UnityPath AssetDir => _prefabFilePath.GetAssetFolder(".ColliderMeshes"); + + public EditorPhysicsColliderImporter(VciData vciData, VCIImporter context, UnityPath prefabFilePath) + { + _data = vciData; + _context = context; + _prefabFilePath = prefabFilePath; + } + + public void ExtractAssetFiles() + { + // NOTE: MeshCollider の Mesh オブジェクトを保存する. + foreach (var node in _context.Nodes) + { + var meshCollider = node.gameObject.GetComponent(); + if (meshCollider == null || meshCollider.sharedMesh == null) continue; + + AssetDir.EnsureFolder(); + // NOTE: Collider Mesh の名前が VCI 内で一意であることを前提とする. + var filePath = AssetDir.Child($"{meshCollider.sharedMesh.name}.asset"); + if (filePath.LoadAsset() == null) + { + filePath.CreateAsset(meshCollider.sharedMesh); + } + } + } + + public void SetupAfterEditorDelayCall() + { + // NOTE: MeshCollider の Mesh オブジェクトを、アセット下のものに差し替える. + foreach (var node in _context.Nodes) + { + var meshCollider = node.gameObject.GetComponent(); + if (meshCollider == null || meshCollider.sharedMesh == null) continue; + + var filePath = AssetDir.Child($"{meshCollider.sharedMesh.name}.asset"); + var mesh = filePath.LoadAsset(); + meshCollider.sharedMesh = mesh; + } + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs.meta b/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs.meta new file mode 100644 index 0000000..945214a --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/ComponentImporters/EditorPhysicsColliderImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9b2d7442637a42ba88ce11ccdd18347d +timeCreated: 1636982847 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/IO/VCIAssetPostprocessor.cs b/Assets/VCI/UniVCI/Editor/IO/VCIAssetPostprocessor.cs index b9ee306..eef3926 100644 --- a/Assets/VCI/UniVCI/Editor/IO/VCIAssetPostprocessor.cs +++ b/Assets/VCI/UniVCI/Editor/IO/VCIAssetPostprocessor.cs @@ -1,17 +1,12 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using UnityEditor; using UniGLTF; using UnityEngine; -using VRMShaders; -using Object = UnityEngine.Object; namespace VCI { -#if !VRM_STOP_ASSETPOSTPROCESSOR - public sealed class VCIAssetPostprocessor : AssetPostprocessor + public sealed class VciAssetPostprocessor : AssetPostprocessor { private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) @@ -43,43 +38,8 @@ private static void ImportVci(UnityPath path) var prefabPath = path.Parent.Child(path.FileNameWithoutExtension + ".prefab"); - Action onCompleted = (paths) => - { - var map = new Dictionary(); - foreach (var texturePath in paths.TexturePaths) - { - var texture = texturePath.LoadAsset(); - map.Add(new SubAssetKey(texture), texture); - } - foreach (var audioClipPath in paths.AudioClipPaths) - { - var clip = audioClipPath.LoadAsset(); - map.Add(new SubAssetKey(typeof(AudioClip), clip.name), clip); - } - - using (var context = new VCIImporter(data, map)) - { - var editor = new VCIEditorImporterContext(data, context, prefabPath); - foreach (var textureInfo in context.TextureDescriptorGenerator.Get().GetEnumerable()) - { - VRMShaders.TextureImporterConfigurator.Configure(textureInfo, context.TextureFactory.ExternalTextures); - } - - // after all - var loaded = context.Load(); - // NOTE: ロード中に物理演算が働かないように Disabled されているため、Enable してから保存する. - context.RuntimeVciInstance.EnablePhysicalBehaviour(true); - editor.SaveAsAsset(loaded); - } - }; - - // extract texture images - using (var context = new VCIImporter(data)) - { - var editor = new VCIEditorImporterContext(data, context, prefabPath); - editor.ConvertAndExtractAssets(onCompleted); - } + var editorImporter = new VciEditorImporter(data, prefabPath); + editorImporter.Load(); } } -#endif } diff --git a/Assets/VCI/UniVCI/Editor/IO/VCIEditorImporterContext.cs b/Assets/VCI/UniVCI/Editor/IO/VCIEditorImporterContext.cs deleted file mode 100644 index 0ebd07b..0000000 --- a/Assets/VCI/UniVCI/Editor/IO/VCIEditorImporterContext.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using UniGLTF; -using UniJSON; -using UnityEditor; -using UnityEngine; -using VRMShaders; - -namespace VCI -{ - public class VCIEditorImporterContext - { - private readonly VciData _data; - private readonly VCIImporter _context; - private readonly UnityPath _prefabPath; - List m_paths = new List(); - - public ITextureDescriptorGenerator TextureDescriptorGenerator => _context.TextureDescriptorGenerator; - - public VCIEditorImporterContext(VciData data, VCIImporter context, UnityPath prefabPath) - { - _data = data; - _context = context; - _prefabPath = prefabPath; - } - - /// - /// Extract images from glb or gltf out of Assets folder. - /// - public void ConvertAndExtractAssets(Action onExtractionCompleted) - { - // - // convert images(metallic roughness, occlusion map) - // - var task = _context.LoadAsync(new ImmediateCaller()); - if (!task.IsCompleted) - { - throw new Exception(); - } - if (task.IsCanceled || task.IsFaulted) - { - throw new Exception(); - } - var result = task.Result; - var loadedTextures = result.RuntimeResources - .Where(x => x.Item1.Type == typeof(Texture)) - .ToDictionary(x => x.Item1, x => x.Item2 as Texture); - - // Extract assets - var audioClipPaths = EditorAudioImporter.ExtractAssetFiles(_data, _prefabPath); - ExtractEffekseerAsEditorAssets(); - ExtractScriptAsEditorAssets(); - - // Finally, extract textures. - var dirName = $"{_prefabPath.FileNameWithoutExtension}.Textures"; - TextureExtractor.ExtractTextures( - _context.Data, - _prefabPath.Parent.Child(dirName), - _context.TextureDescriptorGenerator, - loadedTextures, - (_x, _y) => { }, - (textureAssetPaths) => - { - var paths = new VciEditorImporterResourcePaths(); - paths.TexturePaths.AddRange(textureAssetPaths); - paths.AudioClipPaths.AddRange(audioClipPaths); - onExtractionCompleted(paths); - } - ); - - result.Dispose(); - } - - private void SaveAsAsset(SubAssetKey _, UnityEngine.Object o) - { - if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) - { -#if VRM_DEVELOP - // 来ない? - Debug.LogWarning($"{o} already exists. skip write"); -#endif - return; - } - - var assetPath = GetAssetPath(_prefabPath, o); - if (!assetPath.IsNull) - { - // アセットとして書き込む - assetPath.Parent.EnsureFolder(); - assetPath.CreateAsset(o); - m_paths.Add(assetPath); - } - } - - private UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o) - { - // GLTF assets - if (o is Material) - { - var materialDir = prefabPath.GetAssetFolder(".Materials"); - var materialPath = materialDir.Child(o.name.EscapeFilePath() + ".asset"); - return materialPath; - } - else if (o is Mesh) - { - var meshDir = prefabPath.GetAssetFolder(".Meshes"); - var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset"); - return meshPath; - } - else if (o is AnimationClip) - { - var animDir = prefabPath.GetAssetFolder(".Animations"); - var animPath = animDir.Child(o.name.EscapeFilePath() + ".asset"); - return animPath; - } - else - { - return default(UnityPath); - } - } - - public void SaveAsAsset(UniGLTF.RuntimeGltfInstance loaded) - { - SetupScriptsAfterEditorDelayCall(); - SetupEffekseerAfterEditorDelayCall(); - - loaded.ShowMeshes(); - - // - // save sub assets - // - m_paths.Clear(); - m_paths.Add(_prefabPath); - loaded.TransferOwnership(SaveAsAsset); - var root = loaded.Root; - - // NOTE: RuntimeGltfInstance は prefab には不要. - UnityObjectDestoyer.DestroyRuntimeOrEditor(loaded); - - // Create or update Main Asset - if (_prefabPath.IsFileExists) - { - Debug.LogFormat("replace prefab: {0}", _prefabPath); - var prefab = _prefabPath.LoadAsset(); - PrefabUtility.SaveAsPrefabAssetAndConnect(root, _prefabPath.Value, InteractionMode.AutomatedAction); - } - else - { - Debug.LogFormat("create prefab: {0}", _prefabPath); - PrefabUtility.SaveAsPrefabAssetAndConnect(root, _prefabPath.Value, InteractionMode.AutomatedAction); - } - - // destroy GameObject on scene - UnityObjectDestoyer.DestroyRuntimeOrEditor(root); - - - foreach (var x in m_paths) - { - x.ImportAsset(); - } - } - - private void ExtractEffekseerAsEditorAssets() - { - new EditorEffekseerImporter(_data, _context, _prefabPath).ExtractAssetFiles(); - } - - private void SetupEffekseerAfterEditorDelayCall() - { - new EditorEffekseerImporter(_data, _context, _prefabPath).SetupAfterEditorDelayCall(); - } - - private void ExtractScriptAsEditorAssets() - { - new EditorScriptImporter(_data, _context, _prefabPath).ExtractAssetFiles(); - } - - private void SetupScriptsAfterEditorDelayCall() - { - new EditorScriptImporter(_data, _context, _prefabPath).SetupAfterEditorDelayCall(); - } - } -} diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporter.cs b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporter.cs new file mode 100644 index 0000000..12f617d --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporter.cs @@ -0,0 +1,30 @@ +using UniGLTF; + +namespace VCI +{ + public sealed class VciEditorImporter + { + private readonly VciData _data; + private readonly UnityPath _prefabPath; + + public VciEditorImporter(VciData data, UnityPath prefabPath) + { + _data = data; + _prefabPath = prefabPath; + } + + public void Load() + { + using (var firstPassImporter = new VciEditorImporterFirstPass(_data, _prefabPath)) + { + firstPassImporter.Load((paths) => + { + using (var secondPassImporter = new VciEditorImporterSecondPass(_data, _prefabPath, paths)) + { + secondPassImporter.Load(); + } + }); + } + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/IO/VCIEditorImporterContext.cs.meta b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporter.cs.meta similarity index 100% rename from Assets/VCI/UniVCI/Editor/IO/VCIEditorImporterContext.cs.meta rename to Assets/VCI/UniVCI/Editor/IO/VciEditorImporter.cs.meta diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterExternalAssetPathList.cs b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterExternalAssetPathList.cs new file mode 100644 index 0000000..e8b4c1a --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterExternalAssetPathList.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using UniGLTF; + +namespace VCI +{ + /// + /// VCIImporter に External Asset として渡すオブジェクトリスト + /// + internal sealed class VciEditorImporterExternalAssetPathList + { + public List TexturePaths { get; } + public List AudioClipPaths { get; } + + public VciEditorImporterExternalAssetPathList(List texturePaths, List audioClipPaths) + { + TexturePaths = texturePaths; + AudioClipPaths = audioClipPaths; + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterResourcePaths.cs.meta b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterExternalAssetPathList.cs.meta similarity index 100% rename from Assets/VCI/UniVCI/Editor/IO/VciEditorImporterResourcePaths.cs.meta rename to Assets/VCI/UniVCI/Editor/IO/VciEditorImporterExternalAssetPathList.cs.meta diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs new file mode 100644 index 0000000..0a23353 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs @@ -0,0 +1,89 @@ +using System; +using System.Linq; +using UniGLTF; +using UnityEngine; + +namespace VCI +{ + /// + /// Editor で 1 回目の VCI インポートを行う. + /// 1 回目は、VCI に含まれるアセットのうち、Runtime 上の UnityEngine.Object のシリアライズドオブジェクト "ではない" 形式で Project 上に保存したいものを、展開する責務を持つ. + /// + /// たとえば Texture は VCI ファイルに含まれる PNG や JPG 画像のバイナリデータをそのまま Project 上にアセットとして保存したい. + /// この PNG 画像のアセットに対応する Texture2D は UnityEngine が自動生成するインスタンスである. + /// つまり Runtime 上のユーザコードで new Texture2D().LoadImage(binary) したインスタンスとは無関係である. + /// したがって 1 回目で事前に Editor Asset として展開したものを 2 回目の Importer に渡して参照させる必要がある. + /// + /// 一方で Mesh ファイルは Runtime 上のユーザコードで new Mesh() したものを Project 上にアセットとして保存するだけで済む. + /// この Mesh アセットは、Mesh オブジェクトそのもののシリアライズドオブジェクトである. + /// つまり Runtime 上のユーザコードで new Mesh() したインスタンスと一致する. + /// したがって 1 回目の Import では扱わない. + /// + internal sealed class VciEditorImporterFirstPass : IDisposable + { + private readonly VciData _data; + private readonly UnityPath _prefabPath; + private readonly VCIImporter _importer; + + public VciEditorImporterFirstPass(VciData data, UnityPath prefabPath) + { + _data = data; + _prefabPath = prefabPath; + + _importer = new VCIImporter(_data); + } + + public void Dispose() + { + _importer?.Dispose(); + } + + public void Load(Action continuation) + { + using (var gltfInstance = _importer.Load()) + { + var loadedTextures = gltfInstance.RuntimeResources + .Where(x => x.Item1.Type == typeof(Texture)) + .ToDictionary(x => x.Item1, x => x.Item2 as Texture); + + // NOTE: VCI 用のアセットを Extract する. + var audioClipPaths = EditorAudioImporter.ExtractAssetFiles(_data, _prefabPath); + ExtractEffekseerAsEditorAssets(); + ExtractScriptAsEditorAssets(); + ExtractColliderMeshAsEditorAssets(); + + // NOTE: GLTF の Texture アセット を Extract する. + var dirName = $"{_prefabPath.FileNameWithoutExtension}.Textures"; + TextureExtractor.ExtractTextures( + _importer.Data, + _prefabPath.Parent.Child(dirName), + _importer.TextureDescriptorGenerator, + loadedTextures, + (x, y) => { }, + (textureAssetPaths) => + { + continuation(new VciEditorImporterExternalAssetPathList( + textureAssetPaths.ToList(), + audioClipPaths.ToList() + )); + } + ); + } + } + + private void ExtractEffekseerAsEditorAssets() + { + new EditorEffekseerImporter(_data, _importer, _prefabPath).ExtractAssetFiles(); + } + + private void ExtractScriptAsEditorAssets() + { + new EditorScriptImporter(_data, _importer, _prefabPath).ExtractAssetFiles(); + } + + private void ExtractColliderMeshAsEditorAssets() + { + new EditorPhysicsColliderImporter(_data, _importer, _prefabPath).ExtractAssetFiles(); + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs.meta b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs.meta new file mode 100644 index 0000000..7b25676 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterFirstPass.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 669de11f714d4ca38726ffe3f99991a2 +timeCreated: 1638276093 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterResourcePaths.cs b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterResourcePaths.cs deleted file mode 100644 index 38cb878..0000000 --- a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterResourcePaths.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using UniGLTF; - -namespace VCI -{ - /// - /// VCIImporter に External Asset として渡すオブジェクトリスト - /// - public sealed class VciEditorImporterResourcePaths - { - public List TexturePaths = new List(); - public List AudioClipPaths = new List(); - } -} diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs new file mode 100644 index 0000000..32d7927 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UnityEditor; +using UnityEngine; +using VRMShaders; +using Object = UnityEngine.Object; + +namespace VCI +{ + /// + /// Editor で 2 回目の VCI インポートを行う. + /// 2 回目は、1 回目で展開したアセットファイルを使って、VCI をロードする. + /// また、VCI プレハブおよび通常のアセットファイルを保存する責務を持つ. + /// + internal sealed class VciEditorImporterSecondPass : IDisposable + { + private readonly VciData _data; + private readonly UnityPath _prefabPath; + private readonly VCIImporter _importer; + + public VciEditorImporterSecondPass(VciData data, UnityPath prefabPath, VciEditorImporterExternalAssetPathList vciAssetPathList) + { + _data = data; + _prefabPath = prefabPath; + + // NOTE: VCI 固有の Asset の Path を生成する. + var map = new Dictionary(); + foreach (var texturePath in vciAssetPathList.TexturePaths) + { + var texture = texturePath.LoadAsset(); + map.Add(new SubAssetKey(texture), texture); + } + foreach (var audioClipPath in vciAssetPathList.AudioClipPaths) + { + var clip = audioClipPath.LoadAsset(); + map.Add(new SubAssetKey(typeof(AudioClip), clip.name), clip); + } + + // NOTE: FirstPass で Extract したアセットを入力にあたえてインポータを作る. + _importer = new VCIImporter(_data, map); + + // NOTE: Extract したテクスチャに対して Editor の TextureImporter 設定を行う. + foreach (var textureInfo in _importer.TextureDescriptorGenerator.Get().GetEnumerable()) + { + TextureImporterConfigurator.Configure(textureInfo, _importer.TextureFactory.ExternalTextures); + } + } + + public void Dispose() + { + _importer?.Dispose(); + } + + public void Load() + { + _importer.Load(); + var vciInstance = _importer.RuntimeVciInstance; + // NOTE: Editor 用の特殊な Import 処理が必要なコンポーネントの処理を呼び出す. + SetupScriptsAfterEditorDelayCall(); + SetupEffekseerAfterEditorDelayCall(); + SetupColliderMeshAfterEditorDelayCall(); + vciInstance.ShowMeshes(); + // NOTE: ロード中に物理演算が働かないように Disabled されているため、Enable する. + vciInstance.EnablePhysicalBehaviour(true); + + // NOTE: SubAsset を保存する. + var assetPathList = new List { _prefabPath }; + vciInstance.TransferOwnership((key, o) => + { + var path = SaveSubAssetAsAsset(o, _prefabPath); + if (path.HasValue) + { + assetPathList.Add(path.Value); + } + }); + var root = vciInstance.Root; + + // NOTE: RuntimeGltfInstance Component は prefab には不要. + UnityObjectDestoyer.DestroyRuntimeOrEditor(vciInstance.GltfModel); + + // NOTE: VCI そのものの Prefab を作成するか、アップデートする. + if (_prefabPath.IsFileExists) + { + Debug.LogFormat("replace prefab: {0}", _prefabPath); + var prefab = _prefabPath.LoadAsset(); + PrefabUtility.SaveAsPrefabAssetAndConnect(root, _prefabPath.Value, InteractionMode.AutomatedAction); + } + else + { + Debug.LogFormat("create prefab: {0}", _prefabPath); + PrefabUtility.SaveAsPrefabAssetAndConnect(root, _prefabPath.Value, InteractionMode.AutomatedAction); + } + + // NOTE: シーン上のインスタンスを削除 + UnityObjectDestoyer.DestroyRuntimeOrEditor(root); + + foreach (var x in assetPathList) + { + x.ImportAsset(); + } + } + + private void SetupEffekseerAfterEditorDelayCall() + { + new EditorEffekseerImporter(_data, _importer, _prefabPath).SetupAfterEditorDelayCall(); + } + + private void SetupScriptsAfterEditorDelayCall() + { + new EditorScriptImporter(_data, _importer, _prefabPath).SetupAfterEditorDelayCall(); + } + + private void SetupColliderMeshAfterEditorDelayCall() + { + new EditorPhysicsColliderImporter(_data, _importer, _prefabPath).SetupAfterEditorDelayCall(); + } + + /// + /// 与えられた prefab の SubAsset を、通常の Asset として保存する. + /// + private static UnityPath? SaveSubAssetAsAsset(UnityEngine.Object o, UnityPath prefabPath) + { + if (!string.IsNullOrEmpty(AssetDatabase.GetAssetPath(o))) + { + Debug.LogWarning($"{o} is already extracted. This will be skipped saving as file."); + return default; + } + + var assetPath = GetAssetPath(prefabPath, o); + if (assetPath.IsNull) return default; + + assetPath.Parent.EnsureFolder(); + assetPath.CreateAsset(o); + return assetPath; + } + + private static UnityPath GetAssetPath(UnityPath prefabPath, UnityEngine.Object o) + { + switch (o) + { + // NOTE: GLTF assets + case Material _: + { + var materialDir = prefabPath.GetAssetFolder(".Materials"); + var materialPath = materialDir.Child(o.name.EscapeFilePath() + ".asset"); + return materialPath; + } + // NOTE: GLTF assets + case Mesh _: + { + var meshDir = prefabPath.GetAssetFolder(".Meshes"); + var meshPath = meshDir.Child(o.name.EscapeFilePath() + ".asset"); + return meshPath; + } + // NOTE: GLTF assets + case AnimationClip _: + { + var animDir = prefabPath.GetAssetFolder(".Animations"); + var animPath = animDir.Child(o.name.EscapeFilePath() + ".asset"); + return animPath; + } + // NOTE: VCI assets + case PhysicMaterial _: + { + var materialDir = prefabPath.GetAssetFolder(".PhysicMaterials"); + var materialPath = materialDir.Child(o.name.EscapeFilePath() + ".asset"); + return materialPath; + } + default: + return default; + } + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs.meta b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs.meta new file mode 100644 index 0000000..8f99d8a --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/IO/VciEditorImporterSecondPass.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 86370ffba0d647078437b2fcdf2a9f59 +timeCreated: 1638276074 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/MenuExecutions/VCIExportUnityPackage.cs b/Assets/VCI/UniVCI/Editor/MenuExecutions/VCIExportUnityPackage.cs index cc33b9c..4a9d111 100644 --- a/Assets/VCI/UniVCI/Editor/MenuExecutions/VCIExportUnityPackage.cs +++ b/Assets/VCI/UniVCI/Editor/MenuExecutions/VCIExportUnityPackage.cs @@ -50,15 +50,13 @@ private static string GetGitHash(string path) return System(path, "git.exe", "rev-parse HEAD").Trim(); } - private static string GetPath(string folder) + private static string GetPackagePath(string folder) { //var date = DateTime.Today.ToString(DATE_FORMAT); - var path = string.Format("{0}/{1}.{2}.unitypackage", - folder, - VCIVersion.VCI_VERSION, - VCIVersion.PATCH_NUMBER - ).Replace("\\", "/"); + var path = + $"{folder}/{VCIVersion.VCI_VERSION}.{VCIVersion.PATCH_NUMBER}.unitypackage" + .Replace("\\", "/"); return path; } @@ -76,14 +74,19 @@ private static void CleanUpDirectory(string targetDirectoryPath) } } - private static IEnumerable EnumerateFiles(string path, Func isExclude = null) + // path 以下に存在する、パッケージ含めるべきすべてのファイルを enumerate する + // - 以下のファイルは enumerate 対象から除外する + // - .git ファイル + // - isExclude の条件に引っ掛かったファイル + // - .meta ファイル + private static IEnumerable EnumeratePackageFiles(string path, Func isExclude = null) { path = path.Replace("\\", "/"); if (Directory.Exists(path)) { foreach (var child in Directory.GetFileSystemEntries(path)) - foreach (var x in EnumerateFiles(child, isExclude)) + foreach (var x in EnumeratePackageFiles(child, isExclude)) yield return x; } else @@ -132,83 +135,97 @@ private static bool EndsWith(string path, params string[] exts) return false; } - private static bool IsExclude(string path) + // path が ExportToPackageDirectories に含まれていないフォルダ以下のフォルダ/ファイルであった場合、trueを返す + private static bool IsExcludeFromPackage(string path) { - if (!IncluceFiles.Any(x => path.StartsWith(x))) return true; + if (!ExportToPackageDirectories.Any(path.StartsWith)) return true; return false; } - private static string[] IncluceFiles = new string[] + private static readonly string[] ExportToPackageDirectories = new string[] { + // VCI のメイン実装 "Assets/VCI/UniVCI", - "Assets/VCI/Runtime", + // Effekseer + // - Assets/ScriptsExternalのみビルド対象から外す "Assets/Effekseer/Editor", "Assets/Effekseer/Materials", "Assets/Effekseer/Plugins", "Assets/Effekseer/Resources", "Assets/Effekseer/Scripts", + // NAudio "Assets/NAudio", - // Sample files + // 公式サンプルVCI "Assets/VCI-Official-Samples", // DigitalSignature files "Assets/VCI-DigitalSignature", }; - - private static string[] adfFiles = new string[] + // 明示的に指定して出力するasmdefファイル群 + private static readonly string[] AdfFiles = new string[] { - "Assets/VCI/VCI.asmdef", + // Assets/Effekseerディレクトリ内のファイルはパッケージ出力対象になっていない "Assets/Effekseer/EffekseerAssemblyDefinition.asmdef", }; + // 明示的に指定して出力するpackage.jsonファイル群 + // - unitypackageをインポートするだけでユーザー公開のUniVCIリポジトリをUPM Readyにするために必要 + private static readonly string[] PackageJsonFiles = new string[] + { + "Assets/VCI/package.json", + "Assets/Effekseer/package.json" + // NAudioのpackage.jsonは、EnumeratePackageFilesの対象であるためここで指定する必要はない + }; + #if VCI_DEVELOP [MenuItem(ExportUnityPackageMenuName)] #endif public static void CreateUnityPackage() { - var folder = Path.Combine(Path.GetFullPath(Path.Combine(Application.dataPath, "..")), PACKAGE_DIR); + var packageExportDirectoryPath = Path.Combine(Path.GetFullPath(Path.Combine(Application.dataPath, "..")), PACKAGE_DIR); - if(!Directory.Exists(folder)) + if (!Directory.Exists(packageExportDirectoryPath)) { - Directory.CreateDirectory(folder); + Directory.CreateDirectory(packageExportDirectoryPath); } - CleanUpDirectory(folder); + CleanUpDirectory(packageExportDirectoryPath); - var path = GetPath(folder); + var defaultPackagePath = GetPackagePath(packageExportDirectoryPath); { - var filesA = EnumerateFiles("Assets/VCI", IsExclude).ToArray(); - var filesB = EnumerateFiles("Assets/Effekseer", IsExclude).ToArray(); - var filesC = EnumerateFiles("Assets/NAudio", IsExclude).ToArray(); - var vciSampleFiles = EnumerateFiles("Assets/VCI-Official-Samples", IsExclude).ToArray(); - var files = adfFiles.Concat(filesA.Concat(filesB.Concat(filesC.Concat(vciSampleFiles)))).ToArray(); + var vciFiles = EnumeratePackageFiles("Assets/VCI", IsExcludeFromPackage).ToArray(); + var effekseerFiles = EnumeratePackageFiles("Assets/Effekseer", IsExcludeFromPackage).ToArray(); + var nAudioFiles = EnumeratePackageFiles("Assets/NAudio", IsExcludeFromPackage).ToArray(); + var vciSampleFiles = EnumeratePackageFiles("Assets/VCI-Official-Samples", IsExcludeFromPackage).ToArray(); + var additionalFiles = AdfFiles.Concat(PackageJsonFiles).ToArray(); + var defaultPackageFiles = additionalFiles.Concat(vciFiles.Concat(effekseerFiles.Concat(nAudioFiles.Concat(vciSampleFiles)))).ToArray(); // Default Package Debug.LogFormat("{0}", - string.Join("", files.Select((x, i) => string.Format("[{0:##0}] {1}\n", i, x)).ToArray())); - AssetDatabase.ExportPackage(files - , path, + string.Join("", defaultPackageFiles.Select((x, i) => $"[{i:##0}] {x}\n").ToArray())); + AssetDatabase.ExportPackage(defaultPackageFiles + , defaultPackagePath, ExportPackageOptions.Default); // DigitalSignature Package { - var digitalSignatureFiles = EnumerateFiles("Assets/VCI-DigitalSignature", IsExclude).ToArray(); - var fileName = Path.GetFileNameWithoutExtension(path); - var ext = Path.GetExtension(path); - var exportPath = Path.GetDirectoryName(path) + "\\" + fileName + "_digitalSignature" + ext; - files = files.Concat(digitalSignatureFiles).ToArray(); - AssetDatabase.ExportPackage(files - , exportPath, + var digitalSignatureFiles = EnumeratePackageFiles("Assets/VCI-DigitalSignature", IsExcludeFromPackage).ToArray(); + var defaultPackageFileName = Path.GetFileNameWithoutExtension(defaultPackagePath); + var packageExtension = Path.GetExtension(defaultPackagePath); + var digitalSignaturePackagePath = Path.GetDirectoryName(defaultPackagePath) + "\\" + defaultPackageFileName + "_digitalSignature" + packageExtension; + var digitalSignaturePackageFiles = defaultPackageFiles.Concat(digitalSignatureFiles).ToArray(); + AssetDatabase.ExportPackage(digitalSignaturePackageFiles + , digitalSignaturePackagePath, ExportPackageOptions.Default); } } - Debug.LogFormat("exported: {0}", path); + Debug.LogFormat("exported: {0}", defaultPackagePath); } } } \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs b/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs new file mode 100644 index 0000000..4c0146d --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs @@ -0,0 +1,17 @@ +using UnityEditor; + +namespace VCI +{ + public static class VciPackageJsonMenu + { + private const string GeneratePackageJsonMenuName = Constants.DevelopMenuPrefix + "/Generate package.json"; + +#if VCI_DEVELOP + [MenuItem(GeneratePackageJsonMenuName)] +#endif + private static void GeneratePackageJson() + { + WriteVciPackageJsonService.WritePackageJsonFile(); + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs.meta b/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs.meta new file mode 100644 index 0000000..8a854a4 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/MenuExecutions/VciPackageJsonMenu.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3b9b95b419684c44abec071cc196684a +timeCreated: 1637748501 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson.meta new file mode 100644 index 0000000..eafbf69 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96c3f22d1aa721847bc325d0267240e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs new file mode 100644 index 0000000..643d016 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs @@ -0,0 +1,31 @@ +using System; +using UnityEngine; + +namespace VCI +{ + // パッケージの作者 + // TODO: Nameがない場合Exceptionを投げる + [Serializable] + internal sealed class Author + { + [SerializeField] + private string _name; + + [SerializeField] + private string _email; + + [SerializeField] + private string _url; + + public string Name => _name; + public string Email => _email; + public string Url => _url; + + public Author(string name, string email, string url) + { + _name = name; + _email = email; + _url = url; + } + } +} \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs.meta new file mode 100644 index 0000000..91820d3 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Author.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: db9fd7c7cdb5473bbf43449c94f1f1f9 +timeCreated: 1637736272 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs new file mode 100644 index 0000000..d0c73d7 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs @@ -0,0 +1,25 @@ +using System; +using UnityEngine; + +namespace VCI +{ + // 依存パッケージ + [Serializable] + internal sealed class Dependency + { + [SerializeField] + private OfficialPackageName _officialPackageName; + + [SerializeField] + private PackageVersion _packageVersion; + + public OfficialPackageName OfficialPackageName => _officialPackageName; + public PackageVersion PackageVersion => _packageVersion; + + public Dependency(OfficialPackageName officialPackageName, PackageVersion packageVersion) + { + _officialPackageName = officialPackageName; + _packageVersion = packageVersion; + } + } +} \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs.meta new file mode 100644 index 0000000..4a0a8e2 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/Dependency.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6081ef995adf469c9db63541aae3fac4 +timeCreated: 1637736272 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs new file mode 100644 index 0000000..1fc8239 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs @@ -0,0 +1,30 @@ +using System; +using UnityEngine; + +namespace VCI +{ + // UPMに登録する正式なパッケージ名(not 表示名) + // TODO: companyName, packageNamespaceをValidateする + [Serializable] + internal sealed class OfficialPackageName + { + [SerializeField] + private string _domainNameExtension; + [SerializeField] + private string _companyName; + [SerializeField] + private string _packageNamespace; + + public OfficialPackageName(string domainNameExtension, string companyName, string packageNamespace) + { + _domainNameExtension = domainNameExtension; + _companyName = companyName; + _packageNamespace = packageNamespace; + } + + public string GetValue() + { + return $"{_domainNameExtension}.{_companyName}.{_packageNamespace}"; + } + } +} \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs.meta new file mode 100644 index 0000000..2b815e0 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/OfficialPackageName.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d2c93646c656407fac7086ce50449cc3 +timeCreated: 1637736272 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs new file mode 100644 index 0000000..a3535f8 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs @@ -0,0 +1,30 @@ +using System; +using UnityEngine; + +namespace VCI +{ + // パッケージのバージョン + // * セマンティックバージョニングに従う + [Serializable] + internal sealed class PackageVersion + { + [SerializeField] + private int _major; + [SerializeField] + private int _minor; + [SerializeField] + private int _patch; + + public PackageVersion(int major, int minor, int patch) + { + _major = major; + _minor = minor; + _patch = patch; + } + + public string GetValue() + { + return $"{_major}.{_minor}.{_patch}"; + } + } +} \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs.meta new file mode 100644 index 0000000..6485f82 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/PackageVersion.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5266c636cf0a43318b6e97fe76b74a46 +timeCreated: 1637736272 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs new file mode 100644 index 0000000..5cb887a --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs @@ -0,0 +1,27 @@ +using System; +using UnityEngine; + +namespace VCI +{ + // パッケージに互換性がある最小の Unity バージョン + [Serializable] + internal sealed class UnityVersion + { + [SerializeField] + private int _major; + + [SerializeField] + public int _minor; + + public UnityVersion(int major, int minor) + { + _major = major; + _minor = minor; + } + + public string GetValue() + { + return $"{_major}.{_minor}"; + } + } +} \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs.meta new file mode 100644 index 0000000..6876cff --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/UnityVersion.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8030b8a5609243f59eb9f3be060ba403 +timeCreated: 1637736272 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs new file mode 100644 index 0000000..843829a --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace VCI +{ + // ref: https://docs.unity3d.com/ja/2019.4/Manual/upm-manifestPkg.html + // UniVCIパッケージのpackage.jsonに書き込むべき情報をまとめたクラス + [CreateAssetMenu(fileName = "VciPackageSettings", menuName = "ScriptableObject/Create VciPackageSettings")] + internal sealed class VciPackageSettings : ScriptableObject + { + // required + [SerializeField] + private OfficialPackageName _officialPackageName; + + // required + [SerializeField] + private PackageVersion _packageVersion; + + [SerializeField] + private string _displayName; + + [SerializeField] + private string _description; + + [SerializeField] + private UnityVersion _unityVersion; + + [SerializeField] + private List _keywords; + + [SerializeField] + private Author _author; + + [SerializeField] + private List _dependencies; + + public OfficialPackageName OfficialPackageName => _officialPackageName; + public PackageVersion PackageVersion => _packageVersion; + public string DisplayName => _displayName; + public string Description => _description; + public string UnityVersion => _unityVersion.GetValue(); + public IReadOnlyList Keywords => _keywords; + public Author Author => _author; + public IReadOnlyList Dependencies => _dependencies; + } + + + + + + +} diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs.meta new file mode 100644 index 0000000..0667921 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b56190607ecc4bc4b33f1b7ea6886cdf +timeCreated: 1637054183 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs new file mode 100644 index 0000000..09face7 --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs @@ -0,0 +1,226 @@ +using UnityEditor; +using UnityEngine; + +namespace VCI +{ + [CustomEditor(typeof(VciPackageSettings))] + public sealed class VciPackageSettingsEditor : Editor + { + private VciPackageSettings _vciPackageSettings; + private bool _showUnityVersionSection; + private bool _isDescriptionSectionExpanded; + + private void OnEnable() + { + _vciPackageSettings = target as VciPackageSettings; + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + DrawOfficialPackageName(serializedObject.FindProperty("_officialPackageName"), _vciPackageSettings.OfficialPackageName); + DrawVciPackageVersion(); + DrawPackageDisplayName(); + DrawPackageDescription(); + DrawUnityVersion(); + DrawKeywords(); + DrawAuthor(); + DrawDependencies(); + + serializedObject.ApplyModifiedProperties(); + } + + private void DrawOfficialPackageName(SerializedProperty officialPackageNameProp, OfficialPackageName packageName) + { + var domainNameExtensionProp = officialPackageNameProp.FindPropertyRelative("_domainNameExtension"); + var companyNameExtensionProp = officialPackageNameProp.FindPropertyRelative("_companyName"); + var packageNamespaceProp = officialPackageNameProp.FindPropertyRelative("_packageNamespace"); + + using (new EditorGUILayout.HorizontalScope()) + { + // Foldout付きのラベルを作る + EditorGUILayout.PropertyField(officialPackageNameProp, false); + + // パッケージ名を表示する + // * read onlyにするためにdisableする + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField(packageName.GetValue()); + } + } + + // Foldoutが展開されている場合のみ表示 + if (officialPackageNameProp.isExpanded) + { + using (new EditorGUILayout.VerticalScope(GUI.skin.box)) + { + EditorGUILayout.PropertyField(domainNameExtensionProp); + EditorGUILayout.PropertyField(companyNameExtensionProp); + EditorGUILayout.PropertyField(packageNamespaceProp); + } + } + } + + private void DrawVciPackageVersion() + { + var packageVersionProp = serializedObject.FindProperty("_packageVersion"); + var majorProp = packageVersionProp.FindPropertyRelative("_major"); + var minorProp = packageVersionProp.FindPropertyRelative("_minor"); + var patchProp = packageVersionProp.FindPropertyRelative("_patch"); + + // SerializedPropertyの各値を現在のバージョン値で上書きする + // * OnInspectorGUIの最後にApplyModifiedPropertyされることで変更がassetに反映される + majorProp.intValue = VCIVersion.MAJOR; + minorProp.intValue = VCIVersion.MINOR; + patchProp.intValue = VCIVersion.PATCH; + + // パッケージのバージョンを表示する + // * readonlyにするためにdisableする + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField("Package Version", _vciPackageSettings.PackageVersion.GetValue()); + } + } + + private void DrawDependencyPackageVersion(SerializedProperty packageVersionProp, PackageVersion packageVersion) + { + using (new EditorGUILayout.HorizontalScope()) + { + // Foldout付きのLabelを作る + EditorGUILayout.PropertyField(packageVersionProp, false); + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField(packageVersion.GetValue()); + } + } + + if (packageVersionProp.isExpanded) + { + using (new EditorGUILayout.VerticalScope(GUI.skin.box)) + { + var majorProp = packageVersionProp.FindPropertyRelative("_major"); + var minorProp = packageVersionProp.FindPropertyRelative("_minor"); + var patchProp = packageVersionProp.FindPropertyRelative("_patch"); + + EditorGUILayout.PropertyField(majorProp); + EditorGUILayout.PropertyField(minorProp); + EditorGUILayout.PropertyField(patchProp); + } + } + } + + private void DrawPackageDisplayName() + { + var displayNameProp = serializedObject.FindProperty("_displayName"); + EditorGUILayout.PropertyField(displayNameProp); + } + + private void DrawPackageDescription() + { + var descriptionProp = serializedObject.FindProperty("_description"); + + _isDescriptionSectionExpanded = EditorGUILayout.Foldout(_isDescriptionSectionExpanded, "Package Description"); + + if (_isDescriptionSectionExpanded) + { + descriptionProp.stringValue = EditorGUILayout.TextArea(descriptionProp.stringValue); + } + } + + private void DrawUnityVersion() + { + var unityVersionProp = serializedObject.FindProperty("_unityVersion"); + var majorVersionProp = unityVersionProp.FindPropertyRelative("_major"); + var minorVersionProp = unityVersionProp.FindPropertyRelative("_minor"); + + using (new EditorGUILayout.HorizontalScope()) + { + // Foldout付きのLabelを作る + EditorGUILayout.PropertyField(unityVersionProp, new GUIContent("Compatible Unity Version"), false); + // Unityバージョンを表示する + // * read onlyにするためにdisableする + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextField(_vciPackageSettings.UnityVersion); + } + } + + // 展開されているときのみ表示 + if (unityVersionProp.isExpanded) + { + // 見やすくするためにboxで囲む + using (new EditorGUILayout.VerticalScope(GUI.skin.box)) + { + EditorGUILayout.PropertyField(majorVersionProp); + EditorGUILayout.PropertyField(minorVersionProp); + } + } + } + + private void DrawKeywords() + { + var keywordProperty = serializedObject.FindProperty("_keywords"); + EditorGUILayout.PropertyField(keywordProperty); + } + + private void DrawAuthor() + { + var authorProp = serializedObject.FindProperty("_author"); + var nameProp = authorProp.FindPropertyRelative("_name"); + var emailProp = authorProp.FindPropertyRelative("_email"); + var urlProp = authorProp.FindPropertyRelative("_url"); + + // Foldout付きのLabelを作る + EditorGUILayout.PropertyField(authorProp, false); + + // 展開されているときのみ表示する + if (authorProp.isExpanded) + { + using (new EditorGUILayout.VerticalScope(GUI.skin.box)) + { + EditorGUILayout.PropertyField(nameProp); + EditorGUILayout.PropertyField(emailProp); + EditorGUILayout.PropertyField(urlProp); + } + } + } + + private void DrawDependencies() + { + var dependenciesProp = serializedObject.FindProperty("_dependencies"); + + // Foldout付きのLabelを作る + EditorGUILayout.PropertyField(dependenciesProp, false); + if (dependenciesProp.isExpanded) + { + EditorGUILayout.PropertyField(dependenciesProp.FindPropertyRelative("Array.size")); + // Dependencyを増減させた結果を後続のGUIに反映する + serializedObject.ApplyModifiedProperties(); + + using (new EditorGUI.IndentLevelScope()) + { + for (var i = 0; i < dependenciesProp.arraySize; i++) + { + var dependencyProp = dependenciesProp.GetArrayElementAtIndex(i); + ShowDependency(dependencyProp, i); + } + } + } + } + + private void ShowDependency(SerializedProperty dependencyProp, int arrayIndex) + { + // Foldout付きのLabelを作る + EditorGUILayout.PropertyField(dependencyProp, new GUIContent($"Dependency {arrayIndex}"), false); + if (dependencyProp.isExpanded) + { + using (new EditorGUI.IndentLevelScope()) + { + DrawOfficialPackageName(dependencyProp.FindPropertyRelative("_officialPackageName"), _vciPackageSettings.Dependencies[arrayIndex].OfficialPackageName); + DrawDependencyPackageVersion(dependencyProp.FindPropertyRelative("_packageVersion"), _vciPackageSettings.Dependencies[arrayIndex].PackageVersion); + } + } + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs.meta new file mode 100644 index 0000000..7ce81be --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/VciPackageSettingsEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7720ff11bff4d2ab449c7fa97152249 +timeCreated: 1637119429 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs new file mode 100644 index 0000000..bf4d4cf --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs @@ -0,0 +1,117 @@ +using System.IO; +using UniJSON; +using UnityEditor; +using UnityEngine; + +namespace VCI +{ + public static class WriteVciPackageJsonService + { + // package.json を配置するパス + // * Application.dataPath からの相対パス + private const string VciPackageJsonPath = "VCI\\package.json"; + // package.jsonに書き込む内容が保存されているScriptableObjectの名前 + private const string VciPackageSettingsFileName = "VciPackageSettings"; + + public static void WritePackageJsonFile() + { + var vciPackageSettings = LoadCurrentPackageSettings(); + var jsonText = GeneratePackageJsonText(vciPackageSettings); + + var writePath = + Path.Combine(Application.dataPath, VciPackageJsonPath) + .Replace("/", "\\"); // to windows directory separator + + File.WriteAllText(writePath, jsonText); + Debug.Log($"Wrote package.json: {writePath}"); + + AssetDatabase.Refresh(); + } + + // VCI/UniVCI/Resourcesに置いてあるScriptableObjectから、package.jsonに書き込む内容をロードする + private static VciPackageSettings LoadCurrentPackageSettings() + { + return Resources.Load(VciPackageSettingsFileName); + } + + private static string GeneratePackageJsonText(VciPackageSettings vciPackageSettings) + { + // jsonFormatterを使って package.json の中身を構築する + var jsonFormatter = new JsonFormatter(2); + + // { + jsonFormatter.BeginMap(); + { + // "name": パッケージ名 + jsonFormatter.Key("name"); + jsonFormatter.Value(vciPackageSettings.OfficialPackageName.GetValue()); + + // "version": パッケージのバージョン + jsonFormatter.Key("version"); + jsonFormatter.Value(vciPackageSettings.PackageVersion.GetValue()); + + // "displayName": ユーザーから見えるパッケージ名 + jsonFormatter.Key("displayName"); + jsonFormatter.Value(vciPackageSettings.DisplayName); + + // "description": パッケージの説明 + jsonFormatter.Key("description"); + jsonFormatter.Value(vciPackageSettings.Description); + + // "unity": 互換性のある最小 unity バージョン + jsonFormatter.Key("unity"); + jsonFormatter.Value(vciPackageSettings.UnityVersion); + + // "keywords": パッケージ検索用のキーワード + jsonFormatter.Key("keywords"); + // [ + jsonFormatter.BeginList(); + foreach (var keyword in vciPackageSettings.Keywords) + { + jsonFormatter.Value(keyword); + } + // ] + jsonFormatter.EndList(); + + // author: パッケージの作者 + jsonFormatter.Key("author"); + // { + jsonFormatter.BeginMap(); + // name: 作者名(required) + jsonFormatter.Key("name"); + jsonFormatter.Value(vciPackageSettings.Author.Name); + // email: 作者email(optional) + if (!string.IsNullOrEmpty(vciPackageSettings.Author.Email)) + { + jsonFormatter.Key("email"); + jsonFormatter.Value(vciPackageSettings.Author.Email); + } + // url: 作者ページのurl(optional) + if (!string.IsNullOrEmpty(vciPackageSettings.Author.Url)) + { + jsonFormatter.Key("url"); + jsonFormatter.Value(vciPackageSettings.Author.Url); + } + // } + jsonFormatter.EndMap(); + + // dependencies: 依存パッケージ + jsonFormatter.Key("dependencies"); + // { + jsonFormatter.BeginMap(); + foreach (var dependency in vciPackageSettings.Dependencies) + { + // パッケージ名: パッケージのバージョン + jsonFormatter.Key(dependency.OfficialPackageName.GetValue()); + jsonFormatter.Value(dependency.PackageVersion.GetValue()); + } + // } + jsonFormatter.EndMap(); + } + // } + jsonFormatter.EndMap(); + + return jsonFormatter.ToString(); + } + } +} diff --git a/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs.meta b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs.meta new file mode 100644 index 0000000..00ff5ad --- /dev/null +++ b/Assets/VCI/UniVCI/Editor/Utils/VciPackageJson/WriteVciPackageJsonService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 662dd54dca024ab6a024c144d764735f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset b/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset new file mode 100644 index 0000000..b0b3336 --- /dev/null +++ b/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset @@ -0,0 +1,67 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b56190607ecc4bc4b33f1b7ea6886cdf, type: 3} + m_Name: VciPackageSettings + m_EditorClassIdentifier: + _officialPackageName: + _domainNameExtension: com + _companyName: virtualcast + _packageNamespace: univci + _packageVersion: + _major: 0 + _minor: 33 + _patch: 0 + _displayName: VCI + _description: VCI Exporter + _unityVersion: + _major: 2019 + _minor: 4 + _keywords: + - vci + - vr + _author: + _name: VirtualCast, Inc. + _email: + _url: + _dependencies: + - _officialPackageName: + _domainNameExtension: com + _companyName: vrmc + _packageNamespace: vrm + _packageVersion: + _major: 0 + _minor: 88 + _patch: 0 + - _officialPackageName: + _domainNameExtension: com + _companyName: vrmc + _packageNamespace: univrm + _packageVersion: + _major: 0 + _minor: 88 + _patch: 0 + - _officialPackageName: + _domainNameExtension: com + _companyName: vrmc + _packageNamespace: vrmshaders + _packageVersion: + _major: 0 + _minor: 88 + _patch: 0 + - _officialPackageName: + _domainNameExtension: com + _companyName: vrmc + _packageNamespace: gltf + _packageVersion: + _major: 0 + _minor: 88 + _patch: 0 diff --git a/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset.meta b/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset.meta new file mode 100644 index 0000000..c13d5bd --- /dev/null +++ b/Assets/VCI/UniVCI/Resources/VciPackageSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 206ffa0016cdafe4fa04bb7f41920a51 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs b/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs new file mode 100644 index 0000000..7f95e65 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.CompilerServices; + +#if UNITY_EDITOR +[assembly: InternalsVisibleTo("UniVCI.Editor")] +#endif diff --git a/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs.meta b/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs.meta new file mode 100644 index 0000000..d353df4 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e74085d908804556bc51f148d74b7a35 +timeCreated: 1636983514 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderJsonObject.cs b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderJsonObject.cs index 18e695d..b47f31a 100644 --- a/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderJsonObject.cs +++ b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderJsonObject.cs @@ -1,5 +1,4 @@ using System; -using UniGLTF; using UnityEngine; namespace VCI @@ -13,6 +12,7 @@ public sealed class ColliderJsonObject public const string BoxColliderName = "box"; public const string SphereColliderName = "sphere"; public const string CapsuleColliderName = "capsule"; + public const string MeshColliderName = "mesh"; public const string DefaultColliderLayerName = "default"; public const string LocationColliderLayerName = "location"; @@ -26,9 +26,11 @@ public sealed class ColliderJsonObject [UniGLTF.JsonSchema(MinItems = 3, MaxItems = 3)] public float[] center; - [UniGLTF.JsonSchema(MinItems = 1, MaxItems = 3)] + [UniGLTF.JsonSchema(MinItems = 0, MaxItems = 3)] public float[] shape; + public ColliderMeshJsonObject mesh; + public bool isTrigger; public PhysicMaterialJsonObject physicMaterial; } diff --git a/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs new file mode 100644 index 0000000..37f2d38 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs @@ -0,0 +1,17 @@ +using System; +using UniGLTF; + +namespace VCI +{ + [Serializable] + public sealed class ColliderMeshJsonObject + { + public bool isConvex; + + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] + public int position = -1; + + [JsonSchema(Minimum = 0, ExplicitIgnorableValue = -1)] + public int indices = -1; + } +} diff --git a/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs.meta b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs.meta new file mode 100644 index 0000000..030d363 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/Format/GltfExtensions/NodeExtensions/glTF_VCAST_vci_colliders/ColliderMeshJsonObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a89835d74f6e41ffa71efaf7ba874eae +timeCreated: 1636978269 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Deserialize.g.cs b/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Deserialize.g.cs index 7535fe3..bdfa8cd 100644 --- a/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Deserialize.g.cs +++ b/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Deserialize.g.cs @@ -64,6 +64,11 @@ public static ColliderJsonObject glTF_VCAST_vci_colliders_Deserializevci_collide continue; } + if(key=="mesh"){ + value.mesh = glTF_VCAST_vci_colliders_Deserializevci_colliders__mesh(kv.Value); + continue; + } + if(key=="isTrigger"){ value.isTrigger = kv.Value.GetBoolean(); continue; @@ -100,6 +105,33 @@ public static Single[] glTF_VCAST_vci_colliders_Deserializevci_colliders__shape( return value; } +public static ColliderMeshJsonObject glTF_VCAST_vci_colliders_Deserializevci_colliders__mesh(JsonNode parsed) +{ + var value = new ColliderMeshJsonObject(); + + foreach(var kv in parsed.ObjectItems()) + { + var key = kv.Key.GetString(); + + if(key=="isConvex"){ + value.isConvex = kv.Value.GetBoolean(); + continue; + } + + if(key=="position"){ + value.position = kv.Value.GetInt32(); + continue; + } + + if(key=="indices"){ + value.indices = kv.Value.GetInt32(); + continue; + } + + } + return value; +} + public static PhysicMaterialJsonObject glTF_VCAST_vci_colliders_Deserializevci_colliders__physicMaterial(JsonNode parsed) { var value = new PhysicMaterialJsonObject(); diff --git a/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Serialize.g.cs b/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Serialize.g.cs index 2cf7f66..ea9cdee 100644 --- a/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Serialize.g.cs +++ b/Assets/VCI/UniVCI/Scripts/Format/Serializer/glTF_VCAST_vci_colliders_Serialize.g.cs @@ -55,11 +55,16 @@ public static void glTF_VCAST_vci_colliders_Serializevci_colliders_ITEM(JsonForm glTF_VCAST_vci_colliders_Serializevci_colliders__center(f, value.center); } - if(value.shape!=null&&value.shape.Length>=1){ + if(value.shape!=null&&value.shape.Length>=0){ f.Key("shape"); glTF_VCAST_vci_colliders_Serializevci_colliders__shape(f, value.shape); } + if(value.mesh!=null){ + f.Key("mesh"); + glTF_VCAST_vci_colliders_Serializevci_colliders__mesh(f, value.mesh); + } + if(true){ f.Key("isTrigger"); f.Value(value.isTrigger); @@ -97,6 +102,29 @@ public static void glTF_VCAST_vci_colliders_Serializevci_colliders__shape(JsonFo f.EndList(); } +public static void glTF_VCAST_vci_colliders_Serializevci_colliders__mesh(JsonFormatter f, ColliderMeshJsonObject value) +{ + f.BeginMap(); + + + if(true){ + f.Key("isConvex"); + f.Value(value.isConvex); + } + + if(value.position>=0){ + f.Key("position"); + f.Value(value.position); + } + + if(value.indices>=0){ + f.Key("indices"); + f.Value(value.indices); + } + + f.EndMap(); +} + public static void glTF_VCAST_vci_colliders_Serializevci_colliders__physicMaterial(JsonFormatter f, PhysicMaterialJsonObject value) { f.BeginMap(); diff --git a/Assets/VCI/UniVCI/Scripts/Format/VCIVersion.cs b/Assets/VCI/UniVCI/Scripts/Format/VCIVersion.cs index 4e4edbf..a28089f 100644 --- a/Assets/VCI/UniVCI/Scripts/Format/VCIVersion.cs +++ b/Assets/VCI/UniVCI/Scripts/Format/VCIVersion.cs @@ -7,9 +7,9 @@ public static partial class VCIVersion public const int MAJOR = 0; public const int MINOR = 33; - public const int PATCH = 0; + public const int PATCH = 1; public const string VERSION = "0.33"; - public const string PATCH_NUMBER = "0"; + public const string PATCH_NUMBER = "1"; } } diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderExporter.cs b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderExporter.cs index b895bb7..759f934 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderExporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderExporter.cs @@ -8,9 +8,9 @@ namespace VCI /// /// Collider を Export できる /// - public static class PhysicsColliderExporter + internal static class PhysicsColliderExporter { - public static glTF_VCAST_vci_colliders ExportColliders(Transform node, IVciColliderLayerProvider colliderLayerProvider) + public static glTF_VCAST_vci_colliders ExportColliders(Transform node, ExportingGltfData data, IVciColliderLayerProvider colliderLayerProvider, PhysicsColliderMeshExporter colliderMeshExporter) { // 各ノードに複数のコライダーがあり得る var colliders = node.GetComponents(); @@ -23,7 +23,7 @@ public static glTF_VCAST_vci_colliders ExportColliders(Transform node, IVciColli foreach (var collider in colliders) { - var gltfCollider = ExportCollider(collider, colliderLayerProvider); + var gltfCollider = ExportCollider(collider, colliderLayerProvider, colliderMeshExporter); if (gltfCollider == null) { Debug.LogWarningFormat("collider is not supported: {0}", collider.GetType().Name); @@ -39,7 +39,7 @@ public static glTF_VCAST_vci_colliders ExportColliders(Transform node, IVciColli }; } - private static ColliderJsonObject ExportCollider(Collider collider, IVciColliderLayerProvider colliderLayerProvider) + private static ColliderJsonObject ExportCollider(Collider collider, IVciColliderLayerProvider colliderLayerProvider, PhysicsColliderMeshExporter colliderMeshExporter) { switch (collider) { @@ -49,6 +49,8 @@ private static ColliderJsonObject ExportCollider(Collider collider, IVciCollider return ExportCapsuleCollider(capsuleCollider, colliderLayerProvider); case SphereCollider sphereCollider: return ExportSphereCollider(sphereCollider, colliderLayerProvider); + case MeshCollider meshCollider: + return ExportMeshCollider(meshCollider, colliderLayerProvider, colliderMeshExporter); default: return null; } @@ -63,6 +65,7 @@ private static ColliderJsonObject ExportBoxCollider(BoxCollider collider, IVciCo type = ColliderJsonObject.BoxColliderName, center = collider.center.ReverseZ().ToArray(), shape = collider.size.ToArray(), + mesh = null, isTrigger = collider.isTrigger, physicMaterial = ExportPhysicMaterial(collider.sharedMaterial), layer = ExportLayer(collider.gameObject.layer, colliderLayerProvider), @@ -83,6 +86,7 @@ private static ColliderJsonObject ExportCapsuleCollider(CapsuleCollider collider collider.height, collider.direction // NOTE: 0 = X-Axis, 1 = Y-Axis, 2 = Z-Axis }, + mesh = null, isTrigger = collider.isTrigger, physicMaterial = ExportPhysicMaterial(collider.sharedMaterial), layer = ExportLayer(collider.gameObject.layer, colliderLayerProvider), @@ -101,12 +105,43 @@ private static ColliderJsonObject ExportSphereCollider(SphereCollider collider, { collider.radius }, + mesh = null, isTrigger = collider.isTrigger, physicMaterial = ExportPhysicMaterial(collider.sharedMaterial), layer = ExportLayer(collider.gameObject.layer, colliderLayerProvider), }; } + private static ColliderJsonObject ExportMeshCollider(MeshCollider collider, IVciColliderLayerProvider colliderLayerProvider, PhysicsColliderMeshExporter colliderMeshExporter) + { + if (collider == null || collider.sharedMesh == null) return null; + + return new ColliderJsonObject + { + type = ColliderJsonObject.MeshColliderName, + center = Vector3.zero.ToArray(), + shape = Array.Empty(), + mesh = ExportMeshColliderJsonObject(collider, colliderMeshExporter), + isTrigger = collider.isTrigger, + physicMaterial = ExportPhysicMaterial(collider.sharedMaterial), + layer = ExportLayer(collider.gameObject.layer, colliderLayerProvider) + }; + } + + private static ColliderMeshJsonObject ExportMeshColliderJsonObject(MeshCollider collider, PhysicsColliderMeshExporter colliderMeshExporter) + { + if (collider == null || collider.sharedMesh == null) return null; + + var (positionAccessorIndex, indicesAccessorIndices) = colliderMeshExporter.Export(collider.sharedMesh); + + return new ColliderMeshJsonObject + { + isConvex = collider.convex, + position = positionAccessorIndex, + indices = indicesAccessorIndices, + }; + } + private static PhysicMaterialJsonObject ExportPhysicMaterial(PhysicMaterial material) { if (material == null) return null; diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs new file mode 100644 index 0000000..d8be037 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; + +namespace VCI +{ + internal sealed class PhysicsColliderMeshExporter + { + private readonly ExportingGltfData _data; + private readonly IAxisInverter _axisInverter; + private readonly Dictionary _cache = new Dictionary(); + + public PhysicsColliderMeshExporter(ExportingGltfData data, IAxisInverter axisInverter) + { + _data = data; + _axisInverter = axisInverter; + } + + public (int positionAccessorIndex, int indicesAccessorIndex) Export(Mesh mesh) + { + if (_cache.ContainsKey(mesh)) + { + return _cache[mesh]; + } + + // NOTE: glTF のフォーマットおよび VCI の仕様にあわせて Z 軸反転させる. + var vertices = mesh.vertices + .Select(x => _axisInverter.InvertVector3(x)) + .ToArray(); + var indices = new List(); + for (var subMeshIdx = 0; subMeshIdx < mesh.subMeshCount; ++subMeshIdx) + { + var subMeshIndices = mesh.GetTriangles(subMeshIdx); + for (var idx = 0; idx < subMeshIndices.Length; idx += 3) + { + // NOTE: glTF のフォーマットに合わせて反転させる. + indices.Add((uint)subMeshIndices[idx + 2]); + indices.Add((uint)subMeshIndices[idx + 1]); + indices.Add((uint)subMeshIndices[idx + 0]); + } + } + + var positionAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(vertices, glBufferTarget.ARRAY_BUFFER); + var indicesAccessorIndex = _data.ExtendBufferAndGetAccessorIndex(indices.ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER); + _cache.Add(mesh, (positionAccessorIndex, indicesAccessorIndex)); + + return (positionAccessorIndex, indicesAccessorIndex); + } + } +} diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs.meta b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs.meta new file mode 100644 index 0000000..9294d95 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentExporters/PhysicsColliderMeshExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d8e6369a79f74134ae51d9cfb61cde06 +timeCreated: 1636973044 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderImporter.cs b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderImporter.cs index ea54fbb..ac5f96a 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderImporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderImporter.cs @@ -7,7 +7,7 @@ namespace VCI { - public static class PhysicsColliderImporter + internal static class PhysicsColliderImporter { // NOTE: コライダが増えてくるとかなり重いので、40 個に 1 度待てば 10ms くらいにはなる // FIXME あまり賢い実装ではない @@ -16,7 +16,13 @@ public static class PhysicsColliderImporter /// /// NOTE: ロード時点では、物理演算は無効化されている必要がある. /// - public static async Task> LoadAsync(VciData vciData, IReadOnlyList unityNodes, IVciColliderLayerProvider vciColliderLayer, IAwaitCaller awaitCaller) + public static async Task> LoadAsync( + VciData vciData, + IReadOnlyList unityNodes, + IVciColliderLayerProvider vciColliderLayer, + IAxisInverter axisInverter, + PhysicMaterialFactory factory, + IAwaitCaller awaitCaller) { if (vciColliderLayer == null) { @@ -24,6 +30,7 @@ public static async Task> LoadAsync(VciData vciData, IReadOnlyLis } var colliderComponents = new List(); + var meshImporter = new PhysicsColliderMeshImporter(vciData.GltfData, axisInverter); // Colliders var colliderCount = 0; @@ -38,7 +45,7 @@ public static async Task> LoadAsync(VciData vciData, IReadOnlyLis foreach (var jsonCollider in colliderExtension.colliders) { - var collider = LoadColliderComponent(go, jsonCollider); + var collider = LoadColliderComponent(go, jsonCollider, meshImporter, factory); if (collider == null) { continue; @@ -64,32 +71,34 @@ public static async Task> LoadAsync(VciData vciData, IReadOnlyLis return colliderComponents; } - private static Collider LoadColliderComponent(GameObject go, ColliderJsonObject jsonCollider) + private static Collider LoadColliderComponent(GameObject go, ColliderJsonObject jsonCollider, PhysicsColliderMeshImporter meshImporter, PhysicMaterialFactory factory) { switch (jsonCollider.type) { case ColliderJsonObject.BoxColliderName: - return LoadBoxCollider(go, jsonCollider); + return LoadBoxCollider(go, jsonCollider, factory); case ColliderJsonObject.CapsuleColliderName: - return LoadCapsuleCollider(go, jsonCollider); + return LoadCapsuleCollider(go, jsonCollider, factory); case ColliderJsonObject.SphereColliderName: - return LoadSphereCollider(go, jsonCollider); + return LoadSphereCollider(go, jsonCollider, factory); + case ColliderJsonObject.MeshColliderName: + return LoadMeshCollider(go, jsonCollider, meshImporter, factory); default: // NOTE: 未定義の場合、なにもロードしない. return null; } } - private static BoxCollider LoadBoxCollider(GameObject go, ColliderJsonObject jsonCollider) + private static BoxCollider LoadBoxCollider(GameObject go, ColliderJsonObject jsonCollider, PhysicMaterialFactory factory) { var collider = go.AddComponent(); collider.center = new Vector3(jsonCollider.center[0], jsonCollider.center[1], jsonCollider.center[2]).ReverseZ(); collider.size = new Vector3(jsonCollider.shape[0], jsonCollider.shape[1], jsonCollider.shape[2]); collider.isTrigger = jsonCollider.isTrigger; - collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial); + collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial, factory); return collider; } - private static CapsuleCollider LoadCapsuleCollider(GameObject go, ColliderJsonObject jsonCollider) + private static CapsuleCollider LoadCapsuleCollider(GameObject go, ColliderJsonObject jsonCollider, PhysicMaterialFactory factory) { var collider = go.AddComponent(); collider.center = new Vector3(jsonCollider.center[0], jsonCollider.center[1], jsonCollider.center[2]).ReverseZ(); @@ -97,32 +106,42 @@ private static CapsuleCollider LoadCapsuleCollider(GameObject go, ColliderJsonOb collider.height = jsonCollider.shape[1]; collider.direction = (int) jsonCollider.shape[2]; collider.isTrigger = jsonCollider.isTrigger; - collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial); + collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial, factory); return collider; } - private static SphereCollider LoadSphereCollider(GameObject go, ColliderJsonObject jsonCollider) + private static SphereCollider LoadSphereCollider(GameObject go, ColliderJsonObject jsonCollider, PhysicMaterialFactory factory) { var collider = go.AddComponent(); collider.center = new Vector3(jsonCollider.center[0], jsonCollider.center[1], jsonCollider.center[2]).ReverseZ(); collider.radius = jsonCollider.shape[0]; collider.isTrigger = jsonCollider.isTrigger; - collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial); + collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial, factory); return collider; } - private static PhysicMaterial LoadPhysicMaterial(PhysicMaterialJsonObject jsonMaterial) + private static MeshCollider LoadMeshCollider(GameObject go, ColliderJsonObject jsonCollider, PhysicsColliderMeshImporter meshImporter, PhysicMaterialFactory factory) + { + if (jsonCollider.mesh == null) return null; + + var collider = go.AddComponent(); + collider.convex = jsonCollider.mesh.isConvex; + collider.isTrigger = jsonCollider.isTrigger; + collider.sharedMesh = meshImporter.Load(jsonCollider.mesh); + collider.sharedMaterial = LoadPhysicMaterial(jsonCollider.physicMaterial, factory); + return collider; + } + + private static PhysicMaterial LoadPhysicMaterial(PhysicMaterialJsonObject jsonMaterial, PhysicMaterialFactory factory) { if (jsonMaterial == null) return null; - return new PhysicMaterial - { - dynamicFriction = jsonMaterial.dynamicFriction, - staticFriction = jsonMaterial.staticFriction, - bounciness = jsonMaterial.bounciness, - frictionCombine = LoadPhysicMaterialCombine(jsonMaterial.frictionCombine), - bounceCombine = LoadPhysicMaterialCombine(jsonMaterial.bounceCombine) - }; + return factory.LoadPhysicMaterial( + jsonMaterial.dynamicFriction, + jsonMaterial.staticFriction, + jsonMaterial.bounciness, + LoadPhysicMaterialCombine(jsonMaterial.frictionCombine), + LoadPhysicMaterialCombine(jsonMaterial.bounceCombine)); } private static PhysicMaterialCombine LoadPhysicMaterialCombine(string jsonString) diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs new file mode 100644 index 0000000..9e3c1b7 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs @@ -0,0 +1,34 @@ +using System; + +namespace VCI +{ + internal readonly struct PhysicsColliderMeshIdentifier : IEquatable + { + public int PositionAccessorIndex { get; } + public int IndicesAccessorIndex { get; } + + public PhysicsColliderMeshIdentifier(int positionAccessorIndex, int indicesAccessorIndex) + { + PositionAccessorIndex = positionAccessorIndex; + IndicesAccessorIndex = indicesAccessorIndex; + } + + public bool Equals(PhysicsColliderMeshIdentifier other) + { + return PositionAccessorIndex == other.PositionAccessorIndex && IndicesAccessorIndex == other.IndicesAccessorIndex; + } + + public override bool Equals(object obj) + { + return obj is PhysicsColliderMeshIdentifier other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + return (PositionAccessorIndex * 397) ^ IndicesAccessorIndex; + } + } + } +} diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs.meta b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs.meta new file mode 100644 index 0000000..90e93b9 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshIdentifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3f3fd07e32ba4b4cbaa4b56c71f7c426 +timeCreated: 1636980541 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs new file mode 100644 index 0000000..1fbbb0a --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using UniGLTF; +using UnityEngine; +using UnityEngine.Rendering; + +namespace VCI +{ + internal sealed class PhysicsColliderMeshImporter + { + private readonly GltfData _data; + private readonly IAxisInverter _axisInverter; + private readonly Dictionary _cache = new Dictionary(); + + public PhysicsColliderMeshImporter(GltfData data, IAxisInverter axisInverter) + { + _data = data; + _axisInverter = axisInverter; + } + + public Mesh Load(ColliderMeshJsonObject jsonMesh) + { + var positionAccessorIndex = jsonMesh.position; + var indicesAccessorIndex = jsonMesh.indices; + + if (positionAccessorIndex == -1 || indicesAccessorIndex == -1) + { + return null; + } + + var id = new PhysicsColliderMeshIdentifier(positionAccessorIndex, indicesAccessorIndex); + if (_cache.ContainsKey(id)) + { + return _cache[id]; + } + + // NOTE: VCI の仕様により Z 軸反転する. + var positions= _data.GetArrayFromAccessor(positionAccessorIndex); + for (var idx = 0; idx < positions.Length; ++idx) + { + positions[idx] = _axisInverter.InvertVector3(positions[idx]); + } + + // NOTE: GltfData.GetIndices は内部で glTF -> Unity 変換を行うため、ここでは無変換. + var indices = _data.GetIndices(indicesAccessorIndex); + + var mesh = new Mesh(); + mesh.name = GenerateUniqueMeshName(id); + if (positions.Length > UInt16.MaxValue) + { + mesh.indexFormat = IndexFormat.UInt32; + } + mesh.vertices = positions; + mesh.triangles = indices; + mesh.RecalculateBounds(); + mesh.RecalculateNormals(); + + _cache.Add(id, mesh); + + return mesh; + } + + internal static string GenerateUniqueMeshName(PhysicsColliderMeshIdentifier id) + { + return $"__COLLIDER__{id.PositionAccessorIndex:D}_{id.IndicesAccessorIndex:D}"; + } + } +} diff --git a/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs.meta b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs.meta new file mode 100644 index 0000000..c52e2da --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/ComponentImporters/PhysicsColliderMeshImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5650fd5a27e24685977d50d4ae2d0db5 +timeCreated: 1636979067 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrationTarget.cs b/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrationTarget.cs index ea807fc..1cef72a 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrationTarget.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrationTarget.cs @@ -1,6 +1,6 @@ namespace VCI { - internal enum VciMaterialMigrationTarget + public enum VciMaterialMigrationTarget { Pbr, Unlit, diff --git a/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrator.cs b/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrator.cs index e2fe527..e8b1f11 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrator.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/Materials/VciMaterialMigrator.cs @@ -8,7 +8,7 @@ namespace VCI { - internal static class VciMaterialMigrator + public static class VciMaterialMigrator { public static bool Migrate(GltfData data, int i, MaterialDescriptor matDesc, VciMaterialMigrationTarget target, bool migrateSrgbColor, out MaterialDescriptor migratedMatDesc) { diff --git a/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs b/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs new file mode 100644 index 0000000..b9d921d --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using UnityEngine; +using VRMShaders; + +namespace VCI +{ + internal sealed class PhysicMaterialFactory : IResponsibilityForDestroyObjects + { + private readonly IReadOnlyDictionary _externalMaterials; + private readonly Dictionary _runtimeGeneratedMaterials = new Dictionary(); + + public PhysicMaterialFactory(IReadOnlyDictionary externalMaterials) + { + _externalMaterials = externalMaterials; + } + + public void Dispose() + { + foreach (var kv in _runtimeGeneratedMaterials) + { + UnityEngine.Object.Destroy(kv.Value); + } + _runtimeGeneratedMaterials.Clear(); + } + + /// + /// 与えられたパラメータに対応する PhysicMaterial を返す. + /// + /// 外部から与えられたアセット (例: Editor Import の SecondPass では、 FirstPass で生成したアセットを ExternalObject として受け取っている) があればそれを返す. + /// またすでに同じパラメータで Runtime に生成済みであればそれを返す. + /// 生成済みでなければ、生成して返す. + /// + public PhysicMaterial LoadPhysicMaterial(float dynamicFriction, float staticFriction, float bounciness, PhysicMaterialCombine frictionCombine, PhysicMaterialCombine bounceCombine) + { + var key = new SubAssetKey( + typeof(PhysicMaterial), + GenerateId(dynamicFriction, staticFriction, bounciness, frictionCombine, bounceCombine)); + + var loadedMaterial = GetLoadedPhysicMaterial(key); + if (loadedMaterial != null) return loadedMaterial; + + var material = new PhysicMaterial(key.Name) + { + dynamicFriction = dynamicFriction, + staticFriction = staticFriction, + bounciness = bounciness, + frictionCombine = frictionCombine, + bounceCombine = bounceCombine, + }; + _runtimeGeneratedMaterials.Add(key, material); + return material; + } + + private PhysicMaterial GetLoadedPhysicMaterial(SubAssetKey key) + { + if (_externalMaterials.TryGetValue(key, out var material)) return material; + if (_runtimeGeneratedMaterials.TryGetValue(key, out material)) return material; + return null; + } + + public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) + { + foreach (var (k, v) in _runtimeGeneratedMaterials.ToArray()) + { + take(k, v); + _runtimeGeneratedMaterials.Remove(k); + } + } + + /// + /// PhysicMaterial は VCI のファイル上、ただのパラメータ集合概念であり、名前も存在しない。 + /// したがってパラメータから ID を生成する。 + /// + private static string GenerateId(float dynamicFriction, float staticFriction, float bounciness, PhysicMaterialCombine frictionCombine, PhysicMaterialCombine bounceCombine) + { + var code = GetHashCode(dynamicFriction, staticFriction, bounciness, frictionCombine, bounceCombine); + return code.ToString(CultureInfo.InvariantCulture); + } + + private static int GetHashCode(float dynamicFriction, float staticFriction, float bounciness, PhysicMaterialCombine frictionCombine, PhysicMaterialCombine bounceCombine) + { + unchecked + { + var hashCode = dynamicFriction.GetHashCode(); + hashCode = (hashCode * 397) ^ staticFriction.GetHashCode(); + hashCode = (hashCode * 397) ^ bounciness.GetHashCode(); + hashCode = (hashCode * 397) ^ (int)frictionCombine; + hashCode = (hashCode * 397) ^ (int)bounceCombine; + return hashCode; + } + } + } +} diff --git a/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs.meta b/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs.meta new file mode 100644 index 0000000..31f5a55 --- /dev/null +++ b/Assets/VCI/UniVCI/Scripts/IO/Physics/PhysicMaterialFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 930fa318546a43a58143d3ae154f1c67 +timeCreated: 1638249719 \ No newline at end of file diff --git a/Assets/VCI/UniVCI/Scripts/IO/RuntimeVciInstance.cs b/Assets/VCI/UniVCI/Scripts/IO/RuntimeVciInstance.cs index 920b165..6b2e0a4 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/RuntimeVciInstance.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/RuntimeVciInstance.cs @@ -6,16 +6,18 @@ using TMPro; using UniGLTF; using UnityEngine; +using VRMShaders; namespace VCI { - public sealed class RuntimeVciInstance : IDisposable + public sealed class RuntimeVciInstance : IDisposable, IResponsibilityForDestroyObjects { public RuntimeGltfInstance GltfModel { get; } public GameObject Root => GltfModel.Root; public IReadOnlyList Nodes { get; } public IReadOnlyList AnimationClips { get; } public IReadOnlyList AudioClips { get; } + public IReadOnlyList PhysicMaterials { get; } public VCIObject VCIObject { get; } public IReadOnlyList LoadedMaterials { get; } public IReadOnlyList ColliderComponents { get; } @@ -23,42 +25,74 @@ public sealed class RuntimeVciInstance : IDisposable public IReadOnlyList EffekseerEmitterComponents { get; } public IReadOnlyList RendererComponents { get; } + private readonly List<(SubAssetKey, UnityEngine.Object)> _runtimeVciResources; private readonly List<(string key, TextMeshPro text)> _texts; public RuntimeVciInstance( RuntimeGltfInstance gltfModel, + List<(SubAssetKey, UnityEngine.Object)> runtimeVciResources, IReadOnlyList nodes, IReadOnlyList colliders, IReadOnlyDictionary rigidbodies, IReadOnlyList texts, IReadOnlyList effekseerEmitterComponents) { + // NOTE: GLTF Objects GltfModel = gltfModel; Nodes = nodes; + RendererComponents = Root.GetComponentsInChildren(includeInactive: true); + + // NOTE: GLTF Resources AnimationClips = GltfModel.RuntimeResources .Where(x => x.Item1.Type == typeof(AnimationClip)) .Select(x => x.Item2 as AnimationClip) .ToList(); - AudioClips = GltfModel.RuntimeResources - .Where(x => x.Item1.Type == typeof(AudioClip)) - .Select(x => x.Item2 as AudioClip) - .ToList(); - VCIObject = Root.GetComponent(); LoadedMaterials = GltfModel.RuntimeResources .Where(x => x.Item1.Type == typeof(Material)) .Select(x => x.Item2 as Material) .ToList(); + + // NOTE: VCI Objects + VCIObject = Root.GetComponent(); ColliderComponents = colliders; RigidbodySettings = rigidbodies; EffekseerEmitterComponents = effekseerEmitterComponents; - RendererComponents = Root.GetComponentsInChildren(includeInactive: true); - _texts = texts.Select(x => (x.name.ToLower(CultureInfo.InvariantCulture), x)).ToList(); + + // NOTE: VCI Resources + _runtimeVciResources = runtimeVciResources; + AudioClips = _runtimeVciResources + .Where(x => x.Item1.Type == typeof(AudioClip)) + .Select(x => x.Item2 as AudioClip) + .ToList(); + PhysicMaterials = _runtimeVciResources + .Where(x => x.Item1.Type == typeof(PhysicMaterial)) + .Select(x => x.Item2 as PhysicMaterial) + .ToList(); } public void Dispose() { - GltfModel?.Dispose(); + TransferOwnership((key, obj) => UnityObjectDestoyer.DestroyRuntimeOrEditor(obj)); + + if (GltfModel != null) + { + GltfModel.Dispose(); + } + } + + public void TransferOwnership(TakeResponsibilityForDestroyObjectFunc take) + { + foreach (var (key, obj) in _runtimeVciResources) + { + take(key, obj); + } + _runtimeVciResources.Clear(); + + if (GltfModel != null) + { + GltfModel.TransferOwnership(take); + } } public void ShowMeshes() diff --git a/Assets/VCI/UniVCI/Scripts/IO/Textures/CubemapTextureExporter.cs b/Assets/VCI/UniVCI/Scripts/IO/Textures/CubemapTextureExporter.cs index 031845c..e319775 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/Textures/CubemapTextureExporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/Textures/CubemapTextureExporter.cs @@ -114,14 +114,13 @@ private int ConvertAndAddCubemapTexture(Texture src, CubemapFace face, int origi if (exporterShader == null) return -1; var exporterMaterial = new Material(exporterShader); - var srgbRt = RenderTexture.GetTemporary(width, width, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + var srgbRt = new RenderTexture(width, width, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); exporterMaterial.SetInt(ShaderPropertyFaceIndex, GetFaceIndex(face)); exporterMaterial.SetInt(ShaderPropertyMipValue, mipmap); Graphics.Blit(src, srgbRt, exporterMaterial); var idx = _exporter.RegisterExportingAsSRgb(srgbRt, needsAlpha: true); - RenderTexture.ReleaseTemporary(srgbRt); UnityEngine.Object.DestroyImmediate(exporterMaterial); return idx; diff --git a/Assets/VCI/UniVCI/Scripts/IO/Textures/LightmapTextureExporter.cs b/Assets/VCI/UniVCI/Scripts/IO/Textures/LightmapTextureExporter.cs index 9be414d..7b9fa53 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/Textures/LightmapTextureExporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/Textures/LightmapTextureExporter.cs @@ -94,12 +94,11 @@ private int ConvertAndAddTexture(Texture src) if (exporterShader == null) return -1; var exporterMaterial = new Material(exporterShader); - var srgbRt = RenderTexture.GetTemporary(src.width, src.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + var srgbRt = new RenderTexture(src.width, src.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); Graphics.Blit(src, srgbRt, exporterMaterial); var idx = _exporter.RegisterExportingAsSRgb(srgbRt, needsAlpha: true); - RenderTexture.ReleaseTemporary(srgbRt); UnityEngine.Object.DestroyImmediate(exporterMaterial); return idx; diff --git a/Assets/VCI/UniVCI/Scripts/IO/VCIExporter.cs b/Assets/VCI/UniVCI/Scripts/IO/VCIExporter.cs index 78f575a..1e65722 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/VCIExporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/VCIExporter.cs @@ -111,6 +111,9 @@ public override void ExportExtensions(ITextureSerializer textureSerializer) AddExtensionValue(_gltf, usedExtensions, glTF_VCAST_vci_audios.ExtensionName, f.GetStore().Bytes); } + // 出力キャッシュ + var colliderMeshExporter = new PhysicsColliderMeshExporter(_data, VciExportSettings.InverseAxis.Create()); + // ノード (Transform) ごとに定義される拡張 for (var i = 0; i < exporter.Nodes.Count; i++) { @@ -118,7 +121,7 @@ public override void ExportExtensions(ITextureSerializer textureSerializer) var gltfNode = _gltf.nodes[i]; // Colliders - var collidersExtension = PhysicsColliderExporter.ExportColliders(node, _colliderLayerProvider); + var collidersExtension = PhysicsColliderExporter.ExportColliders(node, _data, _colliderLayerProvider, colliderMeshExporter); if (collidersExtension != null) { var f = new UniJSON.JsonFormatter(); diff --git a/Assets/VCI/UniVCI/Scripts/IO/VCIImporter.cs b/Assets/VCI/UniVCI/Scripts/IO/VCIImporter.cs index e1af7d9..ee44acc 100644 --- a/Assets/VCI/UniVCI/Scripts/IO/VCIImporter.cs +++ b/Assets/VCI/UniVCI/Scripts/IO/VCIImporter.cs @@ -13,7 +13,9 @@ namespace VCI public class VCIImporter : ImporterContext { public RuntimeVciInstance RuntimeVciInstance { get; private set; } - public AudioClipFactory AudioClipFactory { get; } + + private AudioClipFactory AudioClipFactory { get; } + private PhysicMaterialFactory PhysicMaterialFactory { get; } private readonly VciData _data; private readonly bool _isLocation; @@ -41,6 +43,9 @@ public VCIImporter( AudioClipFactory = new AudioClipFactory(ExternalObjectMap .Where(x => x.Value is AudioClip) .ToDictionary(x => x.Key, x => (AudioClip)x.Value)); + PhysicMaterialFactory = new PhysicMaterialFactory(ExternalObjectMap + .Where(x => x.Value is PhysicMaterial) + .ToDictionary(x => x.Key, x => (PhysicMaterial)x.Value)); // VCI Specification InvertAxis = Axes.Z; @@ -67,6 +72,7 @@ public override void TransferOwnership(TakeResponsibilityForDestroyObjectFunc ta base.TransferOwnership(take); AudioClipFactory.TransferOwnership(take); + PhysicMaterialFactory.TransferOwnership(take); } private const string MATERIAL_EXTENSION_NAME = "VCAST_vci_material_unity"; @@ -168,7 +174,7 @@ private async Task SetupVciExtensionsAsync(RuntimeGltfInstan Dictionary rigidbodySettings; using (measureTime("Physics")) { - colliders = await PhysicsColliderImporter.LoadAsync(_data, Nodes, _vciColliderLayerProvider, awaitCaller); + colliders = await PhysicsColliderImporter.LoadAsync(_data, Nodes, _vciColliderLayerProvider, InvertAxis.Create(), PhysicMaterialFactory, awaitCaller); rigidbodySettings = await PhysicsRigidbodyImporter.LoadAsync(_data, Nodes, awaitCaller); await PhysicsJointImporter.LoadAsync(_data, Nodes, awaitCaller); } @@ -202,8 +208,13 @@ private async Task SetupVciExtensionsAsync(RuntimeGltfInstan await LightmapImporter.LoadAsync(_data, Nodes, Root, TextureFactory, _isLocation, awaitCaller); } + // NOTE: VCI ロード時に生成したリソースを移譲する. + var runtimeVciResources = new List<(SubAssetKey, UnityEngine.Object)>(); + TransferOwnership((key, obj) => runtimeVciResources.Add((key, obj))); + return new RuntimeVciInstance( runtimeGltfInstance, + runtimeVciResources, Nodes, colliders, rigidbodySettings, diff --git a/Assets/VCI/package.json b/Assets/VCI/package.json index 9a8a9ac..3bf02e3 100644 --- a/Assets/VCI/package.json +++ b/Assets/VCI/package.json @@ -1,13 +1,10 @@ { "name": "com.virtualcast.univci", - "version": "0.33.0", + "version": "0.33.1", "displayName": "VCI", "description": "VCI Exporter", "unity": "2019.4", - "keywords": [ - "vci", - "vr" - ], + "keywords": ["vci","vr"], "author": { "name": "VirtualCast, Inc." }, @@ -17,4 +14,4 @@ "com.vrmc.vrmshaders": "0.88.0", "com.vrmc.gltf": "0.88.0" } -} +} \ No newline at end of file diff --git a/Assets/VCI/package.json.meta b/Assets/VCI/package.json.meta index 56bdae4..b317739 100644 --- a/Assets/VCI/package.json.meta +++ b/Assets/VCI/package.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9878bd9ea8656114e898d3e3d29ab57c +guid: f27fcb9468a289747afb5d6c0e82bcc7 TextScriptImporter: externalObjects: {} userData: