using GLTF.Schema; using UnityEngine; using UnityEngine.Rendering; namespace UnityGLTF { public abstract class BaseGraphMap : IUniformMap { public abstract IUniformMap Clone(); protected BaseGraphMap(Material mat) { _material = mat; } protected BaseGraphMap(string shaderName, string fallbackGuid) { var s = Shader.Find(shaderName); #if UNITY_EDITOR // workaround for first-import issues with Shader.Find and import order if (!s) s = UnityEditor.AssetDatabase.LoadAssetAtPath(UnityEditor.AssetDatabase.GUIDToAssetPath(fallbackGuid)); #endif if (!s) throw new ShaderNotFoundException(shaderName + " not found. Did you forget to add it to the build?"); _material = new Material(s); } public Material Material => _material; internal Material _material; private AlphaMode _alphaMode; public virtual AlphaMode AlphaMode { get { return _alphaMode; } set { if (value == AlphaMode.MASK) { _material.SetOverrideTag("RenderType", "TransparentCutout"); _material.SetFloat("_Mode", 1); _material.SetInt("_SrcBlend", (int)BlendMode.One); _material.SetInt("_DstBlend", (int)BlendMode.Zero); _material.SetInt("_BUILTIN_SrcBlend", (int)BlendMode.One); _material.SetInt("_BUILTIN_DstBlend", (int)BlendMode.Zero); _material.SetInt("_ZWrite", 1); _material.SetInt("_BUILTIN_ZWrite", 1); _material.SetInt("_AlphaClip", 1); _material.SetInt("_BUILTIN_AlphaClip", 1); _material.EnableKeyword("_ALPHATEST_ON"); _material.EnableKeyword("_BUILTIN_ALPHATEST_ON"); _material.DisableKeyword("_ALPHABLEND_ON"); _material.DisableKeyword("_BUILTIN_ALPHABLEND_ON"); _material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); _material.DisableKeyword("_BUILTIN_ALPHAPREMULTIPLY_ON"); _material.renderQueue = (int)RenderQueue.AlphaTest; if (_material.HasProperty("_Cutoff")) _material.SetFloat("_Cutoff", (float)AlphaCutoff); if (_material.HasProperty("alphaCutoff")) _material.SetFloat("alphaCutoff", (float)AlphaCutoff); SetAlphaModeMask(_material, true); } else if (value == AlphaMode.BLEND) { _material.SetOverrideTag("RenderType", "Transparent"); _material.SetFloat("_Mode", 2); _material.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha); _material.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha); _material.SetInt("_BUILTIN_SrcBlend", (int)BlendMode.SrcAlpha); _material.SetInt("_BUILTIN_DstBlend", (int)BlendMode.OneMinusSrcAlpha); _material.SetInt("_ZWrite", 0); _material.SetInt("_BUILTIN_ZWrite", 0); _material.SetInt("_AlphaClip", 0); _material.SetInt("_BUILTIN_AlphaClip", 0); _material.DisableKeyword("_ALPHATEST_ON"); _material.DisableKeyword("_BUILTIN_ALPHATEST_ON"); _material.EnableKeyword("_ALPHABLEND_ON"); _material.EnableKeyword("_BUILTIN_ALPHABLEND_ON"); _material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); _material.DisableKeyword("_BUILTIN_ALPHAPREMULTIPLY_ON"); _material.renderQueue = (int)RenderQueue.Transparent; _material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); _material.EnableKeyword("_BUILTIN_SURFACE_TYPE_TRANSPARENT"); _material.SetFloat("_BlendModePreserveSpecular", 0); SetShaderModeBlend(_material); } else { _material.SetOverrideTag("RenderType", "Opaque"); _material.SetFloat("_Mode", 0); _material.SetInt("_SrcBlend", (int)BlendMode.One); _material.SetInt("_DstBlend", (int)BlendMode.Zero); _material.SetInt("_BUILTIN_SrcBlend", (int)BlendMode.One); _material.SetInt("_BUILTIN_DstBlend", (int)BlendMode.Zero); _material.SetInt("_ZWrite", 1); _material.SetInt("_BUILTIN_ZWrite", 1); _material.SetInt("_AlphaClip", 0); _material.SetInt("_BUILTIN_AlphaClip", 0); _material.DisableKeyword("_ALPHATEST_ON"); _material.DisableKeyword("_ALPHABLEND_ON"); _material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); _material.DisableKeyword("_BUILTIN_ALPHATEST_ON"); _material.DisableKeyword("_BUILTIN_ALPHABLEND_ON"); _material.DisableKeyword("_BUILTIN_ALPHAPREMULTIPLY_ON"); _material.renderQueue = (int)RenderQueue.Geometry; } _alphaMode = value; } } protected void SetDoubleSided (Material material, bool doubleSided) { material.doubleSidedGI = doubleSided; var mode = doubleSided ? (int)CullMode.Off : (int)CullMode.Back; material.SetFloat(cullPropId, mode); material.SetFloat(cullModePropId, mode); material.SetFloat(cullModePropIdBuiltin, mode); } public static readonly int cutoffPropId = Shader.PropertyToID("_Cutoff"); protected void SetAlphaModeMask(Material material, bool isMask) { material.SetFloat(cutoffPropId, isMask ? 1 : 0); // #if USING_HDRP_10_OR_NEWER || USING_URP_12_OR_NEWER material.EnableKeyword(KW_ALPHATEST_ON); material.EnableKeyword(KW_ALPHATEST_ON_BUILTIN); material.SetOverrideTag(TAG_RENDER_TYPE, TAG_RENDER_TYPE_CUTOUT); material.SetFloat(k_ZTestGBufferPropId, (int)CompareFunction.Equal); //3 // #endif material.SetFloat(k_AlphaClip, 1); material.SetFloat(k_AlphaClipBuiltin, 1); if (isMask) material.EnableKeyword(KW_ALPHACLIP_ON_BUILTIN); else material.DisableKeyword(KW_ALPHACLIP_ON_BUILTIN); material.SetFloat(alphaToMask, isMask ? 1 : 0); } static readonly int cullPropId = Shader.PropertyToID("_Cull"); static readonly int cullModePropId = Shader.PropertyToID("_CullMode"); static readonly int cullModePropIdBuiltin = Shader.PropertyToID("_BUILTIN_CullMode"); static readonly int k_AlphaClip = Shader.PropertyToID("_AlphaClip"); static readonly int k_AlphaClipBuiltin = Shader.PropertyToID("_BUILTIN_AlphaClip"); static readonly int k_Surface = Shader.PropertyToID("_Surface"); static readonly int k_SurfaceBuiltin = Shader.PropertyToID("_BUILTIN_Surface"); static readonly int k_AlphaDstBlendPropId = Shader.PropertyToID("_AlphaDstBlend"); static readonly int k_ZTestGBufferPropId = Shader.PropertyToID("_ZTestGBuffer"); static readonly int srcBlendPropId = Shader.PropertyToID("_SrcBlend"); static readonly int dstBlendPropId = Shader.PropertyToID("_DstBlend"); static readonly int zWritePropId = Shader.PropertyToID("_ZWrite"); static readonly int alphaToMask = Shader.PropertyToID("_AlphaToMask"); const string TAG_RENDER_TYPE = "RenderType"; const string TAG_RENDER_TYPE_CUTOUT = "TransparentCutout"; const string TAG_RENDER_TYPE_OPAQUE = "Opaque"; const string TAG_RENDER_TYPE_FADE = "Fade"; const string TAG_RENDER_TYPE_TRANSPARENT = "Transparent"; const string KW_ALPHATEST_ON = "_ALPHATEST_ON"; const string KW_ALPHATEST_ON_BUILTIN = "_BUILTIN_ALPHATEST_ON"; const string KW_ALPHACLIP_ON_BUILTIN = "_BUILTIN_AlphaClip"; const string KW_DISABLE_SSR_TRANSPARENT = "_DISABLE_SSR_TRANSPARENT"; const string KW_ENABLE_FOG_ON_TRANSPARENT = "_ENABLE_FOG_ON_TRANSPARENT"; const string KW_SURFACE_TYPE_TRANSPARENT = "_SURFACE_TYPE_TRANSPARENT"; const string KW_SURFACE_TYPE_TRANSPARENT_BUILTIN = "_BUILTIN_SURFACE_TYPE_TRANSPARENT"; const string k_ShaderPassTransparentDepthPrepass = "TransparentDepthPrepass"; const string k_ShaderPassTransparentDepthPostpass = "TransparentDepthPostpass"; const string k_ShaderPassTransparentBackface = "TransparentBackface"; const string k_ShaderPassRayTracingPrepass = "RayTracingPrepass"; const string k_ShaderPassDepthOnlyPass = "DepthOnly"; protected void SetShaderModeBlend(Material material) { material.SetOverrideTag(TAG_RENDER_TYPE, TAG_RENDER_TYPE_TRANSPARENT); material.EnableKeyword(KW_SURFACE_TYPE_TRANSPARENT); material.EnableKeyword(KW_SURFACE_TYPE_TRANSPARENT_BUILTIN); material.EnableKeyword(KW_DISABLE_SSR_TRANSPARENT); material.EnableKeyword(KW_ENABLE_FOG_ON_TRANSPARENT); material.SetShaderPassEnabled(k_ShaderPassTransparentDepthPrepass, false); material.SetShaderPassEnabled(k_ShaderPassTransparentDepthPostpass, false); material.SetShaderPassEnabled(k_ShaderPassTransparentBackface, false); material.SetShaderPassEnabled(k_ShaderPassRayTracingPrepass, false); material.SetShaderPassEnabled(k_ShaderPassDepthOnlyPass, false); material.SetFloat(srcBlendPropId, (int) BlendMode.SrcAlpha);//5 material.SetFloat(dstBlendPropId, (int)BlendMode.OneMinusSrcAlpha);//10 material.SetFloat(k_ZTestGBufferPropId, (int)CompareFunction.Equal); //3 material.SetFloat(k_AlphaDstBlendPropId, (int)BlendMode.OneMinusSrcAlpha);//10 material.SetFloat(k_Surface, 1); material.SetFloat(k_SurfaceBuiltin, 1); material.SetFloat(zWritePropId, 0); material.SetFloat(alphaToMask, 0); } public double AlphaCutoff { get => _material.GetFloat("alphaCutoff"); set { _material.SetFloat("alphaCutoff", (float) value); #if !UNITY_2021_2_OR_NEWER // PBRGraph/UnlitGraph always have alphaCutoff on 2020.x, so we need to set it to 0 for non-masked modes if (_alphaMode != AlphaMode.MASK) _material.SetFloat("alphaCutoff", 0f); #endif } } public virtual bool DoubleSided { get { return #if UNITY_2019_3_OR_NEWER !GraphicsSettings.currentRenderPipeline ? _material.GetInt(cullModePropIdBuiltin) == (int)CullMode.Off : #endif _material.GetInt(cullPropId) == (int)CullMode.Off; } set { SetDoubleSided(_material, value); } } public virtual bool VertexColorsEnabled { get { return _material.IsKeywordEnabled("_VERTEX_COLORS_ON"); } set { if (value) _material.EnableKeyword("_VERTEX_COLORS_ON"); else _material.DisableKeyword("_VERTEX_COLORS_ON"); } } public Texture BaseColorTexture { get => _material.GetTexture("baseColorTexture"); set => _material.SetTexture("baseColorTexture", value); } public int BaseColorTexCoord { get => (int) _material.GetFloat("baseColorTextureTexCoord"); set => _material.SetFloat("baseColorTextureTexCoord", Mathf.RoundToInt(value)); } public Vector2 BaseColorXOffset { get => _material.GetTextureOffset("baseColorTexture"); set => _material.SetTextureOffset("baseColorTexture", value); } public double BaseColorXRotation { get => _material.GetFloat("baseColorTextureRotation"); set => _material.SetFloat("baseColorTextureRotation", (float) value); } public Vector2 BaseColorXScale { get => _material.GetTextureScale("baseColorTexture"); set => _material.SetTextureScale("baseColorTexture", value); } public int BaseColorXTexCoord { get => (int) _material.GetFloat("baseColorTextureTexCoord"); set => _material.SetFloat("baseColorTextureTexCoord", Mathf.RoundToInt(value)); } public Color BaseColorFactor { get => _material.GetColor("baseColorFactor"); set => _material.SetColor("baseColorFactor", value); } } }