UniVRM/Assets/VRM10/Runtime/IO/Material/Vrm10MToonMaterialImporter.cs
0b5vr 21eaa5307e fix (VRM1.0, MToon): Fix color space of emissiveFactor (2)
conversion should not be done throughout the entire UniVRM procedure
2021-10-29 13:46:37 +09:00

292 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF;
using UniGLTF.Extensions.VRMC_materials_mtoon;
using UnityEngine;
using VRMShaders;
using VRMShaders.VRM10.MToon10.Runtime;
using ColorSpace = VRMShaders.ColorSpace;
using OutlineWidthMode = UniGLTF.Extensions.VRMC_materials_mtoon.OutlineWidthMode;
namespace UniVRM10
{
/// <summary>
/// Convert MToon parameters from glTF specification to Unity implementation.
/// </summary>
public static class Vrm10MToonMaterialImporter
{
/// <summary>
/// VMRC_materials_mtoon の場合にマテリアル生成情報を作成する
/// </summary>
public static bool TryCreateParam(GltfData data, int i, out MaterialDescriptor matDesc)
{
var m = data.GLTF.materials[i];
if (!UniGLTF.Extensions.VRMC_materials_mtoon.GltfDeserializer.TryGet(m.extensions,
out UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon mtoon))
{
// Fallback to glTF, when MToon extension does not exist.
matDesc = default;
return false;
}
// use material.name, because material name may renamed in GltfParser.
matDesc = new MaterialDescriptor(
m.name,
MToon10Meta.UnityShaderName,
null,
Vrm10MToonTextureImporter.EnumerateAllTextures(data, m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.Item2.Item2),
TryGetAllFloats(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),
TryGetAllColors(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),
TryGetAllFloatArrays(m, mtoon).ToDictionary(tuple => tuple.key, tuple => tuple.value),
new Action<Material>[]
{
material =>
{
// Set hidden properties, keywords from float properties.
new MToonValidator(material).Validate();
}
});
return true;
}
public static IEnumerable<(string key, Color value)> TryGetAllColors(glTFMaterial material, VRMC_materials_mtoon mToon)
{
const ColorSpace gltfColorSpace = ColorSpace.Linear;
// Rendering
var baseColor = material?.pbrMetallicRoughness?.baseColorFactor?.ToColor4(gltfColorSpace, ColorSpace.sRGB);
if (baseColor.HasValue)
{
yield return (MToon10Prop.BaseColorFactor.ToUnityShaderLabName(), baseColor.Value);
}
// Lighting
var shadeColor = mToon?.ShadeColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB);
if (shadeColor.HasValue)
{
yield return (MToon10Prop.ShadeColorFactor.ToUnityShaderLabName(), shadeColor.Value);
}
// GI
// Emission
// Emissive factor should be stored in Linear space
var emissionColor = material?.emissiveFactor?.ToColor3(gltfColorSpace, ColorSpace.Linear);
if (emissionColor.HasValue)
{
yield return (MToon10Prop.EmissiveFactor.ToUnityShaderLabName(), emissionColor.Value);
}
// Rim Lighting
var rimColor = mToon?.ParametricRimColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB);
if (rimColor.HasValue)
{
yield return (MToon10Prop.ParametricRimColorFactor.ToUnityShaderLabName(), rimColor.Value);
}
// Outline
var outlineColor = mToon?.OutlineColorFactor?.ToColor3(gltfColorSpace, ColorSpace.sRGB);
if (outlineColor.HasValue)
{
yield return (MToon10Prop.OutlineColorFactor.ToUnityShaderLabName(), outlineColor.Value);
}
// UV Animation
}
public static IEnumerable<(string key, float value)> TryGetAllFloats(glTFMaterial material, VRMC_materials_mtoon mToon)
{
// Rendering
var alphaMode = GetMToon10AlphaMode(material);
{
yield return (MToon10Prop.AlphaMode.ToUnityShaderLabName(), (float)alphaMode);
}
var transparentWithZWrite = GetMToon10TransparentWithZWriteMode(material, mToon);
{
yield return (MToon10Prop.TransparentWithZWrite.ToUnityShaderLabName(), (float)transparentWithZWrite);
}
var cutoff = material?.alphaCutoff;
if (cutoff.HasValue)
{
yield return (MToon10Prop.AlphaCutoff.ToUnityShaderLabName(), cutoff.Value);
}
var renderQueueOffset = mToon?.RenderQueueOffsetNumber;
if (renderQueueOffset.HasValue)
{
yield return (MToon10Prop.RenderQueueOffsetNumber.ToUnityShaderLabName(), (float)renderQueueOffset);
}
var doubleSidedMode = GetMToon10DoubleSidedMode(material, mToon);
{
yield return (MToon10Prop.DoubleSided.ToUnityShaderLabName(), (float)doubleSidedMode);
}
// Lighting
var normalScale = material?.normalTexture?.scale;
if (normalScale.HasValue)
{
yield return (MToon10Prop.NormalTextureScale.ToUnityShaderLabName(), normalScale.Value);
}
var shadingShift = mToon?.ShadingShiftFactor;
if (shadingShift.HasValue)
{
yield return (MToon10Prop.ShadingShiftFactor.ToUnityShaderLabName(), shadingShift.Value);
}
var shadingShiftTextureScale = mToon?.ShadingShiftTexture?.Scale;
if (shadingShiftTextureScale.HasValue)
{
yield return (MToon10Prop.ShadingShiftTextureScale.ToUnityShaderLabName(), shadingShiftTextureScale.Value);
}
var shadingToony = mToon?.ShadingToonyFactor;
if (shadingToony.HasValue)
{
yield return (MToon10Prop.ShadingToonyFactor.ToUnityShaderLabName(), shadingToony.Value);
}
// GI
var giEqualization = mToon?.GiEqualizationFactor;
if (giEqualization.HasValue)
{
yield return (MToon10Prop.GiEqualizationFactor.ToUnityShaderLabName(), giEqualization.Value);
}
// Emission
// Rim Lighting
var rimFresnelPower = mToon?.ParametricRimFresnelPowerFactor;
if (rimFresnelPower.HasValue)
{
yield return (MToon10Prop.ParametricRimFresnelPowerFactor.ToUnityShaderLabName(), rimFresnelPower.Value);
}
var rimLift = mToon?.ParametricRimLiftFactor;
if (rimLift.HasValue)
{
yield return (MToon10Prop.ParametricRimLiftFactor.ToUnityShaderLabName(), rimLift.Value);
}
var rimLightMix = mToon?.RimLightingMixFactor;
if (rimLightMix.HasValue)
{
yield return (MToon10Prop.RimLightingMixFactor.ToUnityShaderLabName(), rimLightMix.Value);
}
// Outline
var outlineMode = GetMToon10OutlineWidthMode(material, mToon);
{
yield return (MToon10Prop.OutlineWidthMode.ToUnityShaderLabName(), (float)outlineMode);
}
var outlineWidth = mToon?.OutlineWidthFactor;
if (outlineWidth.HasValue)
{
yield return (MToon10Prop.OutlineWidthFactor.ToUnityShaderLabName(), outlineWidth.Value);
}
var outlineLightMix = mToon?.OutlineLightingMixFactor;
if (outlineLightMix.HasValue)
{
yield return (MToon10Prop.OutlineLightingMixFactor.ToUnityShaderLabName(), outlineLightMix.Value);
}
// UV Animation
var uvAnimSpeedScrollX = mToon?.UvAnimationScrollXSpeedFactor;
if (uvAnimSpeedScrollX.HasValue)
{
yield return (MToon10Prop.UvAnimationScrollXSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedScrollX.Value);
}
var uvAnimSpeedScrollY = mToon?.UvAnimationScrollYSpeedFactor;
if (uvAnimSpeedScrollY.HasValue)
{
// UV coords conversion.
// glTF (top-left origin) to Unity (bottom-left origin)
const float invertY = -1f;
yield return (MToon10Prop.UvAnimationScrollYSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedScrollY.Value * invertY);
}
var uvAnimSpeedRotation = mToon?.UvAnimationRotationSpeedFactor;
if (uvAnimSpeedRotation.HasValue)
{
yield return (MToon10Prop.UvAnimationRotationSpeedFactor.ToUnityShaderLabName(), uvAnimSpeedRotation.Value);
}
// UI
if (true /* TODO: mToon.IsAdvancedMode */)
{
yield return (MToon10Prop.EditorEditMode.ToUnityShaderLabName(), 1);
}
}
public static IEnumerable<(string key, Vector4 value)> TryGetAllFloatArrays(glTFMaterial material, VRMC_materials_mtoon mToon)
{
yield break;
}
private static MToon10AlphaMode GetMToon10AlphaMode(glTFMaterial material)
{
switch (material?.alphaMode)
{
case "OPAQUE":
return MToon10AlphaMode.Opaque;
case "MASK":
return MToon10AlphaMode.Cutout;
case "BLEND":
return MToon10AlphaMode.Transparent;
default:
Debug.LogWarning($"Invalid AlphaMode");
return MToon10AlphaMode.Opaque;
}
}
private static MToon10TransparentWithZWriteMode GetMToon10TransparentWithZWriteMode(glTFMaterial material, VRMC_materials_mtoon mtoon)
{
if (mtoon?.TransparentWithZWrite == true)
{
return MToon10TransparentWithZWriteMode.On;
}
else
{
return MToon10TransparentWithZWriteMode.Off;
}
}
private static MToon10DoubleSidedMode GetMToon10DoubleSidedMode(glTFMaterial material, VRMC_materials_mtoon mToon)
{
if (material?.doubleSided == true)
{
return MToon10DoubleSidedMode.On;
}
else
{
return MToon10DoubleSidedMode.Off;
}
}
private static MToon10OutlineMode GetMToon10OutlineWidthMode(glTFMaterial material, VRMC_materials_mtoon mToon)
{
switch (mToon?.OutlineWidthMode)
{
case OutlineWidthMode.none:
return MToon10OutlineMode.None;
case OutlineWidthMode.worldCoordinates:
return MToon10OutlineMode.World;
case OutlineWidthMode.screenCoordinates:
return MToon10OutlineMode.Screen;
default:
// Invalid
Debug.LogWarning("Invalid outlineWidthMode");
return MToon10OutlineMode.None;
}
}
}
}