diff --git a/.gitignore b/.gitignore index d946ba2..0da4c30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,27 @@ +# This .gitignore file should be placed at the root of your Unity project directory # -# https://raw.githubusercontent.com/github/gitignore/master/Unity.gitignore +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore # -[Ll]ibrary/ -[Tt]emp/ -[Oo]bj/ -[Bb]uild/ -[Bb]uilds/ -[Ll]ogs/ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ -# Never ignore Asset meta data -![Aa]ssets/**/*.meta +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ # Uncomment this line if you wish to ignore the asset store tools plugin -# [Aa]ssets/AssetStoreTools* +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* # Visual Studio cache directory .vs/ @@ -48,11 +57,20 @@ sysinfo.txt # Builds *.apk +*.aab *.unitypackage +*.app # Crashlytics generated file crashlytics-build.properties +# Packed Addressables +/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* + +# Temporary auto-generated Android Assets +/[Aa]ssets/[Ss]treamingAssets/aa.meta +/[Aa]ssets/[Ss]treamingAssets/aa/* + # # # diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest.meta b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest.meta new file mode 100644 index 0000000..d539cdb --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4a4ad87c38b8404b853ecb9ba53fc25 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md new file mode 100644 index 0000000..f0a482f --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md @@ -0,0 +1,48 @@ +# Emissive Strength Test + +## Screenshots + +### Plain Rendering (Test Passes) + +![plain screenshot](screenshot/screenshot_large_plain.jpg) + +### Render with Optional Bloom Effect Enabled + +![screenshot with bloom](screenshot/screenshot_large_bloom.jpg) + +These screenshots were rendered in BabylonJS with the default IBL strength dialed +down to help the glow stand out. The second screenshot has an optional "Bloom" effect +applied using the BabylonJS Default Rendering Pipeline. + +## Description + +This model tests if the `KHR_materials_emissive_strength` extension is available in a +given implementation. If it is not, the cubes will all emit the same shade of +light blue. For implementations that support this extension, the cubes will be +progressively brighter to the right. + +## Cube Colors + +The basic emissive color of all the cubes is `[0.1, 0.5, 0.9]` in the glTF file, which +is expected to undergo the usual linear-to-sRGB transfer before being shown to the viewer. +The cube on the far left has no emissive strength extension (`1x`), and each subsequent +cube doubles the strength (`2x`, `4x`, `8x`, and `16x`). + +With a simple output mapping, the cube on the far right may appear as +plain white, due to all of its color components being clamped to the 1.0 upper limit. +If "bloom" effects are enabled, some cubes may appear to glow. In a path-tracing +engine, all of these cubes may emit light, but the ones on the right should +emit substantially more light. + +## Test Failure + +If a given implementation does not support `KHR_materials_emissive_strength`, the +boxes will all appear to emit the same color. For example: + +![test fail screenshot](screenshot/test_fail.jpg) + +## License Information + +Copyright 2022 Analytical Graphics, Inc. +CC-BY 4.0 https://creativecommons.org/licenses/by/4.0/ +Model and textures by Ed Mackey. diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md.meta b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md.meta new file mode 100644 index 0000000..45cad63 --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68f003fe238ea4cc79d4bbb4bebb824c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary.meta b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary.meta new file mode 100644 index 0000000..0de7363 --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b306ecc0937964fb4acf7e1cc47fe0f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb new file mode 100644 index 0000000..6020aa6 Binary files /dev/null and b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb differ diff --git a/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb.meta b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb.meta new file mode 100644 index 0000000..8615a5b --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/EmissiveStrengthTest/glTF-Binary/EmissiveStrengthTest.glb.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7f13bb9df361b4c2d85ab9b306b56aaa +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm b/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm new file mode 100644 index 0000000..4ed141f Binary files /dev/null and b/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm differ diff --git a/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm.meta b/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm.meta new file mode 100644 index 0000000..0f2b874 --- /dev/null +++ b/Assets/StreamingAssets/SampleModels/VroidSampleModelA/Model.vrm.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e78d2af37a95348008f3d9ef02148359 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs b/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs new file mode 100644 index 0000000..831e28a --- /dev/null +++ b/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs @@ -0,0 +1,43 @@ +using System.IO; +using UnityEngine; +# if !UNITY_EDITOR && UNITY_ANDROID +using System; +using UnityEngine.Networking; +# endif + +namespace VGltfExamples.Common +{ + public static class StreamReaderFactory + { +# if !UNITY_EDITOR && UNITY_ANDROID + public static Stream Create(string path) + { + var basePath = "jar:file://" + Application.dataPath + "!/assets/"; + var url = basePath + path; + using (var req = UnityWebRequest.Get(url)) + { + req.SendWebRequest(); + + while (!req.isDone && !req.isNetworkError && !req.isHttpError) { } + if (req.isNetworkError || req.isHttpError) { + throw new Exception($"Failed to load: url = {url}, error = {req.error}"); + } + + return new MemoryStream(req.downloadHandler.data); + } + } +# elif !UNITY_EDITOR && UNITY_IOS + public static Stream Create(string path) + { + var basePath = Path.Combine(Application.dataPath, "Raw"); + return File.OpenRead(Path.Combine(basePath, path)); + } +# else + public static Stream Create(string path) + { + var basePath = Path.Combine(Application.dataPath, "StreamingAssets"); + return File.OpenRead(Path.Combine(basePath, path)); + } +# endif + } +} diff --git a/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs.meta b/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs.meta new file mode 100644 index 0000000..3f6f198 --- /dev/null +++ b/Assets/VGltfExamples/Common/Scripts/StreamReaderFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6ae738be51d446b3ab9c2da075ecef1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VGltfExamples/Common/Scripts/TimeSlicer.cs b/Assets/VGltfExamples/Common/Scripts/TimeSlicer.cs index 0f88252..b245c5d 100644 --- a/Assets/VGltfExamples/Common/Scripts/TimeSlicer.cs +++ b/Assets/VGltfExamples/Common/Scripts/TimeSlicer.cs @@ -5,10 +5,13 @@ namespace VGltfExamples.Common { + // TimeSlicer is a utility class to slice the loading process of glTF. + // If loading takes more than {limitMillisecPerFrame} ms to process on the main thread during {maxFrameCount} frames, + // interrupt the loading and wait for the next frame to avoid continuing to block the main thread. public sealed class TimeSlicer : VGltf.Unity.ITimeSlicer { readonly int limitMillisecPerFrame = 16; - readonly int maxFrameCount = 120; // 120フレーム以内に読まれれば良い + readonly int maxFrameCount = 120; readonly System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); int elapsedFrame = 0; diff --git a/Assets/VGltfExamples/VRMExample/Scenes/VRMLoader.unity b/Assets/VGltfExamples/VRMExample/Scenes/VRMLoader.unity index c99d339..2248ab1 100644 --- a/Assets/VGltfExamples/VRMExample/Scenes/VRMLoader.unity +++ b/Assets/VGltfExamples/VRMExample/Scenes/VRMLoader.unity @@ -38,12 +38,12 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.1801872, g: 0.22559631, b: 0.30677718, a: 1} + m_IndirectSpecularColor: {r: 0.18028426, g: 0.22571369, b: 0.30692106, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 12 + serializedVersion: 11 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 @@ -98,7 +98,7 @@ LightmapSettings: m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_LightingSettings: {fileID: 442704364} + m_UseShadowmask: 1 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -118,8 +118,6 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} @@ -151,7 +149,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 244002972} m_RootOrder: 0 @@ -176,7 +173,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -279,7 +275,6 @@ Light: m_UseColorTemperature: 0 m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 m_ShadowRadius: 0 m_ShadowAngle: 0 --- !u!4 &155851640 @@ -292,7 +287,6 @@ Transform: m_LocalRotation: {x: 0.073386915, y: -0.89253896, z: 0.41619772, w: 0.15737876} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 1 @@ -359,7 +353,6 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 4 @@ -393,7 +386,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 106800088} m_Father: {fileID: 575744737} @@ -418,7 +410,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -463,7 +454,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -515,7 +505,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1458226500} m_Father: {fileID: 575744737} @@ -540,7 +529,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -585,7 +573,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -636,7 +623,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1934839699} m_RootOrder: 1 @@ -661,7 +647,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -688,68 +673,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 335402909} m_CullTransparentMesh: 0 ---- !u!850595691 &442704364 -LightingSettings: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: Settings.lighting - serializedVersion: 4 - m_GIWorkflowMode: 1 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 0 - m_RealtimeEnvironmentLighting: 1 - m_BounceScale: 1 - m_AlbedoBoost: 1 - m_IndirectOutputScale: 1 - m_UsingShadowmask: 1 - m_BakeBackend: 1 - m_LightmapMaxSize: 1024 - m_BakeResolution: 40 - m_Padding: 2 - m_LightmapCompression: 3 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAO: 0 - m_MixedBakeMode: 2 - m_LightmapsBakeMode: 1 - m_FilterMode: 1 - m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_RealtimeResolution: 2 - m_ForceWhiteAlbedo: 0 - m_ForceUpdates: 0 - m_FinalGather: 0 - m_FinalGatherRayCount: 256 - m_FinalGatherFiltering: 1 - m_PVRCulling: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_LightProbeSampleCountMultiplier: 4 - m_PVRBounces: 2 - m_PVRMinBounces: 2 - m_PVREnvironmentMIS: 1 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_PVRTiledBaking: 0 --- !u!1 &575744733 GameObject: m_ObjectHideFlags: 0 @@ -808,7 +731,6 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 --- !u!223 &575744736 Canvas: m_ObjectHideFlags: 0 @@ -840,7 +762,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 2003198535} - {fileID: 244002972} @@ -884,7 +805,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2058808286} m_RootOrder: 0 @@ -909,7 +829,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1012,14 +931,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 790309655} - m_LocalRotation: {x: 0, y: 1, z: 0, w: 0} - m_LocalPosition: {x: 0, y: 0.87, z: 1.86} + m_LocalRotation: {x: 0, y: 0.99611825, z: -0.08802502, w: 0} + m_LocalPosition: {x: 0, y: 1.09, z: 1.86} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} + m_LocalEulerAnglesHint: {x: 10.1, y: 180, z: 0} --- !u!1 &1103151022 GameObject: m_ObjectHideFlags: 0 @@ -1049,7 +967,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1570466268} - {fileID: 2093987080} @@ -1075,7 +992,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -1112,10 +1028,7 @@ MonoBehaviour: m_HideMobileInput: 0 m_CharacterValidation: 0 m_CharacterLimit: 0 - m_OnSubmit: - m_PersistentCalls: - m_Calls: [] - m_OnDidEndEdit: + m_OnEndEdit: m_PersistentCalls: m_Calls: [] m_OnValueChanged: @@ -1124,7 +1037,7 @@ MonoBehaviour: m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_CustomCaretColor: 0 m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} - m_Text: Assets/StreamingAssets/SampleModels/Alicia/VRM/AliciaSolid-0.51.vrm + m_Text: SampleModels/VroidSampleModelA/Model.vrm m_CaretBlinkRate: 0.85 m_CaretWidth: 1 m_ReadOnly: 0 @@ -1144,7 +1057,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1195,7 +1107,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1934839699} m_RootOrder: 0 @@ -1220,7 +1131,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1275,7 +1185,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 334041492} m_RootOrder: 0 @@ -1300,7 +1209,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1369,12 +1277,10 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 m_RayTracingMode: 2 - m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -1399,7 +1305,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &1522748965 MeshFilter: m_ObjectHideFlags: 0 @@ -1418,7 +1323,6 @@ Transform: m_LocalRotation: {x: 0.2588191, y: 0, z: 0, w: 0.9659258} m_LocalPosition: {x: 6.26, y: 0.9, z: -5.86} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 5 @@ -1451,7 +1355,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1103151023} m_RootOrder: 0 @@ -1476,7 +1379,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1530,7 +1432,6 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 2 @@ -1583,7 +1484,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 1167221161} - {fileID: 335402910} @@ -1609,7 +1509,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -1646,10 +1545,7 @@ MonoBehaviour: m_HideMobileInput: 0 m_CharacterValidation: 0 m_CharacterLimit: 0 - m_OnSubmit: - m_PersistentCalls: - m_Calls: [] - m_OnDidEndEdit: + m_OnEndEdit: m_PersistentCalls: m_Calls: [] m_OnValueChanged: @@ -1678,7 +1574,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1730,7 +1625,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 575744737} m_RootOrder: 0 @@ -1755,7 +1649,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1823,7 +1716,6 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 766079266} m_Father: {fileID: 575744737} @@ -1848,7 +1740,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -1893,7 +1784,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1944,7 +1834,6 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1103151023} m_RootOrder: 1 @@ -1969,7 +1858,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1987,7 +1875,7 @@ MonoBehaviour: m_HorizontalOverflow: 1 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: Assets/StreamingAssets/SampleModels/Alicia/VRM/AliciaSoli + m_Text: SampleModels/VroidSampleModelA/Model.vrm --- !u!222 &2093987082 CanvasRenderer: m_ObjectHideFlags: 0 diff --git a/Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs b/Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs index 70b915c..ab6c546 100644 --- a/Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs +++ b/Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Cysharp.Threading.Tasks; using UnityEngine; @@ -85,13 +86,14 @@ async UniTask LoadVRM() var filePath = filePathInput.text; // Read the glTF container (unity-independent) - var gltfContainer = await Task.Run(() => + var gltfContainer = default(GltfContainer); + using (var sr = Common.StreamReaderFactory.Create(filePath)) // get-path can be called on only main-thread... { - using (var fs = new FileStream(filePath, FileMode.Open)) + gltfContainer = await Task.Run(() => { - return GltfContainer.FromGlb(fs); - } - }); + return GltfContainer.FromGlb(sr); + }); + } var res = new VRMResource(); try @@ -213,7 +215,13 @@ async UniTaskVoid UIOnExportButtonClickedAsync() var bridge = new VRM0ExporterBridge(); gltfExporter.AddHook(new VGltf.Ext.Vrm0.Unity.Hooks.ExporterHook(bridge)); - gltfExporter.ExportGameObjectAsScene(head.Go); + // In some implementations of VRM, specifying multiple shape keys in the blendshape proxy may not work correctly, so they should be unified. + using (var unifier = new VGltf.Ext.Vrm0.Unity.Filter.BlendshapeUnifier()) + { + unifier.Unify(head.Go); + + gltfExporter.ExportGameObjectAsScene(unifier.Go); + } gltfContainer = gltfExporter.IntoGlbContainer(); } @@ -226,7 +234,7 @@ async UniTaskVoid UIOnExportButtonClickedAsync() var filePath = outputFilePathInput.text; await Task.Run(() => { - using (var fs = new FileStream(filePath, FileMode.Create)) + using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { GltfContainer.ToGlb(fs, gltfContainer); } @@ -311,3 +319,4 @@ void DebugLogProfile(Common.MemoryProfile now, Common.MemoryProfile prev = null) } } } + diff --git a/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader.unity b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader.unity index eb3325f..01534c6 100644 --- a/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader.unity +++ b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader.unity @@ -1204,6 +1204,7 @@ GameObject: - component: {fileID: 790309658} - component: {fileID: 790309657} - component: {fileID: 790309656} + - component: {fileID: 790309659} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -1228,7 +1229,7 @@ Camera: m_GameObject: {fileID: 790309655} m_Enabled: 1 serializedVersion: 2 - m_ClearFlags: 1 + m_ClearFlags: 2 m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 @@ -1277,6 +1278,66 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0} +--- !u!114 &790309659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 790309655} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 948f4100a11a5c24981795d21301da5c, type: 3} + m_Name: + m_EditorClassIdentifier: + volumeTrigger: {fileID: 790309658} + volumeLayer: + serializedVersion: 2 + m_Bits: 1 + stopNaNPropagation: 1 + finalBlitToCameraTarget: 0 + antialiasingMode: 0 + temporalAntialiasing: + jitterSpread: 0.75 + sharpness: 0.25 + stationaryBlending: 0.95 + motionBlending: 0.85 + subpixelMorphologicalAntialiasing: + quality: 2 + fastApproximateAntialiasing: + fastMode: 0 + keepAlpha: 0 + fog: + enabled: 1 + excludeSkybox: 1 + debugLayer: + lightMeter: + width: 512 + height: 256 + showCurves: 1 + histogram: + width: 512 + height: 256 + channel: 3 + waveform: + exposure: 0.12 + height: 256 + vectorscope: + size: 256 + exposure: 0.12 + overlaySettings: + linearDepth: 0 + motionColorIntensity: 4 + motionGridSize: 64 + colorBlindnessType: 0 + colorBlindnessStrength: 1 + m_Resources: {fileID: 11400000, guid: d82512f9c8e5d4a4d938b575d47f88d4, type: 2} + m_ShowToolkit: 0 + m_ShowCustomSorter: 0 + breakBeforeColorGrading: 0 + m_BeforeTransparentBundles: [] + m_BeforeStackBundles: [] + m_AfterStackBundles: [] --- !u!1 &873957080 GameObject: m_ObjectHideFlags: 0 @@ -2160,6 +2221,55 @@ MonoBehaviour: loadButton: {fileID: 244002973} unloadButton: {fileID: 334041493} exportButton: {fileID: 1853197289} +--- !u!1 &1736942649 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1736942651} + - component: {fileID: 1736942650} + m_Layer: 0 + m_Name: PostProcess + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1736942650 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736942649} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8b9a305e18de0c04dbd257a21cd47087, type: 3} + m_Name: + m_EditorClassIdentifier: + sharedProfile: {fileID: 11400000, guid: a01744b1a65a84ca3ac463a4e0afe2b3, type: 2} + isGlobal: 1 + blendDistance: 0 + weight: 1 + priority: 0 +--- !u!4 &1736942651 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1736942649} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1853197287 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles.meta b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles.meta new file mode 100644 index 0000000..a4ef084 --- /dev/null +++ b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ced29a20e902d4974811223179303220 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset new file mode 100644 index 0000000..3850cbd --- /dev/null +++ b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset @@ -0,0 +1,1375 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7123415973434110789 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: adb84e30e02715445aeb9959894e3b4d, type: 3} + m_Name: ColorGrading + m_EditorClassIdentifier: + active: 0 + enabled: + overrideState: 1 + value: 1 + gradingMode: + overrideState: 1 + value: 1 + externalLut: + overrideState: 0 + value: {fileID: 0} + defaultState: 1 + tonemapper: + overrideState: 1 + value: 2 + toneCurveToeStrength: + overrideState: 0 + value: 0 + toneCurveToeLength: + overrideState: 0 + value: 0.5 + toneCurveShoulderStrength: + overrideState: 0 + value: 0 + toneCurveShoulderLength: + overrideState: 0 + value: 0.5 + toneCurveShoulderAngle: + overrideState: 0 + value: 0 + toneCurveGamma: + overrideState: 0 + value: 1 + ldrLut: + overrideState: 0 + value: {fileID: 0} + defaultState: 4 + ldrLutContribution: + overrideState: 0 + value: 1 + temperature: + overrideState: 0 + value: 0 + tint: + overrideState: 0 + value: 0 + colorFilter: + overrideState: 0 + value: {r: 1, g: 1, b: 1, a: 1} + hueShift: + overrideState: 0 + value: 0 + saturation: + overrideState: 0 + value: 0 + brightness: + overrideState: 0 + value: 0 + postExposure: + overrideState: 0 + value: 0 + contrast: + overrideState: 0 + value: 0 + mixerRedOutRedIn: + overrideState: 0 + value: 100 + mixerRedOutGreenIn: + overrideState: 0 + value: 0 + mixerRedOutBlueIn: + overrideState: 0 + value: 0 + mixerGreenOutRedIn: + overrideState: 0 + value: 0 + mixerGreenOutGreenIn: + overrideState: 0 + value: 100 + mixerGreenOutBlueIn: + overrideState: 0 + value: 0 + mixerBlueOutRedIn: + overrideState: 0 + value: 0 + mixerBlueOutGreenIn: + overrideState: 0 + value: 0 + mixerBlueOutBlueIn: + overrideState: 0 + value: 100 + lift: + overrideState: 0 + value: {x: 1, y: 1, z: 1, w: 0} + gamma: + overrideState: 0 + value: {x: 1, y: 1, z: 1, w: 0} + gain: + overrideState: 0 + value: {x: 1, y: 1, z: 1, w: 0} + masterCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + redCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + greenCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + blueCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + hueVsHueCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + hueVsSatCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + satVsSatCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + lumVsSatCurve: + overrideState: 0 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 +--- !u!114 &-4812486297330136937 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 48a79b01ea5641d4aa6daa2e23605641, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + enabled: + overrideState: 1 + value: 1 + intensity: + overrideState: 1 + value: 12 + threshold: + overrideState: 0 + value: 1 + softKnee: + overrideState: 0 + value: 0.5 + clamp: + overrideState: 0 + value: 65472 + diffusion: + overrideState: 0 + value: 7 + anamorphicRatio: + overrideState: 0 + value: 0 + color: + overrideState: 0 + value: {r: 1, g: 1, b: 1, a: 1} + fastMode: + overrideState: 0 + value: 0 + dirtTexture: + overrideState: 0 + value: {fileID: 0} + defaultState: 1 + dirtIntensity: + overrideState: 0 + value: 0 +--- !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: 8e6292b2c06870d4495f009f912b9600, type: 3} + m_Name: PostProcess Profile + m_EditorClassIdentifier: + settings: + - {fileID: -7123415973434110789} + - {fileID: -4812486297330136937} diff --git a/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset.meta b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset.meta new file mode 100644 index 0000000..ada2fbc --- /dev/null +++ b/Assets/VGltfExamples/glTFExample/Scenes/GltfLoader_Profiles/PostProcess Profile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a01744b1a65a84ca3ac463a4e0afe2b3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs b/Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs index 8bb0e31..a4c3f8f 100644 --- a/Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs +++ b/Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs @@ -44,6 +44,7 @@ public void Dispose() new string[]{"NormalTangentMirrorTest", "glTF-Binary", "NormalTangentMirrorTest.glb"}, new string[]{"MetalRoughSpheres", "glTF-Binary", "MetalRoughSpheres.glb"}, new string[]{"AlphaBlendModeTest", "glTF-Binary", "AlphaBlendModeTest.glb"}, + new string[]{"EmissiveStrengthTest", "glTF-Binary", "EmissiveStrengthTest.glb"}, new string[]{"WaterBottle", "glTF-Binary", "WaterBottle.glb"}, new string[]{"BoomBox", "glTF-Binary", "BoomBox.glb"}, new string[]{"NormalTest02", "normal_test_02.glb"}, @@ -71,41 +72,44 @@ void OnDestroy() } } - async UniTask LoadGltf(string filePath, string name) + async UniTask LoadGltf(string filePath, string name, System.Threading.CancellationToken ct) { - // Read the glTF container (unity-independent) + // Read the glTF container. + // Task.Run is used to avoid blocking the main thread. + // GltfContainer is not dependent on Unity, so it can be used in other threads not only in the main thread. var gltfContainer = await Task.Run(() => { using (var fs = new FileStream(filePath, FileMode.Open)) { return GltfContainer.FromGlb(fs); } - }); + }, ct); + // GltfResource is a wrapper of the resources only used in examples. + // It is used for avoid resource leaks when an exception occurs. var res = new GltfResource(); try { // Create a GameObject that points to root nodes in the glTF scene. - // The GameObject of the glTF's child Node will be created under this object. + // GameObjects of the glTF's child node will be created under the this object. var go = new GameObject(); go.name = name; res.Go = go; - // Create a glTF Importer for Unity. - // The resources will be cached in the internal Context of this Importer. - // Resources can be released by calling Dispose of the Importer (or the internal Context). + // Create a TimeSlicer for Unity. + // TimeSlicer is used to control the time spent in the main thread. var timeSlicer = new Common.TimeSlicer(); + + // Create a glTF Importer for Unity. + // The resources will be stored in the Context in this Importer. + // Resources can be released by calling Dispose of the Importer (or the Context). using (var gltfImporter = new Importer(gltfContainer, timeSlicer)) { // Load the Scene. - res.Context = await gltfImporter.ImportSceneNodes(System.Threading.CancellationToken.None); - } - - foreach (var rootNodeIndex in gltfContainer.Gltf.RootNodesIndices) - { - var rootNode = res.Context.Resources.Nodes[rootNodeIndex]; - rootNode.Value.transform.SetParent(go.transform, false); + // ImportSceneNodes moves ownership of the Context from the Importer, so resources will not be released when the Importer is disposed. + // The Context must be disposed by the caller. + res.Context = await gltfImporter.ImportSceneNodes(go, ct); } } catch (Exception) @@ -164,7 +168,7 @@ public async UniTaskVoid UIOnLoadButtonClickAsync() var loc = _modelLocs[filePathInput.value]; var filePath = SampleAssetPath(loc); // TODO: Support Android - var res = await LoadGltf(filePath, "glTF"); + var res = await LoadGltf(filePath, "glTF", System.Threading.CancellationToken.None); _modelResources.Insert(0, res); var p1 = Common.MemoryProfile.Now; diff --git a/Packages/manifest.json b/Packages/manifest.json index d1663fd..c1c5e22 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,10 +1,12 @@ { "dependencies": { "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask", - "com.unity.ide.vscode": "1.2.3", - "com.unity.test-framework": "1.1.22", + "com.unity.ide.visualstudio": "2.0.15", + "com.unity.ide.vscode": "1.2.5", + "com.unity.postprocessing": "2.3.0", + "com.unity.test-framework": "1.1.31", "com.unity.ugui": "1.0.0", - "net.yutopp.vjson": "0.9.10", + "net.yutopp.vjson": "0.9.12", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IExporterBridge.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IExporterBridge.cs index 118e36f..f5bb3f7 100644 --- a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IExporterBridge.cs +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IExporterBridge.cs @@ -10,12 +10,11 @@ namespace VGltf.Ext.Vrm0.Unity.Bridge { - public interface IExporterBridge + public interface IExporterBridge : IMaterialExporterBridge { void ExportMeta(Exporter exporter, VGltf.Ext.Vrm0.Types.Vrm vrm, GameObject go); void ExportFirstPerson(IExporterContext context, VGltf.Ext.Vrm0.Types.Vrm vrm, GameObject go); void ExportBlendShapeMaster(Exporter exporter, VGltf.Ext.Vrm0.Types.Vrm vrm, GameObject go); void ExportSecondaryAnimation(IExporterContext context, VGltf.Ext.Vrm0.Types.Vrm vrm, GameObject go); - Types.Material CreateMaterialProp(IExporterContext context, Material matRes); } } diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs new file mode 100644 index 0000000..62c055f --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs @@ -0,0 +1,17 @@ +// +// Copyright (c) 2021 - yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using UnityEngine; +using VGltf.Unity; + +namespace VGltf.Ext.Vrm0.Unity.Bridge +{ + public interface IMaterialExporterBridge + { + Types.Material CreateMaterialProp(IExporterContext context, Material matRes); + } +} diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs.meta b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs.meta new file mode 100644 index 0000000..cbbcda2 --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Bridge/IMaterialExporterBridge.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5124880932734639b3826ae453e9762 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultExporterBridge.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultExporterBridge.cs index df5af15..6a25bb9 100644 --- a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultExporterBridge.cs +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultExporterBridge.cs @@ -15,6 +15,8 @@ namespace VGltf.Ext.Vrm0.Unity { public sealed class DefaultExporterBridge : VGltf.Ext.Vrm0.Unity.Bridge.IExporterBridge { + private readonly DefaultMaterialExporterBridge _materialExporterBridge = new DefaultMaterialExporterBridge(); + public void ExportMeta(Exporter exporter, VGltf.Ext.Vrm0.Types.Vrm vrm, GameObject go) { var meta = go.GetComponent(); @@ -198,18 +200,8 @@ public void ExportSecondaryAnimation(IExporterContext context, VGltf.Ext.Vrm0.Ty vrm.SecondaryAnimation = vrmSecondaryAnimation; } - public Types.Material CreateMaterialProp(IExporterContext context, Material mat) - { - var vrmMat = new Types.Material(); - - // TODO: if mat.shader is MToon, support that - - vrmMat.Name = mat.name; - vrmMat.Shader = Types.Material.VRM_USE_GLTFSHADER; - - return vrmMat; - } - + public Types.Material CreateMaterialProp(IExporterContext context, Material mat) => _materialExporterBridge.CreateMaterialProp(context, mat); + static Types.BlendShape.GroupType.BlendShapePresetEnum ToVRM0Preset(VRM0BlendShapeProxy.BlendShapePreset kind) { switch (kind) diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultImporterBridge.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultImporterBridge.cs index c7a6cac..7fb2313 100644 --- a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultImporterBridge.cs +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultImporterBridge.cs @@ -98,11 +98,15 @@ public void ImportBlendShapeMaster(IImporterContext context, VGltf.Ext.Vrm0.Type public void ImportSecondaryAnimation(IImporterContext context, VGltf.Ext.Vrm0.Types.SecondaryAnimation vrmSecondaryAnimation, GameObject go) { - // if the node named "secondary" exists, attach VRM0SecondaryAnimation to this. Otherwise, ignore that. + // if the node named "secondary" exists, attach VRM0SecondaryAnimation to this. + // Otherwise, create a new node named "secondary" and attach VRM0SecondaryAnimation to it. var secondaryNode = go.transform.Find("secondary"); if (secondaryNode == null) { - return; + var secondaryGo = new GameObject("secondary"); + secondaryGo.transform.SetParent(go.transform); + + secondaryNode = secondaryGo.transform; } var sa = secondaryNode.gameObject.AddComponent(); diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs new file mode 100644 index 0000000..d67d7e3 --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) 2021 - yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using UnityEngine; +using VGltf.Unity; + +namespace VGltf.Ext.Vrm0.Unity +{ + public sealed class DefaultMaterialExporterBridge : VGltf.Ext.Vrm0.Unity.Bridge.IMaterialExporterBridge + { + public Types.Material CreateMaterialProp(IExporterContext context, Material mat) + { + var vrmMat = new Types.Material(); + + // TODO: if mat.shader is MToon, support that + + vrmMat.Name = mat.name; + vrmMat.Shader = Types.Material.VRM_USE_GLTFSHADER; + + return vrmMat; + } + } +} diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs.meta b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs.meta new file mode 100644 index 0000000..cb60a99 --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/DefaultMaterialExporterBrigde.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fef5335f0cc0d4fd2831cf6c4b61a078 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter.meta b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter.meta new file mode 100644 index 0000000..566e360 --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38872457f815d4bb8a55bf3f40dce414 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs new file mode 100644 index 0000000..45911ae --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs @@ -0,0 +1,158 @@ +// +// Copyright (c) 2023 - yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using VGltf.Unity; + +namespace VGltf.Ext.Vrm0.Unity.Filter +{ + public sealed class BlendshapeUnifier : IDisposable + { + public GameObject Go { get; private set; } + readonly Dictionary bakedMeshes = new Dictionary(); + + void IDisposable.Dispose() + { + if (Go != null) + { + Utils.Destroy(Go); + Go = null; + } + + // Destroy baked meshes + foreach (var (_, mesh) in bakedMeshes.Values) + { + Utils.Destroy(mesh); + } + bakedMeshes.Clear(); + } + + public void Unify(GameObject go) + { + var nGo = UnityEngine.Object.Instantiate(go) as GameObject; + nGo.name = go.name; + try + { + Normalized(nGo); + } + catch (Exception) + { + Utils.Destroy(nGo); + throw; + } + + Go = nGo; + } + + void Normalized(GameObject nGo) + { + var bsp = nGo.GetComponent(); + if (bsp == null) + { + return; + } + + UnifyWeightsOfBlendShapes(nGo, bsp); + } + + void UnifyWeightsOfBlendShapes(GameObject go, VRM0BlendShapeProxy bsp) + { + foreach (var group in bsp.Groups) + { + var shapes = group.MeshShapes; + if (shapes.Count != 1) + { + continue; + } + + var shape = shapes[0]; + if (shape.Weights.Count > 1) + { + var (originalMesh, nMesh) = AssumeReplaced(shape.SkinnedMeshRenderer); + + // Apply all BlendShapes contained in shape + foreach (var weight in shape.Weights) + { + var shapeIndex = nMesh.GetBlendShapeIndex(weight.ShapeKeyName); + shape.SkinnedMeshRenderer.SetBlendShapeWeight(shapeIndex, weight.WeightValue); // [0, 100] + } + + var generatedShapeName = CreateShapeName(group.Name); + + var bakedMesh = new Mesh(); + try { + shape.SkinnedMeshRenderer.BakeMesh(bakedMesh); + AddNewBlendShape(nMesh, generatedShapeName, originalMesh, bakedMesh); + } finally { + Utils.Destroy(bakedMesh); + } + + // Finally, set all blendshapes of nMesh to 0 + for (int i = 0; i < nMesh.blendShapeCount; ++i) + { + shape.SkinnedMeshRenderer.SetBlendShapeWeight(i, 0); + } + + // Set the Weight of shape to a single blendshape baked in + shape.Weights = new List + { + new VRM0BlendShapeProxy.Weight + { + ShapeKeyName = generatedShapeName, + WeightValue = 100, + } + }; + } + } + } + + void AddNewBlendShape(Mesh targetMesh, string blendShapeName, Mesh originalMesh, Mesh blendShapeMesh) + { + var vertices = originalMesh.vertices; + var normals = originalMesh.normals; + var tangents = originalMesh.tangents; + + var blendShapeVertices = blendShapeMesh.vertices; + var blendShapeNormals = blendShapeMesh.normals; + var blendShapeTangents = blendShapeMesh.tangents; + + var deltaVertices = blendShapeVertices.Select((v, j) => v - vertices[j]).ToArray(); + var deltaNormals = blendShapeNormals.Length > 0 + ? blendShapeNormals.Select((n, j) => n - normals[j]).ToArray() + : null; + var deltaTangents = blendShapeTangents.Length > 0 + ? blendShapeTangents.Select((t, j) => (Vector3)(t - tangents[j])).ToArray() + : null; + + targetMesh.AddBlendShapeFrame(blendShapeName, 100, deltaVertices, deltaNormals, deltaTangents); + } + + (Mesh, Mesh) AssumeReplaced(SkinnedMeshRenderer smr) + { + if (bakedMeshes.TryGetValue(smr, out var result)) { + return result; + } + + var originalMesh = smr.sharedMesh; + + var nMesh = UnityEngine.Object.Instantiate(originalMesh); + bakedMeshes.Add(smr, (originalMesh, nMesh)); + + smr.sharedMesh = nMesh; + + return (originalMesh, nMesh); + } + + static string CreateShapeName(string groupName) + { + return $"_VGltf.Baked_{groupName}"; + } + } +} diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs.meta b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs.meta new file mode 100644 index 0000000..2296fb9 --- /dev/null +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Filter/BlendshapeUnifier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f7aec29ba7174e5184dd141bd1715e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Hooks/ExporterHook.cs b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Hooks/ExporterHook.cs index b48fcc5..a4ec6a5 100644 --- a/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Hooks/ExporterHook.cs +++ b/Packages/net.yutopp.vgltf.ext.vrm0.unity/Runtime/Hooks/ExporterHook.cs @@ -55,16 +55,6 @@ void ExportHumanoid(Exporter exporter, Types.Vrm extVrm, GameObject go) throw new Exception("There is no Animation component"); } - // NOTE: It may break if there are duplicate names - var nodeTransMap = - anim.GetComponentsInChildren().Where(n => - { - return !( - (n.GetComponent() != null) || - (n.GetComponent() != null) - ); - }).ToDictionary(t => t.name); - var avatar = anim.avatar; if (!avatar.isValid || !avatar.isHuman) { @@ -98,10 +88,10 @@ void ExportHumanoid(Exporter exporter, Types.Vrm extVrm, GameObject go) // HumanBone vrmHumBone.Bone = h.humanName.AsHumanBoneNameToVrm(); - var boneTrans = nodeTransMap[h.boneName]; - if (!exporter.Context.Resources.Nodes.TryGetValueByName(boneTrans.name, out var boneNode)) + //var boneTrans = nodeTransMap[h.boneName]; + if (!exporter.Context.Resources.Nodes.TryGetValueByName(h.boneName, out var boneNode)) { - throw new Exception($"bone transform is not found: name={boneTrans.name}"); + throw new Exception($"bone transform is not found or not unique: name={h.boneName}"); } vrmHumBone.Node = boneNode.Index; diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/Exporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/Exporter.cs index 644fa9d..3b2901d 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/Exporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/Exporter.cs @@ -44,6 +44,7 @@ sealed class InnerContext : IExporterContext public CoordUtils CoordUtils { get; } public ResourceExporters Exporters { get; } + public SamplerExporter SamplerExporter { get; } public InnerContext(Config config) { @@ -70,6 +71,8 @@ public InnerContext(Config config) Textures = new TextureExporter(this), Images = new ImageExporter(this), }; + + SamplerExporter = new SamplerExporter(this); } void IDisposable.Dispose() diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/ExporterRuntimeResources.cs b/Packages/net.yutopp.vgltf.unity/Runtime/ExporterRuntimeResources.cs index cf279d5..b33d10d 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/ExporterRuntimeResources.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/ExporterRuntimeResources.cs @@ -6,6 +6,8 @@ // using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace VGltf.Unity @@ -16,7 +18,7 @@ public sealed class ExporterRuntimeResources : IDisposable public IndexedResourceDict Nodes = new IndexedResourceDict(); public IndexedResourceDict Textures = new IndexedResourceDict(); public IndexedResourceDict Materials = new IndexedResourceDict(); - public IndexedResourceDict Meshes = new IndexedResourceDict(); + public IndexedResourceDict<(Mesh, Material[]), Mesh> Meshes = new IndexedResourceDict<(Mesh, Material[]), Mesh>(new MeshEqualityComparer()); public IndexedResourceDict Skins = new IndexedResourceDict(); public IndexedResourceDict Animations = new IndexedResourceDict(); @@ -24,5 +26,23 @@ public void Dispose() { // DO NOT Dispose any resources because these containers have no ownerships. } + + sealed class MeshEqualityComparer : IEqualityComparer<(Mesh, Material[])> + { + public bool Equals((Mesh, Material[]) x, (Mesh, Material[]) y) + { + return x.Item1.Equals(y.Item1) && x.Item2.SequenceEqual(y.Item2); + } + + public int GetHashCode((Mesh, Material[]) obj) + { + var hashCode = obj.Item1.GetHashCode(); + foreach (var m in obj.Item2) + { + hashCode = unchecked(hashCode * 31 + m.GetHashCode()); + } + return hashCode; + } + } } } diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/Extra/TransformNormalizer.cs b/Packages/net.yutopp.vgltf.unity/Runtime/Extra/TransformNormalizer.cs index 8c19ee9..5d6a5de 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/Extra/TransformNormalizer.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/Extra/TransformNormalizer.cs @@ -143,6 +143,12 @@ public void BakeMeshes(GameObject go) smr.sharedMesh = mesh; } + var mf = go.GetComponent(); + if (mf != null) + { + mf.sharedMesh = BakeMeshAndMemoize(mf.sharedMesh, go.transform); + } + for (var i = 0; i < go.transform.childCount; ++i) { var ct = go.transform.GetChild(i); @@ -224,5 +230,19 @@ public void UpdateBonePoses(GameObject go) UpdateBonePoses(ct.gameObject); } } + + Mesh BakeMeshAndMemoize(Mesh m, Transform t) + { + var mesh = UnityEngine.Object.Instantiate(m); + bakedMeshes.Add(mesh); + + mesh.name = m.name; + + mesh.vertices = mesh.vertices.Select(t.TransformVector).ToArray(); + mesh.normals = mesh.normals.Select(t.TransformDirection).ToArray(); + // mesh.tangents = mesh.tangents.Select(go.transform.TransformVector).ToArray(); + + return mesh; + } } } diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/IExporterContext.cs b/Packages/net.yutopp.vgltf.unity/Runtime/IExporterContext.cs index 38fbad4..72a3870 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/IExporterContext.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/IExporterContext.cs @@ -18,6 +18,7 @@ public interface IExporterContext : IDisposable CoordUtils CoordUtils { get; } ResourceExporters Exporters { get; } + SamplerExporter SamplerExporter { get; } } public sealed class ResourceExporters diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/IImporterContext.cs b/Packages/net.yutopp.vgltf.unity/Runtime/IImporterContext.cs index be80b57..270f171 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/IImporterContext.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/IImporterContext.cs @@ -20,6 +20,7 @@ public interface IImporterContext : IDisposable ImportingSetting ImportingSetting { get; } ResourceImporters Importers { get; } + SamplerApplier SamplerApplier { get; } } public sealed class ResourceImporters diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/Importer.cs b/Packages/net.yutopp.vgltf.unity/Runtime/Importer.cs index 88d5121..4548140 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/Importer.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/Importer.cs @@ -53,6 +53,7 @@ sealed class InnerContext : IImporterContext public ImportingSetting ImportingSetting { get; } public ResourceImporters Importers { get; } + public SamplerApplier SamplerApplier { get; } public InnerContext(GltfContainer container, IResourceLoader loader, ITimeSlicer timeSlicer, Config config) { @@ -96,6 +97,8 @@ public InnerContext(GltfContainer container, IResourceLoader loader, ITimeSlicer Textures = new TextureImporter(this), Images = new ImageImporter(this), }; + + SamplerApplier = new SamplerApplier(this); } public void Dispose() @@ -105,7 +108,7 @@ public void Dispose() // helper functions - public void SetRendererEnebled(bool value) + public void SetRendererEnabled(bool value) { foreach (var go in Resources.Nodes.Map(r => r.Value)) { @@ -122,6 +125,12 @@ public void SetRendererEnebled(bool value) } } } + + [Obsolete("Use SetRendererEn'a'bled instead")] + public void SetRendererEnebled(bool value) + { + SetRendererEnabled(value); + } } InnerContext _context; @@ -143,14 +152,14 @@ public Importer(GltfContainer container, ITimeSlicer timeSlicer, Config config = { } - public async Task ImportSceneNodes(CancellationToken ct) + public async Task ImportSceneNodes(GameObject parentGo, CancellationToken ct = default) { var gltf = Context.Container.Gltf; var gltfScene = VGltf.Types.Extensions.GltfExtensions.GetSceneObject(gltf); foreach (var nodeIndex in gltfScene.Nodes) { - await Context.Importers.Nodes.ImportGameObjects(nodeIndex, null, ct); + await Context.Importers.Nodes.ImportGameObjects(nodeIndex, parentGo, ct); await _context.TimeSlicer.Slice(ct); } foreach (var nodeIndex in gltfScene.Nodes) @@ -165,11 +174,16 @@ public async Task ImportSceneNodes(CancellationToken ct) await _context.TimeSlicer.Slice(ct); } - _context.SetRendererEnebled(true); + _context.SetRendererEnabled(true); return TakeContext(); } + public Task ImportSceneNodes(CancellationToken ct = default) + { + return ImportSceneNodes(null, ct); + } + public async Task ImportEmpty(CancellationToken ct) { foreach (var hook in Hooks) diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/IndexedResourceDict.cs b/Packages/net.yutopp.vgltf.unity/Runtime/IndexedResourceDict.cs index 0b988f8..7cbda31 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/IndexedResourceDict.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/IndexedResourceDict.cs @@ -14,8 +14,12 @@ namespace VGltf.Unity { public sealed class IndexedResourceDict : IDisposable where V : UnityEngine.Object { - readonly IndexedDisposableResourceDict> _internal = - new IndexedDisposableResourceDict>(); + readonly IndexedDisposableResourceDict> _internal; + + public IndexedResourceDict(IEqualityComparer equalityComparer = default) + { + _internal = new IndexedDisposableResourceDict>(equalityComparer); + } public IndexedResource Add(K k, int index, string name, V v) { @@ -98,8 +102,13 @@ static IndexedResource Unwrap(IndexedResource> wres public sealed class IndexedDisposableResourceDict : IDisposable where V : IDisposable { - readonly Dictionary> _dict = new Dictionary>(); - readonly Dictionary> _nameDict = new Dictionary>(); + readonly Dictionary> _dict; + readonly MultiMap> _nameDict = new MultiMap>(); + + public IndexedDisposableResourceDict(IEqualityComparer equalityComparer = default) + { + _dict = new Dictionary>(equalityComparer); + } public IndexedResource Add(K k, int index, string name, V v) { @@ -156,14 +165,23 @@ public bool TryGetValue(K k, out IndexedResource res) return _dict.TryGetValue(k, out res); } - public bool ContainsByName(string k) - { - return _nameDict.ContainsKey(k); - } - public bool TryGetValueByName(string k, out IndexedResource res) { - return _nameDict.TryGetValue(k, out res); + if (!_nameDict.TryGetValues(k, out var resList)) + { + res = default; + return false; + } + + // Can not distinguish that there is no element or more elements... (bad interface) + if (resList.Count != 1) + { + res = default; + return false; + } + + res = resList.First(); + return true; } public void Dispose() @@ -177,4 +195,31 @@ public void Dispose() _nameDict.Clear(); } } + + sealed class MultiMap + { + readonly Dictionary> _dict = new Dictionary>(); + + public void Add(K key, V value) + { + if (_dict.TryGetValue(key, out var values)) + { + values.Add(value); + + return; + } + + _dict.Add(key, new List{ value }); + } + + public bool TryGetValues(K key, out List values) + { + return _dict.TryGetValue(key, out values); + } + + public void Clear() + { + _dict.Clear(); + } + } } diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/MaterialExporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/MaterialExporter.cs index 0fc98c4..b02517c 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/MaterialExporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/MaterialExporter.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; +using VGltf.Ext.KhrMaterialsEmissiveStrength.Types; using VGltf.Types.Extensions; namespace VGltf.Unity @@ -134,18 +135,16 @@ public IndexedResource ForceExportStandard(Material mat) var occlusionTexIndex = ExportOcclusionTextureIfExist(mat, "_OcclusionMap"); mat.TryGetFloatOrDefault("_OcclusionStrength", 1.0f, out var occlutionStrength); - Color emissionColor; - int? emissionTexIndex; + var emissionColorLinear = Vector3.zero; // black + var emissionTexIndex = default(int?); if ((mat.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0) { - mat.TryGetColorOrDefault("_EmissionColor", Color.black, out emissionColor); + if (mat.TryGetColorOrDefault("_EmissionColor", Color.black, out var emissionColor)) + { + emissionColorLinear = ValueConv.ColorToLinearRGB(emissionColor); + } emissionTexIndex = ExportTextureIfExist(mat, "_EmissionMap"); } - else - { - emissionColor = Color.black; - emissionTexIndex = null; - } var alphaMode = GetAlphaMode(mat); mat.TryGetFloatOrDefault("_Cutoff", 0.0f, out var alphaCutoff); @@ -188,8 +187,8 @@ public IndexedResource ForceExportStandard(Material mat) Strength = occlutionStrength, } : null, - EmissiveFactor = emissionColor != Color.black - ? PrimitiveExporter.AsArray(ValueConv.ColorToLinearRGB(emissionColor)) + EmissiveFactor = emissionColorLinear != Vector3.zero + ? PrimitiveExporter.AsArray(emissionColorLinear) : null, EmissiveTexture = emissionTexIndex != null ? new Types.Material.EmissiveTextureInfoType { @@ -203,6 +202,21 @@ public IndexedResource ForceExportStandard(Material mat) // DoubleSided = // Not supported }; + // emission HDR + if (Mathf.Max(Mathf.Max(emissionColorLinear.x, emissionColorLinear.y), emissionColorLinear.z) > 1.0f) + { + var strength = emissionColorLinear.magnitude; + + var emissiveStrengthExtName = KhrMaterialsEmissiveStrength.ExtensionName; + gltfMaterial.AddExtension(emissiveStrengthExtName, new KhrMaterialsEmissiveStrength + { + EmissiveStrength = strength, + }); + Context.Gltf.AddExtensionUsed(emissiveStrengthExtName); + + gltfMaterial.EmissiveFactor = PrimitiveExporter.AsArray(emissionColorLinear.normalized); + } + var matIndex = Context.Gltf.AddMaterial(gltfMaterial); var resource = Context.Resources.Materials.Add(mat, matIndex, mat.name, mat); diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/MaterialImporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/MaterialImporter.cs index 81380c6..5737019 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/MaterialImporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/MaterialImporter.cs @@ -10,6 +10,8 @@ using System.Threading.Tasks; using UnityEngine; using UnityEngine.Rendering; +using VGltf.Ext.KhrMaterialsEmissiveStrength.Types; +using VGltf.Types.Extensions; namespace VGltf.Unity { @@ -178,13 +180,25 @@ public async Task ImportStandardMaterialProps(IImporterContext context, Material break; } - // RGB component and NOT [HDR] - var emissionColor = ValueConv.ColorFromLinear(PrimitiveImporter.AsVector3(gltfMat.EmissiveFactor)); - if (emissionColor != Color.black) + // RGB component + var emissionColorLinear = PrimitiveImporter.AsVector3(gltfMat.EmissiveFactor); + if (emissionColorLinear != Vector3.zero) // NOT black { mat.EnableKeyword("_EMISSION"); mat.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack; - mat.SetColor("_EmissionColor", emissionColor); + + // Support HDR + var emissiveStrengthExtName = KhrMaterialsEmissiveStrength.ExtensionName; + if (context.Container.Gltf.ContainsExtensionUsed(emissiveStrengthExtName)) + { + var reg = context.Container.JsonSchemas; + if (gltfMat.TryGetExtension(emissiveStrengthExtName, reg, out var gltfEmissiveStrength)) + { + emissionColorLinear *= gltfEmissiveStrength.EmissiveStrength; + } + } + + mat.SetColor("_EmissionColor", ValueConv.ColorFromLinear(emissionColorLinear)); } if (gltfMat.EmissiveTexture != null) @@ -299,6 +313,15 @@ public static async Task Import( } else { + var key = new NormalTexKey // TODO: support multi-set + { + Index = index, + }; + if (context.Resources.AuxResources.TryGetValue(key, out var auxRes)) + { + return (auxRes as Utils.DestroyOnDispose).Value; + } + var src = await context.Importers.Textures.RawImport(index, true, ct); using (var srcRes = new Utils.DestroyOnDispose(src)) { @@ -310,10 +333,7 @@ public static async Task Import( context.ImportingSetting.TextureUpdateMipmaps, context.ImportingSetting.TextureMakeNoLongerReadable, compressHighQual); - context.Resources.AuxResources.Add(new NormalTexKey // TODO: support multi-set - { - Index = index, - }, new Utils.DestroyOnDispose(texture)); + context.Resources.AuxResources.Add(key, new Utils.DestroyOnDispose(texture)); await context.TimeSlicer.Slice(ct); @@ -375,6 +395,15 @@ public static async Task Import( return res.Value; } + var key = new OcclusionTexKey // TODO: support multi-set + { + Index = index, + }; + if (context.Resources.AuxResources.TryGetValue(key, out var auxRes)) + { + return (auxRes as Utils.DestroyOnDispose).Value; + } + var src = await context.Importers.Textures.RawImport(index, false, ct); using (var srcRes = new Utils.DestroyOnDispose(src)) { @@ -386,10 +415,7 @@ public static async Task Import( context.ImportingSetting.TextureUpdateMipmaps, context.ImportingSetting.TextureMakeNoLongerReadable, compressHighQual); - context.Resources.AuxResources.Add(new OcclusionTexKey // TODO: support multi-set - { - Index = index, - }, new Utils.DestroyOnDispose(texture)); + context.Resources.AuxResources.Add(key, new Utils.DestroyOnDispose(texture)); await context.TimeSlicer.Slice(ct); @@ -457,6 +483,15 @@ public static async Task Import( return res.Value; } + var key = new MetallicRoughnessTexKey // TODO: support multi-set + { + Index = index, + }; + if (context.Resources.AuxResources.TryGetValue(key, out var auxRes)) + { + return (auxRes as Utils.DestroyOnDispose).Value; + } + var src = await context.Importers.Textures.RawImport(index, true, ct); using (var srcRes = new Utils.DestroyOnDispose(src)) { @@ -470,10 +505,7 @@ public static async Task Import( context.ImportingSetting.TextureUpdateMipmaps, context.ImportingSetting.TextureMakeNoLongerReadable, compressHighQual); - context.Resources.AuxResources.Add(new MetallicRoughnessTexKey // TODO: support multi-set - { - Index = index, - }, new Utils.DestroyOnDispose(texture)); + context.Resources.AuxResources.Add(key, new Utils.DestroyOnDispose(texture)); await context.TimeSlicer.Slice(ct); diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/MeshExporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/MeshExporter.cs index 4689c5c..00ec832 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/MeshExporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/MeshExporter.cs @@ -27,9 +27,10 @@ public MeshExporter(IExporterContext context) public IndexedResource Export(Renderer r, Mesh mesh) { - return Context.Resources.Meshes.GetOrCall(mesh, () => + var materials = r.sharedMaterials; + return Context.Resources.Meshes.GetOrCall((mesh, materials), () => { - return ForceExport(r, mesh); + return ForceExport(mesh, materials); }); } @@ -44,15 +45,18 @@ class Target public float Weight; } - public IndexedResource ForceExport(Renderer r, Mesh mesh) + public IndexedResource ForceExport(Mesh mesh, Material[] materials) { var materialIndices = new List(); - foreach (var m in r.sharedMaterials) + foreach (var m in materials) { var materialResource = Context.Exporters.Materials.Export(m); materialIndices.Add(materialResource.Index); } + // TODO: share things other than materials if only materials differ. + // (cache mesh and AccIndices, then use the AccIndices when export same mesh) + // Convert to right-handed coordinate system var positionAccIndex = ExportPositions(mesh.vertices); @@ -239,7 +243,7 @@ public IndexedResource ForceExport(Renderer r, Mesh mesh) } var meshIndex = Context.Gltf.AddMesh(gltfMesh); - var resource = Context.Resources.Meshes.Add(mesh, meshIndex, mesh.name, mesh); + var resource = Context.Resources.Meshes.Add((mesh, materials), meshIndex, mesh.name, mesh); return resource; } @@ -348,7 +352,10 @@ int ExportPositionsBuffer(ref Vector3[] vec3, out Types.Accessor.ComponentTypeEn // VEC3! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(vec3); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); componentType = Types.Accessor.ComponentTypeEnum.FLOAT; @@ -361,7 +368,10 @@ int ExportNormals(Vector3[] vec3) // VEC3! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(vec3); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { @@ -380,7 +390,10 @@ int ExportTangents(Vector4[] vec4) // VEC4! | FLOAT! byte[] buffer = PrimitiveExporter.Marshal(vec4); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { @@ -401,7 +414,10 @@ int ExportUV(Vector2[] uv) // | UNSIGNED_BYTE (normalized) // | UNSIGNED_SHORT (normalized) byte[] buffer = PrimitiveExporter.Marshal(uv); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { @@ -420,7 +436,10 @@ int ExportColors(Color[] colors) // VEC4! | UNSIGNED_BYTE (normalized) // | UNSIGNED_SHORT (normalized) byte[] buffer = PrimitiveExporter.Marshal(colors); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { @@ -442,7 +461,10 @@ int ExportJoints(Vec4[] joints) .Select(v => new Vec4((ushort)v.x, (ushort)v.y, (ushort)v.z, (ushort)v.w)) .ToArray() ); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { @@ -461,7 +483,10 @@ int ExportWeights(Vector4[] weights) // | UNSIGNED_BYTE (normalized) // | UNSIGNED_SHORT (normalized) byte[] buffer = PrimitiveExporter.Marshal(weights); - var viewIndex = Context.BufferBuilder.AddView(new ArraySegment(buffer)); + var viewIndex = Context.BufferBuilder.AddView( + new ArraySegment(buffer), + null, + Types.BufferView.TargetEnum.ARRAY_BUFFER); var accessor = new Types.Accessor { diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/MeshImporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/MeshImporter.cs index 9aa575d..feb78b6 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/MeshImporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/MeshImporter.cs @@ -119,6 +119,8 @@ public IndexedResource ForceImport(int meshIndex) var prims = primsRaw.Select((p, i) => ImportPrimitive(gltfMesh, p, i == 0)); + // TODO: share mesh if all properties are same (can occur when same mesh is used with different materials) + var mesh = new Mesh(); mesh.name = gltfMesh.Name; diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs new file mode 100644 index 0000000..1117b88 --- /dev/null +++ b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs @@ -0,0 +1,77 @@ +// +// Copyright (c) 2019- yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using UnityEngine; +using VGltf.Types; + +namespace VGltf.Unity +{ + // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#samplers + public sealed class SamplerApplier + { + IImporterContext Context { get; } + + public SamplerApplier(IImporterContext context) + { + Context = context; + } + + public void ApplySampler(int? samplerIndex, Texture2D tex) + { + var gltf = Context.Container.Gltf; + + if (samplerIndex.HasValue) + { + var sampler = gltf.Samplers[samplerIndex.Value]; + // UnityEngine.Texture2D has single filterMode, so either one of filters can be used. + tex.filterMode = sampler.MinFilter.HasValue ? AsFilterMode(sampler.MinFilter.Value) : FilterMode.Bilinear; + tex.wrapModeU = AsWrapMode(sampler.WrapS); + tex.wrapModeV = AsWrapMode(sampler.WrapT); + } + else + { + // When texture.sampler is undefined, a sampler with repeat wrapping (in both directions) and auto filtering MUST be used. + tex.filterMode = FilterMode.Bilinear; + tex.wrapMode = TextureWrapMode.Repeat; + } + } + + static FilterMode AsFilterMode(Sampler.MinFilterEnum minFilterEnum) + { + switch (minFilterEnum) + { + case Sampler.MinFilterEnum.NEAREST: + case Sampler.MinFilterEnum.NEAREST_MIPMAP_LINEAR: + case Sampler.MinFilterEnum.NEAREST_MIPMAP_NEAREST: + return FilterMode.Point; + case Sampler.MinFilterEnum.LINEAR: + case Sampler.MinFilterEnum.LINEAR_MIPMAP_NEAREST: + return FilterMode.Bilinear; + case Sampler.MinFilterEnum.LINEAR_MIPMAP_LINEAR: + return FilterMode.Trilinear; + default: + throw new NotImplementedException(); + } + } + + static TextureWrapMode AsWrapMode(Sampler.WrapEnum wrapEnum) + { + switch (wrapEnum) + { + case Sampler.WrapEnum.ClampToEdge: + return TextureWrapMode.Clamp; + case Sampler.WrapEnum.Repeat: + return TextureWrapMode.Repeat; + case Sampler.WrapEnum.MirroredRepeat: + return TextureWrapMode.Mirror; + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs.meta b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs.meta new file mode 100644 index 0000000..4e4bb6f --- /dev/null +++ b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerApplier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 57b69a3f33bc4bd99d12fb83942fcd10 +timeCreated: 1661075659 \ No newline at end of file diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs new file mode 100644 index 0000000..e94a334 --- /dev/null +++ b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs @@ -0,0 +1,83 @@ +// +// Copyright (c) 2019- yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using UnityEngine; +using VGltf.Types; +using VGltf.Types.Extensions; +using Texture = UnityEngine.Texture; + +namespace VGltf.Unity +{ + public class SamplerExporter + { + IExporterContext Context { get; } + + public SamplerExporter(IExporterContext context) + { + Context = context; + } + + public int RawExport(Texture tex) + { + var gltfSampler = new Sampler + { + MagFilter = AsMagFilterEnum(tex.filterMode), + MinFilter = AsMinFilterEnum(tex.filterMode), + WrapS = AsWrapEnum(tex.wrapModeU), + WrapT = AsWrapEnum(tex.wrapModeV), + }; + + return Context.Gltf.AddSampler(gltfSampler); + } + + static Sampler.MagFilterEnum AsMagFilterEnum(FilterMode filterMode) + { + switch (filterMode) + { + case FilterMode.Point: + return Sampler.MagFilterEnum.NEAREST; + case FilterMode.Bilinear: + case FilterMode.Trilinear: + return Sampler.MagFilterEnum.LINEAR; + default: + throw new NotImplementedException(); + } + } + + static Sampler.MinFilterEnum AsMinFilterEnum(FilterMode filterMode) + { + switch (filterMode) + { + case FilterMode.Point: + return Sampler.MinFilterEnum.NEAREST; + case FilterMode.Bilinear: + return Sampler.MinFilterEnum.LINEAR; + case FilterMode.Trilinear: + return Sampler.MinFilterEnum.LINEAR_MIPMAP_LINEAR; + default: + throw new NotImplementedException(); + } + } + + static Sampler.WrapEnum AsWrapEnum(TextureWrapMode wrapMode) + { + switch (wrapMode) + { + case TextureWrapMode.Clamp: + return Sampler.WrapEnum.ClampToEdge; + case TextureWrapMode.Repeat: + return Sampler.WrapEnum.Repeat; + case TextureWrapMode.Mirror: + case TextureWrapMode.MirrorOnce: + return Sampler.WrapEnum.MirroredRepeat; + default: + throw new NotImplementedException(); + } + } + } +} diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs.meta b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs.meta new file mode 100644 index 0000000..1ecf3dd --- /dev/null +++ b/Packages/net.yutopp.vgltf.unity/Runtime/SamplerExporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 93c9c21d3c4743a687d5ee13b1554457 +timeCreated: 1661072198 \ No newline at end of file diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/TextureExporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/TextureExporter.cs index 82f0d46..b4106ac 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/TextureExporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/TextureExporter.cs @@ -37,12 +37,13 @@ public int RawExport( ) { var imageIndex = Context.Exporters.Images.RawExport(tex, isLinear, mat); + var samplerIndex = Context.SamplerExporter.RawExport(tex); var gltfImage = new Types.Texture { Name = tex.name, - //Sampler = primitives, + Sampler = samplerIndex, Source = imageIndex, }; var texIndex = Context.Gltf.AddTexture(gltfImage); diff --git a/Packages/net.yutopp.vgltf.unity/Runtime/TextureImporter.cs b/Packages/net.yutopp.vgltf.unity/Runtime/TextureImporter.cs index 306f341..cf9d7de 100644 --- a/Packages/net.yutopp.vgltf.unity/Runtime/TextureImporter.cs +++ b/Packages/net.yutopp.vgltf.unity/Runtime/TextureImporter.cs @@ -62,8 +62,7 @@ public async Task RawImport(int texIndex, bool isLinear, Cancellation tex.name = gltfTex.Name; } - // When texture.sampler is undefined, a sampler with repeat wrapping (in both directions) and auto filtering MUST be used. - // NOTE: Not implemented currently + Context.SamplerApplier.ApplySampler(gltfTex.Sampler, tex); return tex; } diff --git a/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs b/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs new file mode 100644 index 0000000..800ae17 --- /dev/null +++ b/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022 - yutopp (yutopp@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) +// + +using VJson; +using VJson.Schema; + +namespace VGltf.Ext.KhrMaterialsEmissiveStrength.Types +{ + // https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_emissive_strength/schema/glTF.KHR_materials_emissive_strength.schema.json + [JsonSchema(Title = "KHR_materials_emissive_strength glTF extension", + Description = "glTF extension that adjusts the strength of emissive material properties.", + Id = "glTF.KHR_materials_emissive_strength.schema.json")] + public sealed class KhrMaterialsEmissiveStrength + { + public static readonly string ExtensionName = "KHR_materials_emissive_strength"; + + [JsonField(Name = "emissiveStrength"), JsonFieldIgnorable(WhenValueIs = 1.0f)] + [JsonSchema(Minimum = 0.0f)] + public float EmissiveStrength = 1.0f; + } +} diff --git a/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs.meta b/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs.meta new file mode 100644 index 0000000..d48af77 --- /dev/null +++ b/Packages/net.yutopp.vgltf/Runtime/Ext/KhrMaterialsUnlit/Types/KhrMaterialsEmissiveStrength.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 319ac78c55927485eb3a2c155fd8b174 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index e8c6ca3..3483690 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -14,15 +14,31 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.ide.visualstudio": { + "version": "2.0.15", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, "com.unity.ide.vscode": { - "version": "1.2.3", + "version": "1.2.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.postprocessing": { + "version": "2.3.0", "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.test-framework": { - "version": "1.1.22", + "version": "1.1.31", "depth": 0, "source": "registry", "dependencies": { @@ -66,7 +82,7 @@ "dependencies": {} }, "net.yutopp.vjson": { - "version": "0.9.10", + "version": "0.9.12", "depth": 0, "source": "registry", "dependencies": {}, diff --git a/README.md b/README.md index c17b384..b9b7ae6 100644 --- a/README.md +++ b/README.md @@ -7,34 +7,86 @@ [![gltf-2.0](https://camo.githubusercontent.com/4a2bc1263a5da1ed3190e23186521ffd9a2d51b0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f676c54462d32253245302d677265656e2e7376673f7374796c653d666c6174)](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0) ![unity](https://img.shields.io/badge/unity-2019.4%2B-blue.svg) -![layer](/docs/layer.png) +VGltf is a library that simplifies the import and export of glTF 2.0 assets in your C# standard and Unity projects. -> `VGltf` is a library importing/exporting `glTF 2.0` assets aiming for **extensibility**, **readability**, and **stability**. +

VGltf package structure

-Supported .NET versions are `.NET Standard 2.0` or higher. +## Key Features -The following glTF extensions are also supported as independent libraries. +- **Broad compatibility**: Designed for **both** `C# standard projects` and `Unity`, ensuring seamless integration. +- **Extensibility**: Easily extendable to accommodate custom glTF extensions with `hooks`. + - For example, [VRM 0.x](https://github.com/vrm-c/vrm-specification) is [supported](/Packages/net.yutopp.vgltf.ext.vrm0) without modifying the core library. +- **Readability**: Clean and comprehensible codebase for quick learning and adaptation. +- **Stability**: Focused on reliability and performance across various projects. +- **Flexible support**: Compatible with `.NET Standard 2.0` or `higher` and tested on many platforms. -- [VRM 0.x](https://github.com/vrm-c/vrm-specification) +### Unity Compatibility -## Description for Unity users +VGltf is compatible with `Unity 2019.4` or `higher` and supports the following: -Supported Unity versions are `Unity 2019.4` or higher. +- ⭕ Run-time import +- ⭕ Run-time export +- 🔺 Design-time (Unity Editor) import + - Integration with AssetDatabase is not supported +- ⭕ Design-time (Unity Editor) export -As for importing and exporting resources, you can use it in the following situations. +Tested platforms include: -- [x] Runtime import -- [x] Runtime export -- [ ] Editor import -- [x] Editor export +- Windows [Mono, IL2CPP] +- Linux [Mono, IL2CPP] +- MacOS [Intel and ARM] x [Mono, IL2CPP] +- iOS +- Android +- WebGL ([Sample project](https://github.com/yutopp/webgl-vgltf-sample) for `WebGL` with `Unity 2022.1`) -We have checked that it works with IL2CPP builds on Windows, Linux, MacOS (Intel and ARM), iOS, and Android. +## Getting Started + +### Import glTF file + +The following code demonstrates how to import a glTF file and convert it into a Unity GameObject. +The input glTF data structure assumes multiple root nodes, which are combined into a single GameObject. + +```csharp +using UnityEngine; +using System.IO; +using VGltf.Unity; +using VGltf; + +var gltfContainer = default(GltfContainer); +using (var fs = new FileStream("Lantern.glb", FileMode.Open)) +{ + gltfContainer = GltfContainer.FromGlb(fs); +} + +var go = new GameObject(); + +var timeSlicer = new DefaultTimeSlicer(); +var context = default(IImporterContext); +using (var gltfImporter = new Importer(gltfContainer, timeSlicer)) +{ + context = await gltfImporter.ImportSceneNodes(go, System.Threading.CancellationToken.None); +} +``` + +Passing [Lantern.glb](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Lantern), you can get the following result. + +![Lantern](/docs/lantern.png) + +For a more practical example, see [Assets/Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs](./Assets/VGltfExamples/glTFExample/Scripts/GltfLoader.cs). + +As another topic, skinned meshes with Unity Mecanim is supported by default when using either the VRM 0.x extension or VGltf's [VGLTF_unity_avatar extension](/Packages/net.yutopp.vgltf.unity/Runtime/Extra/AvatarTypes.cs). + +![VroidAvatarSample_A](/docs/vroid-avatar-sample_a.gif) + +For more details, see [Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs](./Assets/VGltfExamples/VRMExample/Scripts/VRMLoader.cs). ## Installation ### For standard C# projects -You can use [Nuget/VGltf](https://www.nuget.org/packages/VGltf/). +#### Using NuGet + +Install [Nuget/VGltf](https://www.nuget.org/packages/VGltf/). ```bash dotnet add package VGltf @@ -42,24 +94,32 @@ dotnet add package VGltf ### For Unity projects -#### By using git +VGltf depends on [VJson](https://github.com/yutopp/VJson), so please add it to the dependencies. -Add a url for VGltf git repository to your `Packages/manifest.json` like below. +#### Using Git + +Add the following VGltf Git repository URLs to your `Packages/manifest.json`: ```json { "dependencies": { "net.yutopp.vgltf": "https://github.com/yutopp/VGltf.git?path=Packages/net.yutopp.vgltf", - "net.yutopp.vgltf.unity": "https://github.com/yutopp/VGltf.git?path=Packages/net.yutopp.vgltf.unity" + "net.yutopp.vgltf.unity": "https://github.com/yutopp/VGltf.git?path=Packages/net.yutopp.vgltf.unity", + + "net.yutopp.vjson": "https://github.com/yutopp/VJson.git?path=Packages/net.yutopp.vjson#v0.9.12", + + // Optional + "net.yutopp.vgltf.ext.vrm0": "https://github.com/yutopp/VGltf.git?path=Packages/net.yutopp.vgltf.ext.vrm0", + "net.yutopp.vgltf.ext.vrm0.unity": "https://github.com/yutopp/VGltf.git?path=Packages/net.yutopp.vgltf.ext.vrm0.unity" } } ``` -**We recommend to use the [stable version](https://github.com/yutopp/VGltf/tags) by [specifying the tag](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-git.html#revision).** +**We recommend using the [stable version](https://github.com/yutopp/VGltf/tags) by [specifying the tag](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-git.html#revision).** -#### By using npm repository +#### Using npm repository -Add scoped registry information shown below to your `Packages/manifest.json` if not exists. +Add scoped registry information to your `Packages/manifest.json` if not exists: ```json { @@ -75,25 +135,23 @@ Add scoped registry information shown below to your `Packages/manifest.json` if } ``` -And add `net.yutopp.vgltf.*` to your `Packages/manifest.json` like below. +Then, add `net.yutopp.vgltf.*` to your `Packages/manifest.json`: ```json { "dependencies": { - "net.yutopp.vgltf": "*", - "net.yutopp.vgltf.unity": "*" + "net.yutopp.vgltf": "v0.2.25", + "net.yutopp.vgltf.unity": "v0.2.25", + + "net.yutopp.vjson": "v0.9.12", + + // Optional + "net.yutopp.vgltf.ext.vrm0": "v0.2.25", + "net.yutopp.vgltf.ext.vrm0.unity": "v0.2.25" } } ``` -#### Dependencies - -- [yutopp/VJson](https://github.com/yutopp/VJson) - -## Usage examples - -See [Assets/VGltfExamples](./Assets/VGltfExamples). - ## TODO - [ ] Performance tuning diff --git a/docs/lantern.png b/docs/lantern.png new file mode 100644 index 0000000..2720981 Binary files /dev/null and b/docs/lantern.png differ diff --git a/docs/layer.png b/docs/layer.png index 001a907..aa38a99 100644 Binary files a/docs/layer.png and b/docs/layer.png differ diff --git a/docs/vroid-avatar-sample_a.gif b/docs/vroid-avatar-sample_a.gif new file mode 100644 index 0000000..1f70b46 Binary files /dev/null and b/docs/vroid-avatar-sample_a.gif differ