mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-13 14:04:29 -05:00
245 lines
10 KiB
C#
245 lines
10 KiB
C#
using System;
|
|
using UniGLTF;
|
|
using UniGLTF.Extensions.VRMC_materials_mtoon;
|
|
using UnityEngine;
|
|
using VRMShaders;
|
|
using VRMShaders.VRM10.MToon10.Runtime;
|
|
using ColorSpace = VRMShaders.ColorSpace;
|
|
|
|
namespace UniVRM10
|
|
{
|
|
public static class Vrm10MToonMaterialExporter
|
|
{
|
|
const string MTOON_SPEC_VERSION = "1.0-beta";
|
|
|
|
public static bool TryExportMaterialAsMToon(Material src, ITextureExporter textureExporter, out glTFMaterial dst)
|
|
{
|
|
if (src.shader.name != MToon10Meta.UnityShaderName)
|
|
{
|
|
dst = null;
|
|
return false;
|
|
}
|
|
|
|
// Get MToon10 Context
|
|
var context = new MToon10Context(src);
|
|
context.Validate();
|
|
|
|
// base material
|
|
dst = glTF_KHR_materials_unlit.CreateDefault();
|
|
dst.name = src.name;
|
|
|
|
// vrmc_materials_mtoon ext
|
|
var mtoon = new UniGLTF.Extensions.VRMC_materials_mtoon.VRMC_materials_mtoon();
|
|
mtoon.SpecVersion = MTOON_SPEC_VERSION;
|
|
|
|
// Rendering
|
|
dst.alphaMode = ExportAlphaMode(context.AlphaMode);
|
|
mtoon.TransparentWithZWrite = context.TransparentWithZWriteMode == MToon10TransparentWithZWriteMode.On;
|
|
dst.alphaCutoff = Mathf.Max(0, context.AlphaCutoff);
|
|
mtoon.RenderQueueOffsetNumber = context.RenderQueueOffsetNumber;
|
|
dst.doubleSided = context.DoubleSidedMode == MToon10DoubleSidedMode.On;
|
|
|
|
// Lighting
|
|
dst.pbrMetallicRoughness = new glTFPbrMetallicRoughness();
|
|
dst.pbrMetallicRoughness.baseColorFactor = context.BaseColorFactorSrgb.ToFloat4(ColorSpace.sRGB, ColorSpace.Linear);
|
|
var baseColorTextureIndex = textureExporter.RegisterExportingAsSRgb(context.BaseColorTexture, context.AlphaMode != MToon10AlphaMode.Opaque);
|
|
if (baseColorTextureIndex != -1)
|
|
{
|
|
dst.pbrMetallicRoughness.baseColorTexture = new glTFMaterialBaseColorTextureInfo
|
|
{
|
|
index = baseColorTextureIndex,
|
|
};
|
|
}
|
|
mtoon.ShadeColorFactor = context.ShadeColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear);
|
|
var shadeColorTextureIndex = textureExporter.RegisterExportingAsSRgb(context.ShadeColorTexture, needsAlpha: false);
|
|
if (shadeColorTextureIndex != -1)
|
|
{
|
|
mtoon.ShadeMultiplyTexture = new TextureInfo
|
|
{
|
|
Index = shadeColorTextureIndex,
|
|
};
|
|
}
|
|
var normalTextureIndex = textureExporter.RegisterExportingAsNormal(context.NormalTexture);
|
|
if (normalTextureIndex != -1)
|
|
{
|
|
dst.normalTexture = new glTFMaterialNormalTextureInfo
|
|
{
|
|
index = normalTextureIndex,
|
|
scale = context.NormalTextureScale,
|
|
};
|
|
}
|
|
mtoon.ShadingShiftFactor = context.ShadingShiftFactor;
|
|
var shadingShiftTextureIndex = textureExporter.RegisterExportingAsLinear(context.ShadingShiftTexture, needsAlpha: false);
|
|
if (shadingShiftTextureIndex != -1)
|
|
{
|
|
mtoon.ShadingShiftTexture = new ShadingShiftTextureInfo
|
|
{
|
|
Index = shadingShiftTextureIndex,
|
|
Scale = context.ShadingShiftTextureScale,
|
|
};
|
|
}
|
|
mtoon.ShadingToonyFactor = context.ShadingToonyFactor;
|
|
|
|
// GI
|
|
mtoon.GiEqualizationFactor = context.GiEqualizationFactor;
|
|
|
|
// Emission
|
|
// Emissive factor is stored in Linear space
|
|
dst.emissiveFactor = context.EmissiveFactorLinear.ToFloat3(ColorSpace.Linear, ColorSpace.Linear);
|
|
var emissiveTextureIndex = textureExporter.RegisterExportingAsSRgb(context.EmissiveTexture, needsAlpha: false);
|
|
if (emissiveTextureIndex != -1)
|
|
{
|
|
dst.emissiveTexture = new glTFMaterialEmissiveTextureInfo
|
|
{
|
|
index = emissiveTextureIndex,
|
|
};
|
|
}
|
|
|
|
// Rim Lighting
|
|
var matcapTextureIndex = textureExporter.RegisterExportingAsSRgb(context.MatcapTexture, needsAlpha: false);
|
|
if (matcapTextureIndex != -1)
|
|
{
|
|
mtoon.MatcapTexture = new TextureInfo
|
|
{
|
|
Index = matcapTextureIndex,
|
|
};
|
|
}
|
|
mtoon.ParametricRimColorFactor = context.ParametricRimColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear);
|
|
mtoon.ParametricRimFresnelPowerFactor = context.ParametricRimFresnelPowerFactor;
|
|
mtoon.ParametricRimLiftFactor = context.ParametricRimLiftFactor;
|
|
var rimMultiplyTextureIndex = textureExporter.RegisterExportingAsSRgb(context.RimMultiplyTexture, needsAlpha: false);
|
|
if (rimMultiplyTextureIndex != -1)
|
|
{
|
|
mtoon.RimMultiplyTexture = new TextureInfo
|
|
{
|
|
Index = rimMultiplyTextureIndex,
|
|
};
|
|
}
|
|
mtoon.RimLightingMixFactor = context.RimLightingMixFactor;
|
|
|
|
// Outline
|
|
mtoon.OutlineWidthMode = ExportOutlineWidthMode(context.OutlineWidthMode);
|
|
mtoon.OutlineWidthFactor = context.OutlineWidthFactor;
|
|
var outlineWidthMultiplyTextureIndex = textureExporter.RegisterExportingAsLinear(context.OutlineWidthMultiplyTexture, needsAlpha: false);
|
|
if (outlineWidthMultiplyTextureIndex != -1)
|
|
{
|
|
mtoon.OutlineWidthMultiplyTexture = new TextureInfo
|
|
{
|
|
Index = outlineWidthMultiplyTextureIndex,
|
|
};
|
|
}
|
|
mtoon.OutlineColorFactor = context.OutlineColorFactorSrgb.ToFloat3(ColorSpace.sRGB, ColorSpace.Linear);
|
|
mtoon.OutlineLightingMixFactor = context.OutlineLightingMixFactor;
|
|
|
|
// UV Animation
|
|
var uvAnimationMaskTextureIndex = textureExporter.RegisterExportingAsLinear(context.UvAnimationMaskTexture, needsAlpha: false);
|
|
if (uvAnimationMaskTextureIndex != -1)
|
|
{
|
|
mtoon.UvAnimationMaskTexture = new TextureInfo
|
|
{
|
|
Index = uvAnimationMaskTextureIndex,
|
|
};
|
|
}
|
|
mtoon.UvAnimationScrollXSpeedFactor = context.UvAnimationScrollXSpeedFactor;
|
|
{
|
|
// Coordinate Conversion
|
|
const float invertY = -1f;
|
|
mtoon.UvAnimationScrollYSpeedFactor = context.UvAnimationScrollYSpeedFactor * invertY;
|
|
}
|
|
mtoon.UvAnimationRotationSpeedFactor = context.UvAnimationRotationSpeedFactor;
|
|
|
|
// Texture Transforms
|
|
var scale = context.TextureScale;
|
|
var offset = context.TextureOffset;
|
|
ExportTextureTransform(dst.pbrMetallicRoughness.baseColorTexture, scale, offset);
|
|
ExportTextureTransform(dst.emissiveTexture, scale, offset);
|
|
ExportTextureTransform(dst.normalTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.ShadeMultiplyTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.ShadingShiftTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.MatcapTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.RimMultiplyTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.OutlineWidthMultiplyTexture, scale, offset);
|
|
ExportTextureTransform(mtoon.UvAnimationMaskTexture, scale, offset);
|
|
|
|
UniGLTF.Extensions.VRMC_materials_mtoon.GltfSerializer.SerializeTo(ref dst.extensions, mtoon);
|
|
|
|
return true;
|
|
}
|
|
|
|
private static string ExportAlphaMode(MToon10AlphaMode alphaMode)
|
|
{
|
|
switch (alphaMode)
|
|
{
|
|
case MToon10AlphaMode.Opaque:
|
|
return "OPAQUE";
|
|
case MToon10AlphaMode.Cutout:
|
|
return "MASK";
|
|
case MToon10AlphaMode.Transparent:
|
|
return "BLEND";
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(alphaMode), alphaMode, null);
|
|
}
|
|
}
|
|
|
|
private static OutlineWidthMode ExportOutlineWidthMode(MToon10OutlineMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case MToon10OutlineMode.None:
|
|
return OutlineWidthMode.none;
|
|
case MToon10OutlineMode.World:
|
|
return OutlineWidthMode.worldCoordinates;
|
|
case MToon10OutlineMode.Screen:
|
|
return OutlineWidthMode.screenCoordinates;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
|
|
}
|
|
}
|
|
|
|
public static void ExportTextureTransform(glTFTextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset)
|
|
{
|
|
if (textureInfo == null)
|
|
{
|
|
return;
|
|
}
|
|
var scale = unityScale;
|
|
var offset = new Vector2(unityOffset.x, 1.0f - unityOffset.y - unityScale.y);
|
|
|
|
glTF_KHR_texture_transform.Serialize(textureInfo, (offset.x, offset.y), (scale.x, scale.y));
|
|
}
|
|
|
|
public static void ExportTextureTransform(TextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset)
|
|
{
|
|
if (textureInfo == null)
|
|
{
|
|
return;
|
|
}
|
|
// Generate extension to empty holder.
|
|
var gltfTextureInfo = new EmptyGltfTextureInfo();
|
|
ExportTextureTransform(gltfTextureInfo, unityScale, unityOffset);
|
|
|
|
// Copy extension from empty holder.
|
|
textureInfo.Extensions = gltfTextureInfo.extensions;
|
|
}
|
|
|
|
public static void ExportTextureTransform(ShadingShiftTextureInfo textureInfo, Vector2 unityScale, Vector2 unityOffset)
|
|
{
|
|
if (textureInfo == null)
|
|
{
|
|
return;
|
|
}
|
|
// Generate extension to empty holder.
|
|
var gltfTextureInfo = new EmptyGltfTextureInfo();
|
|
ExportTextureTransform(gltfTextureInfo, unityScale, unityOffset);
|
|
|
|
// Copy extension from empty holder.
|
|
textureInfo.Extensions = gltfTextureInfo.extensions;
|
|
}
|
|
|
|
private sealed class EmptyGltfTextureInfo : glTFTextureInfo
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|