Merge pull request #1177 from ousttrue/feature/URP_material_importer

Add MaterialGenerator customization point (for URP)
This commit is contained in:
ousttrue
2021-08-31 21:47:38 +09:00
committed by GitHub
21 changed files with 407 additions and 17 deletions

View File

@@ -12,7 +12,7 @@ namespace UniGLTF
{
public override void OnImportAsset(AssetImportContext ctx)
{
Import(this, ctx, m_reverseAxis.ToAxes());
Import(this, ctx, m_reverseAxis.ToAxes(), m_renderPipeline);
}
}
}

View File

@@ -12,7 +12,7 @@ namespace UniGLTF
{
public override void OnImportAsset(AssetImportContext ctx)
{
Import(this, ctx, m_reverseAxis.ToAxes());
Import(this, ctx, m_reverseAxis.ToAxes(), m_renderPipeline);
}
}
}

View File

@@ -1,5 +1,4 @@
using UnityEngine;
using UnityEditor;
using System.Linq;
using VRMShaders;
#if UNITY_2020_2_OR_NEWER
@@ -19,13 +18,32 @@ namespace UniGLTF
[SerializeField]
public ScriptedImporterAxes m_reverseAxis = default;
[SerializeField]
[Header("Experimental")]
public RenderPipelineTypes m_renderPipeline;
static IMaterialDescriptorGenerator GetMaterialGenerator(RenderPipelineTypes renderPipeline)
{
switch (renderPipeline)
{
case RenderPipelineTypes.BuiltinRenderPipeline:
return new GltfUrpMaterialDescriptorGenerator();
case RenderPipelineTypes.UniversalRenderPipeline:
return new GltfMaterialDescriptorGenerator();
default:
throw new System.NotImplementedException();
}
}
/// <summary>
/// glb をパースして、UnityObject化、さらにAsset化する
/// </summary>
/// <param name="scriptedImporter"></param>
/// <param name="context"></param>
/// <param name="reverseAxis"></param>
protected static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axes reverseAxis)
protected static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, Axes reverseAxis, RenderPipelineTypes renderPipeline)
{
#if VRM_DEVELOP
Debug.Log("OnImportAsset to " + scriptedImporter.assetPath);
@@ -46,7 +64,9 @@ namespace UniGLTF
.Where(x => x.Value != null)
.ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value);
using (var loader = new ImporterContext(data, extractedObjects))
IMaterialDescriptorGenerator materialGenerator = GetMaterialGenerator(renderPipeline);
using (var loader = new ImporterContext(data, extractedObjects, materialGenerator: materialGenerator))
{
// Configure TextureImporter to Extracted Textures.
foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable())

View File

@@ -14,7 +14,7 @@ namespace UniGLTF
{
public override void OnImportAsset(AssetImportContext ctx)
{
Import(this, ctx, m_reverseAxis.ToAxes());
Import(this, ctx, m_reverseAxis.ToAxes(), m_renderPipeline);
}
}
}

View File

@@ -22,11 +22,12 @@ namespace UniGLTF
public ImporterContext(
GltfData data,
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
ITextureDeserializer textureDeserializer = null,
IMaterialDescriptorGenerator materialGenerator = null)
{
Data = data;
TextureDescriptorGenerator = new GltfTextureDescriptorGenerator(Data);
MaterialDescriptorGenerator = new GltfMaterialDescriptorGenerator();
MaterialDescriptorGenerator = materialGenerator ?? new GltfMaterialDescriptorGenerator();
ExternalObjectMap = externalObjectMap ?? new Dictionary<SubAssetKey, UnityEngine.Object>();
textureDeserializer = textureDeserializer ?? new UnityTextureDeserializer();

View File

@@ -0,0 +1,12 @@
namespace UniGLTF
{
/// <summary>
/// TODO: HDRP ?
/// TODO: UserCustom ?
/// </summary>
public enum RenderPipelineTypes
{
BuiltinRenderPipeline,
UniversalRenderPipeline,
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87bf5e0c19fe0584084fcddfd5294ad3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e25906189630c09469e8bdfcab01b754
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,169 @@
using UnityEngine;
using VRMShaders;
using ColorSpace = VRMShaders.ColorSpace;
namespace UniGLTF
{
/// <summary>
/// glTF PBR to URP Lit.
///
/// see: https://github.com/Unity-Technologies/Graphics/blob/v7.5.3/com.unity.render-pipelines.universal/Editor/UniversalRenderPipelineMaterialUpgrader.cs#L354-L379
/// </summary>
public static class GltfPbrUrpMaterialImporter
{
public const string ShaderName = "Universal Render Pipeline/Lit";
private enum BlendMode
{
Opaque,
Cutout,
Fade,
Transparent
}
public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc)
{
if (i < 0 || i >= data.GLTF.materials.Count)
{
matDesc = default;
return false;
}
var src = data.GLTF.materials[i];
matDesc = new MaterialDescriptor(GltfMaterialDescriptorGenerator.GetMaterialName(i, src), ShaderName);
var standardTexDesc = default(TextureDescriptor);
if (src.pbrMetallicRoughness != null || src.occlusionTexture != null)
{
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null || src.occlusionTexture != null)
{
SubAssetKey key;
(key, standardTexDesc) = GltfPbrTextureImporter.StandardTexture(data, src);
}
if (src.pbrMetallicRoughness.baseColorFactor != null && src.pbrMetallicRoughness.baseColorFactor.Length == 4)
{
// from _Color !
matDesc.Colors.Add("_BaseColor",
src.pbrMetallicRoughness.baseColorFactor.ToColor4(ColorSpace.Linear, ColorSpace.sRGB)
);
}
if (src.pbrMetallicRoughness.baseColorTexture != null && src.pbrMetallicRoughness.baseColorTexture.index != -1)
{
var (key, textureParam) = GltfPbrTextureImporter.BaseColorTexture(data, src);
// from _MainTex !
matDesc.TextureSlots.Add("_BaseMap", textureParam);
}
if (src.pbrMetallicRoughness.metallicRoughnessTexture != null && src.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
{
matDesc.Actions.Add(material => material.EnableKeyword("_METALLICGLOSSMAP"));
matDesc.TextureSlots.Add("_MetallicGlossMap", standardTexDesc);
// Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212.
matDesc.FloatValues.Add("_Metallic", 1.0f);
matDesc.FloatValues.Add("_GlossMapScale", 1.0f);
// default value is 0.5 !
matDesc.FloatValues.Add("_Smoothness", 1.0f);
}
else
{
matDesc.FloatValues.Add("_Metallic", src.pbrMetallicRoughness.metallicFactor);
// from _Glossiness !
matDesc.FloatValues.Add("_Smoothness", 1.0f - src.pbrMetallicRoughness.roughnessFactor);
}
}
if (src.normalTexture != null && src.normalTexture.index != -1)
{
matDesc.Actions.Add(material => material.EnableKeyword("_NORMALMAP"));
var (key, textureParam) = GltfPbrTextureImporter.NormalTexture(data, src);
matDesc.TextureSlots.Add("_BumpMap", textureParam);
matDesc.FloatValues.Add("_BumpScale", src.normalTexture.scale);
}
if (src.occlusionTexture != null && src.occlusionTexture.index != -1)
{
matDesc.TextureSlots.Add("_OcclusionMap", standardTexDesc);
matDesc.FloatValues.Add("_OcclusionStrength", src.occlusionTexture.strength);
}
if (src.emissiveFactor != null
|| (src.emissiveTexture != null && src.emissiveTexture.index != -1))
{
matDesc.Actions.Add(material =>
{
material.EnableKeyword("_EMISSION");
material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
});
if (src.emissiveFactor != null && src.emissiveFactor.Length == 3)
{
var emissiveFactor = src.emissiveFactor.ToColor3(ColorSpace.Linear, ColorSpace.Linear);
if (UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.GltfDeserializer.TryGet(src.extensions,
out UniGLTF.Extensions.VRMC_materials_hdr_emissiveMultiplier.VRMC_materials_hdr_emissiveMultiplier ex))
{
emissiveFactor *= ex.EmissiveMultiplier.Value;
}
matDesc.Colors.Add("_EmissionColor", emissiveFactor);
}
if (src.emissiveTexture != null && src.emissiveTexture.index != -1)
{
var (key, textureParam) = GltfPbrTextureImporter.EmissiveTexture(data, src);
matDesc.TextureSlots.Add("_EmissionMap", textureParam);
}
}
matDesc.Actions.Add(material =>
{
BlendMode blendMode = BlendMode.Opaque;
// https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
switch (src.alphaMode)
{
case "BLEND":
blendMode = BlendMode.Fade;
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 3000;
break;
case "MASK":
blendMode = BlendMode.Cutout;
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.SetFloat("_Cutoff", src.alphaCutoff);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = 2450;
break;
default: // OPAQUE
blendMode = BlendMode.Opaque;
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
break;
}
material.SetFloat("_Mode", (float)blendMode);
});
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08a0ae763ee70ed45809fad80ffe8e78
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using UnityEngine;
using VRMShaders;
namespace UniGLTF
{
/// <summary>
/// GLTF の MaterialImporter
/// </summary>
public sealed class GltfUrpMaterialDescriptorGenerator : IMaterialDescriptorGenerator
{
public MaterialDescriptor Get(GltfData data, int i)
{
if (!GltfUnlitMaterialImporter.TryCreateParam(data, i, out var param))
{
if (!GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out param))
{
// fallback
#if VRM_DEVELOP
Debug.LogWarning($"material: {i} out of range. fallback");
#endif
return new MaterialDescriptor(GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName);
}
}
return param;
}
public static string GetMaterialName(int index, glTFMaterial src)
{
if (src != null && !string.IsNullOrEmpty(src.name))
{
return src.name;
}
return $"material_{index:00}";
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ae66bf5ee5e1cb44b7dc416727d3bc1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -23,7 +23,8 @@ namespace VRM
public VRMImporterContext(
GltfData data,
IReadOnlyDictionary<SubAssetKey, Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
ITextureDeserializer textureDeserializer = null,
IMaterialDescriptorGenerator materialGenerator = null)
: base(data, externalObjectMap, textureDeserializer)
{
// parse VRM part
@@ -31,7 +32,7 @@ namespace VRM
{
VRM = vrm;
TextureDescriptorGenerator = new VrmTextureDescriptorGenerator(Data, VRM);
MaterialDescriptorGenerator = new VRMMaterialDescriptorGenerator(VRM);
MaterialDescriptorGenerator = materialGenerator ?? new VRMMaterialDescriptorGenerator(VRM);
}
else
{

View File

@@ -0,0 +1,34 @@
using UniGLTF;
using UnityEngine;
using VRMShaders;
namespace VRM
{
public sealed class VRMUrpMaterialDescriptorGenerator : IMaterialDescriptorGenerator
{
readonly glTF_VRM_extensions m_vrm;
public VRMUrpMaterialDescriptorGenerator(glTF_VRM_extensions vrm)
{
m_vrm = vrm;
}
public MaterialDescriptor Get(GltfData data, int i)
{
// mtoon URP "MToon" shader is not ready. import fallback to unlit
// unlit "UniUnlit" work in URP
if (!GltfUnlitMaterialImporter.TryCreateParam(data, i, out MaterialDescriptor matDesc))
{
// pbr "Standard" to "Universal Render Pipeline/Lit"
if (!GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out matDesc))
{
// fallback
#if VRM_DEVELOP
Debug.LogWarning($"material: {i} out of range. fallback");
#endif
return new MaterialDescriptor(GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName);
}
}
return matDesc;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e5aeab73a304ef644b0d20fac93bcfb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -14,9 +14,12 @@ namespace UniVRM10
[SerializeField]
public bool MigrateToVrm1 = default;
[SerializeField]
public UniGLTF.RenderPipelineTypes RenderPipeline = default;
public override void OnImportAsset(AssetImportContext ctx)
{
VrmScriptedImporterImpl.Import(this, ctx, MigrateToVrm1);
VrmScriptedImporterImpl.Import(this, ctx, MigrateToVrm1, RenderPipeline);
}
}
}

View File

@@ -102,6 +102,12 @@ namespace UniVRM10
{
case Vrm10FileType.Vrm1:
EditorGUILayout.HelpBox(m_result.Message, MessageType.Info);
{
serializedObject.Update();
EditorGUILayout.HelpBox("Experimental", MessageType.Warning);
EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(VrmScriptedImporter.RenderPipeline)));
serializedObject.ApplyModifiedProperties();
}
ApplyRevertGUI();
break;

View File

@@ -1,9 +1,7 @@
using System.Linq;
using UnityEngine;
using UniGLTF;
using System.IO;
using System;
using UniJSON;
using VRMShaders;
#if UNITY_2020_2_OR_NEWER
using UnityEditor.AssetImporters;
@@ -16,7 +14,22 @@ namespace UniVRM10
{
public static class VrmScriptedImporterImpl
{
public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool migrateToVrm1)
static IMaterialDescriptorGenerator GetMaterialDescriptorGenerator(RenderPipelineTypes renderPipeline)
{
switch (renderPipeline)
{
case RenderPipelineTypes.BuiltinRenderPipeline:
return new Vrm10MaterialDescriptorGenerator();
case RenderPipelineTypes.UniversalRenderPipeline:
return new Vrm10UrpMaterialDescriptorGenerator();
default:
throw new NotImplementedException();
}
}
public static void Import(ScriptedImporter scriptedImporter, AssetImportContext context, bool migrateToVrm1, RenderPipelineTypes renderPipeline)
{
#if VRM_DEVELOP
Debug.Log("OnImportAsset to " + scriptedImporter.assetPath);
@@ -35,7 +48,9 @@ namespace UniVRM10
.Where(kv => kv.Value != null)
.ToDictionary(kv => new SubAssetKey(kv.Value.GetType(), kv.Key.name), kv => kv.Value);
using (var loader = new Vrm10Importer(result.Data, result.Vrm, extractedObjects))
var materialGenerator = GetMaterialDescriptorGenerator(renderPipeline);
using (var loader = new Vrm10Importer(result.Data, result.Vrm, extractedObjects, materialGenerator: materialGenerator))
{
// settings TextureImporters
foreach (var textureInfo in loader.TextureDescriptorGenerator.Get().GetEnumerable())

View File

@@ -0,0 +1,26 @@
using UniGLTF;
using UnityEngine;
using VRMShaders;
namespace UniVRM10
{
public sealed class Vrm10UrpMaterialDescriptorGenerator : IMaterialDescriptorGenerator
{
public MaterialDescriptor Get(GltfData data, int i)
{
// unlit
if (!GltfUnlitMaterialImporter.TryCreateParam(data, i, out MaterialDescriptor matDesc))
{
// pbr
if (!GltfPbrUrpMaterialImporter.TryCreateParam(data, i, out matDesc))
{
// fallback
Debug.LogWarning($"material: {i} out of range. fallback");
return new MaterialDescriptor(GltfMaterialDescriptorGenerator.GetMaterialName(i, null), GltfPbrMaterialImporter.ShaderName);
}
}
return matDesc;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 377d1bd166d5452408fc7772554715ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -23,7 +23,8 @@ namespace UniVRM10
public Vrm10Importer(
UniGLTF.GltfData data, UniGLTF.Extensions.VRMC_vrm.VRMC_vrm vrm,
IReadOnlyDictionary<SubAssetKey, UnityEngine.Object> externalObjectMap = null,
ITextureDeserializer textureDeserializer = null)
ITextureDeserializer textureDeserializer = null,
IMaterialDescriptorGenerator materialGenerator = null)
: base(data, externalObjectMap, textureDeserializer)
{
if (data == null)
@@ -38,7 +39,7 @@ namespace UniVRM10
m_vrm = vrm;
TextureDescriptorGenerator = new Vrm10TextureDescriptorGenerator(data);
MaterialDescriptorGenerator = new Vrm10MaterialDescriptorGenerator();
MaterialDescriptorGenerator = materialGenerator ?? new Vrm10MaterialDescriptorGenerator();
m_externalMap = externalObjectMap;
if (m_externalMap == null)