This commit is contained in:
SoulliesOfficial
2026-07-17 17:46:16 -04:00
parent b00ac27e3a
commit 40fa80cd70
1178 changed files with 51090 additions and 0 deletions

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 78855065a5a548f490982968a0e01781
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
[InitializeOnLoad]
internal static class NBShaderEditorQualityTierWatcher
{
private const string UndoApplyLoadedTier = "Apply NBShader Quality Tier";
private const string UndoApplyProjectTier = "Apply NBShader Quality Tier To Project Materials";
private static int s_LastQualityLevel;
private static bool s_DialogQueued;
static NBShaderEditorQualityTierWatcher()
{
s_LastQualityLevel = QualitySettings.GetQualityLevel();
EditorApplication.update += WatchQualityLevel;
}
internal static void ApplyCurrentQualityTierToLoadedMaterials()
{
NBShaderFeatureTier tier;
string qualityName;
ResolveCurrentQualityTier(out tier, out qualityName);
var count = ApplyTierToLoadedMaterials(tier);
Debug.LogFormat(
"Applied NBShader2 tier {0} from Unity Quality '{1}' to {2} loaded material(s).",
tier,
qualityName,
count);
}
internal static void ApplyCurrentQualityTierToProjectMaterials()
{
NBShaderFeatureTier tier;
string qualityName;
ResolveCurrentQualityTier(out tier, out qualityName);
var count = ApplyTierToProjectMaterials(tier);
Debug.LogFormat(
"Applied NBShader2 tier {0} from Unity Quality '{1}' to {2} project material asset(s).",
tier,
qualityName,
count);
}
private static void WatchQualityLevel()
{
if (Application.isBatchMode ||
EditorApplication.isCompiling ||
EditorApplication.isUpdating ||
EditorApplication.isPlayingOrWillChangePlaymode ||
s_DialogQueued)
{
return;
}
var current = QualitySettings.GetQualityLevel();
if (current == s_LastQualityLevel)
return;
s_LastQualityLevel = current;
s_DialogQueued = true;
EditorApplication.delayCall += PromptForQualityTierSync;
}
private static void PromptForQualityTierSync()
{
s_DialogQueued = false;
if (Application.isBatchMode ||
EditorApplication.isCompiling ||
EditorApplication.isUpdating ||
EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
NBShaderFeatureTier tier;
string qualityName;
ResolveCurrentQualityTier(out tier, out qualityName);
var syncLoaded = EditorUtility.DisplayDialog(
"NBShader2 Feature Tier",
string.Format(
"Unity Quality has switched to '{0}'.\n\nSync currently loaded NBShader2 materials to tier {1}?",
qualityName,
tier),
"Sync Loaded",
"Skip");
if (!syncLoaded)
return;
var loadedCount = ApplyTierToLoadedMaterials(tier);
var syncProject = EditorUtility.DisplayDialog(
"NBShader2 Feature Tier",
string.Format(
"Applied tier {0} to {1} loaded NBShader2 material(s).\n\nScan Assets and write current keyword/pass state for all NBShader2 material assets?",
tier,
loadedCount),
"Scan Assets",
"Loaded Only");
if (syncProject)
{
var projectCount = ApplyTierToProjectMaterials(tier);
Debug.LogFormat(
"Applied NBShader2 tier {0} from Unity Quality '{1}' to {2} project material asset(s).",
tier,
qualityName,
projectCount);
}
}
private static void ResolveCurrentQualityTier(out NBShaderFeatureTier tier, out string qualityName)
{
qualityName = GetCurrentQualityName();
if (!NBShaderFeatureLevelProjectSettings.instance.TryGetTierForQualityNameNoSave(qualityName, out tier))
tier = NBShaderFeatureTier.Ultra;
}
private static string GetCurrentQualityName()
{
var names = QualitySettings.names;
var index = QualitySettings.GetQualityLevel();
if (names == null || index < 0 || index >= names.Length)
return string.Empty;
return names[index];
}
private static int ApplyTierToLoadedMaterials(NBShaderFeatureTier tier)
{
var materials = Resources.FindObjectsOfTypeAll<Material>();
var editableMaterials = new List<Material>();
var seen = new HashSet<int>();
for (var i = 0; i < materials.Length; i++)
{
var material = materials[i];
if (!CanMutateMaterial(material) || !seen.Add(material.GetInstanceID()))
continue;
editableMaterials.Add(material);
}
if (editableMaterials.Count == 0)
return 0;
var undoGroup = Undo.GetCurrentGroup();
Undo.SetCurrentGroupName(UndoApplyLoadedTier);
for (var i = 0; i < editableMaterials.Count; i++)
ApplyTierToMaterial(editableMaterials[i], tier, UndoApplyLoadedTier);
Undo.CollapseUndoOperations(undoGroup);
return editableMaterials.Count;
}
private static int ApplyTierToProjectMaterials(NBShaderFeatureTier tier)
{
var guids = AssetDatabase.FindAssets("t:Material", new[] { "Assets" });
var changed = 0;
var undoGroup = Undo.GetCurrentGroup();
Undo.SetCurrentGroupName(UndoApplyProjectTier);
try
{
for (var i = 0; i < guids.Length; i++)
{
if (EditorUtility.DisplayCancelableProgressBar(
"NBShader2 Feature Tier",
string.Format("Scanning material {0}/{1}", i + 1, guids.Length),
guids.Length > 0 ? (float)i / guids.Length : 1f))
{
break;
}
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
var material = AssetDatabase.LoadAssetAtPath<Material>(path);
if (!CanMutateMaterial(material))
continue;
if (ApplyTierToMaterial(material, tier, UndoApplyProjectTier))
{
AssetDatabase.SaveAssetIfDirty(material);
changed++;
}
}
}
finally
{
EditorUtility.ClearProgressBar();
Undo.CollapseUndoOperations(undoGroup);
}
return changed;
}
private static bool CanMutateMaterial(Material material)
{
if (!NBShaderMaterialIntentResolver.IsNBShaderMaterial(material))
return false;
var flags = material.hideFlags;
if ((flags & HideFlags.NotEditable) != 0 ||
(flags & HideFlags.HideAndDontSave) != 0)
{
return false;
}
if (!EditorUtility.IsPersistent(material))
return true;
var path = AssetDatabase.GetAssetPath(material);
return !string.IsNullOrEmpty(path) && path.StartsWith("Assets/", StringComparison.Ordinal);
}
private static bool ApplyTierToMaterial(
Material material,
NBShaderFeatureTier tier,
string undoName)
{
Undo.RecordObject(material, undoName);
bool changed;
if (!NBShaderFeatureLevelMaterialApplier.Apply(material, tier, true, true, out changed))
return false;
if (changed)
EditorUtility.SetDirty(material);
return changed;
}
}
}

View File

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

View File

@@ -0,0 +1,749 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEngine;
using UnityEngine.Rendering;
namespace NBShaders2.Editor.FeatureLevel
{
public enum NBShaderBuildInfoMode
{
TierAndPass = 0,
ExactMaterialVariants = 1
}
public sealed class NBShaderBuildInfoSet
{
private readonly NBShaderMaterialBuildInfo[] m_Materials;
private readonly NBShaderVariantBuildInfo[] m_Variants;
private readonly string[] m_AllowedManagedKeywords;
private readonly string[] m_AllowedPassFeatures;
private readonly string[] m_IncludedPassNames;
public readonly NBShaderFeatureTier tier;
public readonly NBShaderBuildInfoMode mode;
public NBShaderMaterialBuildInfo[] materials { get { return (NBShaderMaterialBuildInfo[])m_Materials.Clone(); } }
public NBShaderVariantBuildInfo[] variants { get { return (NBShaderVariantBuildInfo[])m_Variants.Clone(); } }
public string[] allowedManagedKeywords { get { return (string[])m_AllowedManagedKeywords.Clone(); } }
public string[] allowedPassFeatures { get { return (string[])m_AllowedPassFeatures.Clone(); } }
public string[] includedPassNames { get { return (string[])m_IncludedPassNames.Clone(); } }
public bool hasMaterials { get { return m_Materials.Length > 0; } }
public NBShaderBuildInfoSet(
NBShaderFeatureTier tier,
NBShaderBuildInfoMode mode,
NBShaderMaterialBuildInfo[] materials,
string[] allowedManagedKeywords,
string[] allowedPassFeatures = null)
{
this.tier = tier;
this.mode = mode;
m_Materials = materials != null ? (NBShaderMaterialBuildInfo[])materials.Clone() : new NBShaderMaterialBuildInfo[0];
m_AllowedManagedKeywords = allowedManagedKeywords != null ? (string[])allowedManagedKeywords.Clone() : new string[0];
m_AllowedPassFeatures = NBShaderBuildInfoUtility.ToCatalogOrderedPassFeatures(allowedPassFeatures);
m_Variants = BuildUniqueVariants(m_Materials);
m_IncludedPassNames = BuildIncludedPassNames(m_Materials);
}
private static NBShaderVariantBuildInfo[] BuildUniqueVariants(NBShaderMaterialBuildInfo[] materials)
{
var result = new List<NBShaderVariantBuildInfo>();
var keys = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < materials.Length; i++)
{
var material = materials[i];
if (material == null)
continue;
var materialVariants = material.variants;
for (var v = 0; v < materialVariants.Length; v++)
{
var variant = materialVariants[v];
if (variant == null)
continue;
var key = variant.GetStableKey();
if (keys.Add(key))
result.Add(variant);
}
}
return result.ToArray();
}
private static string[] BuildIncludedPassNames(NBShaderMaterialBuildInfo[] materials)
{
var result = new List<string>();
var set = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < materials.Length; i++)
{
var material = materials[i];
if (material == null)
continue;
var passNames = material.includedPassNames;
for (var p = 0; p < passNames.Length; p++)
{
var passName = passNames[p];
if (!string.IsNullOrEmpty(passName) && set.Add(passName))
result.Add(passName);
}
}
return result.ToArray();
}
}
public sealed class NBShaderMaterialBuildInfo
{
private readonly string[] m_EffectiveKeywords;
private readonly string[] m_StrippedManagedKeywords;
private readonly string[] m_AllowedManagedKeywords;
private readonly string[] m_AllowedPassFeatures;
private readonly NBShaderPassBuildInfo[] m_Passes;
private readonly NBShaderVariantBuildInfo[] m_Variants;
private readonly string[] m_IncludedPassNames;
public readonly Material material;
public readonly Shader shader;
public readonly NBShaderFeatureTier tier;
public readonly NBShaderBuildInfoMode mode;
public string[] effectiveKeywords { get { return (string[])m_EffectiveKeywords.Clone(); } }
public string[] strippedManagedKeywords { get { return (string[])m_StrippedManagedKeywords.Clone(); } }
public string[] allowedManagedKeywords { get { return (string[])m_AllowedManagedKeywords.Clone(); } }
public string[] allowedPassFeatures { get { return (string[])m_AllowedPassFeatures.Clone(); } }
public NBShaderPassBuildInfo[] passes { get { return (NBShaderPassBuildInfo[])m_Passes.Clone(); } }
public NBShaderVariantBuildInfo[] variants { get { return (NBShaderVariantBuildInfo[])m_Variants.Clone(); } }
public string[] includedPassNames { get { return (string[])m_IncludedPassNames.Clone(); } }
public NBShaderMaterialBuildInfo(
Material material,
NBShaderFeatureTier tier,
NBShaderBuildInfoMode mode,
string[] allowedManagedKeywords,
string[] effectiveKeywords,
string[] strippedManagedKeywords,
NBShaderPassBuildInfo[] passes,
string[] allowedPassFeatures = null)
{
this.material = material;
shader = material != null ? material.shader : null;
this.tier = tier;
this.mode = mode;
m_AllowedManagedKeywords = NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(allowedManagedKeywords);
m_AllowedPassFeatures = NBShaderBuildInfoUtility.ToCatalogOrderedPassFeatures(allowedPassFeatures);
m_EffectiveKeywords = NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(effectiveKeywords);
m_StrippedManagedKeywords = NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(strippedManagedKeywords);
m_Passes = passes != null ? (NBShaderPassBuildInfo[])passes.Clone() : new NBShaderPassBuildInfo[0];
m_IncludedPassNames = BuildIncludedPassNames(m_Passes);
m_Variants = BuildVariants();
}
private NBShaderVariantBuildInfo[] BuildVariants()
{
if (shader == null)
return new NBShaderVariantBuildInfo[0];
var result = new List<NBShaderVariantBuildInfo>();
var materialKeywords = NBShaderBuildInfoUtility.GetCatalogExternalMaterialKeywords(material);
for (var i = 0; i < m_Passes.Length; i++)
{
var pass = m_Passes[i];
if (pass == null || !pass.included)
continue;
result.Add(new NBShaderVariantBuildInfo(
shader,
pass.passName,
pass.passType,
NBShaderBuildInfoUtility.BuildShaderVariantKeywordsForPass(
pass.passName,
pass.passType,
m_EffectiveKeywords,
materialKeywords)));
}
return result.ToArray();
}
private static string[] BuildIncludedPassNames(NBShaderPassBuildInfo[] passes)
{
var result = new List<string>();
for (var i = 0; i < passes.Length; i++)
{
var pass = passes[i];
if (pass != null && pass.included && !string.IsNullOrEmpty(pass.passName))
result.Add(pass.passName);
}
return result.ToArray();
}
}
public sealed class NBShaderPassBuildInfo
{
public readonly string passName;
public readonly PassType passType;
public readonly bool enabledByMaterial;
public readonly bool allowedByTier;
public readonly bool included;
public readonly string reason;
public NBShaderPassBuildInfo(
string passName,
PassType passType,
bool enabledByMaterial,
bool allowedByTier,
bool included,
string reason)
{
this.passName = passName;
this.passType = passType;
this.enabledByMaterial = enabledByMaterial;
this.allowedByTier = allowedByTier;
this.included = included;
this.reason = reason;
}
}
public sealed class NBShaderVariantBuildInfo
{
private readonly string[] m_Keywords;
public readonly Shader shader;
public readonly string passName;
public readonly PassType passType;
public string[] keywords { get { return (string[])m_Keywords.Clone(); } }
public NBShaderVariantBuildInfo(Shader shader, string passName, PassType passType, string[] keywords)
{
this.shader = shader;
this.passName = passName;
this.passType = passType;
m_Keywords = NBShaderBuildInfoUtility.ToShaderVariantOrderedKeywords(keywords);
}
public string GetStableKey()
{
string shaderName = shader != null ? shader.name : string.Empty;
return shaderName + "|" + passName + "|" + passType + "|" + string.Join(";", m_Keywords);
}
}
internal static class NBShaderBuildInfoUtility
{
public static PassType GetPassType(string passName)
{
if (passName == "SRPDefaultUnlit")
return PassType.ScriptableRenderPipelineDefaultUnlit;
if (passName == "ShadowCaster")
return PassType.ShadowCaster;
return PassType.ScriptableRenderPipeline;
}
public static string[] FilterKeywordsForPass(string passName, PassType passType, IEnumerable<string> keywords)
{
var declaredKeywords = GetDeclaredKeywords(passName, passType);
var result = new List<string>();
var source = ToCatalogOrderedManagedKeywords(keywords);
for (var i = 0; i < source.Length; i++)
{
var keyword = source[i];
if (declaredKeywords.Contains(keyword))
result.Add(keyword);
}
return result.ToArray();
}
public static string[] BuildShaderVariantKeywordsForPass(
string passName,
PassType passType,
IEnumerable<string> managedKeywords,
IEnumerable<string> externalKeywords)
{
var declaredKeywords = GetDeclaredShaderVariantKeywords(passName, passType);
var source = new HashSet<string>(StringComparer.Ordinal);
var managed = ToCatalogOrderedManagedKeywords(managedKeywords);
for (var i = 0; i < managed.Length; i++)
{
var keyword = managed[i];
source.Add(keyword);
if (string.Equals(keyword, "_FX_LIGHT_MODE_SIX_WAY", StringComparison.Ordinal))
source.Add("EVALUATE_SH_VERTEX");
}
if (externalKeywords != null)
{
foreach (var keyword in externalKeywords)
{
if (IsCatalogExternalShaderKeyword(keyword))
source.Add(keyword);
}
}
var result = new List<string>();
for (var i = 0; i < NBShaderFeatureCatalog.RawKeywords.Length; i++)
{
var keyword = NBShaderFeatureCatalog.RawKeywords[i];
if (source.Contains(keyword) && declaredKeywords.Contains(keyword))
result.Add(keyword);
}
for (var i = 0; i < CatalogExternalShaderKeywordOrder.Length; i++)
{
var keyword = CatalogExternalShaderKeywordOrder[i];
if (source.Contains(keyword) && declaredKeywords.Contains(keyword))
result.Add(keyword);
}
return result.ToArray();
}
public static string[] GetCatalogExternalMaterialKeywords(Material material)
{
if (material == null || material.shaderKeywords == null || material.shaderKeywords.Length == 0)
return new string[0];
var result = new List<string>();
var source = new HashSet<string>(material.shaderKeywords, StringComparer.Ordinal);
for (var i = 0; i < CatalogExternalShaderKeywordOrder.Length; i++)
{
var keyword = CatalogExternalShaderKeywordOrder[i];
if (source.Contains(keyword))
result.Add(keyword);
}
return result.ToArray();
}
public static string[] ToCatalogOrderedManagedKeywords(IEnumerable<string> keywords)
{
var set = new HashSet<string>(StringComparer.Ordinal);
if (keywords != null)
{
foreach (var keyword in keywords)
{
if (NBShaderFeatureCatalog.IsManagedKeyword(keyword))
set.Add(keyword);
}
}
if (set.Count == 0)
return new string[0];
var result = new List<string>();
for (var i = 0; i < NBShaderFeatureCatalog.RawKeywords.Length; i++)
{
var keyword = NBShaderFeatureCatalog.RawKeywords[i];
if (set.Contains(keyword))
result.Add(keyword);
}
return result.ToArray();
}
public static string[] ToShaderVariantOrderedKeywords(IEnumerable<string> keywords)
{
var set = new HashSet<string>(StringComparer.Ordinal);
if (keywords != null)
{
foreach (var keyword in keywords)
{
if (NBShaderFeatureCatalog.IsManagedKeyword(keyword) ||
IsCatalogExternalShaderKeyword(keyword))
{
set.Add(keyword);
}
}
}
if (set.Count == 0)
return new string[0];
var result = new List<string>();
for (var i = 0; i < NBShaderFeatureCatalog.RawKeywords.Length; i++)
{
var keyword = NBShaderFeatureCatalog.RawKeywords[i];
if (set.Contains(keyword))
result.Add(keyword);
}
for (var i = 0; i < CatalogExternalShaderKeywordOrder.Length; i++)
{
var keyword = CatalogExternalShaderKeywordOrder[i];
if (set.Contains(keyword))
result.Add(keyword);
}
return result.ToArray();
}
public static string[] ToCatalogOrderedPassFeatures(IEnumerable<string> passFeatures)
{
var set = new HashSet<string>(StringComparer.Ordinal);
if (passFeatures != null)
{
foreach (var passFeature in passFeatures)
{
if (NBShaderPassFeatureCatalog.IsManagedPassFeature(passFeature))
set.Add(passFeature);
}
}
if (set.Count == 0)
return new string[0];
var result = new List<string>();
for (var i = 0; i < NBShaderPassFeatureCatalog.RawPassFeatureIds.Length; i++)
{
var passFeature = NBShaderPassFeatureCatalog.RawPassFeatureIds[i];
if (set.Contains(passFeature))
result.Add(passFeature);
}
return result.ToArray();
}
public static bool ContainsPassName(string[] passNames, string passName)
{
if (passNames == null || string.IsNullOrEmpty(passName))
return false;
for (var i = 0; i < passNames.Length; i++)
{
if (string.Equals(passNames[i], passName, StringComparison.Ordinal))
return true;
}
return false;
}
public static bool IsSubsetOf(string[] subset, string[] superset)
{
var set = new HashSet<string>(superset ?? new string[0], StringComparer.Ordinal);
if (subset == null)
return true;
for (var i = 0; i < subset.Length; i++)
{
if (!set.Contains(subset[i]))
return false;
}
return true;
}
public static bool AreKeywordSetsEqual(string[] a, string[] b)
{
var normalizedA = ToCatalogOrderedManagedKeywords(a);
var normalizedB = ToCatalogOrderedManagedKeywords(b);
if (normalizedA.Length != normalizedB.Length)
return false;
for (var i = 0; i < normalizedA.Length; i++)
{
if (!string.Equals(normalizedA[i], normalizedB[i], StringComparison.Ordinal))
return false;
}
return true;
}
private static HashSet<string> GetDeclaredKeywords(string passName, PassType passType)
{
if (passType == PassType.ShadowCaster)
return DeclaredDepthShadowKeywords;
if (string.Equals(passName, "DepthOnly", StringComparison.Ordinal))
return DeclaredDepthShadowKeywords;
if (string.Equals(passName, "NBCameraOpaqueDistortPass", StringComparison.Ordinal) ||
string.Equals(passName, "NBDeferredDistortPass", StringComparison.Ordinal))
{
return DeclaredDistortKeywords;
}
if (string.Equals(passName, "Universal2D", StringComparison.Ordinal))
return DeclaredUniversal2DKeywords;
return DeclaredForwardKeywords;
}
private static HashSet<string> GetDeclaredShaderVariantKeywords(string passName, PassType passType)
{
if (passType == PassType.ShadowCaster)
return DeclaredShadowCasterShaderVariantKeywords;
if (string.Equals(passName, "DepthOnly", StringComparison.Ordinal))
return DeclaredDepthOnlyShaderVariantKeywords;
if (string.Equals(passName, "NBCameraOpaqueDistortPass", StringComparison.Ordinal) ||
string.Equals(passName, "NBDeferredDistortPass", StringComparison.Ordinal))
{
return DeclaredDistortShaderVariantKeywords;
}
if (string.Equals(passName, "Universal2D", StringComparison.Ordinal))
return DeclaredUniversal2DShaderVariantKeywords;
return DeclaredForwardShaderVariantKeywords;
}
private static bool IsCatalogExternalShaderKeyword(string keyword)
{
return !string.IsNullOrEmpty(keyword) && CatalogExternalShaderKeywordSet.Contains(keyword);
}
private static readonly string[] CatalogExternalShaderKeywordOrder =
{
"EVALUATE_SH_VERTEX",
"EVALUATE_SH_MIXED",
"SOFT_UI_FRAME",
"UNITY_UI_CLIP_RECT",
"_ADDITIONAL_LIGHTS_VERTEX",
"_ADDITIONAL_LIGHTS",
"_CASTING_PUNCTUAL_LIGHT_SHADOW"
};
private static readonly HashSet<string> CatalogExternalShaderKeywordSet =
new HashSet<string>(CatalogExternalShaderKeywordOrder, StringComparer.Ordinal);
private static readonly HashSet<string> DeclaredForwardKeywords = BuildDeclaredKeywordSet(
"NB_DEBUG_DISSOLVE",
"NB_DEBUG_DISTORT",
"NB_DEBUG_FRESNEL",
"NB_DEBUG_MASK",
"NB_DEBUG_PNOISE",
"NB_DEBUG_VERTEX_OFFSET",
"VFX_SIX_WAY_ABSORPTION",
"_ALPHAMODULATE_ON",
"_ALPHAPREMULTIPLY_ON",
"_ALPHATEST_ON",
"_CHROMATIC_ABERRATION",
"_COLORMAPBLEND",
"_COLOR_RAMP",
"_COLOR_RAMP_MAP",
"_DEPTH_DECAL",
"_DEPTH_OUTLINE",
"_DISSOLVE",
"_DISSOLVE_MASK",
"_DISSOLVE_RAMP",
"_DISSOLVE_RAMP_MAP",
"_DISTANCE_FADE",
"_DISTORT_REFRACTION",
"_EMISSION",
"_FLIPBOOKBLENDING_ON",
"_FRESNEL",
"_FX_LIGHT_MODE_BLINN_PHONG",
"_FX_LIGHT_MODE_HALF_LAMBERT",
"_FX_LIGHT_MODE_PBR",
"_FX_LIGHT_MODE_SIX_WAY",
"_FX_LIGHT_MODE_UNLIT",
"_HOUDINI_VAT_DYNAMIC_REMESH",
"_HOUDINI_VAT_PARTICLE_SPRITE",
"_HOUDINI_VAT_RIGIDBODY",
"_HOUDINI_VAT_SOFTBODY",
"_MASKMAP_ON",
"_MASKMAP2_ON",
"_MASKMAP3_ON",
"_MATCAP",
"_NOISEMAP",
"_NOISE_MASKMAP",
"_NORMALMAP",
"_OVERRIDE_Z",
"_PARALLAX_MAPPING",
"_PROGRAM_NOISE",
"_PROGRAM_NOISE_SIMPLE",
"_PROGRAM_NOISE_VORONOI",
"_SCRIPTABLETIME",
"_SHARED_UV",
"_SOFTPARTICLES_ON",
"_SPECULAR_COLOR",
"_STENCIL_WITHOUT_PLAYER",
"_TYFLOW_VAT_ABSOLUTE",
"_TYFLOW_VAT_RELATIVE",
"_TYFLOW_VAT_SKIN_PR",
"_TYFLOW_VAT_SKIN_PRSAVE",
"_TYFLOW_VAT_SKIN_PRSXYZ",
"_TYFLOW_VAT_SKIN_R",
"_UNSCALETIME",
"_VAT",
"_VAT_HOUDINI",
"_VAT_TYFLOW",
"_VERTEX_OFFSET",
"_VERTEX_OFFSET_MASKMAP");
private static readonly HashSet<string> DeclaredDistortKeywords = BuildDeclaredKeywordSet(
"_ALPHAMODULATE_ON",
"_ALPHAPREMULTIPLY_ON",
"_ALPHATEST_ON",
"_CHROMATIC_ABERRATION",
"_DEPTH_DECAL",
"_DEPTH_OUTLINE",
"_DISSOLVE",
"_DISSOLVE_MASK",
"_DISSOLVE_RAMP",
"_DISSOLVE_RAMP_MAP",
"_DISTANCE_FADE",
"_DISTORT_REFRACTION",
"_FLIPBOOKBLENDING_ON",
"_FRESNEL",
"_FX_LIGHT_MODE_UNLIT",
"_MASKMAP_ON",
"_MASKMAP2_ON",
"_MASKMAP3_ON",
"_NOISEMAP",
"_NOISE_MASKMAP",
"_NORMALMAP",
"_PROGRAM_NOISE",
"_PROGRAM_NOISE_SIMPLE",
"_PROGRAM_NOISE_VORONOI",
"_SCRIPTABLETIME",
"_SHARED_UV",
"_SOFTPARTICLES_ON",
"_STENCIL_WITHOUT_PLAYER",
"_UNSCALETIME",
"_VERTEX_OFFSET",
"_VERTEX_OFFSET_MASKMAP");
private static readonly HashSet<string> DeclaredDepthShadowKeywords = BuildDeclaredKeywordSet(
"_ALPHATEST_ON",
"_DISSOLVE",
"_DISSOLVE_MASK",
"_FLIPBOOKBLENDING_ON",
"_HOUDINI_VAT_DYNAMIC_REMESH",
"_HOUDINI_VAT_PARTICLE_SPRITE",
"_HOUDINI_VAT_RIGIDBODY",
"_HOUDINI_VAT_SOFTBODY",
"_MASKMAP_ON",
"_MASKMAP2_ON",
"_MASKMAP3_ON",
"_NOISEMAP",
"_NOISE_MASKMAP",
"_PROGRAM_NOISE",
"_PROGRAM_NOISE_SIMPLE",
"_PROGRAM_NOISE_VORONOI",
"_SCRIPTABLETIME",
"_SHARED_UV",
"_TYFLOW_VAT_ABSOLUTE",
"_TYFLOW_VAT_RELATIVE",
"_TYFLOW_VAT_SKIN_PR",
"_TYFLOW_VAT_SKIN_PRSAVE",
"_TYFLOW_VAT_SKIN_PRSXYZ",
"_TYFLOW_VAT_SKIN_R",
"_UNSCALETIME",
"_VAT",
"_VAT_HOUDINI",
"_VAT_TYFLOW",
"_VERTEX_OFFSET",
"_VERTEX_OFFSET_MASKMAP");
private static readonly HashSet<string> DeclaredUniversal2DKeywords = BuildDeclaredKeywordSet(
"_ALPHAMODULATE_ON",
"_ALPHAPREMULTIPLY_ON",
"_ALPHATEST_ON",
"_CHROMATIC_ABERRATION",
"_COLORMAPBLEND",
"_COLOR_RAMP",
"_COLOR_RAMP_MAP",
"_DISSOLVE",
"_DISSOLVE_MASK",
"_DISSOLVE_RAMP",
"_DISSOLVE_RAMP_MAP",
"_EMISSION",
"_FLIPBOOKBLENDING_ON",
"_FRESNEL",
"_FX_LIGHT_MODE_UNLIT",
"_MASKMAP_ON",
"_MASKMAP2_ON",
"_MASKMAP3_ON",
"_NOISEMAP",
"_NOISE_MASKMAP",
"_NORMALMAP",
"_PARCUSTOMDATA_ON",
"_PROGRAM_NOISE",
"_PROGRAM_NOISE_SIMPLE",
"_PROGRAM_NOISE_VORONOI",
"_SCREEN_DISTORT_MODE",
"_SCRIPTABLETIME",
"_SHARED_UV",
"_STENCIL_WITHOUT_PLAYER",
"_UNSCALETIME",
"_VERTEX_OFFSET",
"_VERTEX_OFFSET_MASKMAP");
private static readonly HashSet<string> DeclaredForwardShaderVariantKeywords =
BuildDeclaredShaderVariantKeywordSet(
DeclaredForwardKeywords,
"SOFT_UI_FRAME",
"EVALUATE_SH_MIXED",
"EVALUATE_SH_VERTEX",
"UNITY_UI_CLIP_RECT",
"_ADDITIONAL_LIGHTS_VERTEX",
"_ADDITIONAL_LIGHTS");
private static readonly HashSet<string> DeclaredDistortShaderVariantKeywords =
BuildDeclaredShaderVariantKeywordSet(
DeclaredDistortKeywords,
"SOFT_UI_FRAME",
"EVALUATE_SH_MIXED",
"EVALUATE_SH_VERTEX");
private static readonly HashSet<string> DeclaredDepthOnlyShaderVariantKeywords =
BuildDeclaredShaderVariantKeywordSet(
DeclaredDepthShadowKeywords);
private static readonly HashSet<string> DeclaredShadowCasterShaderVariantKeywords =
BuildDeclaredShaderVariantKeywordSet(
DeclaredDepthShadowKeywords,
"_CASTING_PUNCTUAL_LIGHT_SHADOW");
private static readonly HashSet<string> DeclaredUniversal2DShaderVariantKeywords =
BuildDeclaredShaderVariantKeywordSet(
DeclaredUniversal2DKeywords,
"SOFT_UI_FRAME",
"EVALUATE_SH_MIXED",
"EVALUATE_SH_VERTEX",
"UNITY_UI_CLIP_RECT",
"_ADDITIONAL_LIGHTS_VERTEX",
"_ADDITIONAL_LIGHTS");
private static HashSet<string> BuildDeclaredKeywordSet(params string[] keywords)
{
var result = new HashSet<string>(StringComparer.Ordinal);
if (keywords == null)
return result;
for (var i = 0; i < keywords.Length; i++)
{
var keyword = keywords[i];
if (NBShaderFeatureCatalog.IsManagedKeyword(keyword))
result.Add(keyword);
}
return result;
}
private static HashSet<string> BuildDeclaredShaderVariantKeywordSet(
HashSet<string> managedKeywords,
params string[] externalKeywords)
{
var result = new HashSet<string>(managedKeywords ?? new HashSet<string>(), StringComparer.Ordinal);
if (externalKeywords == null)
return result;
for (var i = 0; i < externalKeywords.Length; i++)
{
var keyword = externalKeywords[i];
if (IsCatalogExternalShaderKeyword(keyword))
result.Add(keyword);
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using NBShader;
namespace NBShaders2.Editor.FeatureLevel
{
public static class NBShaderFeatureLevelBuildStripOverride
{
private static readonly Stack<NBShaderFeatureTier> s_OverrideStack = new Stack<NBShaderFeatureTier>();
public static bool hasOverride { get { return s_OverrideStack.Count > 0; } }
internal static bool TryGetCurrentTier(out NBShaderFeatureTier tier)
{
if (s_OverrideStack.Count > 0)
{
tier = s_OverrideStack.Peek();
return true;
}
tier = NBShaderFeatureTier.Ultra;
return false;
}
public static IDisposable PushExplicitTier(NBShaderFeatureTier tier)
{
NBShaderVariantStripper.ResetMissingExplicitTierWarning();
s_OverrideStack.Push(tier);
return new Scope();
}
private sealed class Scope : IDisposable
{
private bool m_Disposed;
public void Dispose()
{
if (m_Disposed)
return;
m_Disposed = true;
if (s_OverrideStack.Count > 0)
s_OverrideStack.Pop();
}
}
}
}

View File

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

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using NBShader;
namespace NBShaders2.Editor.FeatureLevel
{
public static class NBShaderFeatureLevelCatalog
{
public const string ShaderName = NBShaderFeatureCatalog.ShaderName;
public static string[] ManagedKeywords
{
get { return (string[])NBShaderFeatureCatalog.RawKeywords.Clone(); }
}
public static string[] ManagedPassFeatures
{
get { return (string[])NBShaderPassFeatureCatalog.RawPassFeatureIds.Clone(); }
}
public static bool IsManagedKeyword(string keyword)
{
return NBShaderFeatureCatalog.IsManagedKeyword(keyword);
}
public static bool IsManagedPassFeature(string passFeatureId)
{
return NBShaderPassFeatureCatalog.IsManagedPassFeature(passFeatureId);
}
public static bool TryGetManagedPassFeatureInfo(
string passFeatureId,
out string passName,
out string displayName)
{
NBShaderPassFeatureInfo feature;
if (NBShaderPassFeatureCatalog.TryGetPassFeature(passFeatureId, out feature))
{
passName = feature.passName;
displayName = feature.displayName;
return true;
}
passName = string.Empty;
displayName = string.Empty;
return false;
}
public static bool TryGetManagedPassFeatureByPassName(
string passName,
out string passFeatureId)
{
NBShaderPassFeatureInfo feature;
if (NBShaderPassFeatureCatalog.TryGetPassFeatureByPassName(passName, out feature))
{
passFeatureId = feature.id;
return true;
}
passFeatureId = string.Empty;
return false;
}
}
}

View File

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

View File

@@ -0,0 +1,285 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
namespace NBShaders2.Editor.FeatureLevel
{
/// <summary>
/// Public Editor API for CI/custom build scripts. Override scopes are process-local and never saved
/// into ProjectSettings/NBShaderFeatureLevels.asset.
/// </summary>
public static class NBShaderFeatureLevelEditorAPI
{
public static IDisposable OverrideBuildStripExplicitTier(NBShaderFeatureTier tier)
{
return NBShaderFeatureLevelBuildStripOverride.PushExplicitTier(tier);
}
public static string DefaultGeneratedRuntimeSettingsAssetPath
{
get { return NBShaderRuntimeSettingsSynchronizer.DefaultGeneratedRuntimeSettingsAssetPath; }
}
public static HashSet<string> GetAllowedManagedKeywords(NBShaderFeatureTier tier)
{
return NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForBuildInfoNoSave(tier);
}
public static HashSet<string> GetAllowedManagedPassFeatures(NBShaderFeatureTier tier)
{
return NBShaderFeatureLevelProjectSettings.instance.GetAllowedPassFeatureSetForBuildInfoNoSave(tier);
}
public static bool TryGetMaterialBuildInfo(
Material material,
NBShaderFeatureTier tier,
out NBShaderMaterialBuildInfo buildInfo,
NBShaderBuildInfoMode mode = NBShaderBuildInfoMode.ExactMaterialVariants)
{
buildInfo = null;
if (!NBShaderMaterialIntentResolver.IsNBShaderMaterial(material))
return false;
buildInfo = GetBuildInfo(material, tier, mode);
return buildInfo != null;
}
public static NBShaderMaterialBuildInfo GetBuildInfo(
Material material,
NBShaderFeatureTier tier,
NBShaderBuildInfoMode mode = NBShaderBuildInfoMode.ExactMaterialVariants)
{
if (!NBShaderMaterialIntentResolver.IsNBShaderMaterial(material))
return null;
var allowedKeywords = NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForBuildInfoNoSave(tier);
var allowedPassFeatures = NBShaderFeatureLevelProjectSettings.instance.GetAllowedPassFeatureSetForBuildInfoNoSave(tier);
var intent = NBShaderMaterialIntentResolver.Resolve(material, tier, allowedKeywords, allowedPassFeatures);
return new NBShaderMaterialBuildInfo(
material,
tier,
mode,
NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(allowedKeywords),
intent.effectiveKeywords,
intent.strippedManagedKeywords,
BuildPassInfo(intent.passes),
NBShaderBuildInfoUtility.ToCatalogOrderedPassFeatures(allowedPassFeatures));
}
public static NBShaderBuildInfoSet GetBuildInfo(
NBShaderFeatureTier tier,
IEnumerable<Material> materials,
NBShaderBuildInfoMode mode = NBShaderBuildInfoMode.ExactMaterialVariants)
{
var result = new List<NBShaderMaterialBuildInfo>();
if (materials != null)
{
foreach (var material in materials)
{
NBShaderMaterialBuildInfo buildInfo;
if (TryGetMaterialBuildInfo(material, tier, out buildInfo, mode))
result.Add(buildInfo);
}
}
if (result.Count == 0)
return null;
return new NBShaderBuildInfoSet(
tier,
mode,
result.ToArray(),
NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(
NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForBuildInfoNoSave(tier)),
NBShaderBuildInfoUtility.ToCatalogOrderedPassFeatures(
NBShaderFeatureLevelProjectSettings.instance.GetAllowedPassFeatureSetForBuildInfoNoSave(tier)));
}
public static bool ShouldKeepVariant(
Shader shader,
ShaderSnippetData snippet,
ShaderCompilerData compilerData,
NBShaderMaterialBuildInfo buildInfo)
{
if (buildInfo == null)
return true;
return ShouldKeepVariant(
shader,
snippet.passName,
snippet.passType,
ExtractManagedKeywords(shader, compilerData),
buildInfo);
}
public static bool ShouldKeepVariant(
Shader shader,
ShaderSnippetData snippet,
ShaderCompilerData compilerData,
NBShaderBuildInfoSet buildInfo)
{
if (buildInfo == null)
return true;
return ShouldKeepVariant(
shader,
snippet.passName,
snippet.passType,
ExtractManagedKeywords(shader, compilerData),
buildInfo);
}
public static bool ShouldKeepVariant(
Shader shader,
string passName,
PassType passType,
IEnumerable<string> keywords,
NBShaderMaterialBuildInfo buildInfo)
{
if (buildInfo == null)
return true;
var set = new NBShaderBuildInfoSet(
buildInfo.tier,
buildInfo.mode,
new[] { buildInfo },
buildInfo.allowedManagedKeywords,
buildInfo.allowedPassFeatures);
return ShouldKeepVariant(shader, passName, passType, keywords, set);
}
public static bool ShouldKeepVariant(
Shader shader,
string passName,
PassType passType,
IEnumerable<string> keywords,
NBShaderBuildInfoSet buildInfo)
{
if (shader == null || shader.name != NBShaderFeatureLevelCatalog.ShaderName || buildInfo == null)
return true;
var managedKeywords = NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(keywords);
if (!buildInfo.hasMaterials)
return true;
if (buildInfo.mode == NBShaderBuildInfoMode.TierAndPass)
return IsPassIncluded(passName, passType, buildInfo) &&
NBShaderBuildInfoUtility.IsSubsetOf(managedKeywords, buildInfo.allowedManagedKeywords);
var variants = buildInfo.variants;
var declaredCompilerKeywords = NBShaderBuildInfoUtility.FilterKeywordsForPass(passName, passType, managedKeywords);
for (var i = 0; i < variants.Length; i++)
{
var variant = variants[i];
if (variant == null || !IsSameShader(shader, variant.shader))
continue;
if (!IsPassMatch(passName, passType, variant.passName, variant.passType))
continue;
if (NBShaderBuildInfoUtility.AreKeywordSetsEqual(declaredCompilerKeywords, variant.keywords))
return true;
}
return false;
}
public static bool WriteRuntimeSettingsAsset(NBShaderFeatureRuntimeSettings asset)
{
return NBShaderRuntimeSettingsSynchronizer.WriteProjectSettingsToRuntimeAsset(asset);
}
public static bool WriteRuntimeSettingsAssetNoSave(NBShaderFeatureRuntimeSettings asset)
{
return NBShaderRuntimeSettingsSynchronizer.WriteProjectSettingsSnapshotToRuntimeAssetNoSave(asset);
}
public static NBShaderFeatureRuntimeSettings WriteDefaultRuntimeSettingsAsset(out string assetPath)
{
return NBShaderRuntimeSettingsSynchronizer.WriteDefaultGeneratedRuntimeSettingsAsset(out assetPath);
}
public static NBShaderFeatureRuntimeSettings WriteRuntimeSettingsAssetOrDefault(
NBShaderFeatureRuntimeSettings explicitAsset,
out string assetPath)
{
return NBShaderRuntimeSettingsSynchronizer.WriteRuntimeSettingsAssetOrDefault(explicitAsset, out assetPath);
}
private static NBShaderPassBuildInfo[] BuildPassInfo(NBShaderPassIntent[] passes)
{
if (passes == null || passes.Length == 0)
return new NBShaderPassBuildInfo[0];
var result = new NBShaderPassBuildInfo[passes.Length];
for (var i = 0; i < passes.Length; i++)
{
var pass = passes[i];
result[i] = new NBShaderPassBuildInfo(
pass.passName,
NBShaderBuildInfoUtility.GetPassType(pass.passName),
pass.enabledByMaterial,
pass.allowedByTier,
pass.included,
pass.reason);
}
return result;
}
private static string[] ExtractManagedKeywords(Shader shader, ShaderCompilerData compilerData)
{
if (shader == null)
return new string[0];
var result = new List<string>();
var keywords = compilerData.shaderKeywordSet.GetShaderKeywords();
for (var i = 0; i < keywords.Length; i++)
{
var keywordName = keywords[i].name;
if (NBShaderFeatureLevelCatalog.IsManagedKeyword(keywordName))
result.Add(keywordName);
}
return NBShaderBuildInfoUtility.ToCatalogOrderedManagedKeywords(result);
}
private static bool IsPassIncluded(string passName, PassType passType, NBShaderBuildInfoSet buildInfo)
{
if (buildInfo == null)
return true;
if (!string.IsNullOrEmpty(passName))
return NBShaderBuildInfoUtility.ContainsPassName(buildInfo.includedPassNames, passName);
var variants = buildInfo.variants;
for (var i = 0; i < variants.Length; i++)
{
var variant = variants[i];
if (variant != null && variant.passType == passType)
return true;
}
return false;
}
private static bool IsPassMatch(string passName, PassType passType, string targetPassName, PassType targetPassType)
{
if (!string.IsNullOrEmpty(passName) && !string.IsNullOrEmpty(targetPassName))
return string.Equals(passName, targetPassName, StringComparison.Ordinal);
return passType == targetPassType;
}
private static bool IsSameShader(Shader a, Shader b)
{
if (a == null || b == null)
return false;
return ReferenceEquals(a, b) || string.Equals(a.name, b.name, StringComparison.Ordinal);
}
}
}

View File

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

View File

@@ -0,0 +1,88 @@
using System.Collections.Generic;
using NBShader;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
internal static class NBShaderFeatureLevelMaterialApplier
{
private const string FeatureTierPropertyName = "_NBShaderFeatureTier";
public static bool Apply(Material material, NBShaderFeatureTier tier, bool writeTierProperty, bool applyResolvedState)
{
bool changed;
return Apply(material, tier, writeTierProperty, applyResolvedState, out changed);
}
public static bool Apply(
Material material,
NBShaderFeatureTier tier,
bool writeTierProperty,
bool applyResolvedState,
out bool changed)
{
changed = false;
if (!NBShaderMaterialIntentResolver.IsNBShaderMaterial(material))
return false;
if (writeTierProperty &&
material.HasProperty(FeatureTierPropertyName) &&
!Mathf.Approximately(material.GetFloat(FeatureTierPropertyName), (float)tier))
{
material.SetFloat(FeatureTierPropertyName, (float)tier);
changed = true;
}
if (!applyResolvedState)
return true;
var allowedKeywords = NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForBuildInfoNoSave(tier);
var allowedPassFeatures = NBShaderFeatureLevelProjectSettings.instance.GetAllowedPassFeatureSetForBuildInfoNoSave(tier);
var result = NBShaderMaterialIntentResolver.Resolve(material, tier, allowedKeywords, allowedPassFeatures);
changed |= ApplyResolvedIntent(material, result);
return true;
}
private static bool ApplyResolvedIntent(Material material, NBShaderMaterialIntentResult result)
{
if (material == null || result == null)
return false;
var changed = false;
var effectiveKeywords = new HashSet<string>(result.effectiveKeywords);
for (int i = 0; i < NBShaderFeatureCatalog.RawKeywords.Length; i++)
{
string keyword = NBShaderFeatureCatalog.RawKeywords[i];
changed |= SetKeyword(material, keyword, effectiveKeywords.Contains(keyword));
}
changed |= SetKeyword(material, "EVALUATE_SH_VERTEX", effectiveKeywords.Contains("_FX_LIGHT_MODE_SIX_WAY"));
for (int i = 0; i < result.passes.Length; i++)
{
NBShaderPassIntent pass = result.passes[i];
if (!string.IsNullOrEmpty(pass.passName) &&
material.GetShaderPassEnabled(pass.passName) != pass.included)
{
material.SetShaderPassEnabled(pass.passName, pass.included);
changed = true;
}
}
return changed;
}
private static bool SetKeyword(Material material, string keyword, bool enabled)
{
if (material == null || string.IsNullOrEmpty(keyword) || material.IsKeywordEnabled(keyword) == enabled)
return false;
if (enabled)
material.EnableKeyword(keyword);
else
material.DisableKeyword(keyword);
return true;
}
}
}

View File

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

View File

@@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
[CreateAssetMenu(fileName = "NBShaderDefaultFeatureLevels", menuName = "NBShader/Feature Level Preset")]
public sealed class NBShaderFeatureLevelPreset : ScriptableObject
{
[SerializeField] private NBShaderFeatureTierKeywordSet[] m_TierKeywordSets = new NBShaderFeatureTierKeywordSet[0];
[SerializeField] private NBShaderFeatureTierPassSet[] m_TierPassSets = new NBShaderFeatureTierPassSet[0];
public NBShaderFeatureTierKeywordSet[] CreateTierKeywordSets()
{
var result = new NBShaderFeatureTierKeywordSet[4];
for (var i = 0; i < result.Length; i++)
{
var tier = (NBShaderFeatureTier)i;
result[i] = new NBShaderFeatureTierKeywordSet
{
tier = tier,
allowedKeywords = GetAllowedKeywords(tier)
};
}
return result;
}
public NBShaderFeatureTierPassSet[] CreateTierPassSets()
{
var result = new NBShaderFeatureTierPassSet[4];
for (var i = 0; i < result.Length; i++)
{
var tier = (NBShaderFeatureTier)i;
result[i] = new NBShaderFeatureTierPassSet
{
tier = tier,
allowedPassFeatures = GetAllowedPassFeatures(tier)
};
}
return result;
}
public string[] GetAllowedKeywords(NBShaderFeatureTier tier)
{
if (m_TierKeywordSets == null)
return new string[0];
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
var set = m_TierKeywordSets[i];
if (set != null && set.tier == tier)
return SanitizeKeywords(set.allowedKeywords);
}
return new string[0];
}
public string[] GetAllowedPassFeatures(NBShaderFeatureTier tier)
{
if (m_TierPassSets == null || m_TierPassSets.Length == 0)
return NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier);
for (var i = 0; i < m_TierPassSets.Length; i++)
{
var set = m_TierPassSets[i];
if (set != null && set.tier == tier)
return SanitizePassFeatures(set.allowedPassFeatures);
}
return NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier);
}
public void SetTierKeywordSets(NBShaderFeatureTierKeywordSet[] tierKeywordSets)
{
m_TierKeywordSets = new NBShaderFeatureTierKeywordSet[4];
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
var tier = (NBShaderFeatureTier)i;
m_TierKeywordSets[i] = new NBShaderFeatureTierKeywordSet
{
tier = tier,
allowedKeywords = GetAllowedKeywords(tierKeywordSets, tier)
};
}
}
public void SetTierPassSets(NBShaderFeatureTierPassSet[] tierPassSets)
{
m_TierPassSets = new NBShaderFeatureTierPassSet[4];
for (var i = 0; i < m_TierPassSets.Length; i++)
{
var tier = (NBShaderFeatureTier)i;
m_TierPassSets[i] = new NBShaderFeatureTierPassSet
{
tier = tier,
allowedPassFeatures = GetAllowedPassFeatures(tierPassSets, tier)
};
}
}
private static string[] SanitizeKeywords(string[] keywords)
{
if (keywords == null || keywords.Length == 0)
return new string[0];
var allowed = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < keywords.Length; i++)
{
var keyword = keywords[i];
if (NBShaderFeatureLevelCatalog.IsManagedKeyword(keyword))
allowed.Add(keyword);
}
var result = new List<string>();
var catalog = NBShaderFeatureLevelCatalog.ManagedKeywords;
for (var i = 0; i < catalog.Length; i++)
{
if (allowed.Contains(catalog[i]))
result.Add(catalog[i]);
}
return result.ToArray();
}
private static string[] SanitizePassFeatures(string[] passFeatures)
{
if (passFeatures == null || passFeatures.Length == 0)
return new string[0];
var allowed = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < passFeatures.Length; i++)
{
var passFeature = passFeatures[i];
if (NBShaderFeatureLevelCatalog.IsManagedPassFeature(passFeature))
allowed.Add(passFeature);
}
var result = new List<string>();
var catalog = NBShaderFeatureLevelCatalog.ManagedPassFeatures;
for (var i = 0; i < catalog.Length; i++)
{
if (allowed.Contains(catalog[i]))
result.Add(catalog[i]);
}
return result.ToArray();
}
private static string[] GetAllowedKeywords(NBShaderFeatureTierKeywordSet[] sets, NBShaderFeatureTier tier)
{
if (sets == null)
return new string[0];
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return SanitizeKeywords(set.allowedKeywords);
}
return new string[0];
}
private static string[] GetAllowedPassFeatures(NBShaderFeatureTierPassSet[] sets, NBShaderFeatureTier tier)
{
if (sets == null || sets.Length == 0)
return NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier);
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return SanitizePassFeatures(set.allowedPassFeatures);
}
return NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier);
}
}
internal static class NBShaderFeatureLevelPresetLoader
{
public const string DefaultPresetAssetPath =
"Packages/com.xuanxuan.nb.fx/NBShaders2/Editor/FeatureLevel/LevelAssets/NBShaderDefaultFeatureLevels.asset";
public static NBShaderFeatureTierKeywordSet[] LoadDefaultTierKeywordSets()
{
var preset = AssetDatabase.LoadAssetAtPath<NBShaderFeatureLevelPreset>(DefaultPresetAssetPath);
if (preset != null)
return preset.CreateTierKeywordSets();
Debug.LogWarning(
"NBShader default feature level preset was not found at " +
DefaultPresetAssetPath +
". Falling back to allowing all Catalog keywords for every tier.");
return CreateAllowAllTierKeywordSets();
}
public static NBShaderFeatureTierPassSet[] LoadDefaultTierPassSets()
{
var preset = AssetDatabase.LoadAssetAtPath<NBShaderFeatureLevelPreset>(DefaultPresetAssetPath);
if (preset != null)
return preset.CreateTierPassSets();
return CreateAllowAllTierPassSets();
}
public static string[] LoadDefaultAllowedKeywords(NBShaderFeatureTier tier)
{
var sets = LoadDefaultTierKeywordSets();
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return set.allowedKeywords ?? new string[0];
}
return new string[0];
}
public static string[] LoadDefaultAllowedPassFeatures(NBShaderFeatureTier tier)
{
var sets = LoadDefaultTierPassSets();
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return set.allowedPassFeatures ?? new string[0];
}
return NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier);
}
public static bool SaveDefaultTierKeywordSets(NBShaderFeatureTierKeywordSet[] tierKeywordSets)
{
return SaveDefaultFeatureSets(tierKeywordSets, null);
}
public static bool SaveDefaultFeatureSets(
NBShaderFeatureTierKeywordSet[] tierKeywordSets,
NBShaderFeatureTierPassSet[] tierPassSets)
{
try
{
var preset = AssetDatabase.LoadAssetAtPath<NBShaderFeatureLevelPreset>(DefaultPresetAssetPath);
if (preset == null)
{
preset = ScriptableObject.CreateInstance<NBShaderFeatureLevelPreset>();
AssetDatabase.CreateAsset(preset, DefaultPresetAssetPath);
}
preset.SetTierKeywordSets(tierKeywordSets);
if (tierPassSets != null)
preset.SetTierPassSets(tierPassSets);
EditorUtility.SetDirty(preset);
AssetDatabase.SaveAssetIfDirty(preset);
AssetDatabase.ImportAsset(DefaultPresetAssetPath);
return AssetDatabase.LoadAssetAtPath<NBShaderFeatureLevelPreset>(DefaultPresetAssetPath) != null;
}
catch (Exception exception)
{
Debug.LogError("Failed to save NBShader default feature level preset: " + exception);
return false;
}
}
private static NBShaderFeatureTierKeywordSet[] CreateAllowAllTierKeywordSets()
{
var result = new NBShaderFeatureTierKeywordSet[4];
for (var i = 0; i < result.Length; i++)
{
result[i] = new NBShaderFeatureTierKeywordSet
{
tier = (NBShaderFeatureTier)i,
allowedKeywords = (string[])NBShaderFeatureLevelCatalog.ManagedKeywords.Clone()
};
}
return result;
}
private static NBShaderFeatureTierPassSet[] CreateAllowAllTierPassSets()
{
var result = new NBShaderFeatureTierPassSet[4];
for (var i = 0; i < result.Length; i++)
{
var tier = (NBShaderFeatureTier)i;
result[i] = new NBShaderFeatureTierPassSet
{
tier = tier,
allowedPassFeatures = NBShaderPassFeatureCatalog.GetDefaultAllowedPassFeatures(tier)
};
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,739 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
[FilePath("ProjectSettings/NBShaderFeatureLevels.asset", FilePathAttribute.Location.ProjectFolder)]
public sealed class NBShaderFeatureLevelProjectSettings : ScriptableSingleton<NBShaderFeatureLevelProjectSettings>
{
private static readonly string[] DefaultQualityNames = { "Default" };
[SerializeField] private NBShaderFeatureTierKeywordSet[] m_TierKeywordSets;
[SerializeField] private NBShaderFeatureTierPassSet[] m_TierPassSets;
[SerializeField] private NBShaderQualityTierMapping[] m_QualityTierMappings;
[SerializeField] private bool m_EnableDebugSymbols;
[NonSerialized] private bool m_Initialized;
[NonSerialized] private HashSet<string>[] m_AllowedKeywordSetCache;
[NonSerialized] private bool m_AllowedKeywordSetCacheValid;
[NonSerialized] private HashSet<string>[] m_AllowedPassFeatureSetCache;
[NonSerialized] private bool m_AllowedPassFeatureSetCacheValid;
public NBShaderFeatureTierKeywordSet[] tierKeywordSets { get { EnsureInitialized(); InvalidateAllowedKeywordSetCache(); return m_TierKeywordSets; } }
public NBShaderFeatureTierPassSet[] tierPassSets { get { EnsureInitialized(); InvalidateAllowedPassFeatureSetCache(); return m_TierPassSets; } }
public NBShaderQualityTierMapping[] qualityTierMappings { get { EnsureInitialized(); return m_QualityTierMappings; } }
public bool enableDebugSymbols { get { return m_EnableDebugSymbols; } }
public void EnsureInitialized()
{
if (m_Initialized &&
HasValidTierKeywordSets() &&
HasValidTierPassSets() &&
HasValidQualityMappings() &&
AreQualityMappingsCurrent())
{
return;
}
var changed = false;
if (m_TierKeywordSets == null || m_TierKeywordSets.Length != 4)
{
ResetTierKeywordSetsToDefault();
changed = true;
}
else
{
changed |= NormalizeTierKeywordSets();
}
if (m_TierPassSets == null || m_TierPassSets.Length != 4)
{
ResetTierPassSetsToDefault();
changed = true;
}
else
{
changed |= NormalizeTierPassSets();
}
if (m_QualityTierMappings == null || m_QualityTierMappings.Length == 0)
{
ResetQualityMappingsToDefault();
changed = true;
}
else
{
changed |= NormalizeQualityMappingsWithCurrentQualityLevels();
}
if (changed)
{
Save(true);
}
m_Initialized = true;
}
public void ResetTierKeywordSetsToDefault()
{
m_TierKeywordSets = NBShaderFeatureLevelPresetLoader.LoadDefaultTierKeywordSets();
InvalidateAllowedKeywordSetCache();
}
public void ResetTierPassSetsToDefault()
{
m_TierPassSets = NBShaderFeatureLevelPresetLoader.LoadDefaultTierPassSets();
InvalidateAllowedPassFeatureSetCache();
}
public void ResetQualityMappingsToDefault()
{
var names = QualitySettings.names;
if (names == null || names.Length == 0)
names = DefaultQualityNames;
m_QualityTierMappings = new NBShaderQualityTierMapping[names.Length];
for (var i = 0; i < names.Length; i++)
{
m_QualityTierMappings[i] = new NBShaderQualityTierMapping
{
qualityName = names[i],
tier = GuessTierForQualityIndex(i, names.Length)
};
}
}
public HashSet<string> GetAllowedKeywordSet(NBShaderFeatureTier tier)
{
return new HashSet<string>(GetAllowedKeywordSetForReadOnlyUse(tier), StringComparer.Ordinal);
}
public HashSet<string> GetAllowedPassFeatureSet(NBShaderFeatureTier tier)
{
return new HashSet<string>(GetAllowedPassFeatureSetForReadOnlyUse(tier), StringComparer.Ordinal);
}
public bool IsKeywordAllowed(NBShaderFeatureTier tier, string keyword)
{
return GetAllowedKeywordSetForReadOnlyUse(tier).Contains(keyword);
}
public bool IsPassFeatureAllowed(NBShaderFeatureTier tier, string passFeatureId)
{
return GetAllowedPassFeatureSetForReadOnlyUse(tier).Contains(passFeatureId);
}
internal HashSet<string> GetAllowedKeywordSetForReadOnlyUse(NBShaderFeatureTier tier)
{
EnsureInitialized();
EnsureAllowedKeywordSetCache();
return m_AllowedKeywordSetCache[ToTierIndex(tier)];
}
internal HashSet<string> GetAllowedPassFeatureSetForReadOnlyUse(NBShaderFeatureTier tier)
{
EnsureInitialized();
EnsureAllowedPassFeatureSetCache();
return m_AllowedPassFeatureSetCache[ToTierIndex(tier)];
}
internal HashSet<string> GetAllowedKeywordSetForBuildInfoNoSave(NBShaderFeatureTier tier)
{
var existing = FindTierKeywordSet(tier);
if (existing != null && existing.allowedKeywords != null)
return BuildSanitizedAllowedSet(existing.allowedKeywords);
return BuildSanitizedAllowedSet(NBShaderFeatureLevelCatalog.ManagedKeywords);
}
internal HashSet<string> GetAllowedPassFeatureSetForBuildInfoNoSave(NBShaderFeatureTier tier)
{
var existing = FindTierPassSet(tier);
if (existing != null && existing.allowedPassFeatures != null)
return BuildSanitizedAllowedPassFeatureSet(existing.allowedPassFeatures);
return BuildSanitizedAllowedPassFeatureSet(NBShaderFeatureLevelCatalog.ManagedPassFeatures);
}
public void SetKeywordAllowed(NBShaderFeatureTier tier, string keyword, bool allowed)
{
EnsureInitialized();
if (!NBShaderFeatureLevelCatalog.IsManagedKeyword(keyword))
return;
NBShaderFeatureTierKeywordSet target = null;
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
if (m_TierKeywordSets[i] != null && m_TierKeywordSets[i].tier == tier)
{
target = m_TierKeywordSets[i];
break;
}
}
if (target == null)
{
target = new NBShaderFeatureTierKeywordSet { tier = tier };
var index = (int)tier;
if (index >= 0 && index < m_TierKeywordSets.Length)
m_TierKeywordSets[index] = target;
}
var keywords = BuildSanitizedAllowedSet(target.allowedKeywords);
if (allowed)
keywords.Add(keyword);
else
keywords.Remove(keyword);
target.allowedKeywords = ToCatalogOrderedArray(keywords);
InvalidateAllowedKeywordSetCache();
}
public void SetPassFeatureAllowed(NBShaderFeatureTier tier, string passFeatureId, bool allowed)
{
EnsureInitialized();
if (!NBShaderFeatureLevelCatalog.IsManagedPassFeature(passFeatureId))
return;
NBShaderFeatureTierPassSet target = null;
for (var i = 0; i < m_TierPassSets.Length; i++)
{
if (m_TierPassSets[i] != null && m_TierPassSets[i].tier == tier)
{
target = m_TierPassSets[i];
break;
}
}
if (target == null)
{
target = new NBShaderFeatureTierPassSet { tier = tier };
var index = (int)tier;
if (index >= 0 && index < m_TierPassSets.Length)
m_TierPassSets[index] = target;
}
var passFeatures = BuildSanitizedAllowedPassFeatureSet(target.allowedPassFeatures);
if (allowed)
passFeatures.Add(passFeatureId);
else
passFeatures.Remove(passFeatureId);
target.allowedPassFeatures = ToCatalogOrderedPassFeatureArray(passFeatures);
InvalidateAllowedPassFeatureSetCache();
}
public bool TryGetTierForQualityName(string qualityName, out NBShaderFeatureTier tier)
{
EnsureInitialized();
tier = NBShaderFeatureTier.Ultra;
return TryGetTierForQualityNameNoSave(qualityName, out tier);
}
internal bool TryGetTierForQualityNameNoSave(string qualityName, out NBShaderFeatureTier tier)
{
tier = NBShaderFeatureTier.Ultra;
if (string.IsNullOrEmpty(qualityName))
return false;
if (m_QualityTierMappings != null)
{
for (var i = 0; i < m_QualityTierMappings.Length; i++)
{
var mapping = m_QualityTierMappings[i];
if (mapping == null || !string.Equals(mapping.qualityName, qualityName, StringComparison.Ordinal))
continue;
tier = mapping.tier;
return true;
}
}
var names = QualitySettings.names;
if (names == null || names.Length == 0)
names = DefaultQualityNames;
for (var i = 0; i < names.Length; i++)
{
if (!string.Equals(names[i], qualityName, StringComparison.Ordinal))
continue;
tier = GuessTierForQualityIndex(i, names.Length);
return true;
}
return false;
}
public string[] GetQualityNamesForTier(NBShaderFeatureTier tier)
{
EnsureInitialized();
if (m_QualityTierMappings == null || m_QualityTierMappings.Length == 0)
return new string[0];
var names = new List<string>();
for (var i = 0; i < m_QualityTierMappings.Length; i++)
{
var mapping = m_QualityTierMappings[i];
if (mapping != null && mapping.tier == tier && !string.IsNullOrEmpty(mapping.qualityName))
names.Add(mapping.qualityName);
}
return names.ToArray();
}
public void MoveQualityToTier(string qualityName, NBShaderFeatureTier tier)
{
EnsureInitialized();
if (string.IsNullOrEmpty(qualityName))
return;
for (var i = 0; i < m_QualityTierMappings.Length; i++)
{
var mapping = m_QualityTierMappings[i];
if (mapping == null || !string.Equals(mapping.qualityName, qualityName, StringComparison.Ordinal))
continue;
mapping.tier = tier;
return;
}
var newMappings = new NBShaderQualityTierMapping[m_QualityTierMappings.Length + 1];
Array.Copy(m_QualityTierMappings, newMappings, m_QualityTierMappings.Length);
newMappings[newMappings.Length - 1] = new NBShaderQualityTierMapping
{
qualityName = qualityName,
tier = tier
};
m_QualityTierMappings = newMappings;
}
public void SaveProjectSettings()
{
EnsureInitialized();
Save(true);
}
public void SetDebugSymbolsEnabled(bool enabled)
{
m_EnableDebugSymbols = enabled;
}
public void SaveDebugSymbolsProjectSettings()
{
Save(true);
}
private static NBShaderFeatureTier GuessTierForQualityIndex(int index, int count)
{
if (count <= 1)
return NBShaderFeatureTier.Ultra;
var normalized = index / (float)(count - 1);
if (normalized < 0.25f) return NBShaderFeatureTier.Low;
if (normalized < 0.50f) return NBShaderFeatureTier.Medium;
if (normalized < 0.75f) return NBShaderFeatureTier.High;
return NBShaderFeatureTier.Ultra;
}
private bool NormalizeTierKeywordSets()
{
var changed = false;
NBShaderFeatureTierKeywordSet[] defaults = null;
var normalized = new NBShaderFeatureTierKeywordSet[4];
for (var tierIndex = 0; tierIndex < normalized.Length; tierIndex++)
{
var tier = (NBShaderFeatureTier)tierIndex;
var existing = FindTierKeywordSet(tier);
if (existing == null)
{
if (defaults == null)
defaults = NBShaderFeatureLevelPresetLoader.LoadDefaultTierKeywordSets();
changed = true;
}
normalized[tierIndex] = new NBShaderFeatureTierKeywordSet
{
tier = tier,
allowedKeywords = existing != null
? ToCatalogOrderedArray(BuildSanitizedAllowedSet(existing.allowedKeywords))
: GetAllowedKeywords(defaults, tier)
};
if (existing != null && !AreKeywordArraysEquivalent(existing.allowedKeywords, normalized[tierIndex].allowedKeywords))
changed = true;
}
m_TierKeywordSets = normalized;
if (changed)
InvalidateAllowedKeywordSetCache();
return changed;
}
private bool NormalizeTierPassSets()
{
var changed = false;
NBShaderFeatureTierPassSet[] defaults = null;
var normalized = new NBShaderFeatureTierPassSet[4];
for (var tierIndex = 0; tierIndex < normalized.Length; tierIndex++)
{
var tier = (NBShaderFeatureTier)tierIndex;
var existing = FindTierPassSet(tier);
if (existing == null)
{
if (defaults == null)
defaults = NBShaderFeatureLevelPresetLoader.LoadDefaultTierPassSets();
changed = true;
}
normalized[tierIndex] = new NBShaderFeatureTierPassSet
{
tier = tier,
allowedPassFeatures = existing != null
? ToCatalogOrderedPassFeatureArray(BuildSanitizedAllowedPassFeatureSet(existing.allowedPassFeatures))
: GetAllowedPassFeatures(defaults, tier)
};
if (existing != null && !ArePassFeatureArraysEquivalent(existing.allowedPassFeatures, normalized[tierIndex].allowedPassFeatures))
changed = true;
}
m_TierPassSets = normalized;
if (changed)
InvalidateAllowedPassFeatureSetCache();
return changed;
}
private bool HasValidTierKeywordSets()
{
if (m_TierKeywordSets == null || m_TierKeywordSets.Length != 4)
return false;
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
var set = m_TierKeywordSets[i];
if (set == null || set.tier != (NBShaderFeatureTier)i || set.allowedKeywords == null)
return false;
}
return true;
}
private bool HasValidTierPassSets()
{
if (m_TierPassSets == null || m_TierPassSets.Length != 4)
return false;
for (var i = 0; i < m_TierPassSets.Length; i++)
{
var set = m_TierPassSets[i];
if (set == null || set.tier != (NBShaderFeatureTier)i || set.allowedPassFeatures == null)
return false;
}
return true;
}
private bool HasValidQualityMappings()
{
return m_QualityTierMappings != null && m_QualityTierMappings.Length > 0;
}
private bool AreQualityMappingsCurrent()
{
var names = QualitySettings.names;
if (names == null || names.Length == 0)
names = DefaultQualityNames;
if (m_QualityTierMappings == null || m_QualityTierMappings.Length != names.Length)
return false;
for (var i = 0; i < names.Length; i++)
{
var mapping = m_QualityTierMappings[i];
if (mapping == null || !string.Equals(mapping.qualityName, names[i], StringComparison.Ordinal))
return false;
}
return true;
}
private void EnsureAllowedKeywordSetCache()
{
if (m_AllowedKeywordSetCacheValid &&
m_AllowedKeywordSetCache != null &&
m_AllowedKeywordSetCache.Length == 4)
{
return;
}
if (m_AllowedKeywordSetCache == null || m_AllowedKeywordSetCache.Length != 4)
m_AllowedKeywordSetCache = new HashSet<string>[4];
for (var i = 0; i < m_AllowedKeywordSetCache.Length; i++)
m_AllowedKeywordSetCache[i] = BuildAllowedKeywordSet((NBShaderFeatureTier)i);
m_AllowedKeywordSetCacheValid = true;
}
private void EnsureAllowedPassFeatureSetCache()
{
if (m_AllowedPassFeatureSetCacheValid &&
m_AllowedPassFeatureSetCache != null &&
m_AllowedPassFeatureSetCache.Length == 4)
{
return;
}
if (m_AllowedPassFeatureSetCache == null || m_AllowedPassFeatureSetCache.Length != 4)
m_AllowedPassFeatureSetCache = new HashSet<string>[4];
for (var i = 0; i < m_AllowedPassFeatureSetCache.Length; i++)
m_AllowedPassFeatureSetCache[i] = BuildAllowedPassFeatureSet((NBShaderFeatureTier)i);
m_AllowedPassFeatureSetCacheValid = true;
}
private void InvalidateAllowedKeywordSetCache()
{
m_AllowedKeywordSetCacheValid = false;
}
private void InvalidateAllowedPassFeatureSetCache()
{
m_AllowedPassFeatureSetCacheValid = false;
}
private HashSet<string> BuildAllowedKeywordSet(NBShaderFeatureTier tier)
{
var result = new HashSet<string>(StringComparer.Ordinal);
if (m_TierKeywordSets == null)
return result;
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
var set = m_TierKeywordSets[i];
if (set == null || set.tier != tier || set.allowedKeywords == null)
continue;
for (var k = 0; k < set.allowedKeywords.Length; k++)
{
var keyword = set.allowedKeywords[k];
if (NBShaderFeatureLevelCatalog.IsManagedKeyword(keyword))
result.Add(keyword);
}
}
return result;
}
private HashSet<string> BuildAllowedPassFeatureSet(NBShaderFeatureTier tier)
{
var result = new HashSet<string>(StringComparer.Ordinal);
if (m_TierPassSets == null)
return result;
for (var i = 0; i < m_TierPassSets.Length; i++)
{
var set = m_TierPassSets[i];
if (set == null || set.tier != tier || set.allowedPassFeatures == null)
continue;
for (var k = 0; k < set.allowedPassFeatures.Length; k++)
{
var passFeature = set.allowedPassFeatures[k];
if (NBShaderFeatureLevelCatalog.IsManagedPassFeature(passFeature))
result.Add(passFeature);
}
}
return result;
}
private static int ToTierIndex(NBShaderFeatureTier tier)
{
var index = (int)tier;
return index >= 0 && index < 4 ? index : (int)NBShaderFeatureTier.Ultra;
}
private NBShaderFeatureTierKeywordSet FindTierKeywordSet(NBShaderFeatureTier tier)
{
if (m_TierKeywordSets == null)
return null;
for (var i = 0; i < m_TierKeywordSets.Length; i++)
{
var set = m_TierKeywordSets[i];
if (set != null && set.tier == tier)
return set;
}
return null;
}
private NBShaderFeatureTierPassSet FindTierPassSet(NBShaderFeatureTier tier)
{
if (m_TierPassSets == null)
return null;
for (var i = 0; i < m_TierPassSets.Length; i++)
{
var set = m_TierPassSets[i];
if (set != null && set.tier == tier)
return set;
}
return null;
}
private bool NormalizeQualityMappingsWithCurrentQualityLevels()
{
var names = QualitySettings.names;
if (names == null || names.Length == 0)
names = DefaultQualityNames;
var previous = new Dictionary<string, NBShaderFeatureTier>(StringComparer.Ordinal);
if (m_QualityTierMappings != null)
{
for (var i = 0; i < m_QualityTierMappings.Length; i++)
{
var mapping = m_QualityTierMappings[i];
if (mapping == null || string.IsNullOrEmpty(mapping.qualityName) || previous.ContainsKey(mapping.qualityName))
continue;
previous.Add(mapping.qualityName, mapping.tier);
}
}
var changed = m_QualityTierMappings == null || m_QualityTierMappings.Length != names.Length;
m_QualityTierMappings = new NBShaderQualityTierMapping[names.Length];
for (var i = 0; i < names.Length; i++)
{
NBShaderFeatureTier tier;
if (!previous.TryGetValue(names[i], out tier))
{
tier = GuessTierForQualityIndex(i, names.Length);
changed = true;
}
m_QualityTierMappings[i] = new NBShaderQualityTierMapping
{
qualityName = names[i],
tier = tier
};
}
return changed;
}
private static HashSet<string> BuildSanitizedAllowedSet(string[] keywords)
{
var result = new HashSet<string>(StringComparer.Ordinal);
if (keywords == null)
return result;
for (var i = 0; i < keywords.Length; i++)
{
var keyword = keywords[i];
if (NBShaderFeatureLevelCatalog.IsManagedKeyword(keyword))
result.Add(keyword);
}
return result;
}
private static HashSet<string> BuildSanitizedAllowedPassFeatureSet(string[] passFeatures)
{
var result = new HashSet<string>(StringComparer.Ordinal);
if (passFeatures == null)
return result;
for (var i = 0; i < passFeatures.Length; i++)
{
var passFeature = passFeatures[i];
if (NBShaderFeatureLevelCatalog.IsManagedPassFeature(passFeature))
result.Add(passFeature);
}
return result;
}
private static string[] ToCatalogOrderedArray(HashSet<string> keywords)
{
if (keywords == null || keywords.Count == 0)
return new string[0];
var result = new List<string>();
var catalog = NBShaderFeatureLevelCatalog.ManagedKeywords;
for (var i = 0; i < catalog.Length; i++)
{
if (keywords.Contains(catalog[i]))
result.Add(catalog[i]);
}
return result.ToArray();
}
private static string[] ToCatalogOrderedPassFeatureArray(HashSet<string> passFeatures)
{
if (passFeatures == null || passFeatures.Count == 0)
return new string[0];
var result = new List<string>();
var catalog = NBShaderFeatureLevelCatalog.ManagedPassFeatures;
for (var i = 0; i < catalog.Length; i++)
{
if (passFeatures.Contains(catalog[i]))
result.Add(catalog[i]);
}
return result.ToArray();
}
private static string[] GetAllowedKeywords(NBShaderFeatureTierKeywordSet[] sets, NBShaderFeatureTier tier)
{
if (sets == null)
return new string[0];
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return set.allowedKeywords ?? new string[0];
}
return new string[0];
}
private static string[] GetAllowedPassFeatures(NBShaderFeatureTierPassSet[] sets, NBShaderFeatureTier tier)
{
if (sets == null)
return new string[0];
for (var i = 0; i < sets.Length; i++)
{
var set = sets[i];
if (set != null && set.tier == tier)
return set.allowedPassFeatures ?? new string[0];
}
return new string[0];
}
private static bool AreKeywordArraysEquivalent(string[] a, string[] b)
{
var setA = BuildSanitizedAllowedSet(a);
var setB = BuildSanitizedAllowedSet(b);
return setA.SetEquals(setB);
}
private static bool ArePassFeatureArraysEquivalent(string[] a, string[] b)
{
var setA = BuildSanitizedAllowedPassFeatureSet(a);
var setB = BuildSanitizedAllowedPassFeatureSet(b);
return setA.SetEquals(setB);
}
}
}

View File

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

View File

@@ -0,0 +1,247 @@
using System.Collections.Generic;
using NBShader;
namespace NBShaders2.Editor.FeatureLevel
{
internal enum NBShaderFeatureLevelRowKind
{
Group,
Keyword,
Pass
}
internal enum NBShaderFeaturePerformanceCost
{
Low,
Medium,
High,
Ultra
}
internal sealed class NBShaderFeatureLevelRow
{
public readonly NBShaderFeatureLevelRowKind kind;
public readonly string key;
public readonly string parentKey;
public readonly string keyword;
public readonly string passFeatureId;
public readonly string labelFallback;
public readonly NBShaderFeaturePerformanceCost performanceCost;
public readonly string effectFallback;
public readonly int depth;
public NBShaderFeatureLevelRow(
NBShaderFeatureLevelRowKind kind,
string key,
string parentKey,
string keyword,
string passFeatureId,
string labelFallback,
NBShaderFeaturePerformanceCost performanceCost,
string effectFallback,
int depth)
{
this.kind = kind;
this.key = key;
this.parentKey = parentKey;
this.keyword = keyword;
this.passFeatureId = passFeatureId;
this.labelFallback = labelFallback;
this.performanceCost = performanceCost;
this.effectFallback = effectFallback;
this.depth = depth;
}
public bool isKeyword
{
get { return kind == NBShaderFeatureLevelRowKind.Keyword; }
}
public bool isPass
{
get { return kind == NBShaderFeatureLevelRowKind.Pass; }
}
}
internal static class NBShaderFeatureLevelRowCatalog
{
public static readonly NBShaderFeatureLevelRow[] Rows =
{
Group("mode", null, "Mode", 0),
Group("transparent", "mode", "Transparent Mode", 1),
Keyword("_ALPHATEST_ON", "transparent", "Alpha Test", 2, NBShaderFeaturePerformanceCost.Medium, "Cuts pixels by alpha threshold."),
Keyword("_ALPHAPREMULTIPLY_ON", "transparent", "Premultiply Alpha", 2, NBShaderFeaturePerformanceCost.Low, "Uses premultiplied alpha blending."),
Keyword("_ALPHAMODULATE_ON", "transparent", "Alpha Modulate", 2, NBShaderFeaturePerformanceCost.Low, "Uses alpha modulation transparent blending."),
Group("time", "mode", "Time Mode", 1),
Keyword("_UNSCALETIME", "time", "Unscaled Time", 2, NBShaderFeaturePerformanceCost.Low, "Uses unscaled time."),
Keyword("_SCRIPTABLETIME", "time", "Scriptable Time", 2, NBShaderFeaturePerformanceCost.Low, "Uses script provided time value."),
Group("base", null, "Base", 0),
Keyword("_DISTANCE_FADE", "base", "Distance Fade", 1, NBShaderFeaturePerformanceCost.Low, "Fades material by camera distance."),
Keyword("_SOFTPARTICLES_ON", "base", "Soft Particles", 1, NBShaderFeaturePerformanceCost.High, "Softens particles using scene depth."),
Keyword("_STENCIL_WITHOUT_PLAYER", "base", "Stencil Without Player", 1, NBShaderFeaturePerformanceCost.Low, "Uses stencil without player mask."),
Group("particle", "base", "Particle Data", 1),
Keyword("_PARCUSTOMDATA_ON", "particle", "Particle Custom Data", 2, NBShaderFeaturePerformanceCost.Low, "Reads particle custom data channels."),
Group("light", null, "Lighting", 0),
Group("lightMode", "light", "Light Mode", 1),
Keyword("_FX_LIGHT_MODE_UNLIT", "lightMode", "Unlit Lighting", 2, NBShaderFeaturePerformanceCost.Low, "Uses unlit shading."),
Keyword("_FX_LIGHT_MODE_BLINN_PHONG", "lightMode", "Blinn-Phong Lighting", 2, NBShaderFeaturePerformanceCost.Medium, "Uses Blinn Phong lighting."),
Keyword("_FX_LIGHT_MODE_HALF_LAMBERT", "lightMode", "Half Lambert Lighting", 2, NBShaderFeaturePerformanceCost.Medium, "Uses half Lambert lighting."),
Keyword("_FX_LIGHT_MODE_PBR", "lightMode", "PBR Lighting", 2, NBShaderFeaturePerformanceCost.High, "Uses PBR lighting calculations."),
Keyword("_FX_LIGHT_MODE_SIX_WAY", "lightMode", "Six Way Lighting", 2, NBShaderFeaturePerformanceCost.Ultra, "Uses six way lighting data."),
Keyword("_SPECULAR_COLOR", "light", "Specular Color", 1, NBShaderFeaturePerformanceCost.Medium, "Adds specular color highlight."),
Keyword("_NORMALMAP", "light", "Normal Map", 1, NBShaderFeaturePerformanceCost.High, "Uses normal map lighting detail."),
Keyword("_MATCAP", "light", "MatCap", 1, NBShaderFeaturePerformanceCost.Medium, "Adds matcap lighting texture."),
Keyword("VFX_SIX_WAY_ABSORPTION", "light", "Six Way Absorption", 1, NBShaderFeaturePerformanceCost.High, "Adds absorption response for six way lighting."),
Group("feature", null, "Feature", 0),
Keyword("_MASKMAP_ON", "feature", "Mask Map", 1, NBShaderFeaturePerformanceCost.Medium, "Uses the first mask map."),
Keyword("_MASKMAP2_ON", "_MASKMAP_ON", "Mask Map 2", 2, NBShaderFeaturePerformanceCost.Medium, "Uses the second mask map."),
Keyword("_MASKMAP3_ON", "_MASKMAP_ON", "Mask Map 3", 2, NBShaderFeaturePerformanceCost.Medium, "Uses the third mask map."),
Keyword("NB_DEBUG_MASK", "_MASKMAP_ON", "Debug Mask", 2, NBShaderFeaturePerformanceCost.Low, "Shows mask values for debugging."),
Keyword("_NOISEMAP", "feature", "Noise Map", 1, NBShaderFeaturePerformanceCost.High, "Uses a noise map for distortion."),
Keyword("_NOISE_MASKMAP", "_NOISEMAP", "Noise Mask Map", 2, NBShaderFeaturePerformanceCost.Medium, "Masks the distortion effect."),
Keyword("NB_DEBUG_DISTORT", "_NOISEMAP", "Debug Distort", 2, NBShaderFeaturePerformanceCost.Low, "Shows distortion strength for debugging."),
Keyword("_SCREEN_DISTORT_MODE", "_NOISEMAP", "Screen Distort", 2, NBShaderFeaturePerformanceCost.Ultra, "Samples screen texture for distortion."),
Keyword("_DISTORT_REFRACTION", "_NOISEMAP", "Distort Refraction", 2, NBShaderFeaturePerformanceCost.High, "Uses refraction style distortion."),
Keyword("_CHROMATIC_ABERRATION", "feature", "Chromatic Aberration", 1, NBShaderFeaturePerformanceCost.High, "Splits color channels for distortion fringe."),
Keyword("_EMISSION", "feature", "Emission", 1, NBShaderFeaturePerformanceCost.Medium, "Adds emissive color or texture contribution."),
Keyword("_COLORMAPBLEND", "feature", "Color Map Blend", 1, NBShaderFeaturePerformanceCost.Medium, "Blends an extra color gradient texture."),
Keyword("_COLOR_RAMP", "feature", "Color Ramp", 1, NBShaderFeaturePerformanceCost.Medium, "Remaps color through a ramp."),
Keyword("_COLOR_RAMP_MAP", "_COLOR_RAMP", "Color Ramp Map", 2, NBShaderFeaturePerformanceCost.Medium, "Uses a texture as the color ramp source."),
Keyword("_DISSOLVE", "feature", "Dissolve", 1, NBShaderFeaturePerformanceCost.High, "Clips and blends pixels for dissolve."),
Keyword("_DISSOLVE_MASK", "_DISSOLVE", "Dissolve Mask", 2, NBShaderFeaturePerformanceCost.High, "Uses a process mask for dissolve."),
Keyword("_DISSOLVE_RAMP", "_DISSOLVE", "Dissolve Ramp", 2, NBShaderFeaturePerformanceCost.Medium, "Adds ramp coloring to dissolve edges."),
Keyword("_DISSOLVE_RAMP_MAP", "_DISSOLVE_RAMP", "Dissolve Ramp Map", 3, NBShaderFeaturePerformanceCost.Medium, "Uses a texture for dissolve ramp color."),
Keyword("NB_DEBUG_DISSOLVE", "_DISSOLVE", "Debug Dissolve", 2, NBShaderFeaturePerformanceCost.Low, "Shows dissolve values for debugging."),
Keyword("_PROGRAM_NOISE", "feature", "Program Noise", 1, NBShaderFeaturePerformanceCost.High, "Generates procedural noise in shader."),
Keyword("_PROGRAM_NOISE_SIMPLE", "_PROGRAM_NOISE", "Program Noise Simple", 2, NBShaderFeaturePerformanceCost.High, "Enables simple procedural noise."),
Keyword("_PROGRAM_NOISE_VORONOI", "_PROGRAM_NOISE", "Program Noise Voronoi", 2, NBShaderFeaturePerformanceCost.High, "Enables Voronoi procedural noise."),
Keyword("NB_DEBUG_PNOISE", "_PROGRAM_NOISE", "Debug Program Noise", 2, NBShaderFeaturePerformanceCost.Low, "Shows procedural noise values for debugging."),
Keyword("_SHARED_UV", "feature", "Shared UV", 1, NBShaderFeaturePerformanceCost.Low, "Shares a common UV transform."),
Keyword("_FRESNEL", "feature", "Fresnel", 1, NBShaderFeaturePerformanceCost.Medium, "Adds view angle based rim lighting."),
Keyword("NB_DEBUG_FRESNEL", "_FRESNEL", "Debug Fresnel", 2, NBShaderFeaturePerformanceCost.Low, "Shows fresnel values for debugging."),
Keyword("_VERTEX_OFFSET", "feature", "Vertex Offset", 1, NBShaderFeaturePerformanceCost.High, "Offsets vertices in the shader."),
Keyword("_VERTEX_OFFSET_MASKMAP", "_VERTEX_OFFSET", "Vertex Offset Mask Map", 2, NBShaderFeaturePerformanceCost.High, "Masks vertex offset by texture."),
Keyword("NB_DEBUG_VERTEX_OFFSET", "_VERTEX_OFFSET", "Debug Vertex Offset", 2, NBShaderFeaturePerformanceCost.Low, "Shows vertex offset values for debugging."),
Group("depth", "feature", "Depth", 1),
Keyword("_DEPTH_DECAL", "depth", "Depth Decal", 2, NBShaderFeaturePerformanceCost.High, "Projects decal effect using scene depth."),
Keyword("_DEPTH_OUTLINE", "depth", "Depth Outline", 2, NBShaderFeaturePerformanceCost.High, "Creates outline effect using depth difference."),
Keyword("_OVERRIDE_Z", "depth", "Override Z", 2, NBShaderFeaturePerformanceCost.Medium, "Writes a fixed camera eye depth through SV_Depth."),
Keyword("_PARALLAX_MAPPING", "feature", "Parallax Mapping", 1, NBShaderFeaturePerformanceCost.High, "Offsets UVs for parallax depth."),
Keyword("_FLIPBOOKBLENDING_ON", "feature", "Flipbook Blending", 1, NBShaderFeaturePerformanceCost.Medium, "Blends between flipbook frames."),
Keyword("_VAT", "feature", "VAT", 1, NBShaderFeaturePerformanceCost.Ultra, "Enables vertex animation texture playback."),
Group("vatMode", "_VAT", "VAT Mode", 2),
Keyword("_VAT_HOUDINI", "vatMode", "Houdini VAT", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses Houdini VAT data layout."),
Keyword("_VAT_TYFLOW", "vatMode", "TyFlow VAT", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow VAT data layout."),
Group("houdiniVat", "_VAT", "Houdini VAT", 2),
Keyword("_HOUDINI_VAT_SOFTBODY", "houdiniVat", "Houdini VAT Soft Body", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses Houdini soft body VAT mode."),
Keyword("_HOUDINI_VAT_RIGIDBODY", "houdiniVat", "Houdini VAT Rigid Body", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses Houdini rigid body VAT mode."),
Keyword("_HOUDINI_VAT_DYNAMIC_REMESH", "houdiniVat", "Houdini VAT Dynamic Remesh", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses Houdini dynamic remesh VAT mode."),
Keyword("_HOUDINI_VAT_PARTICLE_SPRITE", "houdiniVat", "Houdini VAT Particle Sprite", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses Houdini particle sprite VAT mode."),
Group("tyflowVat", "_VAT", "TyFlow VAT", 2),
Keyword("_TYFLOW_VAT_ABSOLUTE", "tyflowVat", "TyFlow VAT Absolute", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow absolute VAT mode."),
Keyword("_TYFLOW_VAT_RELATIVE", "tyflowVat", "TyFlow VAT Relative", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow relative VAT mode."),
Keyword("_TYFLOW_VAT_SKIN_R", "tyflowVat", "TyFlow VAT Skin R", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow skin R VAT mode."),
Keyword("_TYFLOW_VAT_SKIN_PR", "tyflowVat", "TyFlow VAT Skin PR", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow skin PR VAT mode."),
Keyword("_TYFLOW_VAT_SKIN_PRSAVE", "tyflowVat", "TyFlow VAT Skin PR Save", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow skin PR save VAT mode."),
Keyword("_TYFLOW_VAT_SKIN_PRSXYZ", "tyflowVat", "TyFlow VAT Skin PRSXYZ", 3, NBShaderFeaturePerformanceCost.Ultra, "Uses TyFlow skin PRSXYZ VAT mode."),
Group("passes", null, "Passes", 0),
Pass(NBShaderPassFeatureCatalog.BackFirstPassId, "passes", "Back First Pass", 1, NBShaderFeaturePerformanceCost.Medium, "Renders the optional back-face pre-pass."),
Pass(NBShaderPassFeatureCatalog.CameraOpaqueDistortPassId, "passes", "Camera Opaque Distort Pass", 1, NBShaderFeaturePerformanceCost.Ultra, "Renders the camera opaque texture screen distort pass."),
Pass(NBShaderPassFeatureCatalog.DeferredDistortPassId, "passes", "Deferred Distort Pass", 1, NBShaderFeaturePerformanceCost.Ultra, "Renders the deferred screen distort pass."),
Pass(NBShaderPassFeatureCatalog.DepthOnlyPassId, "passes", "Depth Only Pass", 1, NBShaderFeaturePerformanceCost.Medium, "Writes material depth for URP depth prepass usage."),
Pass(NBShaderPassFeatureCatalog.ShadowCasterPassId, "passes", "Shadow Caster Pass", 1, NBShaderFeaturePerformanceCost.High, "Renders the material into shadow maps."),
Pass(NBShaderPassFeatureCatalog.Universal2DPassId, "passes", "Universal 2D Pass", 1, NBShaderFeaturePerformanceCost.Medium, "Allows the material to render through URP 2D renderer.")
};
private static readonly HashSet<string> ParentKeys = BuildParentKeys();
private static readonly Dictionary<string, NBShaderFeatureLevelRow> RowsByKey = BuildRowsByKey();
public static bool HasChildren(NBShaderFeatureLevelRow row)
{
return row != null && ParentKeys.Contains(row.key);
}
public static bool TryGetRow(string key, out NBShaderFeatureLevelRow row)
{
return RowsByKey.TryGetValue(key, out row);
}
private static NBShaderFeatureLevelRow Group(string key, string parentKey, string labelFallback, int depth)
{
return new NBShaderFeatureLevelRow(
NBShaderFeatureLevelRowKind.Group,
key,
parentKey,
null,
null,
labelFallback,
NBShaderFeaturePerformanceCost.Low,
null,
depth);
}
private static NBShaderFeatureLevelRow Keyword(
string keyword,
string parentKey,
string labelFallback,
int depth,
NBShaderFeaturePerformanceCost performanceCost,
string effectFallback)
{
return new NBShaderFeatureLevelRow(
NBShaderFeatureLevelRowKind.Keyword,
keyword,
parentKey,
keyword,
null,
labelFallback,
performanceCost,
effectFallback,
depth);
}
private static NBShaderFeatureLevelRow Pass(
string passFeatureId,
string parentKey,
string labelFallback,
int depth,
NBShaderFeaturePerformanceCost performanceCost,
string effectFallback)
{
return new NBShaderFeatureLevelRow(
NBShaderFeatureLevelRowKind.Pass,
passFeatureId,
parentKey,
null,
passFeatureId,
labelFallback,
performanceCost,
effectFallback,
depth);
}
private static HashSet<string> BuildParentKeys()
{
var result = new HashSet<string>();
for (var i = 0; i < Rows.Length; i++)
{
if (!string.IsNullOrEmpty(Rows[i].parentKey))
result.Add(Rows[i].parentKey);
}
return result;
}
private static Dictionary<string, NBShaderFeatureLevelRow> BuildRowsByKey()
{
var result = new Dictionary<string, NBShaderFeatureLevelRow>();
for (var i = 0; i < Rows.Length; i++)
result[Rows[i].key] = Rows[i];
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,881 @@
using System;
using System.Collections.Generic;
using System.Text;
using NBShader;
using NBShaderEditor;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
[InitializeOnLoad]
public static class NBShaderFeatureLevelSettingsProvider
{
internal const string SettingsPath = NBFXProjectSettings.SettingsPath;
private const float FeatureColumnWidth = 240f;
private const float TierColumnWidth = 92f;
private const float CostColumnWidth = 84f;
private const float EffectColumnWidth = 280f;
private const float DescriptionColumnWidth = 230f;
private const float RowHeight = 22f;
private const float HeaderHeight = 24f;
private const float TableMinHeight = 360f;
private const float TableMaxHeight = 640f;
private const float TableWidth = FeatureColumnWidth + TierColumnWidth * 4f + CostColumnWidth + EffectColumnWidth + DescriptionColumnWidth;
private const float RowIndentWidth = 14f;
private const string FoldoutSessionPrefix = "NBShaderFeatureLevelSettingsProvider.Foldout.";
private sealed class RowContentCache
{
public GUIContent rowContent;
public GUIContent effectContent;
public GUIContent descriptionContent;
}
private static readonly NBShaderFeatureTier[] Tiers =
{
NBShaderFeatureTier.Low,
NBShaderFeatureTier.Medium,
NBShaderFeatureTier.High,
NBShaderFeatureTier.Ultra
};
private static readonly Dictionary<string, RowContentCache> s_RowContentCache =
new Dictionary<string, RowContentCache>(StringComparer.Ordinal);
private static readonly Dictionary<NBShaderFeaturePerformanceCost, GUIContent> s_CostContentCache =
new Dictionary<NBShaderFeaturePerformanceCost, GUIContent>();
private static readonly GUIContent[] s_QualitySummaryContents = new GUIContent[Tiers.Length];
private static readonly string[] s_QualitySummaryTexts = new string[Tiers.Length];
private static readonly StringBuilder s_QualitySummaryBuilder = new StringBuilder(128);
private static Vector2 s_TableScrollPosition;
private static string s_ContentCacheLanguage;
private static GUIContent s_ProviderLabelContent;
private static GUIContent s_QualityDescriptionContent;
private static GUIContent s_NoValueContent;
private static string s_QualityMenuTipText;
private static int s_QualitySummaryHash;
static NBShaderFeatureLevelSettingsProvider()
{
NBFXProjectSettings.RegisterSettingsSection(
"NBShaderFeatureLevels",
GetProviderLabelContent,
OnGUI,
new[]
{
"NBShader",
"Feature",
"Tier",
"Strip",
"Keyword",
"Quality",
"Apply",
"Material",
"Loaded Materials",
"Project Materials",
"应用",
"材质",
"等级",
"分级",
"剔除"
},
100);
}
private static void OnGUI(string searchContext)
{
EnsureContentCacheForCurrentLanguage();
var settings = NBShaderFeatureLevelProjectSettings.instance;
settings.EnsureInitialized();
var changed = false;
EditorGUILayout.HelpBox(
Text(
"featureLevel.help.message",
"Configure NBShader managed Catalog keywords and shader passes per tier, and bind Unity Quality levels. Build scripts select the build stripping tier through NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier. Runtime settings assets can be updated from their own Inspector or Editor API. Catalog-external features are ignored."),
MessageType.Info);
changed |= DrawFeatureLevelTable(settings);
EditorGUILayout.Space();
changed |= DrawButtons(settings);
if (changed)
settings.SaveProjectSettings();
}
private static bool DrawFeatureLevelTable(NBShaderFeatureLevelProjectSettings settings)
{
var changed = false;
EditorGUILayout.LabelField(
Text("featureLevel.table.title", "Feature Level Matrix"),
EditorStyles.boldLabel);
s_TableScrollPosition = EditorGUILayout.BeginScrollView(
s_TableScrollPosition,
true,
true,
GUILayout.MinHeight(TableMinHeight),
GUILayout.MaxHeight(TableMaxHeight));
using (new GUILayout.VerticalScope(GUILayout.Width(TableWidth)))
{
DrawTableHeader();
DrawQualityBindingRow(settings);
DrawTableSeparator();
changed |= DrawFeatureRows(settings);
}
EditorGUILayout.EndScrollView();
return changed;
}
private static void DrawTableHeader()
{
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar, GUILayout.Height(HeaderHeight)))
{
DrawHeaderCell(
Content(
"featureLevel.column.feature",
"Config / Feature",
"Tier settings and managed Catalog features."),
FeatureColumnWidth);
for (var i = 0; i < Tiers.Length; i++)
DrawHeaderCell(GetTierContent(Tiers[i]), TierColumnWidth);
DrawHeaderCell(
Content(
"featureLevel.column.cost",
"Performance Cost",
"Estimated shader cost when this feature is enabled."),
CostColumnWidth);
DrawHeaderCell(
Content(
"featureLevel.column.effect",
"Feature Effect",
"Short description of what this keyword enables."),
EffectColumnWidth);
DrawHeaderCell(
Content(
"featureLevel.column.description",
"Raw Keyword / Note",
"Raw shader keyword or configuration note."),
DescriptionColumnWidth);
}
}
private static void DrawHeaderCell(GUIContent content, float width)
{
GUILayout.Label(content, EditorStyles.toolbarButton, GUILayout.Width(width), GUILayout.Height(HeaderHeight));
}
private static void DrawQualityBindingRow(NBShaderFeatureLevelProjectSettings settings)
{
using (new EditorGUILayout.HorizontalScope(GUILayout.Height(RowHeight)))
{
GUILayout.Label(
Content(
"featureLevel.row.quality",
"Quality Binding",
"Each Unity Quality Level belongs to exactly one NBShader tier."),
GUILayout.Width(FeatureColumnWidth),
GUILayout.Height(RowHeight));
for (var i = 0; i < Tiers.Length; i++)
{
var tier = Tiers[i];
if (GUILayout.Button(
GetQualitySummaryContent(settings, tier, i),
EditorStyles.popup,
GUILayout.Width(TierColumnWidth),
GUILayout.Height(RowHeight)))
{
ShowQualityBindingMenu(settings, tier);
}
}
DrawCostPlaceholderCell();
DrawInfoCell(
Content(
"featureLevel.effect.quality",
"Bind Unity Quality Levels to NBShader tiers.",
"Each Unity Quality Level belongs to exactly one NBShader tier."),
EffectColumnWidth);
DrawInfoCell(
GetQualityDescriptionContent(),
DescriptionColumnWidth);
}
}
private static bool DrawFeatureRows(NBShaderFeatureLevelProjectSettings settings)
{
var changed = false;
var rows = NBShaderFeatureLevelRowCatalog.Rows;
var allowedKeywordSets = new HashSet<string>[Tiers.Length];
var allowedPassFeatureSets = new HashSet<string>[Tiers.Length];
for (var i = 0; i < Tiers.Length; i++)
{
allowedKeywordSets[i] = settings.GetAllowedKeywordSetForReadOnlyUse(Tiers[i]);
allowedPassFeatureSets[i] = settings.GetAllowedPassFeatureSetForReadOnlyUse(Tiers[i]);
}
for (var rowIndex = 0; rowIndex < rows.Length; rowIndex++)
{
var row = rows[rowIndex];
if (!IsRowVisible(row))
continue;
using (var rowScope = new EditorGUILayout.HorizontalScope(GUILayout.Height(RowHeight)))
{
DrawFeatureRowBackground(rowScope.rect, row);
DrawFeatureNameCell(row);
if (row.isKeyword)
{
for (var tierIndex = 0; tierIndex < Tiers.Length; tierIndex++)
{
var tier = Tiers[tierIndex];
var isAllowed = allowedKeywordSets[tierIndex].Contains(row.keyword);
var newAllowed = DrawCellToggle(isAllowed, GUI.skin.toggle);
if (newAllowed == isAllowed)
continue;
Undo.RecordObject(settings, Text("featureLevel.undo.changeKeyword", "Change NBShader Feature Keyword"));
settings.SetKeywordAllowed(tier, row.keyword, newAllowed);
if (newAllowed)
allowedKeywordSets[tierIndex].Add(row.keyword);
else
allowedKeywordSets[tierIndex].Remove(row.keyword);
changed = true;
}
}
else if (row.isPass)
{
for (var tierIndex = 0; tierIndex < Tiers.Length; tierIndex++)
{
var tier = Tiers[tierIndex];
var isAllowed = allowedPassFeatureSets[tierIndex].Contains(row.passFeatureId);
var newAllowed = DrawCellToggle(isAllowed, GUI.skin.toggle);
if (newAllowed == isAllowed)
continue;
Undo.RecordObject(settings, Text("featureLevel.undo.changePassFeature", "Change NBShader Pass Feature"));
settings.SetPassFeatureAllowed(tier, row.passFeatureId, newAllowed);
if (newAllowed)
allowedPassFeatureSets[tierIndex].Add(row.passFeatureId);
else
allowedPassFeatureSets[tierIndex].Remove(row.passFeatureId);
changed = true;
}
}
else
{
DrawEmptyTierCells();
}
DrawCostCell(row);
DrawInfoCell(GetEffectContent(row), EffectColumnWidth);
DrawInfoCell(
GetDescriptionContent(row),
DescriptionColumnWidth,
row.isKeyword ? EditorStyles.miniLabel : EditorStyles.centeredGreyMiniLabel);
}
}
return changed;
}
private static void DrawFeatureNameCell(NBShaderFeatureLevelRow row)
{
var rect = EditorGUILayout.GetControlRect(
false,
RowHeight,
GUILayout.Width(FeatureColumnWidth),
GUILayout.Height(RowHeight));
var hasChildren = NBShaderFeatureLevelRowCatalog.HasChildren(row);
var indent = row.depth * RowIndentWidth;
var foldoutRect = new Rect(rect.x + indent, rect.y, 14f, rect.height);
var labelRect = new Rect(
rect.x + indent + (hasChildren ? 15f : 18f),
rect.y,
Mathf.Max(0f, rect.width - indent - 18f),
rect.height);
if (hasChildren)
{
var expanded = IsExpanded(row.key);
var newExpanded = EditorGUI.Foldout(foldoutRect, expanded, GUIContent.none, true);
if (newExpanded != expanded)
SetExpanded(row.key, newExpanded);
}
var style = hasChildren ? EditorStyles.boldLabel : EditorStyles.label;
EditorGUI.LabelField(labelRect, GetRowContent(row), style);
}
private static void DrawFeatureRowBackground(Rect rowRect, NBShaderFeatureLevelRow row)
{
if (!IsSectionRow(row) || Event.current.type != EventType.Repaint)
return;
rowRect.width = TableWidth;
EditorGUI.DrawRect(rowRect, new Color(0f, 0f, 0f, EditorGUIUtility.isProSkin ? 0.22f : 0.08f));
}
private static bool IsSectionRow(NBShaderFeatureLevelRow row)
{
return row != null &&
row.kind == NBShaderFeatureLevelRowKind.Group &&
string.IsNullOrEmpty(row.parentKey);
}
private static void DrawEmptyTierCells()
{
for (var i = 0; i < Tiers.Length; i++)
GUILayout.Space(TierColumnWidth);
}
private static void DrawCostCell(NBShaderFeatureLevelRow row)
{
if (row != null && (row.isKeyword || row.isPass))
{
DrawInfoCell(GetCostContent(row.performanceCost), CostColumnWidth, EditorStyles.centeredGreyMiniLabel);
return;
}
DrawCostPlaceholderCell();
}
private static void DrawCostPlaceholderCell()
{
DrawInfoCell(GetNoValueContent(), CostColumnWidth, EditorStyles.centeredGreyMiniLabel);
}
private static void DrawInfoCell(GUIContent content, float width, GUIStyle style = null)
{
GUILayout.Label(
content,
style ?? EditorStyles.miniLabel,
GUILayout.Width(width),
GUILayout.Height(RowHeight));
}
private static bool DrawButtons(NBShaderFeatureLevelProjectSettings settings)
{
var changed = false;
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(ButtonContent(
"featureLevel.resetTierKeywords",
"Reset Tier Features",
"Reset the keyword and pass matrix to the built-in defaults.")))
{
Undo.RecordObject(settings, Text("featureLevel.undo.resetTierKeywords", "Reset NBShader Tier Features"));
settings.ResetTierKeywordSetsToDefault();
settings.ResetTierPassSetsToDefault();
changed = true;
}
if (GUILayout.Button(ButtonContent(
"featureLevel.resetQualityMapping",
"Reset Quality Mapping",
"Reset Unity Quality bindings using the default quality-index rule.")))
{
Undo.RecordObject(settings, Text("featureLevel.undo.resetQualityMapping", "Reset NBShader Quality Mapping"));
settings.ResetQualityMappingsToDefault();
changed = true;
}
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(ButtonContent(
"featureLevel.openVariantCollectionBuilder",
"Open Variant Collection Builder",
"Open the NBShader variant collection builder.")))
{
NBShaderSVCBuilderWindow.Open();
}
if (GUILayout.Button(ButtonContent(
"featureLevel.saveCurrentAsDefault",
"Save Current Config as Default",
"Write the current tier keyword and pass matrix into the package default LevelAsset.")))
{
if (!NBShaderFeatureLevelPresetLoader.SaveDefaultFeatureSets(settings.tierKeywordSets, settings.tierPassSets))
{
EditorUtility.DisplayDialog(
Text("featureLevel.saveCurrentAsDefault.failedTitle", "Save Default Config Failed"),
Text("featureLevel.saveCurrentAsDefault.failedMessage", "Could not write the package default LevelAsset."),
Text("featureLevel.dialog.ok", "OK"));
}
}
}
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(ButtonContent(
"featureLevel.applyCurrentQualityTierToLoadedMaterials",
"Apply Current Quality Tier To Loaded Materials",
"Apply the tier bound to the current Unity Quality Level to all loaded NBShader2 materials.")))
{
NBShaderEditorQualityTierWatcher.ApplyCurrentQualityTierToLoadedMaterials();
}
if (GUILayout.Button(ButtonContent(
"featureLevel.applyCurrentQualityTierToProjectMaterials",
"Apply Current Quality Tier To Project Materials",
"Scan Assets and apply the tier bound to the current Unity Quality Level to NBShader2 material assets.")))
{
NBShaderEditorQualityTierWatcher.ApplyCurrentQualityTierToProjectMaterials();
}
}
return changed;
}
private static void ShowQualityBindingMenu(NBShaderFeatureLevelProjectSettings settings, NBShaderFeatureTier targetTier)
{
var menu = new GenericMenu();
var mappings = settings.qualityTierMappings;
if (mappings == null || mappings.Length == 0)
{
menu.AddDisabledItem(new GUIContent(Text("featureLevel.quality.noLevels", "No Quality Levels")));
menu.ShowAsContext();
return;
}
for (var i = 0; i < mappings.Length; i++)
{
var mapping = mappings[i];
if (mapping == null || string.IsNullOrEmpty(mapping.qualityName))
continue;
var qualityName = mapping.qualityName;
NBShaderFeatureTier currentTier;
var isCurrentTier = settings.TryGetTierForQualityName(qualityName, out currentTier) && currentTier == targetTier;
if (isCurrentTier)
{
menu.AddDisabledItem(new GUIContent("✓ " + qualityName));
continue;
}
menu.AddItem(new GUIContent(qualityName), false, () =>
{
Undo.RecordObject(settings, Text("featureLevel.undo.changeQualityBinding", "Change NBShader Quality Binding"));
settings.MoveQualityToTier(qualityName, targetTier);
settings.SaveProjectSettings();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
});
}
menu.ShowAsContext();
}
private static bool DrawCellToggle(bool value, GUIStyle style)
{
bool result;
using (new GUILayout.HorizontalScope(GUILayout.Width(TierColumnWidth), GUILayout.Height(RowHeight)))
{
GUILayout.FlexibleSpace();
result = GUILayout.Toggle(
value,
GUIContent.none,
style,
GUILayout.Width(18f),
GUILayout.Height(RowHeight));
GUILayout.FlexibleSpace();
}
return result;
}
private static void DrawTableSeparator()
{
var rect = EditorGUILayout.GetControlRect(false, 1f, GUILayout.Width(TableWidth));
EditorGUI.DrawRect(rect, new Color(0f, 0f, 0f, 0.25f));
}
private static bool IsRowVisible(NBShaderFeatureLevelRow row)
{
var parentKey = row.parentKey;
while (!string.IsNullOrEmpty(parentKey))
{
if (!IsExpanded(parentKey))
return false;
NBShaderFeatureLevelRow parent;
parentKey = NBShaderFeatureLevelRowCatalog.TryGetRow(parentKey, out parent) ? parent.parentKey : null;
}
return true;
}
private static bool IsExpanded(string key)
{
return SessionState.GetBool(FoldoutSessionPrefix + key, true);
}
private static void SetExpanded(string key, bool expanded)
{
SessionState.SetBool(FoldoutSessionPrefix + key, expanded);
}
private static GUIContent GetTierContent(NBShaderFeatureTier tier)
{
switch (tier)
{
case NBShaderFeatureTier.Low:
return NBShaderInspectorLocalization.MakeContent(
"inspector.toolbar.tierLow.label",
"Low",
"inspector.toolbar.tier.tip",
"NBShader feature tier");
case NBShaderFeatureTier.Medium:
return NBShaderInspectorLocalization.MakeContent(
"inspector.toolbar.tierMedium.label",
"Medium",
"inspector.toolbar.tier.tip",
"NBShader feature tier");
case NBShaderFeatureTier.High:
return NBShaderInspectorLocalization.MakeContent(
"inspector.toolbar.tierHigh.label",
"High",
"inspector.toolbar.tier.tip",
"NBShader feature tier");
default:
return NBShaderInspectorLocalization.MakeContent(
"inspector.toolbar.tierUltra.label",
"Ultra",
"inspector.toolbar.tier.tip",
"NBShader feature tier");
}
}
private static GUIContent GetRowContent(NBShaderFeatureLevelRow row)
{
return GetCachedRowContent(row).rowContent;
}
private static GUIContent BuildRowContent(NBShaderFeatureLevelRow row)
{
if (row.isKeyword)
return BuildKeywordContent(row.keyword, row.labelFallback);
if (row.isPass)
return BuildPassContent(row.passFeatureId, row.labelFallback);
return NBShaderInspectorLocalization.MakeContent(
"inspector.featureLevel.group." + row.key + ".label",
row.labelFallback,
"inspector.featureLevel.group." + row.key + ".tip",
Text("featureLevel.group.tooltip", "Click the foldout to show or hide child rows."));
}
private static GUIContent BuildKeywordContent(string keyword, string fallback)
{
var label = NBShaderInspectorLocalization.Get(
"inspector.featureLevel.keyword." + keyword + ".label",
string.IsNullOrEmpty(fallback) ? keyword : fallback);
var tooltipFormat = Text(
"featureLevel.keyword.tooltip",
"Raw keyword: {0}. Unchecked in a tier strips variants using this Catalog keyword.");
return new GUIContent(label, string.Format(tooltipFormat, keyword));
}
private static GUIContent BuildPassContent(string passFeatureId, string fallback)
{
string passName;
string displayName;
if (!NBShaderFeatureLevelCatalog.TryGetManagedPassFeatureInfo(passFeatureId, out passName, out displayName))
{
passName = passFeatureId;
displayName = string.IsNullOrEmpty(fallback) ? passFeatureId : fallback;
}
var label = NBShaderInspectorLocalization.Get(
"inspector.featureLevel.pass." + passFeatureId + ".label",
string.IsNullOrEmpty(fallback) ? displayName : fallback);
var tooltipFormat = Text(
"featureLevel.pass.tooltip",
"Shader pass: {0}. Unchecked in a tier strips or gates this pass when material intent requires it.");
return new GUIContent(label, string.Format(tooltipFormat, passName));
}
private static GUIContent GetCostContent(NBShaderFeaturePerformanceCost cost)
{
GUIContent content;
if (s_CostContentCache.TryGetValue(cost, out content))
return content;
string key;
string fallback;
switch (cost)
{
case NBShaderFeaturePerformanceCost.Low:
key = "featureLevel.cost.low";
fallback = "Low";
break;
case NBShaderFeaturePerformanceCost.Medium:
key = "featureLevel.cost.medium";
fallback = "Medium";
break;
case NBShaderFeaturePerformanceCost.High:
key = "featureLevel.cost.high";
fallback = "High";
break;
default:
key = "featureLevel.cost.ultra";
fallback = "Ultra";
break;
}
content = new GUIContent(
Text(key, fallback),
Text("featureLevel.cost.tooltip", "Estimated shader performance cost for this feature."));
s_CostContentCache[cost] = content;
return content;
}
private static GUIContent GetEffectContent(NBShaderFeatureLevelRow row)
{
return GetCachedRowContent(row).effectContent;
}
private static GUIContent BuildEffectContent(NBShaderFeatureLevelRow row)
{
if (row.isKeyword)
{
var effect = NBShaderInspectorLocalization.Get(
"inspector.featureLevel.keyword." + row.keyword + ".effect",
string.IsNullOrEmpty(row.effectFallback) ? row.keyword : row.effectFallback);
return new GUIContent(effect, effect);
}
if (row.isPass)
{
var effect = NBShaderInspectorLocalization.Get(
"inspector.featureLevel.pass." + row.passFeatureId + ".effect",
string.IsNullOrEmpty(row.effectFallback) ? row.passFeatureId : row.effectFallback);
return new GUIContent(effect, effect);
}
var groupTip = NBShaderInspectorLocalization.GetTooltip(
"inspector.featureLevel.group." + row.key + ".label",
"inspector.featureLevel.group." + row.key + ".tip",
Text("featureLevel.group.tooltip", "Click the foldout to show or hide child rows."));
return new GUIContent(groupTip, groupTip);
}
private static GUIContent GetDescriptionContent(NBShaderFeatureLevelRow row)
{
return GetCachedRowContent(row).descriptionContent;
}
private static GUIContent BuildDescriptionContent(NBShaderFeatureLevelRow row)
{
if (row.isKeyword)
return new GUIContent(row.keyword, row.keyword);
if (row.isPass)
{
string passName;
string displayName;
if (NBShaderFeatureLevelCatalog.TryGetManagedPassFeatureInfo(row.passFeatureId, out passName, out displayName))
return new GUIContent(passName, row.passFeatureId);
return new GUIContent(row.passFeatureId, row.passFeatureId);
}
return new GUIContent(
Text("featureLevel.desc.group", "Group"),
Text("featureLevel.group.tooltip", "Click the foldout to show or hide child rows."));
}
private static GUIContent GetNoValueContent()
{
if (s_NoValueContent != null)
return s_NoValueContent;
var text = Text("featureLevel.desc.none", "—");
s_NoValueContent = new GUIContent(text, text);
return s_NoValueContent;
}
private static GUIContent GetProviderLabelContent()
{
EnsureContentCacheForCurrentLanguage();
if (s_ProviderLabelContent == null)
s_ProviderLabelContent = new GUIContent(Text("featureLevel.providerLabel", "NBShader Feature Levels"));
return s_ProviderLabelContent;
}
private static GUIContent GetQualityDescriptionContent()
{
if (s_QualityDescriptionContent == null)
{
var text = Text("featureLevel.desc.quality", "Unity Quality Level");
s_QualityDescriptionContent = new GUIContent(text, text);
}
return s_QualityDescriptionContent;
}
private static GUIContent GetQualitySummaryContent(
NBShaderFeatureLevelProjectSettings settings,
NBShaderFeatureTier tier,
int tierIndex)
{
EnsureQualitySummaryCache(settings);
var content = s_QualitySummaryContents[tierIndex];
if (content == null)
{
content = new GUIContent();
s_QualitySummaryContents[tierIndex] = content;
}
content.text = s_QualitySummaryTexts[tierIndex];
content.tooltip = GetQualityMenuTipText();
return content;
}
private static void EnsureQualitySummaryCache(NBShaderFeatureLevelProjectSettings settings)
{
var mappings = settings.qualityTierMappings;
var hash = GetQualitySummaryHash(mappings);
if (s_QualitySummaryTexts[0] != null && s_QualitySummaryHash == hash)
return;
s_QualitySummaryHash = hash;
var noneText = Text("featureLevel.quality.none", "—");
for (var tierIndex = 0; tierIndex < Tiers.Length; tierIndex++)
{
s_QualitySummaryBuilder.Length = 0;
if (mappings != null)
{
var tier = Tiers[tierIndex];
for (var i = 0; i < mappings.Length; i++)
{
var mapping = mappings[i];
if (mapping == null ||
mapping.tier != tier ||
string.IsNullOrEmpty(mapping.qualityName))
{
continue;
}
if (s_QualitySummaryBuilder.Length > 0)
s_QualitySummaryBuilder.Append(", ");
s_QualitySummaryBuilder.Append(mapping.qualityName);
}
}
s_QualitySummaryTexts[tierIndex] =
s_QualitySummaryBuilder.Length == 0
? noneText
: s_QualitySummaryBuilder.ToString();
}
s_QualitySummaryBuilder.Length = 0;
}
private static int GetQualitySummaryHash(NBShaderQualityTierMapping[] mappings)
{
unchecked
{
var hash = 17;
if (mappings == null)
return hash;
for (var i = 0; i < mappings.Length; i++)
{
var mapping = mappings[i];
hash = hash * 31 + (mapping != null ? (int)mapping.tier : -1);
hash = hash * 31 + (mapping != null && mapping.qualityName != null
? StringComparer.Ordinal.GetHashCode(mapping.qualityName)
: 0);
}
return hash;
}
}
private static string GetQualityMenuTipText()
{
if (s_QualityMenuTipText == null)
{
s_QualityMenuTipText = Text(
"featureLevel.quality.menuTip",
"Click to move Unity Quality levels to this NBShader tier.");
}
return s_QualityMenuTipText;
}
private static RowContentCache GetCachedRowContent(NBShaderFeatureLevelRow row)
{
RowContentCache cache;
if (!s_RowContentCache.TryGetValue(row.key, out cache))
{
cache = new RowContentCache
{
rowContent = BuildRowContent(row),
effectContent = BuildEffectContent(row),
descriptionContent = BuildDescriptionContent(row)
};
s_RowContentCache.Add(row.key, cache);
}
return cache;
}
private static void EnsureContentCacheForCurrentLanguage()
{
var language = NBShaderInspectorLocalization.CurrentLanguage;
if (string.Equals(s_ContentCacheLanguage, language, StringComparison.Ordinal))
return;
s_ContentCacheLanguage = language;
s_RowContentCache.Clear();
s_CostContentCache.Clear();
s_ProviderLabelContent = null;
s_QualityDescriptionContent = null;
s_NoValueContent = null;
s_QualityMenuTipText = null;
s_QualitySummaryHash = 0;
for (var i = 0; i < s_QualitySummaryContents.Length; i++)
{
s_QualitySummaryContents[i] = null;
s_QualitySummaryTexts[i] = null;
}
}
private static GUIContent Content(string key, string fallback, string tip = "")
{
return NBShaderInspectorLocalization.MakeInspectorContent(key, fallback, tip);
}
private static GUIContent ButtonContent(string key, string fallback, string tip = "")
{
return NBShaderInspectorLocalization.MakeContent("inspector." + key + ".button", fallback, null, tip);
}
private static string Text(string key, string fallback)
{
return NBShaderInspectorLocalization.GetInspectorText(key, fallback);
}
}
}

View File

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

View File

@@ -0,0 +1,26 @@
using System;
using NBShader;
namespace NBShaders2.Editor.FeatureLevel
{
[Serializable]
public sealed class NBShaderFeatureTierKeywordSet
{
public NBShaderFeatureTier tier;
public string[] allowedKeywords = new string[0];
}
[Serializable]
public sealed class NBShaderFeatureTierPassSet
{
public NBShaderFeatureTier tier;
public string[] allowedPassFeatures = new string[0];
}
[Serializable]
public sealed class NBShaderQualityTierMapping
{
public string qualityName;
public NBShaderFeatureTier tier;
}
}

View File

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

View File

@@ -0,0 +1,58 @@
using NBShader;
using NBShaderEditor;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
[CustomEditor(typeof(NBShaderFeatureRuntimeSettings))]
public sealed class NBShaderFeatureRuntimeSettingsEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
DrawSyncButton();
EditorGUILayout.Space();
DrawDefaultInspector();
}
private void DrawSyncButton()
{
var settings = (NBShaderFeatureRuntimeSettings)target;
using (new EditorGUI.DisabledScope(settings == null))
{
if (!GUILayout.Button(ButtonContent(
"featureRuntimeSettings.updateFromProjectSettings",
"根据当前ProjectSetting更新配置",
"Write the current NBShader Project Settings data into this runtime settings asset.")))
{
return;
}
}
Undo.RecordObject(
settings,
Text(
"featureRuntimeSettings.updateFromProjectSettings.undo",
"Update NBShader Runtime Settings From Project Settings"));
if (NBShaderRuntimeSettingsSynchronizer.WriteProjectSettingsToRuntimeAsset(settings))
{
EditorUtility.DisplayDialog(
Text("featureRuntimeSettings.updateFromProjectSettings.successTitle", "Runtime Settings Updated"),
Text("featureRuntimeSettings.updateFromProjectSettings.successMessage", "The current NBShader Project Settings data was written to this runtime settings asset."),
Text("featureLevel.dialog.ok", "OK"));
}
}
private static GUIContent ButtonContent(string key, string fallback, string tip)
{
return NBShaderInspectorLocalization.MakeInspectorContent(key + ".button", fallback, tip);
}
private static string Text(string key, string fallback)
{
return NBShaderInspectorLocalization.GetInspectorText(key, fallback);
}
}
}

View File

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

View File

@@ -0,0 +1,241 @@
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
public static class NBShaderRuntimeSettingsSynchronizer
{
public const string DefaultGeneratedRuntimeSettingsAssetPath =
"Assets/NBShaderGenerated/RuntimeSettings/NBShaderFeatureRuntimeSettings.asset";
private static bool s_DefaultGeneratedRuntimeSettingsWarningLogged;
public static bool WriteProjectSettingsToRuntimeAsset(NBShaderFeatureRuntimeSettings asset)
{
if (asset == null)
{
Debug.LogWarning("NBShader runtime settings asset is null. Pass an explicit NBShaderFeatureRuntimeSettings asset before writing.");
return false;
}
var settings = NBShaderFeatureLevelProjectSettings.instance;
settings.EnsureInitialized();
ApplyProjectSettingsToRuntimeObject(asset, settings);
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssetIfDirty(asset);
return true;
}
public static bool WriteProjectSettingsSnapshotToRuntimeAssetNoSave(NBShaderFeatureRuntimeSettings asset)
{
if (asset == null)
{
Debug.LogWarning("NBShader runtime settings asset is null. Pass an explicit NBShaderFeatureRuntimeSettings asset before writing.");
return false;
}
ApplyProjectSettingsSnapshotToRuntimeObjectNoSave(asset, NBShaderFeatureLevelProjectSettings.instance);
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssetIfDirty(asset);
return true;
}
public static NBShaderFeatureRuntimeSettings WriteDefaultGeneratedRuntimeSettingsAsset(out string assetPath)
{
assetPath = DefaultGeneratedRuntimeSettingsAssetPath;
LogDefaultGeneratedRuntimeSettingsWarningOnce(assetPath);
var asset = LoadOrCreateRuntimeSettingsAsset(assetPath);
if (asset == null)
return null;
return WriteProjectSettingsToRuntimeAsset(asset) ? asset : null;
}
public static NBShaderFeatureRuntimeSettings WriteRuntimeSettingsAssetOrDefault(
NBShaderFeatureRuntimeSettings explicitAsset,
out string assetPath)
{
if (explicitAsset == null)
return WriteDefaultGeneratedRuntimeSettingsAsset(out assetPath);
assetPath = AssetDatabase.GetAssetPath(explicitAsset);
return WriteProjectSettingsToRuntimeAsset(explicitAsset) ? explicitAsset : null;
}
private static void ApplyProjectSettingsToRuntimeObject(
NBShaderFeatureRuntimeSettings asset,
NBShaderFeatureLevelProjectSettings settings)
{
asset.lowAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSet(NBShaderFeatureTier.Low));
asset.mediumAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSet(NBShaderFeatureTier.Medium));
asset.highAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSet(NBShaderFeatureTier.High));
asset.ultraAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSet(NBShaderFeatureTier.Ultra));
asset.lowAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSet(NBShaderFeatureTier.Low));
asset.mediumAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSet(NBShaderFeatureTier.Medium));
asset.highAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSet(NBShaderFeatureTier.High));
asset.ultraAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSet(NBShaderFeatureTier.Ultra));
asset.qualityTierMappings = ConvertQualityMappings(settings.qualityTierMappings);
}
private static void ApplyProjectSettingsSnapshotToRuntimeObjectNoSave(
NBShaderFeatureRuntimeSettings asset,
NBShaderFeatureLevelProjectSettings settings)
{
asset.lowAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSetForBuildInfoNoSave(NBShaderFeatureTier.Low));
asset.mediumAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSetForBuildInfoNoSave(NBShaderFeatureTier.Medium));
asset.highAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSetForBuildInfoNoSave(NBShaderFeatureTier.High));
asset.ultraAllowedKeywords = ToCatalogOrderedKeywords(settings.GetAllowedKeywordSetForBuildInfoNoSave(NBShaderFeatureTier.Ultra));
asset.lowAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSetForBuildInfoNoSave(NBShaderFeatureTier.Low));
asset.mediumAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSetForBuildInfoNoSave(NBShaderFeatureTier.Medium));
asset.highAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSetForBuildInfoNoSave(NBShaderFeatureTier.High));
asset.ultraAllowedPassFeatures = ToCatalogOrderedPassFeatures(settings.GetAllowedPassFeatureSetForBuildInfoNoSave(NBShaderFeatureTier.Ultra));
asset.qualityTierMappings = ConvertQualityMappingsNoSave(settings);
}
private static NBShaderFeatureRuntimeSettings.QualityTierMapping[] ConvertQualityMappings(NBShaderQualityTierMapping[] source)
{
if (source == null || source.Length == 0)
return new NBShaderFeatureRuntimeSettings.QualityTierMapping[0];
var result = new NBShaderFeatureRuntimeSettings.QualityTierMapping[source.Length];
for (var i = 0; i < source.Length; i++)
{
var item = source[i];
result[i] = new NBShaderFeatureRuntimeSettings.QualityTierMapping
{
qualityName = item != null ? item.qualityName : string.Empty,
tier = item != null ? item.tier : NBShaderFeatureTier.Ultra
};
}
return result;
}
private static NBShaderFeatureRuntimeSettings.QualityTierMapping[] ConvertQualityMappingsNoSave(NBShaderFeatureLevelProjectSettings settings)
{
var qualityNames = QualitySettings.names;
if (qualityNames == null || qualityNames.Length == 0)
qualityNames = new[] { "Default" };
var result = new NBShaderFeatureRuntimeSettings.QualityTierMapping[qualityNames.Length];
for (var i = 0; i < qualityNames.Length; i++)
{
var qualityName = qualityNames[i];
NBShaderFeatureTier tier;
if (!settings.TryGetTierForQualityNameNoSave(qualityName, out tier))
tier = NBShaderFeatureTier.Ultra;
result[i] = new NBShaderFeatureRuntimeSettings.QualityTierMapping
{
qualityName = qualityName,
tier = tier
};
}
return result;
}
private static string[] ToCatalogOrderedKeywords(HashSet<string> allowed)
{
return ToCatalogOrderedArray(allowed, NBShaderFeatureCatalog.RawKeywords);
}
private static string[] ToCatalogOrderedPassFeatures(HashSet<string> allowed)
{
return ToCatalogOrderedArray(allowed, NBShaderPassFeatureCatalog.RawPassFeatureIds);
}
private static string[] ToCatalogOrderedArray(HashSet<string> allowed, string[] catalogOrder)
{
if (allowed == null || catalogOrder == null)
return new string[0];
var result = new List<string>();
for (var i = 0; i < catalogOrder.Length; i++)
{
var value = catalogOrder[i];
if (allowed.Contains(value))
result.Add(value);
}
return result.ToArray();
}
private static NBShaderFeatureRuntimeSettings LoadOrCreateRuntimeSettingsAsset(string assetPath)
{
var existing = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
if (existing == null)
{
if (!EnsureAssetFolder(assetPath))
return null;
var asset = ScriptableObject.CreateInstance<NBShaderFeatureRuntimeSettings>();
AssetDatabase.CreateAsset(asset, assetPath);
return asset;
}
var runtimeSettings = existing as NBShaderFeatureRuntimeSettings;
if (runtimeSettings != null)
return runtimeSettings;
Debug.LogError("NBShader default runtime settings output path is occupied by another asset type: " + assetPath);
return null;
}
private static bool EnsureAssetFolder(string assetPath)
{
var slashIndex = assetPath.LastIndexOf('/');
if (slashIndex <= 0)
return true;
var folderPath = assetPath.Substring(0, slashIndex);
var parts = folderPath.Split('/');
if (parts.Length == 0 || parts[0] != "Assets")
{
Debug.LogError("NBShader default runtime settings asset path must be under Assets: " + assetPath);
return false;
}
var current = "Assets";
for (var i = 1; i < parts.Length; i++)
{
var part = parts[i];
if (string.IsNullOrEmpty(part))
continue;
var next = current + "/" + part;
if (!AssetDatabase.IsValidFolder(next))
AssetDatabase.CreateFolder(current, part);
if (!AssetDatabase.IsValidFolder(next))
{
Debug.LogError("Failed to create NBShader runtime settings folder: " + next);
return false;
}
current = next;
}
return true;
}
private static void LogDefaultGeneratedRuntimeSettingsWarningOnce(string assetPath)
{
if (s_DefaultGeneratedRuntimeSettingsWarningLogged)
return;
s_DefaultGeneratedRuntimeSettingsWarningLogged = true;
Debug.LogWarning(
"NBShader runtime settings asset was not explicitly specified. Generated one from current Project Settings at " +
assetPath +
". Include this asset in the player, Addressables, Resources, or shader AssetBundle before runtime code passes it to NBShaderFeatureRuntime.ApplyTier.");
}
}
}

View File

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

View File

@@ -0,0 +1,290 @@
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor.FeatureLevel
{
internal sealed class NBShaderSVCBuilderWindow : EditorWindow
{
[SerializeField] private List<string> m_SearchFolders = new List<string>();
[SerializeField] private string m_OutputFolder = NBShaderVariantCollectionBuilder.DefaultOutputFolder;
[SerializeField] private int m_TierMask = AllTierMask;
private Vector2 m_Scroll;
private NBShaderVariantCollectionTierResult[] m_Previews = new NBShaderVariantCollectionTierResult[0];
private string m_Status = string.Empty;
private const int AllTierMask =
(1 << (int)NBShaderFeatureTier.Low) |
(1 << (int)NBShaderFeatureTier.Medium) |
(1 << (int)NBShaderFeatureTier.High) |
(1 << (int)NBShaderFeatureTier.Ultra);
private static readonly NBShaderFeatureTier[] Tiers =
{
NBShaderFeatureTier.Low,
NBShaderFeatureTier.Medium,
NBShaderFeatureTier.High,
NBShaderFeatureTier.Ultra
};
internal static void Open()
{
var window = GetWindow<NBShaderSVCBuilderWindow>("NBShader Variant Collection Builder");
window.minSize = new Vector2(620f, 420f);
window.Show();
}
private void OnEnable()
{
if (m_SearchFolders == null)
m_SearchFolders = new List<string>();
if (m_SearchFolders.Count == 0)
m_SearchFolders.Add("Assets");
if (string.IsNullOrEmpty(m_OutputFolder))
m_OutputFolder = NBShaderVariantCollectionBuilder.DefaultOutputFolder;
if (m_TierMask == 0)
m_TierMask = AllTierMask;
}
private void OnGUI()
{
m_Scroll = EditorGUILayout.BeginScrollView(m_Scroll);
DrawSearchFolders();
EditorGUILayout.Space(8f);
DrawOutputFolder();
EditorGUILayout.Space(8f);
DrawTierSelection();
EditorGUILayout.Space(8f);
DrawActions();
EditorGUILayout.Space(8f);
DrawPreview();
EditorGUILayout.EndScrollView();
}
private void DrawSearchFolders()
{
EditorGUILayout.LabelField("Material Search Folders", EditorStyles.boldLabel);
for (var i = 0; i < m_SearchFolders.Count; i++)
{
EditorGUILayout.BeginHorizontal();
m_SearchFolders[i] = EditorGUILayout.TextField(m_SearchFolders[i]);
if (GUILayout.Button("...", GUILayout.Width(28f)))
{
var folder = PickProjectFolder(m_SearchFolders[i]);
if (!string.IsNullOrEmpty(folder))
m_SearchFolders[i] = folder;
}
if (GUILayout.Button("-", GUILayout.Width(28f)))
{
m_SearchFolders.RemoveAt(i);
GUIUtility.ExitGUI();
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Add Folder"))
{
var folder = PickProjectFolder("Assets");
if (!string.IsNullOrEmpty(folder))
AddSearchFolder(folder);
}
if (GUILayout.Button("Add Selected"))
{
AddSelectedFolders();
}
EditorGUILayout.EndHorizontal();
}
private void DrawOutputFolder()
{
EditorGUILayout.LabelField("Output Folder", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
m_OutputFolder = EditorGUILayout.TextField(m_OutputFolder);
if (GUILayout.Button("...", GUILayout.Width(28f)))
{
var folder = PickProjectFolder(m_OutputFolder);
if (!string.IsNullOrEmpty(folder))
m_OutputFolder = folder;
}
EditorGUILayout.EndHorizontal();
}
private void DrawTierSelection()
{
EditorGUILayout.LabelField("Build Tiers", EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope())
{
for (var i = 0; i < Tiers.Length; i++)
DrawTierToggle(Tiers[i]);
GUILayout.FlexibleSpace();
if (GUILayout.Button("All", GUILayout.Width(56f)))
SetTierMask(AllTierMask);
}
if (!HasSelectedTier())
EditorGUILayout.HelpBox("Select at least one tier before previewing or generating SVC assets.", MessageType.Warning);
}
private void DrawTierToggle(NBShaderFeatureTier tier)
{
var selected = IsTierSelected(tier);
var newSelected = EditorGUILayout.ToggleLeft(tier.ToString(), selected, GUILayout.Width(92f));
if (newSelected == selected)
return;
var mask = 1 << (int)tier;
if (newSelected)
SetTierMask(m_TierMask | mask);
else
SetTierMask(m_TierMask & ~mask);
}
private void DrawActions()
{
EditorGUILayout.BeginHorizontal();
using (new EditorGUI.DisabledScope(!HasSelectedTier()))
{
if (GUILayout.Button("Preview", GUILayout.Height(28f)))
Preview();
}
using (new EditorGUI.DisabledScope(!HasSelectedTier() || m_Previews == null || m_Previews.Length == 0))
{
if (GUILayout.Button("Generate SVC", GUILayout.Height(28f)))
Generate();
}
EditorGUILayout.EndHorizontal();
if (!string.IsNullOrEmpty(m_Status))
EditorGUILayout.HelpBox(m_Status, MessageType.Info);
}
private void DrawPreview()
{
if (m_Previews == null || m_Previews.Length == 0)
return;
EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
{
DrawPreviewHeader();
for (var i = 0; i < m_Previews.Length; i++)
{
var preview = m_Previews[i];
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(preview.tier.ToString(), GUILayout.Width(90f));
EditorGUILayout.LabelField(preview.materialCount.ToString(), GUILayout.Width(90f));
EditorGUILayout.LabelField(preview.passCount.ToString(), GUILayout.Width(70f));
EditorGUILayout.LabelField(preview.variantCount.ToString(), GUILayout.Width(90f));
EditorGUILayout.LabelField(preview.outputAssetPath ?? string.Empty);
EditorGUILayout.EndHorizontal();
}
}
}
private static void DrawPreviewHeader()
{
EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
EditorGUILayout.LabelField("Tier", EditorStyles.boldLabel, GUILayout.Width(90f));
EditorGUILayout.LabelField("Materials", EditorStyles.boldLabel, GUILayout.Width(90f));
EditorGUILayout.LabelField("Passes", EditorStyles.boldLabel, GUILayout.Width(70f));
EditorGUILayout.LabelField("Variants", EditorStyles.boldLabel, GUILayout.Width(90f));
EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
EditorGUILayout.EndHorizontal();
}
private void Preview()
{
var selectedTiers = GetSelectedTiers();
var result = NBShaderVariantCollectionBuilder.Preview(m_SearchFolders, m_OutputFolder, selectedTiers);
m_Previews = result.tiers;
m_Status = string.Format(
"Found {0} NBShader materials in {1} valid folder(s). Previewed {2} tier(s) and did not write assets.",
result.materialCount,
result.validSearchFolderCount,
selectedTiers.Length);
}
private void Generate()
{
var result = NBShaderVariantCollectionBuilder.Generate(m_SearchFolders, m_OutputFolder, GetSelectedTiers());
if (result.hasError)
{
EditorUtility.DisplayDialog("Generate NBShader SVC", result.firstErrorMessage, "OK");
m_Previews = result.tiers;
return;
}
m_Previews = result.tiers;
m_Status = string.Format("Generated {0} NBShader shader variant collection asset(s).", result.generatedCount);
}
private void AddSelectedFolders()
{
var guids = Selection.assetGUIDs;
for (var i = 0; i < guids.Length; i++)
{
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
if (AssetDatabase.IsValidFolder(path))
AddSearchFolder(path);
}
}
private void AddSearchFolder(string folder)
{
folder = NBShaderVariantCollectionBuilder.NormalizeAssetPath(folder);
if (string.IsNullOrEmpty(folder))
return;
if (!m_SearchFolders.Contains(folder))
m_SearchFolders.Add(folder);
}
private static string PickProjectFolder(string current)
{
var start = AssetDatabase.IsValidFolder(current) ? current : "Assets";
var absoluteStart = NBShaderVariantCollectionBuilder.ToAbsolutePath(start);
var picked = EditorUtility.OpenFolderPanel("Select Project Folder", absoluteStart, string.Empty);
return NBShaderVariantCollectionBuilder.NormalizeAssetPath(picked);
}
private bool HasSelectedTier()
{
return (m_TierMask & AllTierMask) != 0;
}
private bool IsTierSelected(NBShaderFeatureTier tier)
{
return (m_TierMask & (1 << (int)tier)) != 0;
}
private NBShaderFeatureTier[] GetSelectedTiers()
{
var result = new List<NBShaderFeatureTier>();
for (var i = 0; i < Tiers.Length; i++)
{
var tier = Tiers[i];
if (IsTierSelected(tier))
result.Add(tier);
}
return result.ToArray();
}
private void SetTierMask(int tierMask)
{
tierMask &= AllTierMask;
if (m_TierMask == tierMask)
return;
m_TierMask = tierMask;
m_Previews = new NBShaderVariantCollectionTierResult[0];
m_Status = string.Empty;
}
}
}

View File

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

View File

@@ -0,0 +1,474 @@
using System;
using System.Collections.Generic;
using System.IO;
using NBShader;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace NBShaders2.Editor.FeatureLevel
{
public static class NBShaderVariantCollectionBuilder
{
public const string DefaultOutputFolder = "Assets/NBShader/ShaderVariantCollections";
private static readonly NBShaderFeatureTier[] Tiers =
{
NBShaderFeatureTier.Low,
NBShaderFeatureTier.Medium,
NBShaderFeatureTier.High,
NBShaderFeatureTier.Ultra
};
public static NBShaderVariantCollectionBuildResult Preview(IEnumerable<string> searchFolders, string outputFolder)
{
return Preview(searchFolders, outputFolder, null);
}
public static NBShaderVariantCollectionBuildResult Preview(
IEnumerable<string> searchFolders,
string outputFolder,
IEnumerable<NBShaderFeatureTier> tiers)
{
var validFolders = GetValidSearchFolders(searchFolders);
var materials = CollectMaterialsInValidFolders(validFolders);
return BuildResult(validFolders, materials, NormalizeOutputFolder(outputFolder), NormalizeTiers(tiers), false);
}
public static NBShaderVariantCollectionBuildResult Generate(IEnumerable<string> searchFolders, string outputFolder)
{
return Generate(searchFolders, outputFolder, null);
}
public static NBShaderVariantCollectionBuildResult Generate(
IEnumerable<string> searchFolders,
string outputFolder,
IEnumerable<NBShaderFeatureTier> tiers)
{
var validFolders = GetValidSearchFolders(searchFolders);
var materials = CollectMaterialsInValidFolders(validFolders);
var normalizedOutputFolder = NormalizeOutputFolder(outputFolder);
var normalizedTiers = NormalizeTiers(tiers);
if (normalizedTiers.Length == 0)
return BuildResult(validFolders, materials, normalizedOutputFolder, normalizedTiers, false, "No NBShader feature tiers were selected.");
if (materials.Length == 0)
return BuildResult(validFolders, materials, normalizedOutputFolder, normalizedTiers, false, "No NBShader materials were found in the selected folders.");
string errorMessage;
if (!EnsureOutputFolder(normalizedOutputFolder, out errorMessage))
return BuildResult(validFolders, materials, normalizedOutputFolder, normalizedTiers, false, errorMessage);
return BuildResult(validFolders, materials, normalizedOutputFolder, normalizedTiers, true);
}
public static Material[] CollectMaterials(IEnumerable<string> searchFolders)
{
var folders = GetValidSearchFolders(searchFolders);
return CollectMaterialsInValidFolders(folders);
}
private static Material[] CollectMaterialsInValidFolders(string[] folders)
{
if (folders.Length == 0)
return new Material[0];
var guids = AssetDatabase.FindAssets("t:Material", folders);
var result = new List<Material>();
var seen = new HashSet<string>(StringComparer.Ordinal);
for (var i = 0; i < guids.Length; i++)
{
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
if (string.IsNullOrEmpty(path) || !seen.Add(path))
continue;
var material = AssetDatabase.LoadAssetAtPath<Material>(path);
if (NBShaderMaterialIntentResolver.IsNBShaderMaterial(material))
result.Add(material);
}
return result.ToArray();
}
public static string[] GetValidSearchFolders(IEnumerable<string> searchFolders)
{
if (searchFolders == null)
return new string[0];
var result = new List<string>();
var seen = new HashSet<string>(StringComparer.Ordinal);
foreach (var searchFolder in searchFolders)
{
var path = NormalizeAssetPath(searchFolder);
if (string.IsNullOrEmpty(path) || !AssetDatabase.IsValidFolder(path) || !seen.Add(path))
continue;
result.Add(path);
}
return result.ToArray();
}
internal static string NormalizeAssetPath(string path)
{
if (string.IsNullOrEmpty(path))
return string.Empty;
path = path.Replace('\\', '/').Trim();
if (path.StartsWith("Assets", StringComparison.Ordinal) ||
path.StartsWith("Packages", StringComparison.Ordinal))
{
return path.TrimEnd('/');
}
var projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, "..")).Replace('\\', '/').TrimEnd('/');
var fullPath = Path.GetFullPath(path).Replace('\\', '/').TrimEnd('/');
if (fullPath.StartsWith(projectRoot + "/", StringComparison.OrdinalIgnoreCase))
return fullPath.Substring(projectRoot.Length + 1);
return string.Empty;
}
internal static string ToAbsolutePath(string assetPath)
{
assetPath = NormalizeAssetPath(assetPath);
var projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, "..")).Replace('\\', '/').TrimEnd('/');
if (string.IsNullOrEmpty(assetPath))
return projectRoot;
return Path.Combine(projectRoot, assetPath).Replace('\\', '/');
}
public static string GetOutputPath(string outputFolder, NBShaderFeatureTier tier)
{
outputFolder = NormalizeOutputFolder(outputFolder);
if (string.IsNullOrEmpty(outputFolder))
outputFolder = DefaultOutputFolder;
return outputFolder.TrimEnd('/') + "/NBShader_" + tier + ".shadervariants";
}
private static NBShaderVariantCollectionBuildResult BuildResult(
string[] validFolders,
Material[] materials,
string outputFolder,
NBShaderFeatureTier[] tiers,
bool writeAssets,
string errorMessage = null)
{
if (tiers == null)
tiers = CloneDefaultTiers();
var tierResults = new NBShaderVariantCollectionTierResult[tiers.Length];
for (var i = 0; i < tiers.Length; i++)
{
var tier = tiers[i];
var buildInfo = NBShaderFeatureLevelEditorAPI.GetBuildInfo(
tier,
materials,
NBShaderBuildInfoMode.ExactMaterialVariants);
var variants = BuildSvcVariants(buildInfo);
var path = GetOutputPath(outputFolder, tier);
var generated = false;
string tierError = null;
if (writeAssets)
generated = WriteCollection(path, variants, out tierError);
tierResults[i] = new NBShaderVariantCollectionTierResult(
tier,
buildInfo != null ? buildInfo.materials.Length : 0,
buildInfo != null ? buildInfo.includedPassNames.Length : 0,
variants.Length,
path,
generated,
tierError);
}
return new NBShaderVariantCollectionBuildResult(
validFolders,
materials,
outputFolder,
tierResults,
errorMessage);
}
private static SvcVariant[] BuildSvcVariants(NBShaderBuildInfoSet buildInfo)
{
if (buildInfo == null)
return new SvcVariant[0];
var result = new List<SvcVariant>();
var seen = new HashSet<string>(StringComparer.Ordinal);
var variants = buildInfo.variants;
for (var i = 0; i < variants.Length; i++)
{
var variant = variants[i];
if (variant == null || variant.shader == null)
continue;
var keywords = variant.keywords;
var key = variant.shader.name + "|" + variant.passType + "|" + string.Join(";", keywords);
if (!seen.Add(key))
continue;
result.Add(new SvcVariant(variant.shader, variant.passType, keywords));
}
return result.ToArray();
}
private static bool WriteCollection(string path, SvcVariant[] variants, out string errorMessage)
{
errorMessage = null;
var existing = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
var collection = existing as ShaderVariantCollection;
if (existing != null && collection == null)
{
errorMessage = "Output path already exists and is not a ShaderVariantCollection:\n" + path;
return false;
}
if (collection == null)
{
collection = new ShaderVariantCollection();
AssetDatabase.CreateAsset(collection, path);
}
else
{
collection.Clear();
}
for (var i = 0; i < variants.Length; i++)
{
var variant = variants[i];
try
{
collection.Add(new ShaderVariantCollection.ShaderVariant(
variant.shader,
variant.passType,
variant.keywords));
}
catch (Exception ex)
{
Debug.LogWarning("Failed to add NBShader SVC variant: " + ex.Message);
}
}
EditorUtility.SetDirty(collection);
AssetDatabase.SaveAssetIfDirty(collection);
return true;
}
private static bool EnsureOutputFolder(string outputFolder, out string errorMessage)
{
errorMessage = null;
if (string.IsNullOrEmpty(outputFolder))
{
errorMessage = "Output folder is empty.";
return false;
}
if (AssetDatabase.IsValidFolder(outputFolder))
return true;
if (!outputFolder.StartsWith("Assets/", StringComparison.Ordinal) &&
!string.Equals(outputFolder, "Assets", StringComparison.Ordinal))
{
errorMessage = "Output folder must already exist unless it is under Assets:\n" + outputFolder;
return false;
}
var parts = outputFolder.Split('/');
var current = parts[0];
for (var i = 1; i < parts.Length; i++)
{
var next = current + "/" + parts[i];
if (!AssetDatabase.IsValidFolder(next))
AssetDatabase.CreateFolder(current, parts[i]);
current = next;
}
if (AssetDatabase.IsValidFolder(outputFolder))
return true;
errorMessage = "Could not create output folder:\n" + outputFolder;
return false;
}
private static string NormalizeOutputFolder(string outputFolder)
{
if (string.IsNullOrEmpty(outputFolder))
return DefaultOutputFolder;
return NormalizeAssetPath(outputFolder);
}
private static NBShaderFeatureTier[] NormalizeTiers(IEnumerable<NBShaderFeatureTier> tiers)
{
if (tiers == null)
return CloneDefaultTiers();
var selected = new HashSet<NBShaderFeatureTier>();
foreach (var tier in tiers)
{
if (IsValidTier(tier))
selected.Add(tier);
}
var result = new List<NBShaderFeatureTier>();
for (var i = 0; i < Tiers.Length; i++)
{
var tier = Tiers[i];
if (selected.Contains(tier))
result.Add(tier);
}
return result.ToArray();
}
private static bool IsValidTier(NBShaderFeatureTier tier)
{
return tier == NBShaderFeatureTier.Low ||
tier == NBShaderFeatureTier.Medium ||
tier == NBShaderFeatureTier.High ||
tier == NBShaderFeatureTier.Ultra;
}
private static NBShaderFeatureTier[] CloneDefaultTiers()
{
return (NBShaderFeatureTier[])Tiers.Clone();
}
private sealed class SvcVariant
{
public readonly Shader shader;
public readonly PassType passType;
public readonly string[] keywords;
public SvcVariant(Shader shader, PassType passType, string[] keywords)
{
this.shader = shader;
this.passType = passType;
this.keywords = keywords != null ? (string[])keywords.Clone() : new string[0];
}
}
}
public sealed class NBShaderVariantCollectionBuildResult
{
private readonly string[] m_ValidSearchFolders;
private readonly Material[] m_Materials;
private readonly NBShaderVariantCollectionTierResult[] m_Tiers;
public readonly string outputFolder;
public readonly string errorMessage;
public string[] validSearchFolders { get { return (string[])m_ValidSearchFolders.Clone(); } }
public Material[] materials { get { return (Material[])m_Materials.Clone(); } }
public NBShaderVariantCollectionTierResult[] tiers { get { return (NBShaderVariantCollectionTierResult[])m_Tiers.Clone(); } }
public int materialCount { get { return m_Materials.Length; } }
public int validSearchFolderCount { get { return m_ValidSearchFolders.Length; } }
public int generatedCount { get { return CountGenerated(m_Tiers); } }
public bool hasError { get { return !string.IsNullOrEmpty(firstErrorMessage); } }
public bool hasTierError { get { return HasTierError(m_Tiers); } }
public bool allTiersGenerated { get { return m_Tiers.Length > 0 && generatedCount == m_Tiers.Length; } }
public bool succeeded { get { return !hasError && allTiersGenerated; } }
public string firstErrorMessage { get { return GetFirstErrorMessage(errorMessage, m_Tiers); } }
public NBShaderVariantCollectionBuildResult(
string[] validSearchFolders,
Material[] materials,
string outputFolder,
NBShaderVariantCollectionTierResult[] tiers,
string errorMessage)
{
m_ValidSearchFolders = validSearchFolders != null ? (string[])validSearchFolders.Clone() : new string[0];
m_Materials = materials != null ? (Material[])materials.Clone() : new Material[0];
this.outputFolder = outputFolder;
m_Tiers = tiers != null ? (NBShaderVariantCollectionTierResult[])tiers.Clone() : new NBShaderVariantCollectionTierResult[0];
this.errorMessage = errorMessage;
}
private static int CountGenerated(NBShaderVariantCollectionTierResult[] tiers)
{
if (tiers == null || tiers.Length == 0)
return 0;
var count = 0;
for (var i = 0; i < tiers.Length; i++)
{
var tier = tiers[i];
if (tier != null && tier.generated)
count++;
}
return count;
}
private static bool HasTierError(NBShaderVariantCollectionTierResult[] tiers)
{
if (tiers == null || tiers.Length == 0)
return false;
for (var i = 0; i < tiers.Length; i++)
{
var tier = tiers[i];
if (tier != null && tier.hasError)
return true;
}
return false;
}
private static string GetFirstErrorMessage(string resultError, NBShaderVariantCollectionTierResult[] tiers)
{
if (!string.IsNullOrEmpty(resultError))
return resultError;
if (tiers == null || tiers.Length == 0)
return null;
for (var i = 0; i < tiers.Length; i++)
{
var tier = tiers[i];
if (tier != null && tier.hasError)
return tier.errorMessage;
}
return null;
}
}
public sealed class NBShaderVariantCollectionTierResult
{
public readonly NBShaderFeatureTier tier;
public readonly int materialCount;
public readonly int passCount;
public readonly int variantCount;
public readonly string outputAssetPath;
public readonly bool generated;
public readonly string errorMessage;
public bool hasError { get { return !string.IsNullOrEmpty(errorMessage); } }
public NBShaderVariantCollectionTierResult(
NBShaderFeatureTier tier,
int materialCount,
int passCount,
int variantCount,
string outputAssetPath,
bool generated,
string errorMessage)
{
this.tier = tier;
this.materialCount = materialCount;
this.passCount = passCount;
this.variantCount = variantCount;
this.outputAssetPath = outputAssetPath;
this.generated = generated;
this.errorMessage = errorMessage;
}
}
}

View File

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

View File

@@ -0,0 +1,114 @@
using System.Collections.Generic;
using NBShader;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
namespace NBShaders2.Editor.FeatureLevel
{
public sealed class NBShaderVariantStripper : IPreprocessShaders, IPreprocessBuildWithReport
{
private static bool s_MissingExplicitTierWarningLogged;
public int callbackOrder { get { return 0; } }
public void OnPreprocessBuild(BuildReport report)
{
ResetMissingExplicitTierWarning();
}
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
{
if (shader == null || shader.name != NBShaderFeatureLevelCatalog.ShaderName || data == null || data.Count == 0)
return;
NBShaderFeatureTier tier;
if (!NBShaderFeatureLevelBuildStripOverride.TryGetCurrentTier(out tier))
LogMissingExplicitTierWarning();
var projectSettings = NBShaderFeatureLevelProjectSettings.instance;
HashSet<string> allowedKeywords = projectSettings.GetAllowedKeywordSetForBuildInfoNoSave(tier);
HashSet<string> allowedPassFeatures = projectSettings.GetAllowedPassFeatureSetForBuildInfoNoSave(tier);
if (IsDisallowedManagedPass(snippet, allowedPassFeatures))
{
data.Clear();
return;
}
for (var i = data.Count - 1; i >= 0; i--)
{
if (ContainsDisallowedManagedKeyword(shader, data[i], allowedKeywords))
data.RemoveAt(i);
}
}
private static void LogMissingExplicitTierWarning()
{
if (s_MissingExplicitTierWarningLogged)
return;
s_MissingExplicitTierWarningLogged = true;
Debug.LogWarning(
"NBShader2 build stripping tier was not specified. Defaulting to Ultra. " +
"Wrap BuildPipeline.BuildPlayer or BuildPipeline.BuildAssetBundles in " +
"NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier(tier) to build lower-tier NBShader variants intentionally.");
}
internal static void ResetMissingExplicitTierWarning()
{
s_MissingExplicitTierWarningLogged = false;
}
private static bool IsDisallowedManagedPass(ShaderSnippetData snippet, HashSet<string> allowedPassFeatures)
{
if (allowedPassFeatures == null)
return false;
string passFeatureId;
if (!TryResolveManagedPassFeature(snippet, out passFeatureId))
return false;
return !allowedPassFeatures.Contains(passFeatureId);
}
private static bool TryResolveManagedPassFeature(ShaderSnippetData snippet, out string passFeatureId)
{
if (!string.IsNullOrEmpty(snippet.passName) &&
NBShaderFeatureLevelCatalog.TryGetManagedPassFeatureByPassName(snippet.passName, out passFeatureId))
{
return true;
}
switch (snippet.passType)
{
case PassType.ScriptableRenderPipelineDefaultUnlit:
passFeatureId = NBShaderPassFeatureCatalog.BackFirstPassId;
return true;
case PassType.ShadowCaster:
passFeatureId = NBShaderPassFeatureCatalog.ShadowCasterPassId;
return true;
default:
passFeatureId = string.Empty;
return false;
}
}
private static bool ContainsDisallowedManagedKeyword(Shader shader, ShaderCompilerData compilerData, HashSet<string> allowed)
{
var keywords = compilerData.shaderKeywordSet.GetShaderKeywords();
for (var i = 0; i < keywords.Length; i++)
{
var keywordName = keywords[i].name;
if (!NBShaderFeatureLevelCatalog.IsManagedKeyword(keywordName))
continue;
if (allowed != null && !allowed.Contains(keywordName))
return true;
}
return false;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,80 @@
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
[InitializeOnLoad]
internal static class NBShaderInspectorLocalization
{
internal const string TableName = "NBShader";
private const string CsvAssetPath = "Packages/com.xuanxuan.nb.fx/NBShaders2/Editor/Localization/NBShaderInspectorLocalization.csv";
static NBShaderInspectorLocalization()
{
RegisterTable();
}
public static string CurrentLanguage
{
get
{
RegisterTable();
return ShaderGUILocalization.GetCurrentLanguage(TableName);
}
}
public static GUIContent MakeContent(string labelKey, string labelFallback, string tooltipKey = null, string tooltipFallback = "")
{
RegisterTable();
return ShaderGUILocalization.MakeContent(TableName, labelKey, labelFallback, tooltipKey, tooltipFallback);
}
public static GUIContent MakeInspectorContent(string key, string fallback, string tip = "")
{
RegisterTable();
return ShaderGUILocalization.MakeInspectorContent(TableName, key, fallback, tip);
}
public static string GetInspectorText(string key, string fallback = "")
{
RegisterTable();
return ShaderGUILocalization.GetInspectorText(TableName, key, fallback);
}
public static string[] GetInspectorOptions(string key, string[] fallback)
{
RegisterTable();
return ShaderGUILocalization.GetInspectorOptions(TableName, key, fallback);
}
public static string[] GetOptions(string keyPrefix, string[] fallback)
{
RegisterTable();
return ShaderGUILocalization.GetOptions(TableName, keyPrefix, fallback);
}
public static string Get(string key, string fallback = "")
{
RegisterTable();
return ShaderGUILocalization.Get(TableName, key, fallback);
}
public static string GetTooltip(string labelKey, string tooltipKey = null, string fallback = "")
{
RegisterTable();
return ShaderGUILocalization.GetTooltip(TableName, labelKey, tooltipKey, fallback);
}
public static void Reload()
{
RegisterTable();
ShaderGUILocalization.Reload(TableName);
}
private static void RegisterTable()
{
ShaderGUILocalization.RegisterCsv(TableName, CsvAssetPath);
}
}
}

View File

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

View File

@@ -0,0 +1,805 @@
key,zh-CN,en-US,zh-CN-tip,en-US-tip
inspector.block.mode.label,模式设置,Mode,各种基础模式设置,Mode and source setup
inspector.block.base.label,基本全局功能,Base,全局控制功能,Base global controls
inspector.block.maintex.label,主贴图功能,Main Texture,主贴图以及主颜色相关功能,Main texture and base color controls
inspector.block.light.label,光照功能,Lighting,法线、MatCap 和光照模式相关功能,Lighting normal and material response controls
inspector.block.feature.label,特别功能,Feature,遮罩、扭曲、溶解等特效功能,Effect feature controls
inspector.block.ta.label,TA调试,TA Debug,技术美术调试和辅助功能,Technical art debug and helper controls
inspector.common.tilling.label,Tilling,Tilling,,
inspector.common.offset.label,Offset,Offset,,
inspector.common.none,None,None,,
inspector.mode.meshSource.label,Mesh来源模式,Mesh Source Mode,Mesh来源模式和当前的对象类型一致,Matches the current object type
inspector.mode.meshSource.option.0,粒子系统,Particle System,,
inspector.mode.meshSource.option.1,模型(非粒子发射),Mesh,,
inspector.mode.meshSource.option.2,2D RawImage,2D RawImage,,
inspector.mode.meshSource.option.3,2D 精灵,2D Sprite,,
inspector.mode.meshSource.option.4,2D 材质贴图,2D Material Texture,,
inspector.mode.meshSource.option.5,2D UIParticle,2D UIParticle,,
inspector.mode.transparent.label,透明模式,Transparent Mode,透明模式,Controls opaque transparent and cutoff rendering
inspector.mode.transparent.option.0,不透明Opaque,Opaque,,
inspector.mode.transparent.option.1,半透明Transparent,Transparent,,
inspector.mode.transparent.option.2,不透明裁剪CutOff,CutOff,,
inspector.mode.cutoff.label,裁剪位置,Cutoff,0为完全不裁剪1为完全裁剪,0 keeps everything and 1 clips everything
inspector.mode.blend.label,混合模式,Blend Mode,,
inspector.mode.blend.option.0,透明度混合AlphaBlend,Alpha Blend,,
inspector.mode.blend.option.1,预乘PreMultiply,Premultiply,,
inspector.mode.blend.option.2,叠加Additive,Additive,,
inspector.mode.blend.option.3,正片叠底Multiply,Multiply,,
inspector.mode.additiveToPremultiply.label,叠加到预乘混合,Additive To Premultiply,0为叠加混合1为预乘混合,0 is additive and 1 is premultiply
inspector.base.colorIntensity.label,整体颜色强度,Base Color Intensity,,
inspector.base.alphaAll.label,整体透明度,Overall Alpha,,
inspector.base.colorAdjustment.label,颜色调整,Color Adjustment,,
inspector.base.colorAdjustment.onlyMainTex.label,颜色调整仅影响主贴图,Color Adjustment Only Affects Main Texture,,
inspector.base.hueShift.label,色相偏移,Hue Shift,,
inspector.base.hueShift.value.label,色相,Hue,,
inspector.base.hueShift.customData.label,色相自定义曲线,Hue Custom Data,,
inspector.base.saturability.label,饱和度,Saturation,,
inspector.base.saturability.value.label,饱和度,Saturation,,
inspector.base.saturability.customData.label,饱和度强度自定义曲线,Saturation Strength Custom Data,,
inspector.base.contrast.label,对比度,Contrast,,
inspector.base.contrast.mid.label,对比度中值颜色,Contrast Mid Color,,
inspector.base.contrast.value.label,对比度,Contrast,,
inspector.base.contrast.customData.label,对比度自定义曲线,Contrast Custom Data,,
inspector.base.colorRefine.label,颜色修正,Color Refine,,
inspector.base.colorRefine.a.label,A:主颜色相乘,A Main Color Multiply,,
inspector.base.colorRefine.bPower.label,B:主颜色Power,B Main Color Power,,
inspector.base.colorRefine.bMultiply.label,B:主颜色Power后相乘,B After Power Multiply,,
inspector.base.colorRefine.lerp.label,A/B线性差值,A/B Lerp,,
inspector.base.colorMultiAlpha.label,颜色乘透明度(改善锯齿),Color Multiply Alpha,,
inspector.base.ztest.label,深度测试,ZTest,,
inspector.base.ztest.option.0,关闭(Disabled),Disabled,,
inspector.base.ztest.option.1,永不通过(Never),Never,,
inspector.base.ztest.option.2,小于(Less),Less,,
inspector.base.ztest.option.3,等于(Equal),Equal,,
inspector.base.ztest.option.4,小于等于(LessEqual),LessEqual,,
inspector.base.ztest.option.5,大于(Greater),Greater,,
inspector.base.ztest.option.6,不等于(NotEqual),NotEqual,,
inspector.base.ztest.option.7,大于等于(GreaterEqual),GreaterEqual,,
inspector.base.ztest.option.8,始终通过(Always),Always,,
inspector.base.cull.label,渲染面向,Cull,,
inspector.base.cull.option.0,双面(Both),Both,,
inspector.base.cull.option.1,背面(Back),Back,,
inspector.base.cull.option.2,正面(Front),Front,,
inspector.base.backFirstPass.label,预渲染反面,Back First Pass,,
inspector.base.forceZWrite.label,深度写入强制控制,Force ZWrite,,
inspector.base.forceZWrite.option.0,默认,Default,,
inspector.base.forceZWrite.option.1,强制开启,Force On,,
inspector.base.forceZWrite.option.2,强制关闭,Force Off,,
inspector.base.affectsShadows.label,投射阴影,Affects Shadows,,
inspector.base.transparentShadowDither.label,半透明 Dither 阴影,Transparent Dither Shadows,,
inspector.base.backColor.label,背面颜色,Back Color,,
inspector.base.backColor.color.label,背面颜色,Back Color,,
inspector.base.distanceFade.label,近距离透明,Distance Fade,,
inspector.base.distanceFade.range.label,透明过度范围,Fade Range,,
inspector.base.softParticles.label,软粒子,Soft Particles,,
inspector.base.softParticles.range.label,远近裁剪面,Near/Far Fade,,
inspector.base.stencilWithoutPlayer.label,剔除主角色,Stencil Without Player,,
inspector.base.ignoreVertexColor.label,忽略顶点色,Ignore Vertex Color,,
inspector.base.fogIntensity.label,雾影响强度,Fog Intensity,,
inspector.maintex.basemap.label,主贴图,Main Texture,,
inspector.maintex.basemap.related.label,主贴图相关功能,Main Texture Related,,
inspector.maintex.graphic.message,当前模式使用 Graphic 贴图。仅颜色和 ST 可编辑。,Current mode uses Graphic texture. Only color and ST remain editable.,,
inspector.maintex.uicolor.label,贴图颜色叠加,Graphic Color,,
inspector.maintex.alphaChannel.label,主贴图透明度通道,Alpha Channel,,
inspector.maintex.wrap.label,主贴图循环模式,Main Texture Wrap,,
inspector.maintex.uvmode.label,主贴图UV来源,Main Texture UV Source,,
inspector.maintex.customdata.offsetx.label,主贴图X轴偏移自定义曲线,Main Texture Offset X Custom Data,,
inspector.maintex.customdata.offsety.label,主贴图Y轴偏移自定义曲线,Main Texture Offset Y Custom Data,,
inspector.maintex.offsetspeed.label,偏移速度,Offset Speed,,
inspector.maintex.rotation.label,主贴图旋转,Rotation,,
inspector.maintex.rotationspeed.label,主贴图旋转速度,Rotation Speed,,
inspector.maintex.distortionIntensity.label,主贴图扭曲强度控制,Main Texture Distortion,,
inspector.maintex.pnoiseBlend.label,主贴图程序噪波混合,Main Texture Program Noise Blend,,
inspector.maintex.mixedMeshSource.message,混合的 Mesh 来源模式会按材质状态显示对应贴图控件。,Mixed mesh-source modes will show the matching texture controls per material state.,,
inspector.light.mode.label,光照类型,Light Mode,,
inspector.light.mode.option.0,默认无光(Unlit),Unlit,,
inspector.light.mode.option.1,简单光照(BlinnPhong),BlinnPhong,,
inspector.light.mode.option.2,简单光照通透(HalfLambert),HalfLambert,,
inspector.light.mode.option.3,高级光照(PBR),PBR,,
inspector.light.mode.option.4,六路光照(SixWay),SixWay,,
inspector.light.specular.toggle.label,高光开关,Specular,,
inspector.light.specular.color.label,高光颜色,Specular Color,,
inspector.light.specular.smoothness.label,光滑度,Smoothness,,
inspector.light.pbr.metallic.label,金属度,Metallic,,
inspector.light.pbr.smoothness.label,光滑度,Smoothness,,
inspector.light.bump.toggle.label,法线贴图开关,Normal Map,,
inspector.light.bump.texture.label,法线贴图,Normal Map,,
inspector.light.bump.related.label,法线贴图相关功能,Normal Map Related,,
inspector.light.bump.wrap.label,法线贴图循环模式,Normal Map Wrap,,
inspector.light.bump.uvmode.label,法线贴图UV来源,Normal Map UV Source,,
inspector.light.bump.maskMode.label,法线贴图多通道模式,Normal Map Multi Channel,,
inspector.light.bump.scale.label,法线强度,Normal Strength,,
inspector.light.matcap.toggle.label,MatCap模拟材质,MatCap,,
inspector.light.matcap.texture.label,MatCap图,MatCap Texture,,
inspector.light.matcap.blend.label,MatCap相加到相乘过渡,Add/Multiply Blend,,
inspector.light.sixway.positive.label,六路正方向图(P),SixWay Positive,,
inspector.light.sixway.negative.label,六路反方向图(N),SixWay Negative,,
inspector.light.sixway.absorption.toggle.label,光照颜色吸收,Light Color Absorption,,
inspector.light.sixway.absorption.strength.label,六路吸收强度,Absorption Strength,,
inspector.light.sixway.ramp.label,六路自发光Ramp,SixWay Emission Ramp,,
inspector.light.sixway.emissionPow.label,六路自发光Pow,SixWay Emission Pow,,
inspector.light.sixway.color.label,六路自发光颜色,SixWay Emission Color,,
inspector.protocol.colorChannel.option.0,R,R,,
inspector.protocol.colorChannel.option.1,G,G,,
inspector.protocol.colorChannel.option.2,B,B,,
inspector.protocol.colorChannel.option.3,A,A,,
inspector.protocol.customData.option.0,**不使用**,Off,,
inspector.protocol.customData.option.1,CustomData1_X,CustomData1.x,,
inspector.protocol.customData.option.2,CustomData1_Y,CustomData1.y,,
inspector.protocol.customData.option.3,CustomData1_Z,CustomData1.z,,
inspector.protocol.customData.option.4,CustomData1_W,CustomData1.w,,
inspector.protocol.customData.option.5,CustomData2_X,CustomData2.x,,
inspector.protocol.customData.option.6,CustomData2_Y,CustomData2.y,,
inspector.protocol.customData.option.7,CustomData2_Z,CustomData2.z,,
inspector.protocol.customData.option.8,CustomData2_W,CustomData2.w,,
inspector.protocol.wrapMode.option.0,Repeat,Repeat,,
inspector.protocol.wrapMode.option.1,Clamp,Clamp,,
inspector.protocol.wrapMode.option.2,RepeatX_ClampY,RepeatX_ClampY,,
inspector.protocol.wrapMode.option.3,ClampX_RepeatY,ClampX_RepeatY,,
inspector.protocol.pnoise.opacity.label,程序噪波混合强度,Program Noise Blend Opacity,,
inspector.protocol.pnoiseBlend.option.0,不使用,Not Used,,
inspector.protocol.pnoiseBlend.option.1,Multiply,Multiply,,
inspector.protocol.pnoiseBlend.option.2,Min,Min,,
inspector.protocol.pnoiseBlend.option.3,HardLight,HardLight,,
inspector.protocol.uv.twirl.label,旋转扭曲,Twirl,,
inspector.protocol.uv.twirlCenter.label,旋转扭曲中心,Twirl Center,,
inspector.protocol.uv.twirlStrength.label,旋转扭曲强度,Twirl Strength,,
inspector.protocol.uv.polar.label,极坐标,Polar Coordinates,,
inspector.protocol.uv.polarCenter.label,极坐标中心,Polar Center,,
inspector.protocol.uv.polarStrength.label,极坐标强度,Polar Strength,,
inspector.protocol.uv.cylinderRotate.label,圆柱坐标旋转,Cylinder Rotation,,
inspector.protocol.uv.cylinderOffset.label,圆柱坐标偏移,Cylinder Offset,,
inspector.protocol.uv.coordinatePlane.label,坐标平面,Coordinate Plane,,
inspector.protocol.uv.sharedMaterial.message,以下设置材质内通用:,The following settings are shared in the material:,,
inspector.protocol.uv.cylinderWarning.message,圆柱模式消耗比较大,慎用,Cylinder mode is expensive. Use it carefully.,,
inspector.protocol.uv.mode.option.0,默认UV通道,Default UV Channel,,
inspector.protocol.uv.mode.option.1,特殊UV通道,Special UV Channel,,
inspector.protocol.uv.mode.option.2,极坐标|旋转,Polar/Twirl,,
inspector.protocol.uv.mode.option.3,圆柱无缝,Cylinder Seamless,,
inspector.protocol.uv.mode.option.4,主贴图,Main Texture,,
inspector.protocol.uv.mode.option.5,屏幕UV,Screen UV,,
inspector.protocol.uv.mode.option.6,世界坐标,World Space,,
inspector.protocol.uv.mode.option.7,局部本地坐标,Object Space,,
inspector.protocol.uv.mode.option.8,公共UV,Shared UV,,
inspector.protocol.uv.positionPlane.option.0,xy平面,XY Plane,,
inspector.protocol.uv.positionPlane.option.1,xz平面,XZ Plane,,
inspector.protocol.uv.positionPlane.option.2,yz平面,YZ Plane,,
inspector.protocol.uv.specialChannel.label,特殊UV通道选择,Special UV Channel,,
inspector.protocol.uv.specialChannel.option.0,UV2_Texcoord1,UV2_Texcoord1,,
inspector.protocol.uv.specialChannel.option.1,UV3_Texcoord2,UV3_Texcoord2,,
inspector.ta.zoffset.label,深度偏移,Z Offset,,
inspector.ta.overrideZ.label,Override Z,Override Z,,
inspector.ta.renderQueue.label,渲染队列偏移,Queue Bias,,
inspector.ta.customStencil.label,模板手动调试开关,Custom Stencil Test,,
inspector.ta.keywords.label,已开启Keyword:,Enabled Keywords,,
inspector.ta.keywords.list.label,已开启Keyword:,Enabled Keywords,,
inspector.ta.property._offsetFactor.label,OffsetFactor,Offset Factor,,
inspector.ta.property._offsetUnits.label,Offset单位,Offset Units,,
inspector.ta.property._OverrideZValue.label,Override Z Value,Override Z Value,,
inspector.ta.property._ColorMask.label,RGBA Mask,RGBA Mask,控制最终写入 RenderTarget 的颜色通道,Controls final RenderTarget color channel writes
inspector.ta.colorMask.option.0,R,R,,
inspector.ta.colorMask.option.1,G,G,,
inspector.ta.colorMask.option.2,B,B,,
inspector.ta.colorMask.option.3,A,A,,
inspector.ta.property._StencilKeyIndex.label,Stencil配置索引,Stencil Config Index,,
inspector.ta.property._Stencil.label,模板值,Stencil Value,,
inspector.ta.property._StencilComp.label,模板比较方式,Stencil Compare,,
inspector.ta.property._StencilOp.label,模板处理方式,Stencil Operation,,
inspector.ta.property._StencilFail.label,模板失败处理方式,Stencil Fail,,
inspector.ta.property._StencilZFail.label,模板深度失败处理方式,Stencil ZFail,,
inspector.ta.property._StencilReadMask.label,模板读取掩码,Stencil Read Mask,,
inspector.ta.property._StencilWriteMask.label,模板写入掩码,Stencil Write Mask,,
inspector.vertexStreams.title.label,顶点流统计,Particle Vertex Streams,The vertex streams needed for this Material to function properly.,The vertex streams needed for this Material to function properly.
inspector.vertexStreams.mismatch,下面的粒子系统Renderer顶点流不正确:,Particle renderers with mismatched vertex streams:,,
inspector.vertexStreams.trailMismatch,下面的粒子系统Renderer拖尾顶点流不正确:,Particle trail renderers with mismatched vertex streams:,,
inspector.vertexStreams.applyTrail.button,使粒子拖尾与材质顶点流相同,Apply Trail Vertex Streams,Apply the trail vertex stream layout to all Particle Systems using this material,Apply the trail vertex stream layout to all Particle Systems using this material
inspector.vertexStreams.apply.button,使粒子与材质顶点流相同,Apply Vertex Streams,Apply the vertex stream layout to all Particle Systems using this material,Apply the vertex stream layout to all Particle Systems using this material
inspector.vertexStreams.apply.undo,Apply custom vertex streams from material,Apply custom vertex streams from material,,
inspector.feature.popup._ScreenDistortModeToggle.option.0,不扰动屏幕,No Screen Distort,,
inspector.feature.popup._ScreenDistortModeToggle.option.1,全部扰动(后处理扰动),Deferred Distort,,
inspector.feature.popup._ScreenDistortModeToggle.option.2,仅影响场景(半透明前扰动),Camera Opaque Distort,,
inspector.feature.screenDistort.missingNbPostProcess.message,屏幕扭曲需要当前 URP Pipeline Asset 的任意 RendererData 中包含已启用的 NB 后处理 Feature。,Screen Distort requires at least one RendererData in the current URP Pipeline Asset to include an active NB Post Process Feature.,,
inspector.feature.screenDistort.missingOpaqueTextureCopy.message,Camera Opaque 扭曲需要在当前 URP Pipeline Asset 中开启 Opaque Texture。,Camera Opaque Distort requires Opaque Texture to be enabled on the current URP Pipeline Asset.,,
inspector.feature.screenDistort.pingRendererData.button,定位 Renderer,Ping Renderer,,
inspector.feature.screenDistort.pingPipelineAsset.button,定位 Pipeline Asset,Ping Pipeline Asset,,
inspector.feature.popup._DistortMode.option.0,扰动贴图,FlowMap/RG Texture,,
inspector.feature.popup._DistortMode.option.1,折射,Refraction IOR,,
inspector.feature.popup._ColorBlendAlphaMultiplyMode.option.0,颜色渐变强度,Off,,
inspector.feature.popup._ColorBlendAlphaMultiplyMode.option.1,遮罩(乘以主贴图Alpha),On,,
inspector.feature.popup._RampColorSourceMode.option.0,UV,Gradient,,
inspector.feature.popup._RampColorSourceMode.option.1,映射贴图,Texture,,
inspector.feature.popup._RampColorBlendMode.option.0,相乘Multiply,Add,,
inspector.feature.popup._RampColorBlendMode.option.1,相加Add,Multiply,,
inspector.feature.popup._DissolveRampSourceMode.option.0,渐变控件,Gradient,,
inspector.feature.popup._DissolveRampSourceMode.option.1,Ramp贴图,Texture,,
inspector.feature.popup._DissolveRampColorBlendMode.option.0,线性差值Lerp,Add,,
inspector.feature.popup._DissolveRampColorBlendMode.option.1,相乘Multiply,Multiply,,
inspector.feature.popup._DissolveMaskMode.option.0,过程溶解,Process Dissolve,,
inspector.feature.popup._DissolveMaskMode.option.1,溶解遮罩,Dissolve Mask,,
inspector.feature.popup._FresnelMode.option.0,颜色|边缘光,Color,,
inspector.feature.popup._FresnelMode.option.1,半透明|渐隐,Alpha,,
inspector.feature.popup._VATMode.option.0,Houdini,Houdini,,
inspector.feature.popup._VATMode.option.1,TyFlow,TyFlow,,
inspector.feature.popup._HoudiniVATSubMode.option.0,SoftBody (Deformation),SoftBody (Deformation),,
inspector.feature.popup._HoudiniVATSubMode.option.1,RigidBody (Pieces),RigidBody (Pieces),,
inspector.feature.popup._HoudiniVATSubMode.option.2,Dynamic Remeshing (Lookup),Dynamic Remeshing (Lookup),,
inspector.feature.popup._HoudiniVATSubMode.option.3,Particle Sprites (Billboard),Particle Sprites (Billboard),,
inspector.feature.popup._TyFlowVATSubMode.option.0,Absolute positions,Absolute positions,,
inspector.feature.popup._TyFlowVATSubMode.option.1,Relative offsets,Relative offsets,,
inspector.feature.popup._TyFlowVATSubMode.option.2,Skin (R),Skin (R),,
inspector.feature.popup._TyFlowVATSubMode.option.3,Skin (PR),Skin (PR),,
inspector.feature.popup._TyFlowVATSubMode.option.4,Skin (PRSAVE),Skin (PRSAVE),,
inspector.feature.popup._TyFlowVATSubMode.option.5,Skin (PRSXYZ),Skin (PRSXYZ),,
inspector.feature.popup._MaskMapGradientToggle.option.0,遮罩贴图,Texture,,
inspector.feature.popup._MaskMapGradientToggle.option.1,渐变控件,Gradient,,
inspector.feature.popup._MaskMap2GradientToggle.option.0,遮罩贴图,Texture,,
inspector.feature.popup._MaskMap2GradientToggle.option.1,渐变控件,Gradient,,
inspector.feature.popup._MaskMap3GradientToggle.option.0,遮罩贴图,Texture,,
inspector.feature.popup._MaskMap3GradientToggle.option.1,渐变控件,Gradient,,
inspector.feature.vat.houdiniUnsupportedParticle.message,该 Houdini VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。,This Houdini VAT type requires mesh multi-UV data and does not support ParticleSystem VertexStream mode.,,
inspector.feature.vat.tyflowUnsupportedParticle.message,该 TyFlow VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。,This TyFlow VAT type requires mesh multi-UV data and does not support ParticleSystem VertexStream mode.,,
inspector.feature.vat.tyflowUv2Conflict.message,TyFlow VAT 在粒子模式下使用 UV2 (TEXCOORD0.zw) 作为 vertexIndex / vertexCount。序列帧融帧或特殊 UV (UV2) 会冲突VAT 优先。,TyFlow VAT uses UV2 (TEXCOORD0.zw) as vertexIndex / vertexCount in ParticleSystem mode. Flipbook blending or Special UV (UV2) conflicts with it; VAT takes priority.,,
inspector.feature.遮罩.label,遮罩,Mask,,
inspector.feature.测试遮罩颜色.label,测试遮罩颜色,Debug Mask Color,,
inspector.feature.遮罩强度.label,遮罩强度,Mask Strength,,
inspector.feature.遮罩整体调整.label,遮罩整体调整,Mask Refine,,
inspector.feature.范围(Pow).label,范围(Pow),Range (Pow),,
inspector.feature.相乘.label,相乘,Multiply,,
inspector.feature.偏移(相加).label,偏移(相加),Offset (Add),,
inspector.feature.遮罩程序噪波混合.label,遮罩程序噪波混合,Mask Program Noise Blend,,
inspector.feature.遮罩模式.label,遮罩模式,Mask Mode,,
inspector.feature.遮罩贴图.label,遮罩贴图,Mask Texture,,
inspector.feature.遮罩通道选择.label,遮罩通道选择,Mask Channel,,
inspector.feature.遮罩渐变.label,遮罩渐变,Mask Gradient,,
inspector.feature.遮罩UV Wrap.label,遮罩循环模式,Mask UV Wrap,,
inspector.feature.遮罩UV来源.label,遮罩UV来源,Mask UV Source,,
inspector.feature.Mask图X轴偏移自定义曲线.label,Mask图X轴偏移自定义曲线,Mask Offset X Custom Data,,
inspector.feature.Mask图Y轴偏移自定义曲线.label,Mask图Y轴偏移自定义曲线,Mask Offset Y Custom Data,,
inspector.feature.遮罩偏移速度.label,遮罩偏移速度,Mask Offset Speed,,
inspector.feature.遮罩旋转.label,遮罩旋转,Mask Rotation,,
inspector.feature.遮罩旋转速度.label,遮罩旋转速度,Mask Rotation Speed,,
inspector.feature.旋转速度.label,旋转速度,Rotation Speed,,
inspector.feature.遮罩扭曲强度.label,遮罩扭曲强度,Mask Distortion Strength,,
inspector.feature.遮罩2.label,遮罩2,Mask 2,,
inspector.feature.遮罩2模式.label,遮罩2模式,Mask 2 Mode,,
inspector.feature.遮罩2贴图.label,遮罩2贴图,Mask 2 Texture,,
inspector.feature.遮罩2通道选择.label,遮罩2通道选择,Mask 2 Channel,,
inspector.feature.遮罩2渐变.label,遮罩2渐变(UV纵向),Mask 2 Gradient,,
inspector.feature.遮罩2UV Wrap.label,遮罩2UV循环模式,Mask 2 UV Wrap,,
inspector.feature.遮罩2UV来源.label,遮罩2UV来源,Mask 2 UV Source,,
inspector.feature.遮罩2旋转.label,遮罩2旋转,Mask 2 Rotation,,
inspector.feature.遮罩2偏移速度.label,遮罩2偏移速度,Mask 2 Offset Speed,,
inspector.feature.遮罩3.label,遮罩3,Mask 3,,
inspector.feature.遮罩3模式.label,遮罩3模式,Mask 3 Mode,,
inspector.feature.遮罩3贴图.label,遮罩3贴图,Mask 3 Texture,,
inspector.feature.遮罩3通道选择.label,遮罩3通道选择,Mask 3 Channel,,
inspector.feature.遮罩3渐变.label,遮罩3渐变(UV横向),Mask 3 Gradient,,
inspector.feature.遮罩3UV Wrap.label,遮罩3UV循环模式,Mask 3 UV Wrap,,
inspector.feature.遮罩3UV来源.label,遮罩3UV来源,Mask 3 UV Source,,
inspector.feature.遮罩3旋转.label,遮罩3旋转,Mask 3 Rotation,,
inspector.feature.遮罩3偏移速度.label,遮罩3偏移速度,Mask 3 Offset Speed,,
inspector.feature.扭曲.label,扭曲,Distort,,
inspector.feature.扭曲强度值测试.label,扭曲强度值测试,Debug Distort Strength,,
inspector.feature.整体扭曲强度.label,整体扭曲强度,Overall Distort Strength,,
inspector.feature.扭曲强度自定义曲线.label,扭曲强度自定义曲线,Distort Strength Custom Data,,
inspector.feature.屏幕扰动模式.label,屏幕扰动模式,Screen Distort Mode,,
inspector.feature.屏幕扭曲强度.label,屏幕扭曲强度,Screen Distort Strength,,
inspector.feature.关闭主材质Pass.label,关闭主材质Pass,Disable Main Material Pass,,
inspector.feature.屏幕扭曲Alpha整体调整.label,屏幕扭曲Alpha整体调整,Screen Distort Alpha Refine,,
inspector.feature.扭曲模式.label,扭曲模式,Distort Mode,,
inspector.feature.扭曲贴图.label,扭曲贴图,Distort Texture,,
inspector.feature.扭曲贴图 Wrap.label,扭曲贴图循环模式,Distort Texture Wrap,,
inspector.feature.扭曲贴图UV来源.label,扭曲贴图UV来源,Distort Texture UV Source,,
inspector.feature.扭曲方向强度.label,扭曲方向强度,Distort Direction Strength,,
inspector.feature.扭曲方向强度X自定义曲线.label,扭曲方向强度X自定义曲线,Distort Direction X Custom Data,,
inspector.feature.扭曲方向强度Y自定义曲线.label,扭曲方向强度Y自定义曲线,Distort Direction Y Custom Data,,
inspector.feature.扭曲旋转.label,扭曲旋转,Distort Rotation,,
inspector.feature.扭曲偏移速度.label,扭曲偏移速度,Distort Offset Speed,,
inspector.feature.0.5为中值,双向扭曲.label,0.5为中值,双向扭曲,0.5 Is Mid Value Bidirectional Distort,,
inspector.feature.折射率.label,折射率,Refraction IOR,,
inspector.feature.扭曲程序噪波混合.label,扭曲程序噪波混合,Distort Program Noise Blend,,
inspector.feature.扭曲遮罩.label,扭曲遮罩,Distort Mask,,
inspector.feature.扭曲遮罩贴图.label,扭曲遮罩贴图,Distort Mask Texture,,
inspector.feature.扭曲遮罩贴图 Wrap.label,扭曲遮罩贴图循环模式,Distort Mask Texture Wrap,,
inspector.feature.扭曲遮罩图通道选择.label,扭曲遮罩图通道选择,Distort Mask Channel,,
inspector.feature.扭曲遮罩贴图UV来源.label,扭曲遮罩贴图UV来源,Distort Mask UV Source,,
inspector.feature.色散.label,色散,Chromatic Aberration,,
inspector.feature.色散强度受扭曲强度影响.label,色散强度受扭曲强度影响,Chromatic Strength Follows Distort Strength,,
inspector.feature.色散强度.label,色散强度,Chromatic Strength,,
inspector.feature.色散强度自定义曲线.label,色散强度自定义曲线,Chromatic Strength Custom Data,,
inspector.feature.流光(颜色相加).label,流光(颜色相加),Emission (Add Color),,
inspector.feature.流光贴图.label,流光贴图,Emission Texture,,
inspector.feature.流光贴图 Wrap.label,流光贴图循环模式,Emission Texture Wrap,,
inspector.feature.流光贴图UV来源.label,流光贴图UV来源,Emission Texture UV Source,,
inspector.feature.流光贴图X轴偏移自定义曲线.label,流光贴图X轴偏移自定义曲线,Emission Offset X Custom Data,,
inspector.feature.流光贴图Y轴偏移自定义曲线.label,流光贴图Y轴偏移自定义曲线,Emission Offset Y Custom Data,,
inspector.feature.流光贴图旋转.label,流光贴图旋转,Emission Texture Rotation,,
inspector.feature.流光贴图偏移速度.label,流光贴图偏移速度,Emission Offset Speed,,
inspector.feature.流光贴图扭曲强度.label,流光贴图扭曲强度,Emission Distortion Strength,,
inspector.feature.流光颜色强度.label,流光颜色强度,Emission Color Intensity,,
inspector.feature.渐变(颜色相乘).label,渐变(颜色相乘),Color Blend (Multiply),,
inspector.feature.颜色渐变贴图.label,颜色渐变贴图,Color Blend Texture,,
inspector.feature.颜色渐变贴图 Wrap.label,颜色渐变贴图循环模式,Color Blend Texture Wrap,,
inspector.feature.颜色渐变贴图UV来源.label,颜色渐变贴图UV来源,Color Blend UV Source,,
inspector.feature.颜色渐变贴图X轴偏移自定义曲线.label,颜色渐变贴图X轴偏移自定义曲线,Color Blend Offset X Custom Data,,
inspector.feature.颜色渐变贴图Y轴偏移自定义曲线.label,颜色渐变贴图Y轴偏移自定义曲线,Color Blend Offset Y Custom Data,,
inspector.feature.颜色渐变贴图旋转.label,颜色渐变贴图旋转,Color Blend Texture Rotation,,
inspector.feature.颜色渐变贴图偏移速度.label,颜色渐变贴图偏移速度,Color Blend Offset Speed,,
inspector.feature.颜色渐变扭曲强度.label,颜色渐变扭曲强度,Color Blend Distortion Strength,,
inspector.feature.颜色渐变图Alpha作用.label,颜色渐变图Alpha作用,Color Blend Alpha Mode,,
inspector.feature.颜色渐变图Alpha强度.label,颜色渐变图Alpha强度,Color Blend Alpha Strength,,
inspector.feature.颜色映射(Ramp).label,颜色映射(Ramp),Ramp Color,,
inspector.feature.Ramp来源模式.label,Ramp来源模式,Ramp Source Mode,,
inspector.feature.颜色映射黑白图.label,颜色映射黑白图,Ramp Mask Texture,,
inspector.feature.颜色映射黑白图 Wrap.label,颜色映射黑白图循环模式,Ramp Mask Texture Wrap,,
inspector.feature.颜色映射UV Wrap.label,颜色映射UV循环模式,Ramp UV Wrap,,
inspector.feature.颜色映射黑白图通道选择.label,颜色映射黑白图通道选择,Ramp Mask Channel,,
inspector.feature.颜色映射黑白图UV来源.label,颜色映射黑白图UV来源,Ramp Mask UV Source,,
inspector.feature.颜色映射贴图偏移速度.label,颜色映射贴图偏移速度,Ramp Texture Offset Speed,,
inspector.feature.颜色映射贴图旋转.label,颜色映射贴图旋转,Ramp Texture Rotation,,
inspector.feature.映射颜色.label,映射颜色,Ramp Colors,,
inspector.feature.Ramp颜色混合模式.label,Ramp颜色混合模式,Ramp Color Blend Mode,,
inspector.feature.颜色映射叠加颜色.label,颜色映射叠加颜色_hdr,Ramp Blend Color,,
inspector.feature.溶解.label,溶解,Dissolve,,
inspector.feature.溶解度黑白值测试.label,溶解度黑白值测试,Debug Dissolve Value,,
inspector.feature.溶解贴图.label,溶解贴图,Dissolve Texture,,
inspector.feature.溶解贴图 Wrap.label,溶解贴图循环模式,Dissolve Texture Wrap,,
inspector.feature.溶解贴图通道选择.label,溶解贴图通道选择,Dissolve Channel,,
inspector.feature.溶解贴图X轴偏移自定义曲线.label,溶解贴图X轴偏移自定义曲线,Dissolve Offset X Custom Data,,
inspector.feature.溶解贴图Y轴偏移自定义曲线.label,溶解贴图Y轴偏移自定义曲线,Dissolve Offset Y Custom Data,,
inspector.feature.溶解贴图UV来源.label,溶解贴图UV来源,Dissolve UV Source,,
inspector.feature.溶解贴图偏移速度.label,溶解贴图偏移速度,Dissolve Offset Speed,,
inspector.feature.溶解贴图旋转.label,溶解贴图旋转,Dissolve Texture Rotation,,
inspector.feature.溶解程序噪波混合.label,溶解程序噪波混合,Dissolve Program Noise Blend,,
inspector.feature.溶解值Pow.label,溶解值Pow,Dissolve Value Pow,,
inspector.feature.溶解强度.label,溶解强度,Dissolve Strength,,
inspector.feature.溶解强度自定义曲线.label,溶解强度自定义曲线,Dissolve Strength Custom Data,,
inspector.feature.溶解硬软度.label,溶解硬软度,Dissolve Softness,,
inspector.feature.溶解贴图扭曲强度.label,溶解贴图扭曲强度,Dissolve Texture Distortion Strength,,
inspector.feature.溶解描边.label,溶解描边,Dissolve Edge,,
inspector.feature.溶解描边颜色.label,溶解描边颜色,Dissolve Edge Color,,
inspector.feature.描边位置.label,描边位置,Edge Position,,
inspector.feature.描边软硬.label,描边软硬,Edge Softness,,
inspector.feature.溶解Ramp图功能.label,溶解Ramp图功能,Dissolve Ramp,,
inspector.feature.溶解Ramp模式.label,溶解Ramp模式,Dissolve Ramp Mode,,
inspector.feature.溶解Ramp图.label,溶解Ramp图,Dissolve Ramp Texture,,
inspector.feature.溶解Ramp图 Wrap.label,溶解Ramp图循环模式,Dissolve Ramp Texture Wrap,,
inspector.feature.Ramp颜色.label,Ramp颜色,Ramp Color,,
inspector.feature.Ramp颜色叠加.label,Ramp颜色叠加,Ramp Color Multiply,,
inspector.feature.溶解RampUV Wrap.label,溶解RampUV循环模式,Dissolve Ramp UV Wrap,,
inspector.feature.溶解Ramp混合模式.label,溶解Ramp混合模式,Dissolve Ramp Blend Mode,,
inspector.feature.溶解遮罩图(过程溶解).label,溶解遮罩图(过程溶解),Dissolve Mask (Process),,
inspector.feature.溶解遮罩模式.label,溶解遮罩模式,Dissolve Mask Mode,,
inspector.feature.溶解遮罩图.label,溶解遮罩图,Dissolve Mask Texture,,
inspector.feature.溶解遮罩图 Wrap.label,溶解遮罩图循环模式,Dissolve Mask Texture Wrap,,
inspector.feature.溶解遮罩图UV来源.label,溶解遮罩图UV来源,Dissolve Mask UV Source,,
inspector.feature.溶解遮罩图通道选择.label,溶解遮罩图通道选择,Dissolve Mask Channel,,
inspector.feature.溶解遮罩强度.label,溶解遮罩强度,Dissolve Mask Strength,,
inspector.feature.溶解遮罩图强度自定义曲线.label,溶解遮罩图强度自定义曲线,Dissolve Mask Strength Custom Data,,
inspector.feature.程序化噪波.label,程序化噪波,Program Noise,,
inspector.feature.程序化噪波测试颜色.label,程序化噪波测试颜色,Debug Program Noise,,
inspector.feature.程序噪波UV来源.label,程序噪波UV来源,Program Noise UV Source,,
inspector.feature.程序化噪波旋转.label,程序化噪波旋转,Program Noise Rotation,,
inspector.feature.Perlin噪波.label,Perlin噪波,Perlin Noise,,
inspector.feature.噪波1缩放.label,噪波1缩放,Noise 1 Scale,,
inspector.feature.噪波1速度.label,噪波1速度,Noise 1 Speed,,
inspector.feature.噪波1偏移.label,噪波1偏移,Noise 1 Offset,,
inspector.feature.噪波1偏移速度.label,噪波1偏移速度,Noise 1 Offset Speed,,
inspector.feature.噪波1偏移速度X自定义曲线.label,噪波1偏移速度X自定义曲线,Noise 1 Offset X Custom Data,,
inspector.feature.噪波1偏移速度Y自定义曲线.label,噪波1偏移速度Y自定义曲线,Noise 1 Offset Y Custom Data,,
inspector.feature.Voronoi噪波.label,Voronoi噪波,Voronoi Noise,,
inspector.feature.噪波2缩放.label,噪波2缩放,Noise 2 Scale,,
inspector.feature.噪波2速度.label,噪波2速度,Noise 2 Speed,,
inspector.feature.噪波2偏移.label,噪波2偏移,Noise 2 Offset,,
inspector.feature.噪波2偏移速度.label,噪波2偏移速度,Noise 2 Offset Speed,,
inspector.feature.噪波2偏移速度X自定义曲线.label,噪波2偏移速度X自定义曲线,Noise 2 Offset X Custom Data,,
inspector.feature.噪波2偏移速度Y自定义曲线.label,噪波2偏移速度Y自定义曲线,Noise 2 Offset Y Custom Data,,
inspector.feature.噪波1和噪波2混合系数.label,噪波1和噪波2混合系数,Noise 1/2 Blend,,
inspector.feature.两种程序噪波混合.label,两种程序噪波混合,Two Program Noise Blend,,
inspector.feature.公共UV.label,公共UV,Shared UV,,
inspector.feature.公共UV来源.label,公共UV来源,Shared UV Source,,
inspector.feature.公共UV Tiling.label,Tilling,Shared UV Tiling,,
inspector.feature.公共UV Offset.label,Offset,Shared UV Offset,,
inspector.feature.公共UV偏移速度.label,偏移速度,Shared UV Offset Speed,,
inspector.feature.旋转.label,旋转,Rotation,,
inspector.feature.公共UV X轴偏移自定义曲线.label,偏移X自定义曲线,Shared UV Offset X Custom Data,,
inspector.feature.公共UV Y轴偏移自定义曲线.label,偏移Y自定义曲线,Shared UV Offset Y Custom Data,,
inspector.feature.菲涅尔.label,菲涅尔,Fresnel,,
inspector.feature.菲涅尔测试颜色.label,菲涅尔值测试,Debug Fresnel,,
inspector.feature.菲涅尔模式.label,菲涅尔模式,Fresnel Mode,,
inspector.feature.菲涅尔颜色.label,菲涅尔颜色,Fresnel Color,,
inspector.feature.菲涅尔透明乘数.label,菲涅尔透明乘数,Fresnel Alpha Multiplier,,
inspector.feature.菲涅尔强度.label,菲涅尔强度,Fresnel Strength,,
inspector.feature.菲涅尔位置.label,菲涅尔位置,Fresnel Position,,
inspector.feature.菲涅尔位置自定义曲线.label,菲尼尔位置自定义曲线,Fresnel Position Custom Data,,
inspector.feature.菲涅尔范围Pow.label,菲涅尔范围Pow,Fresnel Range Pow,,
inspector.feature.菲涅尔硬度.label,菲涅尔硬度,Fresnel Hardness,,
inspector.feature.翻转菲涅尔.label,翻转菲涅尔,Invert Fresnel,,
inspector.feature.菲涅尔颜色受Alpha影响.label,菲涅尔颜色受Alpha影响,Fresnel Color Affected By Alpha,,
inspector.feature.菲涅尔方向偏移X.label,菲涅尔方向偏移X,Fresnel Direction Offset X,,
inspector.feature.菲涅尔方向偏移Y.label,菲涅尔方向偏移Y,Fresnel Direction Offset Y,,
inspector.feature.菲涅尔方向偏移Z.label,菲涅尔方向偏移Z,Fresnel Direction Offset Z,,
inspector.feature.顶点偏移.label,顶点偏移,Vertex Offset,,
inspector.feature.顶点偏移方向测试.label,顶点偏移方向测试,Debug Vertex Offset Direction,,
inspector.feature.顶点偏移贴图.label,顶点偏移贴图,Vertex Offset Texture,,
inspector.feature.顶点偏移贴图 Wrap.label,顶点偏移贴图循环模式,Vertex Offset Texture Wrap,,
inspector.feature.顶点偏移贴图UV来源.label,顶点偏移贴图UV来源,Vertex Offset UV Source,,
inspector.feature.顶点扰动X轴偏移自定义曲线.label,顶点扰动X轴偏移自定义曲线,Vertex Offset X Custom Data,,
inspector.feature.顶点扰动Y轴偏移自定义曲线.label,顶点扰动Y轴偏移自定义曲线,Vertex Offset Y Custom Data,,
inspector.feature.顶点偏移动画.label,顶点偏移动画,Vertex Offset Animation,,
inspector.feature.顶点偏移强度.label,顶点偏移强度,Vertex Offset Strength,,
inspector.feature.顶点扰动强度自定义曲线.label,顶点扰动强度自定义曲线,Vertex Offset Strength Custom Data,,
inspector.feature.顶点偏移从零开始.label,顶点偏移从零开始,Vertex Offset Starts From Zero,,
inspector.feature.顶点偏移使用法线方向.label,顶点偏移使用法线方向,Use Normal Direction,,
inspector.feature.顶点偏移本地方向X.label,顶点偏移本地方向X,Vertex Offset Local Direction X,,
inspector.feature.顶点偏移本地方向Y.label,顶点偏移本地方向Y,Vertex Offset Local Direction Y,,
inspector.feature.顶点偏移本地方向Z.label,顶点偏移本地方向Z,Vertex Offset Local Direction Z,,
inspector.feature.顶点偏移遮罩.label,顶点偏移遮罩,Vertex Offset Mask,,
inspector.feature.顶点偏移遮罩图.label,顶点偏移遮罩图,Vertex Offset Mask Texture,,
inspector.feature.顶点偏移遮罩图 Wrap.label,顶点偏移遮罩图循环模式,Vertex Offset Mask Texture Wrap,,
inspector.feature.顶点偏移遮罩图UV来源.label,顶点偏移遮罩图UV来源,Vertex Offset Mask UV Source,,
inspector.feature.顶点扰动遮罩X轴偏移自定义曲线.label,顶点扰动遮罩X轴偏移自定义曲线,Vertex Offset Mask X Custom Data,,
inspector.feature.顶点扰动遮罩Y轴偏移自定义曲线.label,顶点扰动遮罩Y轴偏移自定义曲线,Vertex Offset Mask Y Custom Data,,
inspector.feature.顶点偏移遮罩动画.label,顶点偏移遮罩动画,Vertex Offset Mask Animation,,
inspector.feature.顶点偏移遮罩强度.label,顶点偏移遮罩强度,Vertex Offset Mask Strength,,
inspector.feature.深度描边.label,深度描边,Depth Outline,,
inspector.feature.深度描边颜色.label,深度描边颜色,Depth Outline Color,,
inspector.feature.深度描边距离.label,深度描边距离,Depth Outline Distance,,
inspector.feature.深度贴花.label,深度贴花,Depth Decal,,
inspector.feature.遮蔽视差.label,遮蔽视差,Parallax,,
inspector.feature.视差贴图.label,视差贴图,Parallax Texture,,
inspector.feature.视差贴图 Wrap.label,视差贴图循环模式,Parallax Texture Wrap,,
inspector.feature.视差.label,视差,Parallax,,
inspector.feature.遮蔽视差最小层数.label,遮蔽视差最小层数,Parallax Min Layers,,
inspector.feature.遮蔽视差最大层数.label,遮蔽视差最大层数,Parallax Max Layers,,
inspector.feature.模板视差.label,模板视差,Portal,,
inspector.feature.模板视差蒙版.label,模板视差蒙版,Portal Mask,,
inspector.feature.序列帧融帧(丝滑).label,序列帧融帧(丝滑),Flipbook Blending,,
inspector.feature.VAT顶点动画图.label,VAT顶点动画图,VAT Vertex Animation Texture,,
inspector.feature.VAT模式.label,VAT模式,VAT Mode,,
inspector.feature.Houdini VAT Sub Mode.label,Houdini VAT Sub Mode,Houdini VAT Sub Mode,,
inspector.feature.VAT Frame CustomData.label,VAT Frame CustomData,VAT Frame CustomData,,
inspector.feature.Playback.label,Playback,Playback,,
inspector.feature.Auto Playback.label,Auto Playback,Auto Playback,,
inspector.feature.Display Frame.label,Display Frame,Display Frame,,
inspector.feature.Game Time at First Frame.label,Game Time at First Frame,Game Time at First Frame,,
inspector.feature.Playback Speed.label,Playback Speed,Playback Speed,,
inspector.feature.Houdini FPS.label,Houdini FPS,Houdini FPS,,
inspector.feature.Interframe Interpolation.label,Interframe Interpolation,Interframe Interpolation,,
inspector.feature.Animate First Frame.label,Animate First Frame,Animate First Frame,,
inspector.feature.Frame Count.label,Frame Count,Frame Count,,
inspector.feature.Bounds Metadata.label,Bounds Metadata,Bounds Metadata,,
inspector.feature.Bound Min X.label,Bound Min X,Bound Min X,,
inspector.feature.Bound Min Y.label,Bound Min Y,Bound Min Y,,
inspector.feature.Bound Min Z.label,Bound Min Z,Bound Min Z,,
inspector.feature.Bound Max X.label,Bound Max X,Bound Max X,,
inspector.feature.Bound Max Y.label,Bound Max Y,Bound Max Y,,
inspector.feature.Bound Max Z.label,Bound Max Z,Bound Max Z,,
inspector.feature.Textures.label,Textures,Textures,,
inspector.feature.Position Texture.label,Position Texture,Position Texture,,
inspector.feature.Position Texture 2.label,Position Texture 2,Position Texture 2,,
inspector.feature.Rotation Texture.label,Rotation Texture,Rotation Texture,,
inspector.feature.Color Texture.label,Color Texture,Color Texture,,
inspector.feature.Lookup Table.label,Lookup Table,Lookup Table,,
inspector.feature.Scale.label,Scale,Scale,,
inspector.feature.Global Piece Scale Multiplier.label,Global Piece Scale Multiplier,Global Piece Scale Multiplier,,
inspector.feature.Piece Scales in Position Alpha.label,Piece Scales in Position Alpha,Piece Scales in Position Alpha,,
inspector.feature.Particle Sprite.label,Particle Sprite,Particle Sprite,,
inspector.feature.Width Base Scale.label,Width Base Scale,Width Base Scale,,
inspector.feature.Height Base Scale.label,Height Base Scale,Height Base Scale,,
inspector.feature.Hide Overlapping Origin.label,Hide Overlapping Origin,Hide Overlapping Origin,,
inspector.feature.Origin Effective Radius.label,Origin Effective Radius,Origin Effective Radius,,
inspector.feature.Particles Can Spin.label,Particles Can Spin,Particles Can Spin,,
inspector.feature.Compute Spin from Heading.label,Compute Spin from Heading,Compute Spin from Heading,,
inspector.feature.Particle Spin Phase.label,Particle Spin Phase,Particle Spin Phase,,
inspector.feature.Scale by Velocity Amount.label,Scale by Velocity Amount,Scale by Velocity Amount,,
inspector.feature.Particle Texture U Scale.label,Particle Texture U Scale,Particle Texture U Scale,,
inspector.feature.Particle Texture V Scale.label,Particle Texture V Scale,Particle Texture V Scale,,
inspector.feature.Flags.label,Flags,Flags,,
inspector.feature.Positions Require Two Textures.label,Positions Require Two Textures,Positions Require Two Textures,,
inspector.feature.Use Compressed Normals (no rotTex).label,Use Compressed Normals (no rotTex),Use Compressed Normals (no rotTex),,
inspector.feature.Load Color Texture.label,Load Color Texture,Load Color Texture,,
inspector.feature.Load Lookup Table.label,Load Lookup Table,Load Lookup Table,,
inspector.feature.VAT texture.label,VAT texture,VAT Texture,,
inspector.feature.ImportScale.label,ImportScale,Import Scale,,
inspector.feature.TyFlow VAT Sub Mode.label,TyFlow VAT Sub Mode,TyFlow VAT Sub Mode,,
inspector.feature.Deforming skin.label,Deforming skin,Deforming Skin,,
inspector.feature.Skin bone count.label,Skin bone count,Skin Bone Count,,
inspector.feature.RGBA encoded.label,RGBA encoded,RGBA Encoded,,
inspector.feature.RGBA half.label,RGBA half,RGBA Half,,
inspector.feature.Gamma correction.label,Gamma correction,Gamma Correction,,
inspector.feature.VAT includes normals.label,VAT includes normals,VAT Includes Normals,,
inspector.feature.Affects shadows.label,Affects shadows,Affects Shadows,,
inspector.feature.Frame.label,Frame,Frame,,
inspector.feature.Frames.label,Frames,Frames,,
inspector.feature.Frame interpolation.label,Frame interpolation,Frame Interpolation,,
inspector.feature.Loop.label,Loop,Loop,,
inspector.feature.Interpolate loop.label,Interpolate loop,Interpolate Loop,,
inspector.feature.Autoplay.label,Autoplay,Autoplay,,
inspector.feature.AutoplaySpeed.label,AutoplaySpeed,Autoplay Speed,,
inspector.toolbar.ping.label,,,,
inspector.toolbar.ping.tip,跳到当前材质,Ping current material,,
inspector.toolbar.cleanUnusedTextures.label,,,,
inspector.toolbar.cleanUnusedTextures.tip,清除没有使用的贴图,Clean unused textures,,
inspector.toolbar.cleanUnusedTextures.undo,清除没有使用的贴图,Clean unused textures,,
inspector.toolbar.cleanUnusedTextures.log,清理 {0} 的无效贴图属性: {1},Cleaned unused texture property '{1}' on material '{0}',,
inspector.toolbar.copy.label,C,C,复制材质属性,Copy material properties
inspector.toolbar.paste.label,V,V,粘贴材质属性,Paste material properties
inspector.toolbar.paste.undo,粘贴材质属性,Paste material properties,,
inspector.toolbar.tierFormat.label,等级: {0},Tier: {0},,
inspector.toolbar.tierMixed.label,等级: Mixed,Tier: Mixed,,
inspector.toolbar.tierLow.label,,Low,,
inspector.toolbar.tierMedium.label,,Medium,,
inspector.toolbar.tierHigh.label,,High,,
inspector.toolbar.tierUltra.label,顶配,Ultra,,
inspector.toolbar.tier.tip,NBShader分级,NBShader feature tier,,
inspector.toolbar.setTier.undo,设置 NBShader 分级,Set NBShader Feature Tier,,
inspector.toolbar.specialReset.label,R,R,特殊重置功能,Special reset tools
inspector.toolbar.resetAll.label,重置所有,Reset All,,
inspector.toolbar.resetAll.undo,重置所有特殊功能,Reset All Special Tools,,
inspector.toolbar.resetDisabledFeatureChildren.label,重置关闭功能子属性,Reset Disabled Feature Children,,
inspector.toolbar.resetDisabledFeatureChildren.undo,重置关闭功能子属性,Reset Disabled Feature Children,,
inspector.toolbar.resetSpecialUV.label,重置特殊UV通道,Reset Special UV Channel,,
inspector.toolbar.resetSpecialUV.undo,重置特殊UV通道,Reset Special UV Channel,,
inspector.toolbar.resetTwirl.label,重置旋转扭曲,Reset Twirl,,
inspector.toolbar.resetTwirl.undo,重置旋转扭曲,Reset Twirl,,
inspector.toolbar.resetPolar.label,重置极坐标,Reset Polar Coordinates,,
inspector.toolbar.resetPolar.undo,重置极坐标,Reset Polar Coordinates,,
inspector.toolbar.collapseAll.label,,,,
inspector.toolbar.collapseAll.tip,折叠所有控件,Collapse all controls,,
inspector.toolbar.collapseAll.undo,折叠所有控件,Collapse all controls,,
inspector.toolbar.help.label,,,,
inspector.toolbar.help.tip,说明文档,Documentation,,
inspector.toolbar.settings.tip,NBShader设置,NBShader settings,,
inspector.projectSettings.generalSection,基础设置,General Settings,,
inspector.projectSettings.defaultLanguage,默认语言,Default Language,,
inspector.projectSettings.languageMode.option.0,跟随编辑器,Follow Editor,,
inspector.projectSettings.languageMode.option.1,中文,Chinese,,
inspector.projectSettings.languageMode.option.2,英文,English,,
inspector.featureLevel.providerLabel,NBShader 分级,NBShader Feature Levels,,
inspector.featureLevel.help.message,配置 NBShader Catalog Keyword 和 Pass 的分级白名单、Unity Quality 绑定和运行时资源导出。构建脚本通过 NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier 选择打包剔除等级。Catalog 外 Feature 会被忽略。,Configure NBShader managed Catalog keywords and shader passes per tier bind Unity Quality levels and export runtime settings. Build scripts select the build stripping tier through NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier. Catalog-external features are ignored.,,
inspector.featureLevel.undo.changeKeyword,修改 NBShader Feature Keyword,Change NBShader Feature Keyword,,
inspector.featureLevel.undo.resetTierKeywords,重置 NBShader 等级 Keyword,Reset NBShader Tier Keywords,,
inspector.featureLevel.undo.resetQualityMapping,重置 NBShader Quality 映射,Reset NBShader Quality Mapping,,
inspector.featureLevel.undo.changeQualityBinding,修改 NBShader Quality 绑定,Change NBShader Quality Binding,,
inspector.featureLevel.table.title,分级功能表,Feature Level Matrix,,
inspector.featureLevel.column.feature.label,配置 / Feature,Config / Feature,等级设置和受管理的 Catalog Feature,Tier settings and managed Catalog features
inspector.featureLevel.column.description.label,Raw Keyword / 说明,Raw Keyword / Note,原始 Shader Keyword 或配置说明,Raw shader keyword or configuration note
inspector.featureLevel.row.quality.label,Quality 绑定,Quality Binding,每个 Unity Quality Level 只能属于一个 NBShader 等级,Each Unity Quality Level belongs to exactly one NBShader tier
inspector.featureLevel.desc.quality,Unity Quality Level,Unity Quality Level,,
inspector.featureLevel.quality.menuTip,点击可把 Unity Quality Level 移动到这个 NBShader 等级,Click to move Unity Quality levels to this NBShader tier,,
inspector.featureLevel.quality.noLevels,没有 Quality Level,No Quality Levels,,
inspector.featureLevel.quality.none,,,,
inspector.featureLevel.keyword.tooltip,Raw Keyword{0}。该等级未勾选时会剔除使用此 Catalog Keyword 的 Variant。,Raw keyword: {0}. Unchecked in a tier strips variants using this Catalog keyword.,,
inspector.featureLevel.resetTierKeywords.button,重置等级 Keywords,Reset Tier Keywords,将 Feature 表格重置为内置默认值,Reset the keyword matrix to the built-in defaults
inspector.featureLevel.resetQualityMapping.button,重置 Quality 映射,Reset Quality Mapping,按默认 Quality 索引规则重置 Unity Quality 绑定,Reset Unity Quality bindings using the default quality-index rule
inspector.featureRuntimeSettings.updateFromProjectSettings.button,根据当前ProjectSetting更新配置,Update From Current Project Settings,将当前 Project Settings 数据写入这个 RuntimeSettings 配置资源,Write the current Project Settings data into this RuntimeSettings asset
inspector.featureRuntimeSettings.updateFromProjectSettings.successTitle,运行时配置已更新,Runtime Settings Updated,,
inspector.featureRuntimeSettings.updateFromProjectSettings.successMessage,当前 NBShader Project Settings 数据已写入这个 RuntimeSettings 配置资源,The current NBShader Project Settings data was written to this RuntimeSettings asset,,
inspector.featureLevel.openVariantCollectionBuilder.button,打开变体集合生成器,Open Variant Collection Builder,打开 NBShader 变体集合生成器,Open the NBShader variant collection builder
inspector.featureLevel.applyCurrentQualityTierToLoadedMaterials.button,应用当前 Quality 等级到已加载材质,Apply Current Quality Tier To Loaded Materials,将当前 Unity Quality 映射到的 NBShader 等级应用到所有已加载的 NBShader2 材质,Apply the tier bound to the current Unity Quality Level to all loaded NBShader2 materials
inspector.featureLevel.applyCurrentQualityTierToProjectMaterials.button,应用当前 Quality 等级到项目材质,Apply Current Quality Tier To Project Materials,扫描 Assets 并将当前 Unity Quality 映射到的 NBShader 等级应用到 NBShader2 材质资源,Scan Assets and apply the tier bound to the current Unity Quality Level to NBShader2 material assets
inspector.featureLevel.keyword.NB_DEBUG_DISSOLVE.label,调试溶解,Debug Dissolve,,
inspector.featureLevel.keyword.NB_DEBUG_DISTORT.label,调试扭曲,Debug Distort,,
inspector.featureLevel.keyword.NB_DEBUG_FRESNEL.label,调试菲涅尔,Debug Fresnel,,
inspector.featureLevel.keyword.NB_DEBUG_MASK.label,调试遮罩,Debug Mask,,
inspector.featureLevel.keyword.NB_DEBUG_PNOISE.label,调试程序噪声,Debug Program Noise,,
inspector.featureLevel.keyword.NB_DEBUG_VERTEX_OFFSET.label,调试顶点偏移,Debug Vertex Offset,,
inspector.featureLevel.keyword.VFX_SIX_WAY_ABSORPTION.label,六向光吸收,Six Way Absorption,,
inspector.featureLevel.keyword._ALPHAMODULATE_ON.label,Alpha 调制,Alpha Modulate,,
inspector.featureLevel.keyword._ALPHAPREMULTIPLY_ON.label,预乘 Alpha,Premultiply Alpha,,
inspector.featureLevel.keyword._ALPHATEST_ON.label,Alpha 裁剪,Alpha Test,,
inspector.featureLevel.keyword._COLORMAPBLEND.label,颜色图混合,Color Map Blend,,
inspector.featureLevel.keyword._COLOR_RAMP.label,颜色渐变,Color Ramp,,
inspector.featureLevel.keyword._DEPTH_DECAL.label,深度贴花,Depth Decal,,
inspector.featureLevel.keyword._DISSOLVE.label,溶解,Dissolve,,
inspector.featureLevel.keyword._DISTORT_REFRACTION.label,折射扭曲,Distort Refraction,,
inspector.featureLevel.keyword._EMISSION.label,自发光,Emission,,
inspector.featureLevel.keyword._FLIPBOOKBLENDING_ON.label,序列帧混合,Flipbook Blending,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_BLINN_PHONG.label,Blinn-Phong 光照,Blinn-Phong Lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_HALF_LAMBERT.label,Half Lambert 光照,Half Lambert Lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_PBR.label,PBR 光照,PBR Lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_SIX_WAY.label,六向光照,Six Way Lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_UNLIT.label,无光照,Unlit Lighting,,
inspector.featureLevel.keyword._HOUDINI_VAT_DYNAMIC_REMESH.label,Houdini VAT 动态重网格,Houdini VAT Dynamic Remesh,,
inspector.featureLevel.keyword._HOUDINI_VAT_PARTICLE_SPRITE.label,Houdini VAT 粒子精灵,Houdini VAT Particle Sprite,,
inspector.featureLevel.keyword._HOUDINI_VAT_RIGIDBODY.label,Houdini VAT 刚体,Houdini VAT Rigid Body,,
inspector.featureLevel.keyword._HOUDINI_VAT_SOFTBODY.label,Houdini VAT 软体,Houdini VAT Soft Body,,
inspector.featureLevel.keyword._MASKMAP_ON.label,遮罩贴图,Mask Map,,
inspector.featureLevel.keyword._MATCAP.label,MatCap,MatCap,,
inspector.featureLevel.keyword._NOISEMAP.label,噪声贴图,Noise Map,,
inspector.featureLevel.keyword._NOISEMAP_NORMALIZEED.label,噪声归一化,Noise Normalize,,
inspector.featureLevel.keyword._NORMALMAP.label,法线贴图,Normal Map,,
inspector.featureLevel.keyword._OVERRIDE_Z.label,Override Z,Override Z,,
inspector.featureLevel.keyword._PARALLAX_MAPPING.label,视差映射,Parallax Mapping,,
inspector.featureLevel.keyword._PARCUSTOMDATA_ON.label,粒子自定义数据,Particle Custom Data,,
inspector.featureLevel.keyword._PROGRAM_NOISE.label,程序噪声,Program Noise,,
inspector.featureLevel.keyword._SCREEN_DISTORT_MODE.label,屏幕扭曲,Screen Distort,,
inspector.featureLevel.keyword._SCRIPTABLETIME.label,可编程时间,Scriptable Time,,
inspector.featureLevel.keyword._SHARED_UV.label,共享 UV,Shared UV,,
inspector.featureLevel.keyword._SOFTPARTICLES_ON.label,软粒子,Soft Particles,,
inspector.featureLevel.keyword._SPECULAR_COLOR.label,高光颜色,Specular Color,,
inspector.featureLevel.keyword._STENCIL_WITHOUT_PLAYER.label,无 Player 模板,Stencil Without Player,,
inspector.featureLevel.keyword._TYFLOW_VAT_ABSOLUTE.label,TyFlow VAT 绝对模式,TyFlow VAT Absolute,,
inspector.featureLevel.keyword._TYFLOW_VAT_RELATIVE.label,TyFlow VAT 相对模式,TyFlow VAT Relative,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PR.label,TyFlow VAT 皮肤 PR,TyFlow VAT Skin PR,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSAVE.label,TyFlow VAT 皮肤 PR 保存,TyFlow VAT Skin PR Save,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSXYZ.label,TyFlow VAT 皮肤 PRSXYZ,TyFlow VAT Skin PRSXYZ,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_R.label,TyFlow VAT 皮肤 R,TyFlow VAT Skin R,,
inspector.featureLevel.keyword._UNSCALETIME.label,非缩放时间,Unscaled Time,,
inspector.featureLevel.keyword._VAT.label,VAT,VAT,,
inspector.featureLevel.keyword._VAT_HOUDINI.label,Houdini VAT,Houdini VAT,,
inspector.featureLevel.keyword._VAT_TYFLOW.label,TyFlow VAT,TyFlow VAT,,
inspector.featureLevel.group.tooltip,点击折叠按钮显示或隐藏子级 Row,Click the foldout to show or hide child rows,,
inspector.featureLevel.desc.group,分组,Group,,
inspector.featureLevel.group.mode.label,模式设置,Mode,跟随材质面板的模式设置顺序,Matches the material inspector Mode order
inspector.featureLevel.group.transparent.label,透明模式,Transparent Mode,透明模式相关 Keyword,Transparent mode related keywords
inspector.featureLevel.group.time.label,时间模式,Time Mode,时间来源相关 Keyword,Time source related keywords
inspector.featureLevel.group.base.label,基本全局功能,Base,跟随材质面板的基本全局功能顺序,Matches the material inspector Base order
inspector.featureLevel.group.particle.label,粒子数据,Particle Data,粒子自定义数据相关 Keyword,Particle custom data related keywords
inspector.featureLevel.group.light.label,光照功能,Lighting,跟随材质面板的光照功能顺序,Matches the material inspector Lighting order
inspector.featureLevel.group.lightMode.label,光照模式,Light Mode,光照模式 Keyword,Light mode keywords
inspector.featureLevel.group.feature.label,特别功能,Feature,跟随材质面板的特别功能 Toggle 顺序,Matches the material inspector Feature toggle order
inspector.featureLevel.group.fresnel.label,菲涅尔,Fresnel,菲涅尔相关 Keyword,Fresnel related keywords
inspector.featureLevel.group.vertexOffset.label,顶点偏移,Vertex Offset,顶点偏移相关 Keyword,Vertex offset related keywords
inspector.featureLevel.group.depth.label,深度功能,Depth,深度相关 Keyword,Depth related keywords
inspector.featureLevel.group.vatMode.label,VAT 模式,VAT Mode,VAT 主模式 Keyword,VAT main mode keywords
inspector.featureLevel.group.houdiniVat.label,Houdini VAT,Houdini VAT,Houdini VAT 子模式 Keyword,Houdini VAT sub-mode keywords
inspector.featureLevel.group.tyflowVat.label,TyFlow VAT,TyFlow VAT,TyFlow VAT 子模式 Keyword,TyFlow VAT sub-mode keywords
inspector.featureLevel.column.cost.label,性能消耗,Performance Cost,估算启用该功能后的 Shader 性能消耗,Estimated shader cost when this feature is enabled
inspector.featureLevel.column.effect.label,功能说明,Feature Effect,简要说明该 Keyword 控制的功能,Short description of what this keyword enables
inspector.featureLevel.cost.low,,Low,,
inspector.featureLevel.cost.medium,,Medium,,
inspector.featureLevel.cost.high,,High,,
inspector.featureLevel.cost.ultra,超高,Ultra,,
inspector.featureLevel.cost.tooltip,该 Keyword 估算的 Shader 性能消耗,Estimated shader performance cost for this keyword,,
inspector.featureLevel.desc.none,,,,
inspector.featureLevel.desc.config,配置,Config,,
inspector.featureLevel.effect.quality.label,绑定 Unity Quality 到 NBShader 等级,Bind Unity Quality Levels to NBShader tiers,每个 Unity Quality Level 只能属于一个 NBShader 等级,Each Unity Quality Level belongs to exactly one NBShader tier
inspector.featureLevel.keyword._CHROMATIC_ABERRATION.label,色散,Chromatic Aberration,,
inspector.featureLevel.keyword._COLOR_RAMP_MAP.label,颜色渐变贴图,Color Ramp Map,,
inspector.featureLevel.keyword._DEPTH_OUTLINE.label,深度描边,Depth Outline,,
inspector.featureLevel.keyword._DISSOLVE_MASK.label,溶解遮罩,Dissolve Mask,,
inspector.featureLevel.keyword._DISSOLVE_RAMP.label,溶解 Ramp,Dissolve Ramp,,
inspector.featureLevel.keyword._DISSOLVE_RAMP_MAP.label,溶解 Ramp 图,Dissolve Ramp Map,,
inspector.featureLevel.keyword._DISTANCE_FADE.label,距离淡化,Distance Fade,,
inspector.featureLevel.keyword._FRESNEL.label,菲涅尔,Fresnel,,
inspector.featureLevel.keyword._MASKMAP2_ON.label,遮罩贴图 2,Mask Map 2,,
inspector.featureLevel.keyword._MASKMAP3_ON.label,遮罩贴图 3,Mask Map 3,,
inspector.featureLevel.keyword._NOISE_MASKMAP.label,扭曲遮罩,Noise Mask Map,,
inspector.featureLevel.keyword._PROGRAM_NOISE_SIMPLE.label,程序噪声 Perlin,Program Noise Simple,,
inspector.featureLevel.keyword._PROGRAM_NOISE_VORONOI.label,程序噪声 Voronoi,Program Noise Voronoi,,
inspector.featureLevel.keyword._VERTEX_OFFSET.label,顶点偏移,Vertex Offset,,
inspector.featureLevel.keyword._VERTEX_OFFSET_MASKMAP.label,顶点偏移遮罩,Vertex Offset Mask Map,,
inspector.featureLevel.keyword.NB_DEBUG_DISSOLVE.effect,显示溶解数值方便调试,Shows dissolve values for debugging,,
inspector.featureLevel.keyword.NB_DEBUG_DISTORT.effect,显示扭曲强度方便调试,Shows distortion strength for debugging,,
inspector.featureLevel.keyword.NB_DEBUG_FRESNEL.effect,显示菲涅尔数值方便调试,Shows fresnel values for debugging,,
inspector.featureLevel.keyword.NB_DEBUG_MASK.effect,显示遮罩数值方便调试,Shows mask values for debugging,,
inspector.featureLevel.keyword.NB_DEBUG_PNOISE.effect,显示程序噪声数值方便调试,Shows procedural noise values for debugging,,
inspector.featureLevel.keyword.NB_DEBUG_VERTEX_OFFSET.effect,显示顶点偏移数值方便调试,Shows vertex offset values for debugging,,
inspector.featureLevel.keyword.VFX_SIX_WAY_ABSORPTION.effect,为六向光照增加吸收效果,Adds absorption response for six way lighting,,
inspector.featureLevel.keyword._ALPHAMODULATE_ON.effect,使用 Alpha 调制透明混合,Uses alpha modulation transparent blending,,
inspector.featureLevel.keyword._ALPHAPREMULTIPLY_ON.effect,使用预乘 Alpha 透明混合,Uses premultiplied alpha blending,,
inspector.featureLevel.keyword._ALPHATEST_ON.effect,按 Alpha 阈值裁剪像素,Cuts pixels by alpha threshold,,
inspector.featureLevel.keyword._CHROMATIC_ABERRATION.effect,分离颜色通道产生色散,Splits color channels for distortion fringe,,
inspector.featureLevel.keyword._COLORMAPBLEND.effect,混合额外的颜色渐变贴图,Blends an extra color gradient texture,,
inspector.featureLevel.keyword._COLOR_RAMP.effect,使用 Ramp 重新映射颜色,Remaps color through a ramp,,
inspector.featureLevel.keyword._COLOR_RAMP_MAP.effect,使用贴图作为颜色 Ramp 来源,Uses a texture as the color ramp source,,
inspector.featureLevel.keyword._DEPTH_DECAL.effect,使用场景深度投射贴花效果,Projects decal effect using scene depth,,
inspector.featureLevel.keyword._DEPTH_OUTLINE.effect,使用深度差生成描边效果,Creates outline effect using depth difference,,
inspector.featureLevel.keyword._OVERRIDE_Z.effect,写入固定相机眼深度到 SV_Depth,Writes a fixed camera eye depth through SV_Depth,,
inspector.featureLevel.keyword._DISSOLVE.effect,按噪声或贴图裁剪并混合溶解,Clips and blends pixels for dissolve,,
inspector.featureLevel.keyword._DISSOLVE_MASK.effect,使用遮罩控制过程溶解范围,Uses a process mask for dissolve,,
inspector.featureLevel.keyword._DISSOLVE_RAMP.effect,为溶解边缘增加 Ramp 着色,Adds ramp coloring to dissolve edges,,
inspector.featureLevel.keyword._DISSOLVE_RAMP_MAP.effect,使用贴图控制溶解 Ramp 颜色,Uses a texture for dissolve ramp color,,
inspector.featureLevel.keyword._DISTANCE_FADE.effect,根据相机距离淡化材质,Fades material by camera distance,,
inspector.featureLevel.keyword._DISTORT_REFRACTION.effect,使用折射方式计算扭曲,Uses refraction style distortion,,
inspector.featureLevel.keyword._EMISSION.effect,增加自发光颜色或贴图贡献,Adds emissive color or texture contribution,,
inspector.featureLevel.keyword._FLIPBOOKBLENDING_ON.effect,在序列帧之间进行平滑混合,Blends between flipbook frames,,
inspector.featureLevel.keyword._FRESNEL.effect,增加基于视角的边缘光,Adds view angle based rim lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_BLINN_PHONG.effect,使用 Blinn Phong 光照模型,Uses Blinn Phong lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_HALF_LAMBERT.effect,使用 Half Lambert 光照模型,Uses half Lambert lighting,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_PBR.effect,使用 PBR 光照计算,Uses PBR lighting calculations,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_SIX_WAY.effect,使用六向光照数据,Uses six way lighting data,,
inspector.featureLevel.keyword._FX_LIGHT_MODE_UNLIT.effect,使用无光照渲染,Uses unlit shading,,
inspector.featureLevel.keyword._HOUDINI_VAT_DYNAMIC_REMESH.effect,使用 Houdini 动态重网格 VAT 类型,Uses Houdini dynamic remesh VAT mode,,
inspector.featureLevel.keyword._HOUDINI_VAT_PARTICLE_SPRITE.effect,使用 Houdini 粒子精灵 VAT 类型,Uses Houdini particle sprite VAT mode,,
inspector.featureLevel.keyword._HOUDINI_VAT_RIGIDBODY.effect,使用 Houdini 刚体 VAT 类型,Uses Houdini rigid body VAT mode,,
inspector.featureLevel.keyword._HOUDINI_VAT_SOFTBODY.effect,使用 Houdini 软体 VAT 类型,Uses Houdini soft body VAT mode,,
inspector.featureLevel.keyword._MASKMAP_ON.effect,启用第一张遮罩贴图,Uses the first mask map,,
inspector.featureLevel.keyword._MASKMAP2_ON.effect,启用第二张遮罩贴图,Uses the second mask map,,
inspector.featureLevel.keyword._MASKMAP3_ON.effect,启用第三张遮罩贴图,Uses the third mask map,,
inspector.featureLevel.keyword._MATCAP.effect,增加 MatCap 贴图光照,Adds matcap lighting texture,,
inspector.featureLevel.keyword._NOISEMAP.effect,使用噪声贴图产生扭曲,Uses a noise map for distortion,,
inspector.featureLevel.keyword._NOISE_MASKMAP.effect,使用遮罩限制扭曲范围,Masks the distortion effect,,
inspector.featureLevel.keyword._NORMALMAP.effect,使用法线贴图增加光照细节,Uses normal map lighting detail,,
inspector.featureLevel.keyword._PARALLAX_MAPPING.effect,偏移 UV 模拟视差深度,Offsets UVs for parallax depth,,
inspector.featureLevel.keyword._PARCUSTOMDATA_ON.effect,读取粒子 Custom Data 通道,Reads particle custom data channels,,
inspector.featureLevel.keyword._PROGRAM_NOISE.effect,在 Shader 中生成程序噪声,Generates procedural noise in shader,,
inspector.featureLevel.keyword._PROGRAM_NOISE_SIMPLE.effect,启用简单程序噪声,Enables simple procedural noise,,
inspector.featureLevel.keyword._PROGRAM_NOISE_VORONOI.effect,启用 Voronoi 程序噪声,Enables Voronoi procedural noise,,
inspector.featureLevel.keyword._SCREEN_DISTORT_MODE.effect,采样屏幕纹理实现扭曲,Samples screen texture for distortion,,
inspector.featureLevel.keyword._SCRIPTABLETIME.effect,使用脚本传入的时间值,Uses script provided time value,,
inspector.featureLevel.keyword._SHARED_UV.effect,共享一组通用 UV 变换,Shares a common UV transform,,
inspector.featureLevel.keyword._SOFTPARTICLES_ON.effect,使用场景深度柔化粒子边缘,Softens particles using scene depth,,
inspector.featureLevel.keyword._SPECULAR_COLOR.effect,增加高光颜色控制,Adds specular color highlight,,
inspector.featureLevel.keyword._STENCIL_WITHOUT_PLAYER.effect,使用不含 Player 的模板遮罩,Uses stencil without player mask,,
inspector.featureLevel.keyword._TYFLOW_VAT_ABSOLUTE.effect,使用 TyFlow 绝对 VAT 模式,Uses TyFlow absolute VAT mode,,
inspector.featureLevel.keyword._TYFLOW_VAT_RELATIVE.effect,使用 TyFlow 相对 VAT 模式,Uses TyFlow relative VAT mode,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PR.effect,使用 TyFlow Skin PR VAT 模式,Uses TyFlow skin PR VAT mode,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSAVE.effect,使用 TyFlow Skin PR Save VAT 模式,Uses TyFlow skin PR save VAT mode,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSXYZ.effect,使用 TyFlow Skin PRSXYZ VAT 模式,Uses TyFlow skin PRSXYZ VAT mode,,
inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_R.effect,使用 TyFlow Skin R VAT 模式,Uses TyFlow skin R VAT mode,,
inspector.featureLevel.keyword._UNSCALETIME.effect,使用不受 TimeScale 影响的时间,Uses unscaled time,,
inspector.featureLevel.keyword._VAT.effect,启用顶点动画贴图播放,Enables vertex animation texture playback,,
inspector.featureLevel.keyword._VAT_HOUDINI.effect,使用 Houdini VAT 数据布局,Uses Houdini VAT data layout,,
inspector.featureLevel.keyword._VAT_TYFLOW.effect,使用 TyFlow VAT 数据布局,Uses TyFlow VAT data layout,,
inspector.featureLevel.keyword._VERTEX_OFFSET.effect,在 Shader 中偏移顶点,Offsets vertices in the shader,,
inspector.featureLevel.keyword._VERTEX_OFFSET_MASKMAP.effect,用贴图遮罩顶点偏移范围,Masks vertex offset by texture,,
inspector.featureLevel.saveCurrentAsDefault.button,保存当前配置为默认,Save Current Config as Default,将当前四个等级的 Keyword 配置写入 Package 默认 LevelAsset,Write the current tier keyword matrix into the package default LevelAsset
inspector.featureLevel.saveCurrentAsDefault.failedTitle,保存默认配置失败,Save Default Config Failed,,
inspector.featureLevel.saveCurrentAsDefault.failedMessage,无法写入 Package 默认 LevelAsset。请确认 Package 路径可写。,Could not write the package default LevelAsset. Please make sure the package path is writable.,,
inspector.featureLevel.dialog.ok,确定,OK,,
inspector.debugSymbols.providerLabel,NBShader2 调试符号,NBShader2 Debug Symbols,,
inspector.debugSymbols.help.message,通过改写 NBShader.shader 引用的包内 include 控制 NBShader2 编译调试符号。仅在外部工具调试 Shader 时开启。,Controls NBShader2 shader compiler debug symbols by rewriting the package include used by NBShader.shader. Enable only while debugging external shader tools.,,
inspector.debugSymbols.includeMismatch.message,ProjectSettings 值和包内 include 内容不一致。应用当前设置以重新同步 Shader 编译输入。,The ProjectSettings value and package include content do not match. Apply the current setting to resync the shader compiler input.,,
inspector.debugSymbols.enable.label,启用 NBShader2 调试符号,Enable NBShader2 Debug Symbols,将 #pragma enable_d3d11_debug_symbols 写入 NBShader2 调试 pragma include,Writes #pragma enable_d3d11_debug_symbols into the NBShader2 debug pragma include
inspector.debugSymbols.dirtyWarning.message,启用此选项会修改 NB_FX 包内的 NBShaderDebugPragmas.hlsl。除非明确需要 Shader 调试符号,否则不要提交开启状态的 include。,Enabling this option modifies NBShaderDebugPragmas.hlsl in the NB_FX package. Do not commit the enabled include unless shader debug symbols are deliberately required.,,
inspector.debugSymbols.cachingPreprocessor.label,Caching Shader Preprocessor,Caching Shader Preprocessor,#include_with_pragmas 需要启用 Caching Shader Preprocessor,#include_with_pragmas requires the Caching Shader Preprocessor
inspector.debugSymbols.cachingPreprocessorWarning.message,#include_with_pragmas 需要启用 Caching Shader Preprocessor。使用 NBShader2 调试符号前请先启用。,#include_with_pragmas requires the Caching Shader Preprocessor. Enable it before using NBShader2 debug symbols.,,
inspector.debugSymbols.settingsState.label,ProjectSettings 状态,ProjectSettings State,保存于 ProjectSettings/NBShaderFeatureLevels.asset 的状态,Saved state in ProjectSettings/NBShaderFeatureLevels.asset
inspector.debugSymbols.includeState.label,Include 文件状态,Include File State,NBShader.shader 实际使用的包内 include 内容,Actual package include content used by NBShader.shader
inspector.debugSymbols.status.enabled,已启用,Enabled,,
inspector.debugSymbols.status.disabled,已关闭,Disabled,,
inspector.debugSymbols.status.missing,缺失,Missing,,
inspector.debugSymbols.undo.changeSetting,修改 NBShader2 调试符号,Change NBShader2 Debug Symbols,,
inspector.debugSymbols.applyFailed.title,应用 NBShader2 调试符号失败,Apply NBShader2 Debug Symbols Failed,,
inspector.debugSymbols.applyFailed.message,无法写入 NBShaderDebugPragmas.hlsl,Could not write NBShaderDebugPragmas.hlsl: ,,
inspector.debugSymbols.confirmEnable.title,启用 NBShader2 调试符号,Enable NBShader2 Debug Symbols,,
inspector.debugSymbols.confirmEnable.message,此操作会把 #pragma enable_d3d11_debug_symbols 写入 NB_FX 包内 include。开启期间 Shader 体积可能增加并关闭优化。,This writes #pragma enable_d3d11_debug_symbols into the NB_FX package include. Shader size can increase and optimizations are disabled while it is enabled.,,
inspector.debugSymbols.dialog.enable,启用,Enable,,
inspector.debugSymbols.dialog.cancel,取消,Cancel,,
inspector.debugSymbols.dialog.ok,确定,OK,,
inspector.debugSymbols.applySetting.button,应用当前设置到 Include,Apply Current Setting To Include,,
inspector.debugSymbols.pingInclude.button,选中调试开关include,Select Debug Toggle Include,,
inspector.debugSymbols.enableCachingPreprocessor.button,启用 Caching Shader Preprocessor,Enable Caching Shader Preprocessor,,
inspector.particleBaseMigration.providerLabel,ParticleBase 迁移,ParticleBase Migration,,
inspector.particleBaseMigration.settingsHelp,扫描引用旧版 ParticleBase Shader GUID 的材质资源,确认后迁移到 NBShader2。转换前请先做好资产备份或版本管理。,Scan material assets that reference the legacy ParticleBase shader GUID and migrate them to NBShader2 after confirmation. Back up assets or commit to version control before converting.,,
inspector.particleBaseMigration.openWindow.button,打开 ParticleBase 迁移窗口,Open ParticleBase Migration Window,,
inspector.particleBaseMigration.windowTitle,ParticleBase 迁移,ParticleBase Migration,,
inspector.particleBaseMigration.title,ParticleBase -> NBShader2,ParticleBase -> NBShader2,,
inspector.particleBaseMigration.windowWarning,此操作会修改材质 Shader 绑定并同步材质状态。转换前请先做好资产备份或版本管理。工具不会提供自动回退。,This operation changes material shader assignments and synchronized material state. Back up assets or commit to version control before converting. The tool does not provide an automatic rollback.,,
inspector.particleBaseMigration.scan.button,扫描 ParticleBase 材质,Scan ParticleBase Materials,,
inspector.particleBaseMigration.selectAll.button,全选,Select All,,
inspector.particleBaseMigration.selectNone.button,全不选,Select None,,
inspector.particleBaseMigration.scanPrompt,点击扫描查找引用 ParticleBase Shader 资源 GUID 的 .mat 资源。Shader 名称只作为回退匹配。,Click Scan to find .mat assets that reference the ParticleBase shader asset GUID. Shader name is only used as a fallback.,,
inspector.particleBaseMigration.noMaterials,没有找到 ParticleBase 材质资源。,No ParticleBase material assets were found.,,
inspector.particleBaseMigration.listSummary,找到 {0} 个材质资源。已选择:{1},Found {0} material asset(s). Selected: {1},,
inspector.particleBaseMigration.column.material,材质,Material,,
inspector.particleBaseMigration.column.match,匹配方式,Match,,
inspector.particleBaseMigration.column.path,路径,Path,,
inspector.particleBaseMigration.ping.button,定位,Ping,,
inspector.particleBaseMigration.convertSelected.button,转换选中的材质到 NBShader2,Convert Selected Materials To NBShader2,,
inspector.particleBaseMigration.progress.scanning,正在扫描材质 {0}/{1},Scanning materials {0}/{1},,
inspector.particleBaseMigration.scanCanceled,扫描已取消。取消前找到 {0} 个材质资源。,Scan canceled. Found {0} material asset(s) before canceling.,,
inspector.particleBaseMigration.scanComplete,扫描完成。找到 {0} 个 ParticleBase 材质资源。,Scan complete. Found {0} ParticleBase material asset(s).,,
inspector.particleBaseMigration.nbShader2Missing.title,缺少 NBShader2,NBShader2 Missing,,
inspector.particleBaseMigration.nbShader2Missing.message,无法加载 NBShader2 Shader 资源,迁移无法继续。,Could not load NBShader2 shader asset. Migration cannot continue.,,
inspector.particleBaseMigration.dialog.ok,确定,OK,,
inspector.particleBaseMigration.progress.converting,正在转换 {0}/{1}{2},Converting {0}/{1}: {2},,
inspector.particleBaseMigration.failuresLogged,ParticleBase 迁移完成但存在失败项:,ParticleBase migration completed with failures:,,
inspector.particleBaseMigration.failure.loadMaterial,{0}:无法加载材质。,{0}: material could not be loaded.,,
inspector.particleBaseMigration.failure.noLongerParticleBase,{0}:已跳过,因为它不再引用 ParticleBase。,{0}: skipped because it no longer references ParticleBase.,,
inspector.particleBaseMigration.failure.exception,{0}{1},{0}: {1},,
inspector.particleBaseMigration.match.converted,已转换,Converted,,
inspector.particleBaseMigration.confirm.title,确认 ParticleBase 迁移,Confirm ParticleBase Migration,,
inspector.particleBaseMigration.confirm.message,即将把 {0} 个材质资源从 ParticleBase 转换到 NBShader2。继续前请先做好资产备份或版本管理。工具不会提供自动回退。,You are about to convert {0} material asset(s) from ParticleBase to NBShader2. Back up assets or commit to version control before continuing. This tool does not provide an automatic rollback.,,
inspector.particleBaseMigration.dialog.convert,转换,Convert,,
inspector.particleBaseMigration.dialog.cancel,取消,Cancel,,
inspector.particleBaseMigration.conversionCanceled,转换已取消。已转换 {0}/{1} 个选中材质资源。,Conversion canceled. Converted {0}/{1} selected material asset(s).,,
inspector.particleBaseMigration.conversionComplete,转换完成。已转换 {0}/{1} 个选中材质资源。,Conversion complete. Converted {0}/{1} selected material asset(s).,,
inspector.particleBaseMigration.conversionFailures,{0} 个失败项已记录到 Console。,{0} failure(s) were logged to the Console.,,
inspector.particleBaseMigration.match.shaderGuid,Shader GUID,Shader GUID,,
inspector.particleBaseMigration.match.shaderObject,Shader 对象,Shader object,,
inspector.particleBaseMigration.match.shaderNameFallback,Shader 名称回退,Shader name fallback,,
inspector.particleBaseMigration.undo,迁移 ParticleBase 材质到 NBShader2,Migrate ParticleBase Materials To NBShader2,,
1 key zh-CN en-US zh-CN-tip en-US-tip
2 inspector.block.mode.label 模式设置 Mode 各种基础模式设置 Mode and source setup
3 inspector.block.base.label 基本全局功能 Base 全局控制功能 Base global controls
4 inspector.block.maintex.label 主贴图功能 Main Texture 主贴图以及主颜色相关功能 Main texture and base color controls
5 inspector.block.light.label 光照功能 Lighting 法线、MatCap 和光照模式相关功能 Lighting normal and material response controls
6 inspector.block.feature.label 特别功能 Feature 遮罩、扭曲、溶解等特效功能 Effect feature controls
7 inspector.block.ta.label TA调试 TA Debug 技术美术调试和辅助功能 Technical art debug and helper controls
8 inspector.common.tilling.label Tilling Tilling
9 inspector.common.offset.label Offset Offset
10 inspector.common.none None None
11 inspector.mode.meshSource.label Mesh来源模式 Mesh Source Mode Mesh来源模式和当前的对象类型一致 Matches the current object type
12 inspector.mode.meshSource.option.0 粒子系统 Particle System
13 inspector.mode.meshSource.option.1 模型(非粒子发射) Mesh
14 inspector.mode.meshSource.option.2 2D RawImage 2D RawImage
15 inspector.mode.meshSource.option.3 2D 精灵 2D Sprite
16 inspector.mode.meshSource.option.4 2D 材质贴图 2D Material Texture
17 inspector.mode.meshSource.option.5 2D UIParticle 2D UIParticle
18 inspector.mode.transparent.label 透明模式 Transparent Mode 透明模式 Controls opaque transparent and cutoff rendering
19 inspector.mode.transparent.option.0 不透明Opaque Opaque
20 inspector.mode.transparent.option.1 半透明Transparent Transparent
21 inspector.mode.transparent.option.2 不透明裁剪CutOff CutOff
22 inspector.mode.cutoff.label 裁剪位置 Cutoff 0为完全不裁剪,1为完全裁剪 0 keeps everything and 1 clips everything
23 inspector.mode.blend.label 混合模式 Blend Mode
24 inspector.mode.blend.option.0 透明度混合AlphaBlend Alpha Blend
25 inspector.mode.blend.option.1 预乘PreMultiply Premultiply
26 inspector.mode.blend.option.2 叠加Additive Additive
27 inspector.mode.blend.option.3 正片叠底Multiply Multiply
28 inspector.mode.additiveToPremultiply.label 叠加到预乘混合 Additive To Premultiply 0为叠加混合,1为预乘混合 0 is additive and 1 is premultiply
29 inspector.base.colorIntensity.label 整体颜色强度 Base Color Intensity
30 inspector.base.alphaAll.label 整体透明度 Overall Alpha
31 inspector.base.colorAdjustment.label 颜色调整 Color Adjustment
32 inspector.base.colorAdjustment.onlyMainTex.label 颜色调整仅影响主贴图 Color Adjustment Only Affects Main Texture
33 inspector.base.hueShift.label 色相偏移 Hue Shift
34 inspector.base.hueShift.value.label 色相 Hue
35 inspector.base.hueShift.customData.label 色相自定义曲线 Hue Custom Data
36 inspector.base.saturability.label 饱和度 Saturation
37 inspector.base.saturability.value.label 饱和度 Saturation
38 inspector.base.saturability.customData.label 饱和度强度自定义曲线 Saturation Strength Custom Data
39 inspector.base.contrast.label 对比度 Contrast
40 inspector.base.contrast.mid.label 对比度中值颜色 Contrast Mid Color
41 inspector.base.contrast.value.label 对比度 Contrast
42 inspector.base.contrast.customData.label 对比度自定义曲线 Contrast Custom Data
43 inspector.base.colorRefine.label 颜色修正 Color Refine
44 inspector.base.colorRefine.a.label A:主颜色相乘 A Main Color Multiply
45 inspector.base.colorRefine.bPower.label B:主颜色Power B Main Color Power
46 inspector.base.colorRefine.bMultiply.label B:主颜色Power后相乘 B After Power Multiply
47 inspector.base.colorRefine.lerp.label A/B线性差值 A/B Lerp
48 inspector.base.colorMultiAlpha.label 颜色乘透明度(改善锯齿) Color Multiply Alpha
49 inspector.base.ztest.label 深度测试 ZTest
50 inspector.base.ztest.option.0 关闭(Disabled) Disabled
51 inspector.base.ztest.option.1 永不通过(Never) Never
52 inspector.base.ztest.option.2 小于(Less) Less
53 inspector.base.ztest.option.3 等于(Equal) Equal
54 inspector.base.ztest.option.4 小于等于(LessEqual) LessEqual
55 inspector.base.ztest.option.5 大于(Greater) Greater
56 inspector.base.ztest.option.6 不等于(NotEqual) NotEqual
57 inspector.base.ztest.option.7 大于等于(GreaterEqual) GreaterEqual
58 inspector.base.ztest.option.8 始终通过(Always) Always
59 inspector.base.cull.label 渲染面向 Cull
60 inspector.base.cull.option.0 双面(Both) Both
61 inspector.base.cull.option.1 背面(Back) Back
62 inspector.base.cull.option.2 正面(Front) Front
63 inspector.base.backFirstPass.label 预渲染反面 Back First Pass
64 inspector.base.forceZWrite.label 深度写入强制控制 Force ZWrite
65 inspector.base.forceZWrite.option.0 默认 Default
66 inspector.base.forceZWrite.option.1 强制开启 Force On
67 inspector.base.forceZWrite.option.2 强制关闭 Force Off
68 inspector.base.affectsShadows.label 投射阴影 Affects Shadows
69 inspector.base.transparentShadowDither.label 半透明 Dither 阴影 Transparent Dither Shadows
70 inspector.base.backColor.label 背面颜色 Back Color
71 inspector.base.backColor.color.label 背面颜色 Back Color
72 inspector.base.distanceFade.label 近距离透明 Distance Fade
73 inspector.base.distanceFade.range.label 透明过度范围 Fade Range
74 inspector.base.softParticles.label 软粒子 Soft Particles
75 inspector.base.softParticles.range.label 远近裁剪面 Near/Far Fade
76 inspector.base.stencilWithoutPlayer.label 剔除主角色 Stencil Without Player
77 inspector.base.ignoreVertexColor.label 忽略顶点色 Ignore Vertex Color
78 inspector.base.fogIntensity.label 雾影响强度 Fog Intensity
79 inspector.maintex.basemap.label 主贴图 Main Texture
80 inspector.maintex.basemap.related.label 主贴图相关功能 Main Texture Related
81 inspector.maintex.graphic.message 当前模式使用 Graphic 贴图。仅颜色和 ST 可编辑。 Current mode uses Graphic texture. Only color and ST remain editable.
82 inspector.maintex.uicolor.label 贴图颜色叠加 Graphic Color
83 inspector.maintex.alphaChannel.label 主贴图透明度通道 Alpha Channel
84 inspector.maintex.wrap.label 主贴图循环模式 Main Texture Wrap
85 inspector.maintex.uvmode.label 主贴图UV来源 Main Texture UV Source
86 inspector.maintex.customdata.offsetx.label 主贴图X轴偏移自定义曲线 Main Texture Offset X Custom Data
87 inspector.maintex.customdata.offsety.label 主贴图Y轴偏移自定义曲线 Main Texture Offset Y Custom Data
88 inspector.maintex.offsetspeed.label 偏移速度 Offset Speed
89 inspector.maintex.rotation.label 主贴图旋转 Rotation
90 inspector.maintex.rotationspeed.label 主贴图旋转速度 Rotation Speed
91 inspector.maintex.distortionIntensity.label 主贴图扭曲强度控制 Main Texture Distortion
92 inspector.maintex.pnoiseBlend.label 主贴图程序噪波混合 Main Texture Program Noise Blend
93 inspector.maintex.mixedMeshSource.message 混合的 Mesh 来源模式会按材质状态显示对应贴图控件。 Mixed mesh-source modes will show the matching texture controls per material state.
94 inspector.light.mode.label 光照类型 Light Mode
95 inspector.light.mode.option.0 默认无光(Unlit) Unlit
96 inspector.light.mode.option.1 简单光照(BlinnPhong) BlinnPhong
97 inspector.light.mode.option.2 简单光照通透(HalfLambert) HalfLambert
98 inspector.light.mode.option.3 高级光照(PBR) PBR
99 inspector.light.mode.option.4 六路光照(SixWay) SixWay
100 inspector.light.specular.toggle.label 高光开关 Specular
101 inspector.light.specular.color.label 高光颜色 Specular Color
102 inspector.light.specular.smoothness.label 光滑度 Smoothness
103 inspector.light.pbr.metallic.label 金属度 Metallic
104 inspector.light.pbr.smoothness.label 光滑度 Smoothness
105 inspector.light.bump.toggle.label 法线贴图开关 Normal Map
106 inspector.light.bump.texture.label 法线贴图 Normal Map
107 inspector.light.bump.related.label 法线贴图相关功能 Normal Map Related
108 inspector.light.bump.wrap.label 法线贴图循环模式 Normal Map Wrap
109 inspector.light.bump.uvmode.label 法线贴图UV来源 Normal Map UV Source
110 inspector.light.bump.maskMode.label 法线贴图多通道模式 Normal Map Multi Channel
111 inspector.light.bump.scale.label 法线强度 Normal Strength
112 inspector.light.matcap.toggle.label MatCap模拟材质 MatCap
113 inspector.light.matcap.texture.label MatCap图 MatCap Texture
114 inspector.light.matcap.blend.label MatCap相加到相乘过渡 Add/Multiply Blend
115 inspector.light.sixway.positive.label 六路正方向图(P) SixWay Positive
116 inspector.light.sixway.negative.label 六路反方向图(N) SixWay Negative
117 inspector.light.sixway.absorption.toggle.label 光照颜色吸收 Light Color Absorption
118 inspector.light.sixway.absorption.strength.label 六路吸收强度 Absorption Strength
119 inspector.light.sixway.ramp.label 六路自发光Ramp SixWay Emission Ramp
120 inspector.light.sixway.emissionPow.label 六路自发光Pow SixWay Emission Pow
121 inspector.light.sixway.color.label 六路自发光颜色 SixWay Emission Color
122 inspector.protocol.colorChannel.option.0 R R
123 inspector.protocol.colorChannel.option.1 G G
124 inspector.protocol.colorChannel.option.2 B B
125 inspector.protocol.colorChannel.option.3 A A
126 inspector.protocol.customData.option.0 **不使用** Off
127 inspector.protocol.customData.option.1 CustomData1_X CustomData1.x
128 inspector.protocol.customData.option.2 CustomData1_Y CustomData1.y
129 inspector.protocol.customData.option.3 CustomData1_Z CustomData1.z
130 inspector.protocol.customData.option.4 CustomData1_W CustomData1.w
131 inspector.protocol.customData.option.5 CustomData2_X CustomData2.x
132 inspector.protocol.customData.option.6 CustomData2_Y CustomData2.y
133 inspector.protocol.customData.option.7 CustomData2_Z CustomData2.z
134 inspector.protocol.customData.option.8 CustomData2_W CustomData2.w
135 inspector.protocol.wrapMode.option.0 Repeat Repeat
136 inspector.protocol.wrapMode.option.1 Clamp Clamp
137 inspector.protocol.wrapMode.option.2 RepeatX_ClampY RepeatX_ClampY
138 inspector.protocol.wrapMode.option.3 ClampX_RepeatY ClampX_RepeatY
139 inspector.protocol.pnoise.opacity.label 程序噪波混合强度 Program Noise Blend Opacity
140 inspector.protocol.pnoiseBlend.option.0 不使用 Not Used
141 inspector.protocol.pnoiseBlend.option.1 Multiply Multiply
142 inspector.protocol.pnoiseBlend.option.2 Min Min
143 inspector.protocol.pnoiseBlend.option.3 HardLight HardLight
144 inspector.protocol.uv.twirl.label 旋转扭曲 Twirl
145 inspector.protocol.uv.twirlCenter.label 旋转扭曲中心 Twirl Center
146 inspector.protocol.uv.twirlStrength.label 旋转扭曲强度 Twirl Strength
147 inspector.protocol.uv.polar.label 极坐标 Polar Coordinates
148 inspector.protocol.uv.polarCenter.label 极坐标中心 Polar Center
149 inspector.protocol.uv.polarStrength.label 极坐标强度 Polar Strength
150 inspector.protocol.uv.cylinderRotate.label 圆柱坐标旋转 Cylinder Rotation
151 inspector.protocol.uv.cylinderOffset.label 圆柱坐标偏移 Cylinder Offset
152 inspector.protocol.uv.coordinatePlane.label 坐标平面 Coordinate Plane
153 inspector.protocol.uv.sharedMaterial.message 以下设置材质内通用: The following settings are shared in the material:
154 inspector.protocol.uv.cylinderWarning.message 圆柱模式消耗比较大,慎用 Cylinder mode is expensive. Use it carefully.
155 inspector.protocol.uv.mode.option.0 默认UV通道 Default UV Channel
156 inspector.protocol.uv.mode.option.1 特殊UV通道 Special UV Channel
157 inspector.protocol.uv.mode.option.2 极坐标|旋转 Polar/Twirl
158 inspector.protocol.uv.mode.option.3 圆柱无缝 Cylinder Seamless
159 inspector.protocol.uv.mode.option.4 主贴图 Main Texture
160 inspector.protocol.uv.mode.option.5 屏幕UV Screen UV
161 inspector.protocol.uv.mode.option.6 世界坐标 World Space
162 inspector.protocol.uv.mode.option.7 局部本地坐标 Object Space
163 inspector.protocol.uv.mode.option.8 公共UV Shared UV
164 inspector.protocol.uv.positionPlane.option.0 xy平面 XY Plane
165 inspector.protocol.uv.positionPlane.option.1 xz平面 XZ Plane
166 inspector.protocol.uv.positionPlane.option.2 yz平面 YZ Plane
167 inspector.protocol.uv.specialChannel.label 特殊UV通道选择 Special UV Channel
168 inspector.protocol.uv.specialChannel.option.0 UV2_Texcoord1 UV2_Texcoord1
169 inspector.protocol.uv.specialChannel.option.1 UV3_Texcoord2 UV3_Texcoord2
170 inspector.ta.zoffset.label 深度偏移 Z Offset
171 inspector.ta.overrideZ.label Override Z Override Z
172 inspector.ta.renderQueue.label 渲染队列偏移 Queue Bias
173 inspector.ta.customStencil.label 模板手动调试开关 Custom Stencil Test
174 inspector.ta.keywords.label 已开启Keyword: Enabled Keywords
175 inspector.ta.keywords.list.label 已开启Keyword: Enabled Keywords
176 inspector.ta.property._offsetFactor.label OffsetFactor Offset Factor
177 inspector.ta.property._offsetUnits.label Offset单位 Offset Units
178 inspector.ta.property._OverrideZValue.label Override Z Value Override Z Value
179 inspector.ta.property._ColorMask.label RGBA Mask RGBA Mask 控制最终写入 RenderTarget 的颜色通道 Controls final RenderTarget color channel writes
180 inspector.ta.colorMask.option.0 R R
181 inspector.ta.colorMask.option.1 G G
182 inspector.ta.colorMask.option.2 B B
183 inspector.ta.colorMask.option.3 A A
184 inspector.ta.property._StencilKeyIndex.label Stencil配置索引 Stencil Config Index
185 inspector.ta.property._Stencil.label 模板值 Stencil Value
186 inspector.ta.property._StencilComp.label 模板比较方式 Stencil Compare
187 inspector.ta.property._StencilOp.label 模板处理方式 Stencil Operation
188 inspector.ta.property._StencilFail.label 模板失败处理方式 Stencil Fail
189 inspector.ta.property._StencilZFail.label 模板深度失败处理方式 Stencil ZFail
190 inspector.ta.property._StencilReadMask.label 模板读取掩码 Stencil Read Mask
191 inspector.ta.property._StencilWriteMask.label 模板写入掩码 Stencil Write Mask
192 inspector.vertexStreams.title.label 顶点流统计 Particle Vertex Streams The vertex streams needed for this Material to function properly. The vertex streams needed for this Material to function properly.
193 inspector.vertexStreams.mismatch 下面的粒子系统Renderer顶点流不正确: Particle renderers with mismatched vertex streams:
194 inspector.vertexStreams.trailMismatch 下面的粒子系统Renderer拖尾顶点流不正确: Particle trail renderers with mismatched vertex streams:
195 inspector.vertexStreams.applyTrail.button 使粒子拖尾与材质顶点流相同 Apply Trail Vertex Streams Apply the trail vertex stream layout to all Particle Systems using this material Apply the trail vertex stream layout to all Particle Systems using this material
196 inspector.vertexStreams.apply.button 使粒子与材质顶点流相同 Apply Vertex Streams Apply the vertex stream layout to all Particle Systems using this material Apply the vertex stream layout to all Particle Systems using this material
197 inspector.vertexStreams.apply.undo Apply custom vertex streams from material Apply custom vertex streams from material
198 inspector.feature.popup._ScreenDistortModeToggle.option.0 不扰动屏幕 No Screen Distort
199 inspector.feature.popup._ScreenDistortModeToggle.option.1 全部扰动(后处理扰动) Deferred Distort
200 inspector.feature.popup._ScreenDistortModeToggle.option.2 仅影响场景(半透明前扰动) Camera Opaque Distort
201 inspector.feature.screenDistort.missingNbPostProcess.message 屏幕扭曲需要当前 URP Pipeline Asset 的任意 RendererData 中包含已启用的 NB 后处理 Feature。 Screen Distort requires at least one RendererData in the current URP Pipeline Asset to include an active NB Post Process Feature.
202 inspector.feature.screenDistort.missingOpaqueTextureCopy.message Camera Opaque 扭曲需要在当前 URP Pipeline Asset 中开启 Opaque Texture。 Camera Opaque Distort requires Opaque Texture to be enabled on the current URP Pipeline Asset.
203 inspector.feature.screenDistort.pingRendererData.button 定位 Renderer Ping Renderer
204 inspector.feature.screenDistort.pingPipelineAsset.button 定位 Pipeline Asset Ping Pipeline Asset
205 inspector.feature.popup._DistortMode.option.0 扰动贴图 FlowMap/RG Texture
206 inspector.feature.popup._DistortMode.option.1 折射 Refraction IOR
207 inspector.feature.popup._ColorBlendAlphaMultiplyMode.option.0 颜色渐变强度 Off
208 inspector.feature.popup._ColorBlendAlphaMultiplyMode.option.1 遮罩(乘以主贴图Alpha) On
209 inspector.feature.popup._RampColorSourceMode.option.0 UV Gradient
210 inspector.feature.popup._RampColorSourceMode.option.1 映射贴图 Texture
211 inspector.feature.popup._RampColorBlendMode.option.0 相乘Multiply Add
212 inspector.feature.popup._RampColorBlendMode.option.1 相加Add Multiply
213 inspector.feature.popup._DissolveRampSourceMode.option.0 渐变控件 Gradient
214 inspector.feature.popup._DissolveRampSourceMode.option.1 Ramp贴图 Texture
215 inspector.feature.popup._DissolveRampColorBlendMode.option.0 线性差值Lerp Add
216 inspector.feature.popup._DissolveRampColorBlendMode.option.1 相乘Multiply Multiply
217 inspector.feature.popup._DissolveMaskMode.option.0 过程溶解 Process Dissolve
218 inspector.feature.popup._DissolveMaskMode.option.1 溶解遮罩 Dissolve Mask
219 inspector.feature.popup._FresnelMode.option.0 颜色|边缘光 Color
220 inspector.feature.popup._FresnelMode.option.1 半透明|渐隐 Alpha
221 inspector.feature.popup._VATMode.option.0 Houdini Houdini
222 inspector.feature.popup._VATMode.option.1 TyFlow TyFlow
223 inspector.feature.popup._HoudiniVATSubMode.option.0 SoftBody (Deformation) SoftBody (Deformation)
224 inspector.feature.popup._HoudiniVATSubMode.option.1 RigidBody (Pieces) RigidBody (Pieces)
225 inspector.feature.popup._HoudiniVATSubMode.option.2 Dynamic Remeshing (Lookup) Dynamic Remeshing (Lookup)
226 inspector.feature.popup._HoudiniVATSubMode.option.3 Particle Sprites (Billboard) Particle Sprites (Billboard)
227 inspector.feature.popup._TyFlowVATSubMode.option.0 Absolute positions Absolute positions
228 inspector.feature.popup._TyFlowVATSubMode.option.1 Relative offsets Relative offsets
229 inspector.feature.popup._TyFlowVATSubMode.option.2 Skin (R) Skin (R)
230 inspector.feature.popup._TyFlowVATSubMode.option.3 Skin (PR) Skin (PR)
231 inspector.feature.popup._TyFlowVATSubMode.option.4 Skin (PRSAVE) Skin (PRSAVE)
232 inspector.feature.popup._TyFlowVATSubMode.option.5 Skin (PRSXYZ) Skin (PRSXYZ)
233 inspector.feature.popup._MaskMapGradientToggle.option.0 遮罩贴图 Texture
234 inspector.feature.popup._MaskMapGradientToggle.option.1 渐变控件 Gradient
235 inspector.feature.popup._MaskMap2GradientToggle.option.0 遮罩贴图 Texture
236 inspector.feature.popup._MaskMap2GradientToggle.option.1 渐变控件 Gradient
237 inspector.feature.popup._MaskMap3GradientToggle.option.0 遮罩贴图 Texture
238 inspector.feature.popup._MaskMap3GradientToggle.option.1 渐变控件 Gradient
239 inspector.feature.vat.houdiniUnsupportedParticle.message 该 Houdini VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。 This Houdini VAT type requires mesh multi-UV data and does not support ParticleSystem VertexStream mode.
240 inspector.feature.vat.tyflowUnsupportedParticle.message 该 TyFlow VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。 This TyFlow VAT type requires mesh multi-UV data and does not support ParticleSystem VertexStream mode.
241 inspector.feature.vat.tyflowUv2Conflict.message TyFlow VAT 在粒子模式下使用 UV2 (TEXCOORD0.zw) 作为 vertexIndex / vertexCount。序列帧融帧或特殊 UV (UV2) 会冲突,VAT 优先。 TyFlow VAT uses UV2 (TEXCOORD0.zw) as vertexIndex / vertexCount in ParticleSystem mode. Flipbook blending or Special UV (UV2) conflicts with it; VAT takes priority.
242 inspector.feature.遮罩.label 遮罩 Mask
243 inspector.feature.测试遮罩颜色.label 测试遮罩颜色 Debug Mask Color
244 inspector.feature.遮罩强度.label 遮罩强度 Mask Strength
245 inspector.feature.遮罩整体调整.label 遮罩整体调整 Mask Refine
246 inspector.feature.范围(Pow).label 范围(Pow) Range (Pow)
247 inspector.feature.相乘.label 相乘 Multiply
248 inspector.feature.偏移(相加).label 偏移(相加) Offset (Add)
249 inspector.feature.遮罩程序噪波混合.label 遮罩程序噪波混合 Mask Program Noise Blend
250 inspector.feature.遮罩模式.label 遮罩模式 Mask Mode
251 inspector.feature.遮罩贴图.label 遮罩贴图 Mask Texture
252 inspector.feature.遮罩通道选择.label 遮罩通道选择 Mask Channel
253 inspector.feature.遮罩渐变.label 遮罩渐变 Mask Gradient
254 inspector.feature.遮罩UV Wrap.label 遮罩循环模式 Mask UV Wrap
255 inspector.feature.遮罩UV来源.label 遮罩UV来源 Mask UV Source
256 inspector.feature.Mask图X轴偏移自定义曲线.label Mask图X轴偏移自定义曲线 Mask Offset X Custom Data
257 inspector.feature.Mask图Y轴偏移自定义曲线.label Mask图Y轴偏移自定义曲线 Mask Offset Y Custom Data
258 inspector.feature.遮罩偏移速度.label 遮罩偏移速度 Mask Offset Speed
259 inspector.feature.遮罩旋转.label 遮罩旋转 Mask Rotation
260 inspector.feature.遮罩旋转速度.label 遮罩旋转速度 Mask Rotation Speed
261 inspector.feature.旋转速度.label 旋转速度 Rotation Speed
262 inspector.feature.遮罩扭曲强度.label 遮罩扭曲强度 Mask Distortion Strength
263 inspector.feature.遮罩2.label 遮罩2 Mask 2
264 inspector.feature.遮罩2模式.label 遮罩2模式 Mask 2 Mode
265 inspector.feature.遮罩2贴图.label 遮罩2贴图 Mask 2 Texture
266 inspector.feature.遮罩2通道选择.label 遮罩2通道选择 Mask 2 Channel
267 inspector.feature.遮罩2渐变.label 遮罩2渐变(UV纵向) Mask 2 Gradient
268 inspector.feature.遮罩2UV Wrap.label 遮罩2UV循环模式 Mask 2 UV Wrap
269 inspector.feature.遮罩2UV来源.label 遮罩2UV来源 Mask 2 UV Source
270 inspector.feature.遮罩2旋转.label 遮罩2旋转 Mask 2 Rotation
271 inspector.feature.遮罩2偏移速度.label 遮罩2偏移速度 Mask 2 Offset Speed
272 inspector.feature.遮罩3.label 遮罩3 Mask 3
273 inspector.feature.遮罩3模式.label 遮罩3模式 Mask 3 Mode
274 inspector.feature.遮罩3贴图.label 遮罩3贴图 Mask 3 Texture
275 inspector.feature.遮罩3通道选择.label 遮罩3通道选择 Mask 3 Channel
276 inspector.feature.遮罩3渐变.label 遮罩3渐变(UV横向) Mask 3 Gradient
277 inspector.feature.遮罩3UV Wrap.label 遮罩3UV循环模式 Mask 3 UV Wrap
278 inspector.feature.遮罩3UV来源.label 遮罩3UV来源 Mask 3 UV Source
279 inspector.feature.遮罩3旋转.label 遮罩3旋转 Mask 3 Rotation
280 inspector.feature.遮罩3偏移速度.label 遮罩3偏移速度 Mask 3 Offset Speed
281 inspector.feature.扭曲.label 扭曲 Distort
282 inspector.feature.扭曲强度值测试.label 扭曲强度值测试 Debug Distort Strength
283 inspector.feature.整体扭曲强度.label 整体扭曲强度 Overall Distort Strength
284 inspector.feature.扭曲强度自定义曲线.label 扭曲强度自定义曲线 Distort Strength Custom Data
285 inspector.feature.屏幕扰动模式.label 屏幕扰动模式 Screen Distort Mode
286 inspector.feature.屏幕扭曲强度.label 屏幕扭曲强度 Screen Distort Strength
287 inspector.feature.关闭主材质Pass.label 关闭主材质Pass Disable Main Material Pass
288 inspector.feature.屏幕扭曲Alpha整体调整.label 屏幕扭曲Alpha整体调整 Screen Distort Alpha Refine
289 inspector.feature.扭曲模式.label 扭曲模式 Distort Mode
290 inspector.feature.扭曲贴图.label 扭曲贴图 Distort Texture
291 inspector.feature.扭曲贴图 Wrap.label 扭曲贴图循环模式 Distort Texture Wrap
292 inspector.feature.扭曲贴图UV来源.label 扭曲贴图UV来源 Distort Texture UV Source
293 inspector.feature.扭曲方向强度.label 扭曲方向强度 Distort Direction Strength
294 inspector.feature.扭曲方向强度X自定义曲线.label 扭曲方向强度X自定义曲线 Distort Direction X Custom Data
295 inspector.feature.扭曲方向强度Y自定义曲线.label 扭曲方向强度Y自定义曲线 Distort Direction Y Custom Data
296 inspector.feature.扭曲旋转.label 扭曲旋转 Distort Rotation
297 inspector.feature.扭曲偏移速度.label 扭曲偏移速度 Distort Offset Speed
298 inspector.feature.0.5为中值,双向扭曲.label 0.5为中值,双向扭曲 0.5 Is Mid Value Bidirectional Distort
299 inspector.feature.折射率.label 折射率 Refraction IOR
300 inspector.feature.扭曲程序噪波混合.label 扭曲程序噪波混合 Distort Program Noise Blend
301 inspector.feature.扭曲遮罩.label 扭曲遮罩 Distort Mask
302 inspector.feature.扭曲遮罩贴图.label 扭曲遮罩贴图 Distort Mask Texture
303 inspector.feature.扭曲遮罩贴图 Wrap.label 扭曲遮罩贴图循环模式 Distort Mask Texture Wrap
304 inspector.feature.扭曲遮罩图通道选择.label 扭曲遮罩图通道选择 Distort Mask Channel
305 inspector.feature.扭曲遮罩贴图UV来源.label 扭曲遮罩贴图UV来源 Distort Mask UV Source
306 inspector.feature.色散.label 色散 Chromatic Aberration
307 inspector.feature.色散强度受扭曲强度影响.label 色散强度受扭曲强度影响 Chromatic Strength Follows Distort Strength
308 inspector.feature.色散强度.label 色散强度 Chromatic Strength
309 inspector.feature.色散强度自定义曲线.label 色散强度自定义曲线 Chromatic Strength Custom Data
310 inspector.feature.流光(颜色相加).label 流光(颜色相加) Emission (Add Color)
311 inspector.feature.流光贴图.label 流光贴图 Emission Texture
312 inspector.feature.流光贴图 Wrap.label 流光贴图循环模式 Emission Texture Wrap
313 inspector.feature.流光贴图UV来源.label 流光贴图UV来源 Emission Texture UV Source
314 inspector.feature.流光贴图X轴偏移自定义曲线.label 流光贴图X轴偏移自定义曲线 Emission Offset X Custom Data
315 inspector.feature.流光贴图Y轴偏移自定义曲线.label 流光贴图Y轴偏移自定义曲线 Emission Offset Y Custom Data
316 inspector.feature.流光贴图旋转.label 流光贴图旋转 Emission Texture Rotation
317 inspector.feature.流光贴图偏移速度.label 流光贴图偏移速度 Emission Offset Speed
318 inspector.feature.流光贴图扭曲强度.label 流光贴图扭曲强度 Emission Distortion Strength
319 inspector.feature.流光颜色强度.label 流光颜色强度 Emission Color Intensity
320 inspector.feature.渐变(颜色相乘).label 渐变(颜色相乘) Color Blend (Multiply)
321 inspector.feature.颜色渐变贴图.label 颜色渐变贴图 Color Blend Texture
322 inspector.feature.颜色渐变贴图 Wrap.label 颜色渐变贴图循环模式 Color Blend Texture Wrap
323 inspector.feature.颜色渐变贴图UV来源.label 颜色渐变贴图UV来源 Color Blend UV Source
324 inspector.feature.颜色渐变贴图X轴偏移自定义曲线.label 颜色渐变贴图X轴偏移自定义曲线 Color Blend Offset X Custom Data
325 inspector.feature.颜色渐变贴图Y轴偏移自定义曲线.label 颜色渐变贴图Y轴偏移自定义曲线 Color Blend Offset Y Custom Data
326 inspector.feature.颜色渐变贴图旋转.label 颜色渐变贴图旋转 Color Blend Texture Rotation
327 inspector.feature.颜色渐变贴图偏移速度.label 颜色渐变贴图偏移速度 Color Blend Offset Speed
328 inspector.feature.颜色渐变扭曲强度.label 颜色渐变扭曲强度 Color Blend Distortion Strength
329 inspector.feature.颜色渐变图Alpha作用.label 颜色渐变图Alpha作用 Color Blend Alpha Mode
330 inspector.feature.颜色渐变图Alpha强度.label 颜色渐变图Alpha强度 Color Blend Alpha Strength
331 inspector.feature.颜色映射(Ramp).label 颜色映射(Ramp) Ramp Color
332 inspector.feature.Ramp来源模式.label Ramp来源模式 Ramp Source Mode
333 inspector.feature.颜色映射黑白图.label 颜色映射黑白图 Ramp Mask Texture
334 inspector.feature.颜色映射黑白图 Wrap.label 颜色映射黑白图循环模式 Ramp Mask Texture Wrap
335 inspector.feature.颜色映射UV Wrap.label 颜色映射UV循环模式 Ramp UV Wrap
336 inspector.feature.颜色映射黑白图通道选择.label 颜色映射黑白图通道选择 Ramp Mask Channel
337 inspector.feature.颜色映射黑白图UV来源.label 颜色映射黑白图UV来源 Ramp Mask UV Source
338 inspector.feature.颜色映射贴图偏移速度.label 颜色映射贴图偏移速度 Ramp Texture Offset Speed
339 inspector.feature.颜色映射贴图旋转.label 颜色映射贴图旋转 Ramp Texture Rotation
340 inspector.feature.映射颜色.label 映射颜色 Ramp Colors
341 inspector.feature.Ramp颜色混合模式.label Ramp颜色混合模式 Ramp Color Blend Mode
342 inspector.feature.颜色映射叠加颜色.label 颜色映射叠加颜色_hdr Ramp Blend Color
343 inspector.feature.溶解.label 溶解 Dissolve
344 inspector.feature.溶解度黑白值测试.label 溶解度黑白值测试 Debug Dissolve Value
345 inspector.feature.溶解贴图.label 溶解贴图 Dissolve Texture
346 inspector.feature.溶解贴图 Wrap.label 溶解贴图循环模式 Dissolve Texture Wrap
347 inspector.feature.溶解贴图通道选择.label 溶解贴图通道选择 Dissolve Channel
348 inspector.feature.溶解贴图X轴偏移自定义曲线.label 溶解贴图X轴偏移自定义曲线 Dissolve Offset X Custom Data
349 inspector.feature.溶解贴图Y轴偏移自定义曲线.label 溶解贴图Y轴偏移自定义曲线 Dissolve Offset Y Custom Data
350 inspector.feature.溶解贴图UV来源.label 溶解贴图UV来源 Dissolve UV Source
351 inspector.feature.溶解贴图偏移速度.label 溶解贴图偏移速度 Dissolve Offset Speed
352 inspector.feature.溶解贴图旋转.label 溶解贴图旋转 Dissolve Texture Rotation
353 inspector.feature.溶解程序噪波混合.label 溶解程序噪波混合 Dissolve Program Noise Blend
354 inspector.feature.溶解值Pow.label 溶解值Pow Dissolve Value Pow
355 inspector.feature.溶解强度.label 溶解强度 Dissolve Strength
356 inspector.feature.溶解强度自定义曲线.label 溶解强度自定义曲线 Dissolve Strength Custom Data
357 inspector.feature.溶解硬软度.label 溶解硬软度 Dissolve Softness
358 inspector.feature.溶解贴图扭曲强度.label 溶解贴图扭曲强度 Dissolve Texture Distortion Strength
359 inspector.feature.溶解描边.label 溶解描边 Dissolve Edge
360 inspector.feature.溶解描边颜色.label 溶解描边颜色 Dissolve Edge Color
361 inspector.feature.描边位置.label 描边位置 Edge Position
362 inspector.feature.描边软硬.label 描边软硬 Edge Softness
363 inspector.feature.溶解Ramp图功能.label 溶解Ramp图功能 Dissolve Ramp
364 inspector.feature.溶解Ramp模式.label 溶解Ramp模式 Dissolve Ramp Mode
365 inspector.feature.溶解Ramp图.label 溶解Ramp图 Dissolve Ramp Texture
366 inspector.feature.溶解Ramp图 Wrap.label 溶解Ramp图循环模式 Dissolve Ramp Texture Wrap
367 inspector.feature.Ramp颜色.label Ramp颜色 Ramp Color
368 inspector.feature.Ramp颜色叠加.label Ramp颜色叠加 Ramp Color Multiply
369 inspector.feature.溶解RampUV Wrap.label 溶解RampUV循环模式 Dissolve Ramp UV Wrap
370 inspector.feature.溶解Ramp混合模式.label 溶解Ramp混合模式 Dissolve Ramp Blend Mode
371 inspector.feature.溶解遮罩图(过程溶解).label 溶解遮罩图(过程溶解) Dissolve Mask (Process)
372 inspector.feature.溶解遮罩模式.label 溶解遮罩模式 Dissolve Mask Mode
373 inspector.feature.溶解遮罩图.label 溶解遮罩图 Dissolve Mask Texture
374 inspector.feature.溶解遮罩图 Wrap.label 溶解遮罩图循环模式 Dissolve Mask Texture Wrap
375 inspector.feature.溶解遮罩图UV来源.label 溶解遮罩图UV来源 Dissolve Mask UV Source
376 inspector.feature.溶解遮罩图通道选择.label 溶解遮罩图通道选择 Dissolve Mask Channel
377 inspector.feature.溶解遮罩强度.label 溶解遮罩强度 Dissolve Mask Strength
378 inspector.feature.溶解遮罩图强度自定义曲线.label 溶解遮罩图强度自定义曲线 Dissolve Mask Strength Custom Data
379 inspector.feature.程序化噪波.label 程序化噪波 Program Noise
380 inspector.feature.程序化噪波测试颜色.label 程序化噪波测试颜色 Debug Program Noise
381 inspector.feature.程序噪波UV来源.label 程序噪波UV来源 Program Noise UV Source
382 inspector.feature.程序化噪波旋转.label 程序化噪波旋转 Program Noise Rotation
383 inspector.feature.Perlin噪波.label Perlin噪波 Perlin Noise
384 inspector.feature.噪波1缩放.label 噪波1缩放 Noise 1 Scale
385 inspector.feature.噪波1速度.label 噪波1速度 Noise 1 Speed
386 inspector.feature.噪波1偏移.label 噪波1偏移 Noise 1 Offset
387 inspector.feature.噪波1偏移速度.label 噪波1偏移速度 Noise 1 Offset Speed
388 inspector.feature.噪波1偏移速度X自定义曲线.label 噪波1偏移速度X自定义曲线 Noise 1 Offset X Custom Data
389 inspector.feature.噪波1偏移速度Y自定义曲线.label 噪波1偏移速度Y自定义曲线 Noise 1 Offset Y Custom Data
390 inspector.feature.Voronoi噪波.label Voronoi噪波 Voronoi Noise
391 inspector.feature.噪波2缩放.label 噪波2缩放 Noise 2 Scale
392 inspector.feature.噪波2速度.label 噪波2速度 Noise 2 Speed
393 inspector.feature.噪波2偏移.label 噪波2偏移 Noise 2 Offset
394 inspector.feature.噪波2偏移速度.label 噪波2偏移速度 Noise 2 Offset Speed
395 inspector.feature.噪波2偏移速度X自定义曲线.label 噪波2偏移速度X自定义曲线 Noise 2 Offset X Custom Data
396 inspector.feature.噪波2偏移速度Y自定义曲线.label 噪波2偏移速度Y自定义曲线 Noise 2 Offset Y Custom Data
397 inspector.feature.噪波1和噪波2混合系数.label 噪波1和噪波2混合系数 Noise 1/2 Blend
398 inspector.feature.两种程序噪波混合.label 两种程序噪波混合 Two Program Noise Blend
399 inspector.feature.公共UV.label 公共UV Shared UV
400 inspector.feature.公共UV来源.label 公共UV来源 Shared UV Source
401 inspector.feature.公共UV Tiling.label Tilling Shared UV Tiling
402 inspector.feature.公共UV Offset.label Offset Shared UV Offset
403 inspector.feature.公共UV偏移速度.label 偏移速度 Shared UV Offset Speed
404 inspector.feature.旋转.label 旋转 Rotation
405 inspector.feature.公共UV X轴偏移自定义曲线.label 偏移X自定义曲线 Shared UV Offset X Custom Data
406 inspector.feature.公共UV Y轴偏移自定义曲线.label 偏移Y自定义曲线 Shared UV Offset Y Custom Data
407 inspector.feature.菲涅尔.label 菲涅尔 Fresnel
408 inspector.feature.菲涅尔测试颜色.label 菲涅尔值测试 Debug Fresnel
409 inspector.feature.菲涅尔模式.label 菲涅尔模式 Fresnel Mode
410 inspector.feature.菲涅尔颜色.label 菲涅尔颜色 Fresnel Color
411 inspector.feature.菲涅尔透明乘数.label 菲涅尔透明乘数 Fresnel Alpha Multiplier
412 inspector.feature.菲涅尔强度.label 菲涅尔强度 Fresnel Strength
413 inspector.feature.菲涅尔位置.label 菲涅尔位置 Fresnel Position
414 inspector.feature.菲涅尔位置自定义曲线.label 菲尼尔位置自定义曲线 Fresnel Position Custom Data
415 inspector.feature.菲涅尔范围Pow.label 菲涅尔范围Pow Fresnel Range Pow
416 inspector.feature.菲涅尔硬度.label 菲涅尔硬度 Fresnel Hardness
417 inspector.feature.翻转菲涅尔.label 翻转菲涅尔 Invert Fresnel
418 inspector.feature.菲涅尔颜色受Alpha影响.label 菲涅尔颜色受Alpha影响 Fresnel Color Affected By Alpha
419 inspector.feature.菲涅尔方向偏移X.label 菲涅尔方向偏移X Fresnel Direction Offset X
420 inspector.feature.菲涅尔方向偏移Y.label 菲涅尔方向偏移Y Fresnel Direction Offset Y
421 inspector.feature.菲涅尔方向偏移Z.label 菲涅尔方向偏移Z Fresnel Direction Offset Z
422 inspector.feature.顶点偏移.label 顶点偏移 Vertex Offset
423 inspector.feature.顶点偏移方向测试.label 顶点偏移方向测试 Debug Vertex Offset Direction
424 inspector.feature.顶点偏移贴图.label 顶点偏移贴图 Vertex Offset Texture
425 inspector.feature.顶点偏移贴图 Wrap.label 顶点偏移贴图循环模式 Vertex Offset Texture Wrap
426 inspector.feature.顶点偏移贴图UV来源.label 顶点偏移贴图UV来源 Vertex Offset UV Source
427 inspector.feature.顶点扰动X轴偏移自定义曲线.label 顶点扰动X轴偏移自定义曲线 Vertex Offset X Custom Data
428 inspector.feature.顶点扰动Y轴偏移自定义曲线.label 顶点扰动Y轴偏移自定义曲线 Vertex Offset Y Custom Data
429 inspector.feature.顶点偏移动画.label 顶点偏移动画 Vertex Offset Animation
430 inspector.feature.顶点偏移强度.label 顶点偏移强度 Vertex Offset Strength
431 inspector.feature.顶点扰动强度自定义曲线.label 顶点扰动强度自定义曲线 Vertex Offset Strength Custom Data
432 inspector.feature.顶点偏移从零开始.label 顶点偏移从零开始 Vertex Offset Starts From Zero
433 inspector.feature.顶点偏移使用法线方向.label 顶点偏移使用法线方向 Use Normal Direction
434 inspector.feature.顶点偏移本地方向X.label 顶点偏移本地方向X Vertex Offset Local Direction X
435 inspector.feature.顶点偏移本地方向Y.label 顶点偏移本地方向Y Vertex Offset Local Direction Y
436 inspector.feature.顶点偏移本地方向Z.label 顶点偏移本地方向Z Vertex Offset Local Direction Z
437 inspector.feature.顶点偏移遮罩.label 顶点偏移遮罩 Vertex Offset Mask
438 inspector.feature.顶点偏移遮罩图.label 顶点偏移遮罩图 Vertex Offset Mask Texture
439 inspector.feature.顶点偏移遮罩图 Wrap.label 顶点偏移遮罩图循环模式 Vertex Offset Mask Texture Wrap
440 inspector.feature.顶点偏移遮罩图UV来源.label 顶点偏移遮罩图UV来源 Vertex Offset Mask UV Source
441 inspector.feature.顶点扰动遮罩X轴偏移自定义曲线.label 顶点扰动遮罩X轴偏移自定义曲线 Vertex Offset Mask X Custom Data
442 inspector.feature.顶点扰动遮罩Y轴偏移自定义曲线.label 顶点扰动遮罩Y轴偏移自定义曲线 Vertex Offset Mask Y Custom Data
443 inspector.feature.顶点偏移遮罩动画.label 顶点偏移遮罩动画 Vertex Offset Mask Animation
444 inspector.feature.顶点偏移遮罩强度.label 顶点偏移遮罩强度 Vertex Offset Mask Strength
445 inspector.feature.深度描边.label 深度描边 Depth Outline
446 inspector.feature.深度描边颜色.label 深度描边颜色 Depth Outline Color
447 inspector.feature.深度描边距离.label 深度描边距离 Depth Outline Distance
448 inspector.feature.深度贴花.label 深度贴花 Depth Decal
449 inspector.feature.遮蔽视差.label 遮蔽视差 Parallax
450 inspector.feature.视差贴图.label 视差贴图 Parallax Texture
451 inspector.feature.视差贴图 Wrap.label 视差贴图循环模式 Parallax Texture Wrap
452 inspector.feature.视差.label 视差 Parallax
453 inspector.feature.遮蔽视差最小层数.label 遮蔽视差最小层数 Parallax Min Layers
454 inspector.feature.遮蔽视差最大层数.label 遮蔽视差最大层数 Parallax Max Layers
455 inspector.feature.模板视差.label 模板视差 Portal
456 inspector.feature.模板视差蒙版.label 模板视差蒙版 Portal Mask
457 inspector.feature.序列帧融帧(丝滑).label 序列帧融帧(丝滑) Flipbook Blending
458 inspector.feature.VAT顶点动画图.label VAT顶点动画图 VAT Vertex Animation Texture
459 inspector.feature.VAT模式.label VAT模式 VAT Mode
460 inspector.feature.Houdini VAT Sub Mode.label Houdini VAT Sub Mode Houdini VAT Sub Mode
461 inspector.feature.VAT Frame CustomData.label VAT Frame CustomData VAT Frame CustomData
462 inspector.feature.Playback.label Playback Playback
463 inspector.feature.Auto Playback.label Auto Playback Auto Playback
464 inspector.feature.Display Frame.label Display Frame Display Frame
465 inspector.feature.Game Time at First Frame.label Game Time at First Frame Game Time at First Frame
466 inspector.feature.Playback Speed.label Playback Speed Playback Speed
467 inspector.feature.Houdini FPS.label Houdini FPS Houdini FPS
468 inspector.feature.Interframe Interpolation.label Interframe Interpolation Interframe Interpolation
469 inspector.feature.Animate First Frame.label Animate First Frame Animate First Frame
470 inspector.feature.Frame Count.label Frame Count Frame Count
471 inspector.feature.Bounds Metadata.label Bounds Metadata Bounds Metadata
472 inspector.feature.Bound Min X.label Bound Min X Bound Min X
473 inspector.feature.Bound Min Y.label Bound Min Y Bound Min Y
474 inspector.feature.Bound Min Z.label Bound Min Z Bound Min Z
475 inspector.feature.Bound Max X.label Bound Max X Bound Max X
476 inspector.feature.Bound Max Y.label Bound Max Y Bound Max Y
477 inspector.feature.Bound Max Z.label Bound Max Z Bound Max Z
478 inspector.feature.Textures.label Textures Textures
479 inspector.feature.Position Texture.label Position Texture Position Texture
480 inspector.feature.Position Texture 2.label Position Texture 2 Position Texture 2
481 inspector.feature.Rotation Texture.label Rotation Texture Rotation Texture
482 inspector.feature.Color Texture.label Color Texture Color Texture
483 inspector.feature.Lookup Table.label Lookup Table Lookup Table
484 inspector.feature.Scale.label Scale Scale
485 inspector.feature.Global Piece Scale Multiplier.label Global Piece Scale Multiplier Global Piece Scale Multiplier
486 inspector.feature.Piece Scales in Position Alpha.label Piece Scales in Position Alpha Piece Scales in Position Alpha
487 inspector.feature.Particle Sprite.label Particle Sprite Particle Sprite
488 inspector.feature.Width Base Scale.label Width Base Scale Width Base Scale
489 inspector.feature.Height Base Scale.label Height Base Scale Height Base Scale
490 inspector.feature.Hide Overlapping Origin.label Hide Overlapping Origin Hide Overlapping Origin
491 inspector.feature.Origin Effective Radius.label Origin Effective Radius Origin Effective Radius
492 inspector.feature.Particles Can Spin.label Particles Can Spin Particles Can Spin
493 inspector.feature.Compute Spin from Heading.label Compute Spin from Heading Compute Spin from Heading
494 inspector.feature.Particle Spin Phase.label Particle Spin Phase Particle Spin Phase
495 inspector.feature.Scale by Velocity Amount.label Scale by Velocity Amount Scale by Velocity Amount
496 inspector.feature.Particle Texture U Scale.label Particle Texture U Scale Particle Texture U Scale
497 inspector.feature.Particle Texture V Scale.label Particle Texture V Scale Particle Texture V Scale
498 inspector.feature.Flags.label Flags Flags
499 inspector.feature.Positions Require Two Textures.label Positions Require Two Textures Positions Require Two Textures
500 inspector.feature.Use Compressed Normals (no rotTex).label Use Compressed Normals (no rotTex) Use Compressed Normals (no rotTex)
501 inspector.feature.Load Color Texture.label Load Color Texture Load Color Texture
502 inspector.feature.Load Lookup Table.label Load Lookup Table Load Lookup Table
503 inspector.feature.VAT texture.label VAT texture VAT Texture
504 inspector.feature.ImportScale.label ImportScale Import Scale
505 inspector.feature.TyFlow VAT Sub Mode.label TyFlow VAT Sub Mode TyFlow VAT Sub Mode
506 inspector.feature.Deforming skin.label Deforming skin Deforming Skin
507 inspector.feature.Skin bone count.label Skin bone count Skin Bone Count
508 inspector.feature.RGBA encoded.label RGBA encoded RGBA Encoded
509 inspector.feature.RGBA half.label RGBA half RGBA Half
510 inspector.feature.Gamma correction.label Gamma correction Gamma Correction
511 inspector.feature.VAT includes normals.label VAT includes normals VAT Includes Normals
512 inspector.feature.Affects shadows.label Affects shadows Affects Shadows
513 inspector.feature.Frame.label Frame Frame
514 inspector.feature.Frames.label Frames Frames
515 inspector.feature.Frame interpolation.label Frame interpolation Frame Interpolation
516 inspector.feature.Loop.label Loop Loop
517 inspector.feature.Interpolate loop.label Interpolate loop Interpolate Loop
518 inspector.feature.Autoplay.label Autoplay Autoplay
519 inspector.feature.AutoplaySpeed.label AutoplaySpeed Autoplay Speed
520 inspector.toolbar.ping.label
521 inspector.toolbar.ping.tip 跳到当前材质 Ping current material
522 inspector.toolbar.cleanUnusedTextures.label
523 inspector.toolbar.cleanUnusedTextures.tip 清除没有使用的贴图 Clean unused textures
524 inspector.toolbar.cleanUnusedTextures.undo 清除没有使用的贴图 Clean unused textures
525 inspector.toolbar.cleanUnusedTextures.log 清理 {0} 的无效贴图属性: {1} Cleaned unused texture property '{1}' on material '{0}'
526 inspector.toolbar.copy.label C C 复制材质属性 Copy material properties
527 inspector.toolbar.paste.label V V 粘贴材质属性 Paste material properties
528 inspector.toolbar.paste.undo 粘贴材质属性 Paste material properties
529 inspector.toolbar.tierFormat.label 等级: {0} Tier: {0}
530 inspector.toolbar.tierMixed.label 等级: Mixed Tier: Mixed
531 inspector.toolbar.tierLow.label Low
532 inspector.toolbar.tierMedium.label Medium
533 inspector.toolbar.tierHigh.label High
534 inspector.toolbar.tierUltra.label 顶配 Ultra
535 inspector.toolbar.tier.tip NBShader分级 NBShader feature tier
536 inspector.toolbar.setTier.undo 设置 NBShader 分级 Set NBShader Feature Tier
537 inspector.toolbar.specialReset.label R R 特殊重置功能 Special reset tools
538 inspector.toolbar.resetAll.label 重置所有 Reset All
539 inspector.toolbar.resetAll.undo 重置所有特殊功能 Reset All Special Tools
540 inspector.toolbar.resetDisabledFeatureChildren.label 重置关闭功能子属性 Reset Disabled Feature Children
541 inspector.toolbar.resetDisabledFeatureChildren.undo 重置关闭功能子属性 Reset Disabled Feature Children
542 inspector.toolbar.resetSpecialUV.label 重置特殊UV通道 Reset Special UV Channel
543 inspector.toolbar.resetSpecialUV.undo 重置特殊UV通道 Reset Special UV Channel
544 inspector.toolbar.resetTwirl.label 重置旋转扭曲 Reset Twirl
545 inspector.toolbar.resetTwirl.undo 重置旋转扭曲 Reset Twirl
546 inspector.toolbar.resetPolar.label 重置极坐标 Reset Polar Coordinates
547 inspector.toolbar.resetPolar.undo 重置极坐标 Reset Polar Coordinates
548 inspector.toolbar.collapseAll.label
549 inspector.toolbar.collapseAll.tip 折叠所有控件 Collapse all controls
550 inspector.toolbar.collapseAll.undo 折叠所有控件 Collapse all controls
551 inspector.toolbar.help.label
552 inspector.toolbar.help.tip 说明文档 Documentation
553 inspector.toolbar.settings.tip NBShader设置 NBShader settings
554 inspector.projectSettings.generalSection 基础设置 General Settings
555 inspector.projectSettings.defaultLanguage 默认语言 Default Language
556 inspector.projectSettings.languageMode.option.0 跟随编辑器 Follow Editor
557 inspector.projectSettings.languageMode.option.1 中文 Chinese
558 inspector.projectSettings.languageMode.option.2 英文 English
559 inspector.featureLevel.providerLabel NBShader 分级 NBShader Feature Levels
560 inspector.featureLevel.help.message 配置 NBShader Catalog Keyword 和 Pass 的分级白名单、Unity Quality 绑定和运行时资源导出。构建脚本通过 NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier 选择打包剔除等级。Catalog 外 Feature 会被忽略。 Configure NBShader managed Catalog keywords and shader passes per tier bind Unity Quality levels and export runtime settings. Build scripts select the build stripping tier through NBShaderFeatureLevelEditorAPI.OverrideBuildStripExplicitTier. Catalog-external features are ignored.
561 inspector.featureLevel.undo.changeKeyword 修改 NBShader Feature Keyword Change NBShader Feature Keyword
562 inspector.featureLevel.undo.resetTierKeywords 重置 NBShader 等级 Keyword Reset NBShader Tier Keywords
563 inspector.featureLevel.undo.resetQualityMapping 重置 NBShader Quality 映射 Reset NBShader Quality Mapping
564 inspector.featureLevel.undo.changeQualityBinding 修改 NBShader Quality 绑定 Change NBShader Quality Binding
565 inspector.featureLevel.table.title 分级功能表 Feature Level Matrix
566 inspector.featureLevel.column.feature.label 配置 / Feature Config / Feature 等级设置和受管理的 Catalog Feature Tier settings and managed Catalog features
567 inspector.featureLevel.column.description.label Raw Keyword / 说明 Raw Keyword / Note 原始 Shader Keyword 或配置说明 Raw shader keyword or configuration note
568 inspector.featureLevel.row.quality.label Quality 绑定 Quality Binding 每个 Unity Quality Level 只能属于一个 NBShader 等级 Each Unity Quality Level belongs to exactly one NBShader tier
569 inspector.featureLevel.desc.quality Unity Quality Level Unity Quality Level
570 inspector.featureLevel.quality.menuTip 点击可把 Unity Quality Level 移动到这个 NBShader 等级 Click to move Unity Quality levels to this NBShader tier
571 inspector.featureLevel.quality.noLevels 没有 Quality Level No Quality Levels
572 inspector.featureLevel.quality.none
573 inspector.featureLevel.keyword.tooltip Raw Keyword:{0}。该等级未勾选时会剔除使用此 Catalog Keyword 的 Variant。 Raw keyword: {0}. Unchecked in a tier strips variants using this Catalog keyword.
574 inspector.featureLevel.resetTierKeywords.button 重置等级 Keywords Reset Tier Keywords 将 Feature 表格重置为内置默认值 Reset the keyword matrix to the built-in defaults
575 inspector.featureLevel.resetQualityMapping.button 重置 Quality 映射 Reset Quality Mapping 按默认 Quality 索引规则重置 Unity Quality 绑定 Reset Unity Quality bindings using the default quality-index rule
576 inspector.featureRuntimeSettings.updateFromProjectSettings.button 根据当前ProjectSetting更新配置 Update From Current Project Settings 将当前 Project Settings 数据写入这个 RuntimeSettings 配置资源 Write the current Project Settings data into this RuntimeSettings asset
577 inspector.featureRuntimeSettings.updateFromProjectSettings.successTitle 运行时配置已更新 Runtime Settings Updated
578 inspector.featureRuntimeSettings.updateFromProjectSettings.successMessage 当前 NBShader Project Settings 数据已写入这个 RuntimeSettings 配置资源 The current NBShader Project Settings data was written to this RuntimeSettings asset
579 inspector.featureLevel.openVariantCollectionBuilder.button 打开变体集合生成器 Open Variant Collection Builder 打开 NBShader 变体集合生成器 Open the NBShader variant collection builder
580 inspector.featureLevel.applyCurrentQualityTierToLoadedMaterials.button 应用当前 Quality 等级到已加载材质 Apply Current Quality Tier To Loaded Materials 将当前 Unity Quality 映射到的 NBShader 等级应用到所有已加载的 NBShader2 材质 Apply the tier bound to the current Unity Quality Level to all loaded NBShader2 materials
581 inspector.featureLevel.applyCurrentQualityTierToProjectMaterials.button 应用当前 Quality 等级到项目材质 Apply Current Quality Tier To Project Materials 扫描 Assets 并将当前 Unity Quality 映射到的 NBShader 等级应用到 NBShader2 材质资源 Scan Assets and apply the tier bound to the current Unity Quality Level to NBShader2 material assets
582 inspector.featureLevel.keyword.NB_DEBUG_DISSOLVE.label 调试溶解 Debug Dissolve
583 inspector.featureLevel.keyword.NB_DEBUG_DISTORT.label 调试扭曲 Debug Distort
584 inspector.featureLevel.keyword.NB_DEBUG_FRESNEL.label 调试菲涅尔 Debug Fresnel
585 inspector.featureLevel.keyword.NB_DEBUG_MASK.label 调试遮罩 Debug Mask
586 inspector.featureLevel.keyword.NB_DEBUG_PNOISE.label 调试程序噪声 Debug Program Noise
587 inspector.featureLevel.keyword.NB_DEBUG_VERTEX_OFFSET.label 调试顶点偏移 Debug Vertex Offset
588 inspector.featureLevel.keyword.VFX_SIX_WAY_ABSORPTION.label 六向光吸收 Six Way Absorption
589 inspector.featureLevel.keyword._ALPHAMODULATE_ON.label Alpha 调制 Alpha Modulate
590 inspector.featureLevel.keyword._ALPHAPREMULTIPLY_ON.label 预乘 Alpha Premultiply Alpha
591 inspector.featureLevel.keyword._ALPHATEST_ON.label Alpha 裁剪 Alpha Test
592 inspector.featureLevel.keyword._COLORMAPBLEND.label 颜色图混合 Color Map Blend
593 inspector.featureLevel.keyword._COLOR_RAMP.label 颜色渐变 Color Ramp
594 inspector.featureLevel.keyword._DEPTH_DECAL.label 深度贴花 Depth Decal
595 inspector.featureLevel.keyword._DISSOLVE.label 溶解 Dissolve
596 inspector.featureLevel.keyword._DISTORT_REFRACTION.label 折射扭曲 Distort Refraction
597 inspector.featureLevel.keyword._EMISSION.label 自发光 Emission
598 inspector.featureLevel.keyword._FLIPBOOKBLENDING_ON.label 序列帧混合 Flipbook Blending
599 inspector.featureLevel.keyword._FX_LIGHT_MODE_BLINN_PHONG.label Blinn-Phong 光照 Blinn-Phong Lighting
600 inspector.featureLevel.keyword._FX_LIGHT_MODE_HALF_LAMBERT.label Half Lambert 光照 Half Lambert Lighting
601 inspector.featureLevel.keyword._FX_LIGHT_MODE_PBR.label PBR 光照 PBR Lighting
602 inspector.featureLevel.keyword._FX_LIGHT_MODE_SIX_WAY.label 六向光照 Six Way Lighting
603 inspector.featureLevel.keyword._FX_LIGHT_MODE_UNLIT.label 无光照 Unlit Lighting
604 inspector.featureLevel.keyword._HOUDINI_VAT_DYNAMIC_REMESH.label Houdini VAT 动态重网格 Houdini VAT Dynamic Remesh
605 inspector.featureLevel.keyword._HOUDINI_VAT_PARTICLE_SPRITE.label Houdini VAT 粒子精灵 Houdini VAT Particle Sprite
606 inspector.featureLevel.keyword._HOUDINI_VAT_RIGIDBODY.label Houdini VAT 刚体 Houdini VAT Rigid Body
607 inspector.featureLevel.keyword._HOUDINI_VAT_SOFTBODY.label Houdini VAT 软体 Houdini VAT Soft Body
608 inspector.featureLevel.keyword._MASKMAP_ON.label 遮罩贴图 Mask Map
609 inspector.featureLevel.keyword._MATCAP.label MatCap MatCap
610 inspector.featureLevel.keyword._NOISEMAP.label 噪声贴图 Noise Map
611 inspector.featureLevel.keyword._NOISEMAP_NORMALIZEED.label 噪声归一化 Noise Normalize
612 inspector.featureLevel.keyword._NORMALMAP.label 法线贴图 Normal Map
613 inspector.featureLevel.keyword._OVERRIDE_Z.label Override Z Override Z
614 inspector.featureLevel.keyword._PARALLAX_MAPPING.label 视差映射 Parallax Mapping
615 inspector.featureLevel.keyword._PARCUSTOMDATA_ON.label 粒子自定义数据 Particle Custom Data
616 inspector.featureLevel.keyword._PROGRAM_NOISE.label 程序噪声 Program Noise
617 inspector.featureLevel.keyword._SCREEN_DISTORT_MODE.label 屏幕扭曲 Screen Distort
618 inspector.featureLevel.keyword._SCRIPTABLETIME.label 可编程时间 Scriptable Time
619 inspector.featureLevel.keyword._SHARED_UV.label 共享 UV Shared UV
620 inspector.featureLevel.keyword._SOFTPARTICLES_ON.label 软粒子 Soft Particles
621 inspector.featureLevel.keyword._SPECULAR_COLOR.label 高光颜色 Specular Color
622 inspector.featureLevel.keyword._STENCIL_WITHOUT_PLAYER.label 无 Player 模板 Stencil Without Player
623 inspector.featureLevel.keyword._TYFLOW_VAT_ABSOLUTE.label TyFlow VAT 绝对模式 TyFlow VAT Absolute
624 inspector.featureLevel.keyword._TYFLOW_VAT_RELATIVE.label TyFlow VAT 相对模式 TyFlow VAT Relative
625 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PR.label TyFlow VAT 皮肤 PR TyFlow VAT Skin PR
626 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSAVE.label TyFlow VAT 皮肤 PR 保存 TyFlow VAT Skin PR Save
627 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSXYZ.label TyFlow VAT 皮肤 PRSXYZ TyFlow VAT Skin PRSXYZ
628 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_R.label TyFlow VAT 皮肤 R TyFlow VAT Skin R
629 inspector.featureLevel.keyword._UNSCALETIME.label 非缩放时间 Unscaled Time
630 inspector.featureLevel.keyword._VAT.label VAT VAT
631 inspector.featureLevel.keyword._VAT_HOUDINI.label Houdini VAT Houdini VAT
632 inspector.featureLevel.keyword._VAT_TYFLOW.label TyFlow VAT TyFlow VAT
633 inspector.featureLevel.group.tooltip 点击折叠按钮显示或隐藏子级 Row Click the foldout to show or hide child rows
634 inspector.featureLevel.desc.group 分组 Group
635 inspector.featureLevel.group.mode.label 模式设置 Mode 跟随材质面板的模式设置顺序 Matches the material inspector Mode order
636 inspector.featureLevel.group.transparent.label 透明模式 Transparent Mode 透明模式相关 Keyword Transparent mode related keywords
637 inspector.featureLevel.group.time.label 时间模式 Time Mode 时间来源相关 Keyword Time source related keywords
638 inspector.featureLevel.group.base.label 基本全局功能 Base 跟随材质面板的基本全局功能顺序 Matches the material inspector Base order
639 inspector.featureLevel.group.particle.label 粒子数据 Particle Data 粒子自定义数据相关 Keyword Particle custom data related keywords
640 inspector.featureLevel.group.light.label 光照功能 Lighting 跟随材质面板的光照功能顺序 Matches the material inspector Lighting order
641 inspector.featureLevel.group.lightMode.label 光照模式 Light Mode 光照模式 Keyword Light mode keywords
642 inspector.featureLevel.group.feature.label 特别功能 Feature 跟随材质面板的特别功能 Toggle 顺序 Matches the material inspector Feature toggle order
643 inspector.featureLevel.group.fresnel.label 菲涅尔 Fresnel 菲涅尔相关 Keyword Fresnel related keywords
644 inspector.featureLevel.group.vertexOffset.label 顶点偏移 Vertex Offset 顶点偏移相关 Keyword Vertex offset related keywords
645 inspector.featureLevel.group.depth.label 深度功能 Depth 深度相关 Keyword Depth related keywords
646 inspector.featureLevel.group.vatMode.label VAT 模式 VAT Mode VAT 主模式 Keyword VAT main mode keywords
647 inspector.featureLevel.group.houdiniVat.label Houdini VAT Houdini VAT Houdini VAT 子模式 Keyword Houdini VAT sub-mode keywords
648 inspector.featureLevel.group.tyflowVat.label TyFlow VAT TyFlow VAT TyFlow VAT 子模式 Keyword TyFlow VAT sub-mode keywords
649 inspector.featureLevel.column.cost.label 性能消耗 Performance Cost 估算启用该功能后的 Shader 性能消耗 Estimated shader cost when this feature is enabled
650 inspector.featureLevel.column.effect.label 功能说明 Feature Effect 简要说明该 Keyword 控制的功能 Short description of what this keyword enables
651 inspector.featureLevel.cost.low Low
652 inspector.featureLevel.cost.medium Medium
653 inspector.featureLevel.cost.high High
654 inspector.featureLevel.cost.ultra 超高 Ultra
655 inspector.featureLevel.cost.tooltip 该 Keyword 估算的 Shader 性能消耗 Estimated shader performance cost for this keyword
656 inspector.featureLevel.desc.none
657 inspector.featureLevel.desc.config 配置 Config
658 inspector.featureLevel.effect.quality.label 绑定 Unity Quality 到 NBShader 等级 Bind Unity Quality Levels to NBShader tiers 每个 Unity Quality Level 只能属于一个 NBShader 等级 Each Unity Quality Level belongs to exactly one NBShader tier
659 inspector.featureLevel.keyword._CHROMATIC_ABERRATION.label 色散 Chromatic Aberration
660 inspector.featureLevel.keyword._COLOR_RAMP_MAP.label 颜色渐变贴图 Color Ramp Map
661 inspector.featureLevel.keyword._DEPTH_OUTLINE.label 深度描边 Depth Outline
662 inspector.featureLevel.keyword._DISSOLVE_MASK.label 溶解遮罩 Dissolve Mask
663 inspector.featureLevel.keyword._DISSOLVE_RAMP.label 溶解 Ramp Dissolve Ramp
664 inspector.featureLevel.keyword._DISSOLVE_RAMP_MAP.label 溶解 Ramp 图 Dissolve Ramp Map
665 inspector.featureLevel.keyword._DISTANCE_FADE.label 距离淡化 Distance Fade
666 inspector.featureLevel.keyword._FRESNEL.label 菲涅尔 Fresnel
667 inspector.featureLevel.keyword._MASKMAP2_ON.label 遮罩贴图 2 Mask Map 2
668 inspector.featureLevel.keyword._MASKMAP3_ON.label 遮罩贴图 3 Mask Map 3
669 inspector.featureLevel.keyword._NOISE_MASKMAP.label 扭曲遮罩 Noise Mask Map
670 inspector.featureLevel.keyword._PROGRAM_NOISE_SIMPLE.label 程序噪声 Perlin Program Noise Simple
671 inspector.featureLevel.keyword._PROGRAM_NOISE_VORONOI.label 程序噪声 Voronoi Program Noise Voronoi
672 inspector.featureLevel.keyword._VERTEX_OFFSET.label 顶点偏移 Vertex Offset
673 inspector.featureLevel.keyword._VERTEX_OFFSET_MASKMAP.label 顶点偏移遮罩 Vertex Offset Mask Map
674 inspector.featureLevel.keyword.NB_DEBUG_DISSOLVE.effect 显示溶解数值方便调试 Shows dissolve values for debugging
675 inspector.featureLevel.keyword.NB_DEBUG_DISTORT.effect 显示扭曲强度方便调试 Shows distortion strength for debugging
676 inspector.featureLevel.keyword.NB_DEBUG_FRESNEL.effect 显示菲涅尔数值方便调试 Shows fresnel values for debugging
677 inspector.featureLevel.keyword.NB_DEBUG_MASK.effect 显示遮罩数值方便调试 Shows mask values for debugging
678 inspector.featureLevel.keyword.NB_DEBUG_PNOISE.effect 显示程序噪声数值方便调试 Shows procedural noise values for debugging
679 inspector.featureLevel.keyword.NB_DEBUG_VERTEX_OFFSET.effect 显示顶点偏移数值方便调试 Shows vertex offset values for debugging
680 inspector.featureLevel.keyword.VFX_SIX_WAY_ABSORPTION.effect 为六向光照增加吸收效果 Adds absorption response for six way lighting
681 inspector.featureLevel.keyword._ALPHAMODULATE_ON.effect 使用 Alpha 调制透明混合 Uses alpha modulation transparent blending
682 inspector.featureLevel.keyword._ALPHAPREMULTIPLY_ON.effect 使用预乘 Alpha 透明混合 Uses premultiplied alpha blending
683 inspector.featureLevel.keyword._ALPHATEST_ON.effect 按 Alpha 阈值裁剪像素 Cuts pixels by alpha threshold
684 inspector.featureLevel.keyword._CHROMATIC_ABERRATION.effect 分离颜色通道产生色散 Splits color channels for distortion fringe
685 inspector.featureLevel.keyword._COLORMAPBLEND.effect 混合额外的颜色渐变贴图 Blends an extra color gradient texture
686 inspector.featureLevel.keyword._COLOR_RAMP.effect 使用 Ramp 重新映射颜色 Remaps color through a ramp
687 inspector.featureLevel.keyword._COLOR_RAMP_MAP.effect 使用贴图作为颜色 Ramp 来源 Uses a texture as the color ramp source
688 inspector.featureLevel.keyword._DEPTH_DECAL.effect 使用场景深度投射贴花效果 Projects decal effect using scene depth
689 inspector.featureLevel.keyword._DEPTH_OUTLINE.effect 使用深度差生成描边效果 Creates outline effect using depth difference
690 inspector.featureLevel.keyword._OVERRIDE_Z.effect 写入固定相机眼深度到 SV_Depth Writes a fixed camera eye depth through SV_Depth
691 inspector.featureLevel.keyword._DISSOLVE.effect 按噪声或贴图裁剪并混合溶解 Clips and blends pixels for dissolve
692 inspector.featureLevel.keyword._DISSOLVE_MASK.effect 使用遮罩控制过程溶解范围 Uses a process mask for dissolve
693 inspector.featureLevel.keyword._DISSOLVE_RAMP.effect 为溶解边缘增加 Ramp 着色 Adds ramp coloring to dissolve edges
694 inspector.featureLevel.keyword._DISSOLVE_RAMP_MAP.effect 使用贴图控制溶解 Ramp 颜色 Uses a texture for dissolve ramp color
695 inspector.featureLevel.keyword._DISTANCE_FADE.effect 根据相机距离淡化材质 Fades material by camera distance
696 inspector.featureLevel.keyword._DISTORT_REFRACTION.effect 使用折射方式计算扭曲 Uses refraction style distortion
697 inspector.featureLevel.keyword._EMISSION.effect 增加自发光颜色或贴图贡献 Adds emissive color or texture contribution
698 inspector.featureLevel.keyword._FLIPBOOKBLENDING_ON.effect 在序列帧之间进行平滑混合 Blends between flipbook frames
699 inspector.featureLevel.keyword._FRESNEL.effect 增加基于视角的边缘光 Adds view angle based rim lighting
700 inspector.featureLevel.keyword._FX_LIGHT_MODE_BLINN_PHONG.effect 使用 Blinn Phong 光照模型 Uses Blinn Phong lighting
701 inspector.featureLevel.keyword._FX_LIGHT_MODE_HALF_LAMBERT.effect 使用 Half Lambert 光照模型 Uses half Lambert lighting
702 inspector.featureLevel.keyword._FX_LIGHT_MODE_PBR.effect 使用 PBR 光照计算 Uses PBR lighting calculations
703 inspector.featureLevel.keyword._FX_LIGHT_MODE_SIX_WAY.effect 使用六向光照数据 Uses six way lighting data
704 inspector.featureLevel.keyword._FX_LIGHT_MODE_UNLIT.effect 使用无光照渲染 Uses unlit shading
705 inspector.featureLevel.keyword._HOUDINI_VAT_DYNAMIC_REMESH.effect 使用 Houdini 动态重网格 VAT 类型 Uses Houdini dynamic remesh VAT mode
706 inspector.featureLevel.keyword._HOUDINI_VAT_PARTICLE_SPRITE.effect 使用 Houdini 粒子精灵 VAT 类型 Uses Houdini particle sprite VAT mode
707 inspector.featureLevel.keyword._HOUDINI_VAT_RIGIDBODY.effect 使用 Houdini 刚体 VAT 类型 Uses Houdini rigid body VAT mode
708 inspector.featureLevel.keyword._HOUDINI_VAT_SOFTBODY.effect 使用 Houdini 软体 VAT 类型 Uses Houdini soft body VAT mode
709 inspector.featureLevel.keyword._MASKMAP_ON.effect 启用第一张遮罩贴图 Uses the first mask map
710 inspector.featureLevel.keyword._MASKMAP2_ON.effect 启用第二张遮罩贴图 Uses the second mask map
711 inspector.featureLevel.keyword._MASKMAP3_ON.effect 启用第三张遮罩贴图 Uses the third mask map
712 inspector.featureLevel.keyword._MATCAP.effect 增加 MatCap 贴图光照 Adds matcap lighting texture
713 inspector.featureLevel.keyword._NOISEMAP.effect 使用噪声贴图产生扭曲 Uses a noise map for distortion
714 inspector.featureLevel.keyword._NOISE_MASKMAP.effect 使用遮罩限制扭曲范围 Masks the distortion effect
715 inspector.featureLevel.keyword._NORMALMAP.effect 使用法线贴图增加光照细节 Uses normal map lighting detail
716 inspector.featureLevel.keyword._PARALLAX_MAPPING.effect 偏移 UV 模拟视差深度 Offsets UVs for parallax depth
717 inspector.featureLevel.keyword._PARCUSTOMDATA_ON.effect 读取粒子 Custom Data 通道 Reads particle custom data channels
718 inspector.featureLevel.keyword._PROGRAM_NOISE.effect 在 Shader 中生成程序噪声 Generates procedural noise in shader
719 inspector.featureLevel.keyword._PROGRAM_NOISE_SIMPLE.effect 启用简单程序噪声 Enables simple procedural noise
720 inspector.featureLevel.keyword._PROGRAM_NOISE_VORONOI.effect 启用 Voronoi 程序噪声 Enables Voronoi procedural noise
721 inspector.featureLevel.keyword._SCREEN_DISTORT_MODE.effect 采样屏幕纹理实现扭曲 Samples screen texture for distortion
722 inspector.featureLevel.keyword._SCRIPTABLETIME.effect 使用脚本传入的时间值 Uses script provided time value
723 inspector.featureLevel.keyword._SHARED_UV.effect 共享一组通用 UV 变换 Shares a common UV transform
724 inspector.featureLevel.keyword._SOFTPARTICLES_ON.effect 使用场景深度柔化粒子边缘 Softens particles using scene depth
725 inspector.featureLevel.keyword._SPECULAR_COLOR.effect 增加高光颜色控制 Adds specular color highlight
726 inspector.featureLevel.keyword._STENCIL_WITHOUT_PLAYER.effect 使用不含 Player 的模板遮罩 Uses stencil without player mask
727 inspector.featureLevel.keyword._TYFLOW_VAT_ABSOLUTE.effect 使用 TyFlow 绝对 VAT 模式 Uses TyFlow absolute VAT mode
728 inspector.featureLevel.keyword._TYFLOW_VAT_RELATIVE.effect 使用 TyFlow 相对 VAT 模式 Uses TyFlow relative VAT mode
729 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PR.effect 使用 TyFlow Skin PR VAT 模式 Uses TyFlow skin PR VAT mode
730 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSAVE.effect 使用 TyFlow Skin PR Save VAT 模式 Uses TyFlow skin PR save VAT mode
731 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_PRSXYZ.effect 使用 TyFlow Skin PRSXYZ VAT 模式 Uses TyFlow skin PRSXYZ VAT mode
732 inspector.featureLevel.keyword._TYFLOW_VAT_SKIN_R.effect 使用 TyFlow Skin R VAT 模式 Uses TyFlow skin R VAT mode
733 inspector.featureLevel.keyword._UNSCALETIME.effect 使用不受 TimeScale 影响的时间 Uses unscaled time
734 inspector.featureLevel.keyword._VAT.effect 启用顶点动画贴图播放 Enables vertex animation texture playback
735 inspector.featureLevel.keyword._VAT_HOUDINI.effect 使用 Houdini VAT 数据布局 Uses Houdini VAT data layout
736 inspector.featureLevel.keyword._VAT_TYFLOW.effect 使用 TyFlow VAT 数据布局 Uses TyFlow VAT data layout
737 inspector.featureLevel.keyword._VERTEX_OFFSET.effect 在 Shader 中偏移顶点 Offsets vertices in the shader
738 inspector.featureLevel.keyword._VERTEX_OFFSET_MASKMAP.effect 用贴图遮罩顶点偏移范围 Masks vertex offset by texture
739 inspector.featureLevel.saveCurrentAsDefault.button 保存当前配置为默认 Save Current Config as Default 将当前四个等级的 Keyword 配置写入 Package 默认 LevelAsset Write the current tier keyword matrix into the package default LevelAsset
740 inspector.featureLevel.saveCurrentAsDefault.failedTitle 保存默认配置失败 Save Default Config Failed
741 inspector.featureLevel.saveCurrentAsDefault.failedMessage 无法写入 Package 默认 LevelAsset。请确认 Package 路径可写。 Could not write the package default LevelAsset. Please make sure the package path is writable.
742 inspector.featureLevel.dialog.ok 确定 OK
743 inspector.debugSymbols.providerLabel NBShader2 调试符号 NBShader2 Debug Symbols
744 inspector.debugSymbols.help.message 通过改写 NBShader.shader 引用的包内 include 控制 NBShader2 编译调试符号。仅在外部工具调试 Shader 时开启。 Controls NBShader2 shader compiler debug symbols by rewriting the package include used by NBShader.shader. Enable only while debugging external shader tools.
745 inspector.debugSymbols.includeMismatch.message ProjectSettings 值和包内 include 内容不一致。应用当前设置以重新同步 Shader 编译输入。 The ProjectSettings value and package include content do not match. Apply the current setting to resync the shader compiler input.
746 inspector.debugSymbols.enable.label 启用 NBShader2 调试符号 Enable NBShader2 Debug Symbols 将 #pragma enable_d3d11_debug_symbols 写入 NBShader2 调试 pragma include Writes #pragma enable_d3d11_debug_symbols into the NBShader2 debug pragma include
747 inspector.debugSymbols.dirtyWarning.message 启用此选项会修改 NB_FX 包内的 NBShaderDebugPragmas.hlsl。除非明确需要 Shader 调试符号,否则不要提交开启状态的 include。 Enabling this option modifies NBShaderDebugPragmas.hlsl in the NB_FX package. Do not commit the enabled include unless shader debug symbols are deliberately required.
748 inspector.debugSymbols.cachingPreprocessor.label Caching Shader Preprocessor Caching Shader Preprocessor #include_with_pragmas 需要启用 Caching Shader Preprocessor #include_with_pragmas requires the Caching Shader Preprocessor
749 inspector.debugSymbols.cachingPreprocessorWarning.message #include_with_pragmas 需要启用 Caching Shader Preprocessor。使用 NBShader2 调试符号前请先启用。 #include_with_pragmas requires the Caching Shader Preprocessor. Enable it before using NBShader2 debug symbols.
750 inspector.debugSymbols.settingsState.label ProjectSettings 状态 ProjectSettings State 保存于 ProjectSettings/NBShaderFeatureLevels.asset 的状态 Saved state in ProjectSettings/NBShaderFeatureLevels.asset
751 inspector.debugSymbols.includeState.label Include 文件状态 Include File State NBShader.shader 实际使用的包内 include 内容 Actual package include content used by NBShader.shader
752 inspector.debugSymbols.status.enabled 已启用 Enabled
753 inspector.debugSymbols.status.disabled 已关闭 Disabled
754 inspector.debugSymbols.status.missing 缺失 Missing
755 inspector.debugSymbols.undo.changeSetting 修改 NBShader2 调试符号 Change NBShader2 Debug Symbols
756 inspector.debugSymbols.applyFailed.title 应用 NBShader2 调试符号失败 Apply NBShader2 Debug Symbols Failed
757 inspector.debugSymbols.applyFailed.message 无法写入 NBShaderDebugPragmas.hlsl: Could not write NBShaderDebugPragmas.hlsl:
758 inspector.debugSymbols.confirmEnable.title 启用 NBShader2 调试符号 Enable NBShader2 Debug Symbols
759 inspector.debugSymbols.confirmEnable.message 此操作会把 #pragma enable_d3d11_debug_symbols 写入 NB_FX 包内 include。开启期间 Shader 体积可能增加并关闭优化。 This writes #pragma enable_d3d11_debug_symbols into the NB_FX package include. Shader size can increase and optimizations are disabled while it is enabled.
760 inspector.debugSymbols.dialog.enable 启用 Enable
761 inspector.debugSymbols.dialog.cancel 取消 Cancel
762 inspector.debugSymbols.dialog.ok 确定 OK
763 inspector.debugSymbols.applySetting.button 应用当前设置到 Include Apply Current Setting To Include
764 inspector.debugSymbols.pingInclude.button 选中调试开关include Select Debug Toggle Include
765 inspector.debugSymbols.enableCachingPreprocessor.button 启用 Caching Shader Preprocessor Enable Caching Shader Preprocessor
766 inspector.particleBaseMigration.providerLabel ParticleBase 迁移 ParticleBase Migration
767 inspector.particleBaseMigration.settingsHelp 扫描引用旧版 ParticleBase Shader GUID 的材质资源,确认后迁移到 NBShader2。转换前请先做好资产备份或版本管理。 Scan material assets that reference the legacy ParticleBase shader GUID and migrate them to NBShader2 after confirmation. Back up assets or commit to version control before converting.
768 inspector.particleBaseMigration.openWindow.button 打开 ParticleBase 迁移窗口 Open ParticleBase Migration Window
769 inspector.particleBaseMigration.windowTitle ParticleBase 迁移 ParticleBase Migration
770 inspector.particleBaseMigration.title ParticleBase -> NBShader2 ParticleBase -> NBShader2
771 inspector.particleBaseMigration.windowWarning 此操作会修改材质 Shader 绑定并同步材质状态。转换前请先做好资产备份或版本管理。工具不会提供自动回退。 This operation changes material shader assignments and synchronized material state. Back up assets or commit to version control before converting. The tool does not provide an automatic rollback.
772 inspector.particleBaseMigration.scan.button 扫描 ParticleBase 材质 Scan ParticleBase Materials
773 inspector.particleBaseMigration.selectAll.button 全选 Select All
774 inspector.particleBaseMigration.selectNone.button 全不选 Select None
775 inspector.particleBaseMigration.scanPrompt 点击扫描查找引用 ParticleBase Shader 资源 GUID 的 .mat 资源。Shader 名称只作为回退匹配。 Click Scan to find .mat assets that reference the ParticleBase shader asset GUID. Shader name is only used as a fallback.
776 inspector.particleBaseMigration.noMaterials 没有找到 ParticleBase 材质资源。 No ParticleBase material assets were found.
777 inspector.particleBaseMigration.listSummary 找到 {0} 个材质资源。已选择:{1} Found {0} material asset(s). Selected: {1}
778 inspector.particleBaseMigration.column.material 材质 Material
779 inspector.particleBaseMigration.column.match 匹配方式 Match
780 inspector.particleBaseMigration.column.path 路径 Path
781 inspector.particleBaseMigration.ping.button 定位 Ping
782 inspector.particleBaseMigration.convertSelected.button 转换选中的材质到 NBShader2 Convert Selected Materials To NBShader2
783 inspector.particleBaseMigration.progress.scanning 正在扫描材质 {0}/{1} Scanning materials {0}/{1}
784 inspector.particleBaseMigration.scanCanceled 扫描已取消。取消前找到 {0} 个材质资源。 Scan canceled. Found {0} material asset(s) before canceling.
785 inspector.particleBaseMigration.scanComplete 扫描完成。找到 {0} 个 ParticleBase 材质资源。 Scan complete. Found {0} ParticleBase material asset(s).
786 inspector.particleBaseMigration.nbShader2Missing.title 缺少 NBShader2 NBShader2 Missing
787 inspector.particleBaseMigration.nbShader2Missing.message 无法加载 NBShader2 Shader 资源,迁移无法继续。 Could not load NBShader2 shader asset. Migration cannot continue.
788 inspector.particleBaseMigration.dialog.ok 确定 OK
789 inspector.particleBaseMigration.progress.converting 正在转换 {0}/{1}:{2} Converting {0}/{1}: {2}
790 inspector.particleBaseMigration.failuresLogged ParticleBase 迁移完成但存在失败项: ParticleBase migration completed with failures:
791 inspector.particleBaseMigration.failure.loadMaterial {0}:无法加载材质。 {0}: material could not be loaded.
792 inspector.particleBaseMigration.failure.noLongerParticleBase {0}:已跳过,因为它不再引用 ParticleBase。 {0}: skipped because it no longer references ParticleBase.
793 inspector.particleBaseMigration.failure.exception {0}:{1} {0}: {1}
794 inspector.particleBaseMigration.match.converted 已转换 Converted
795 inspector.particleBaseMigration.confirm.title 确认 ParticleBase 迁移 Confirm ParticleBase Migration
796 inspector.particleBaseMigration.confirm.message 即将把 {0} 个材质资源从 ParticleBase 转换到 NBShader2。继续前请先做好资产备份或版本管理。工具不会提供自动回退。 You are about to convert {0} material asset(s) from ParticleBase to NBShader2. Back up assets or commit to version control before continuing. This tool does not provide an automatic rollback.
797 inspector.particleBaseMigration.dialog.convert 转换 Convert
798 inspector.particleBaseMigration.dialog.cancel 取消 Cancel
799 inspector.particleBaseMigration.conversionCanceled 转换已取消。已转换 {0}/{1} 个选中材质资源。 Conversion canceled. Converted {0}/{1} selected material asset(s).
800 inspector.particleBaseMigration.conversionComplete 转换完成。已转换 {0}/{1} 个选中材质资源。 Conversion complete. Converted {0}/{1} selected material asset(s).
801 inspector.particleBaseMigration.conversionFailures {0} 个失败项已记录到 Console。 {0} failure(s) were logged to the Console.
802 inspector.particleBaseMigration.match.shaderGuid Shader GUID Shader GUID
803 inspector.particleBaseMigration.match.shaderObject Shader 对象 Shader object
804 inspector.particleBaseMigration.match.shaderNameFallback Shader 名称回退 Shader name fallback
805 inspector.particleBaseMigration.undo 迁移 ParticleBase 材质到 NBShader2 Migrate ParticleBase Materials To NBShader2

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4463b85718cfaeb4cb989148b4548e0a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,339 @@
using System;
using System.IO;
using System.Text;
using NBShaderEditor;
using NBShaders2.Editor.FeatureLevel;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor
{
[InitializeOnLoad]
internal static class NBShaderDebugSymbolsSettingsProvider
{
internal const string DebugIncludeAssetPath = "Packages/com.xuanxuan.nb.fx/NBShaders2/Shader/HLSL/NBShaderDebugPragmas.hlsl";
private const string ShaderAssetPath = "Packages/com.xuanxuan.nb.fx/NBShaders2/Shader/NBShader.shader";
private const string PackageJsonAssetPath = "Packages/com.xuanxuan.nb.fx/package.json";
private const string PackageRootAssetPath = "Packages/com.xuanxuan.nb.fx/";
private static readonly Encoding Utf8NoBom = new UTF8Encoding(false);
private const string DisabledIncludeContent =
"// NBShader2 shader compiler debug switches.\n" +
"// This file is intentionally included with #include_with_pragmas.\n" +
"\n" +
"#undef NB_SHADER_DEBUG_SYMBOLS\n" +
"#define NB_SHADER_DEBUG_SYMBOLS 0\n";
private const string EnabledIncludeContent =
"// NBShader2 shader compiler debug switches.\n" +
"// This file is intentionally included with #include_with_pragmas.\n" +
"\n" +
"#undef NB_SHADER_DEBUG_SYMBOLS\n" +
"#define NB_SHADER_DEBUG_SYMBOLS 1\n" +
"#pragma enable_d3d11_debug_symbols\n";
private enum IncludeDebugState
{
Missing,
Disabled,
Enabled
}
static NBShaderDebugSymbolsSettingsProvider()
{
NBFXProjectSettings.RegisterSettingsSection(
"NBShaderDebugSymbols",
() => new GUIContent(Text("debugSymbols.providerLabel", "NBShader2 Debug Symbols")),
OnGUI,
new[]
{
"NBShader",
"Debug",
"Symbols",
"D3D11",
"enable_d3d11_debug_symbols"
},
90);
}
private static void OnGUI(string searchContext)
{
var settings = NBShaderFeatureLevelProjectSettings.instance;
settings.EnsureInitialized();
var includeState = GetIncludeDebugState();
var includeEnabled = includeState == IncludeDebugState.Enabled;
EditorGUILayout.HelpBox(
Text(
"debugSymbols.help.message",
"Controls NBShader2 shader compiler debug symbols by rewriting the package include used by NBShader.shader. Enable only while debugging external shader tools."),
MessageType.Info);
DrawCachingShaderPreprocessorState();
DrawStateRows(settings.enableDebugSymbols, includeState);
if (settings.enableDebugSymbols != includeEnabled || includeState == IncludeDebugState.Missing)
{
EditorGUILayout.HelpBox(
Text(
"debugSymbols.includeMismatch.message",
"The ProjectSettings value and package include content do not match. Apply the current setting to resync the shader compiler input."),
MessageType.Warning);
if (GUILayout.Button(ButtonContent("debugSymbols.applySetting", "Apply Current Setting To Include")))
ApplySettingToInclude(settings, settings.enableDebugSymbols);
}
var enabled = settings.enableDebugSymbols;
var toggleChanged = false;
using (new EditorGUILayout.HorizontalScope())
{
EditorGUI.BeginChangeCheck();
enabled = EditorGUILayout.Toggle(
Content(
"debugSymbols.enable",
"Enable NBShader2 Debug Symbols",
"Writes #pragma enable_d3d11_debug_symbols into the NBShader2 debug pragma include."),
settings.enableDebugSymbols);
toggleChanged = EditorGUI.EndChangeCheck();
if (GUILayout.Button(ButtonContent("debugSymbols.pingInclude", "Select Debug Toggle Include"), GUILayout.Width(180f)))
PingIncludeAsset();
}
if (toggleChanged)
{
if (!enabled || ConfirmEnableDebugSymbols())
ApplySettingToInclude(settings, enabled);
}
EditorGUILayout.HelpBox(
Text(
"debugSymbols.dirtyWarning.message",
"Enabling this option modifies NBShaderDebugPragmas.hlsl in the NB_FX package. Do not commit the enabled include unless shader debug symbols are deliberately required."),
MessageType.Warning);
}
internal static bool WriteDebugInclude(bool enabled, out string error)
{
error = null;
string physicalPath;
if (!TryGetPhysicalPath(DebugIncludeAssetPath, out physicalPath, out error))
return false;
var desiredContent = enabled ? EnabledIncludeContent : DisabledIncludeContent;
try
{
var folder = Path.GetDirectoryName(physicalPath);
if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
Directory.CreateDirectory(folder);
if (File.Exists(physicalPath) && string.Equals(File.ReadAllText(physicalPath), desiredContent, StringComparison.Ordinal))
{
ReimportShaderAssets();
return true;
}
File.WriteAllText(physicalPath, desiredContent, Utf8NoBom);
ReimportShaderAssets();
return true;
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
}
private static void DrawCachingShaderPreprocessorState()
{
var enabled = EditorSettings.cachingShaderPreprocessor;
EditorGUILayout.LabelField(
Content(
"debugSymbols.cachingPreprocessor",
"Caching Shader Preprocessor",
"#include_with_pragmas requires the Caching Shader Preprocessor."),
new GUIContent(enabled
? Text("debugSymbols.status.enabled", "Enabled")
: Text("debugSymbols.status.disabled", "Disabled")));
if (enabled)
return;
EditorGUILayout.HelpBox(
Text(
"debugSymbols.cachingPreprocessorWarning.message",
"#include_with_pragmas requires the Caching Shader Preprocessor. Enable it before using NBShader2 debug symbols."),
MessageType.Warning);
if (GUILayout.Button(ButtonContent("debugSymbols.enableCachingPreprocessor", "Enable Caching Shader Preprocessor")))
{
EditorSettings.cachingShaderPreprocessor = true;
ReimportShaderAssets();
}
}
private static void DrawStateRows(bool settingsEnabled, IncludeDebugState includeState)
{
EditorGUILayout.LabelField(
Content("debugSymbols.settingsState", "ProjectSettings State", "Saved state in ProjectSettings/NBShaderFeatureLevels.asset."),
new GUIContent(settingsEnabled
? Text("debugSymbols.status.enabled", "Enabled")
: Text("debugSymbols.status.disabled", "Disabled")));
EditorGUILayout.LabelField(
Content("debugSymbols.includeState", "Include File State", "Actual package include content used by NBShader.shader."),
new GUIContent(GetIncludeStateText(includeState)));
}
private static void ApplySettingToInclude(NBShaderFeatureLevelProjectSettings settings, bool enabled)
{
Undo.RecordObject(settings, Text("debugSymbols.undo.changeSetting", "Change NBShader2 Debug Symbols"));
string error;
if (WriteDebugInclude(enabled, out error))
{
if (settings.enableDebugSymbols != enabled)
{
settings.SetDebugSymbolsEnabled(enabled);
settings.SaveDebugSymbolsProjectSettings();
}
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
return;
}
EditorUtility.DisplayDialog(
Text("debugSymbols.applyFailed.title", "Apply NBShader2 Debug Symbols Failed"),
Text("debugSymbols.applyFailed.message", "Could not write NBShaderDebugPragmas.hlsl: ") + error,
Text("debugSymbols.dialog.ok", "OK"));
}
private static bool ConfirmEnableDebugSymbols()
{
return EditorUtility.DisplayDialog(
Text("debugSymbols.confirmEnable.title", "Enable NBShader2 Debug Symbols"),
Text(
"debugSymbols.confirmEnable.message",
"This writes #pragma enable_d3d11_debug_symbols into the NB_FX package include. Shader size can increase and optimizations are disabled while it is enabled."),
Text("debugSymbols.dialog.enable", "Enable"),
Text("debugSymbols.dialog.cancel", "Cancel"));
}
private static IncludeDebugState GetIncludeDebugState()
{
string physicalPath;
string error;
if (!TryGetPhysicalPath(DebugIncludeAssetPath, out physicalPath, out error) || !File.Exists(physicalPath))
return IncludeDebugState.Missing;
try
{
return ContainsActiveDebugPragma(File.ReadAllText(physicalPath))
? IncludeDebugState.Enabled
: IncludeDebugState.Disabled;
}
catch
{
return IncludeDebugState.Missing;
}
}
private static bool ContainsActiveDebugPragma(string content)
{
if (string.IsNullOrEmpty(content))
return false;
using (var reader = new StringReader(content))
{
string line;
while ((line = reader.ReadLine()) != null)
{
var trimmed = line.TrimStart();
if (trimmed.StartsWith("//", StringComparison.Ordinal))
continue;
if (trimmed.StartsWith("#pragma", StringComparison.Ordinal) &&
trimmed.IndexOf("enable_d3d11_debug_symbols", StringComparison.Ordinal) >= 0)
{
return true;
}
}
}
return false;
}
private static bool TryGetPhysicalPath(string assetPath, out string physicalPath, out string error)
{
physicalPath = null;
error = null;
var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(assetPath);
if (packageInfo == null)
packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(PackageJsonAssetPath);
if (packageInfo == null || string.IsNullOrEmpty(packageInfo.resolvedPath))
{
error = "Could not resolve package path for " + assetPath;
return false;
}
if (!assetPath.StartsWith(PackageRootAssetPath, StringComparison.Ordinal))
{
error = "Asset path is outside NB_FX package: " + assetPath;
return false;
}
var relativePath = assetPath.Substring(PackageRootAssetPath.Length).Replace('/', Path.DirectorySeparatorChar);
physicalPath = Path.Combine(packageInfo.resolvedPath, relativePath);
return true;
}
private static void ReimportShaderAssets()
{
AssetDatabase.ImportAsset(DebugIncludeAssetPath, ImportAssetOptions.ForceUpdate);
AssetDatabase.ImportAsset(ShaderAssetPath, ImportAssetOptions.ForceUpdate);
}
private static void PingIncludeAsset()
{
var asset = AssetDatabase.LoadMainAssetAtPath(DebugIncludeAssetPath);
if (asset == null)
return;
EditorGUIUtility.PingObject(asset);
Selection.activeObject = asset;
}
private static string GetIncludeStateText(IncludeDebugState state)
{
switch (state)
{
case IncludeDebugState.Enabled:
return Text("debugSymbols.status.enabled", "Enabled");
case IncludeDebugState.Disabled:
return Text("debugSymbols.status.disabled", "Disabled");
default:
return Text("debugSymbols.status.missing", "Missing");
}
}
private static GUIContent Content(string key, string fallback, string tip)
{
return NBShaderInspectorLocalization.MakeInspectorContent(key, fallback, tip);
}
private static GUIContent ButtonContent(string key, string fallback)
{
return NBShaderInspectorLocalization.MakeContent("inspector." + key + ".button", fallback);
}
private static string Text(string key, string fallback)
{
return NBShaderInspectorLocalization.GetInspectorText(key, fallback);
}
}
}

View File

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

View File

@@ -0,0 +1,138 @@
using UnityEditor;
using UnityEngine;
using NBShader;
namespace NBShaderEditor
{
public class NBShaderGUI : ShaderGUI
{
private NBShaderRootItem _rootItem;
private string _currentLanguage;
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
string currentLanguage = NBShaderInspectorLocalization.CurrentLanguage;
if (_rootItem == null || !string.Equals(_currentLanguage, currentLanguage, System.StringComparison.OrdinalIgnoreCase))
{
_rootItem = new NBShaderRootItem();
_currentLanguage = currentLanguage;
}
_rootItem.OnGUI(materialEditor, properties);
}
}
public class NBShaderRootItem : ShaderGUIRootItem
{
public NBShaderGUIContext Context { get; private set; }
public NBShaderSyncService SyncService { get; private set; }
private ModeBigBlockItem _modeBlock;
private BaseOptionBigBlockItem _baseBlock;
private MainTexBigBlockItem _mainTexBlock;
private LightBigBlockItem _lightBlock;
private FeatureBigBlockItem _featureBlock;
private TABigBlockItem _taBlock;
private ParticleVertexStreamsItem _particleVertexStreamsItem;
private NBShaderGUIToolBar _toolBar;
public override void InitFlags(System.Collections.Generic.List<Material> mats)
{
ShaderFlags = new System.Collections.Generic.List<ShaderFlagsBase>();
foreach (Material mat in mats)
{
ShaderFlags.Add(new NBShaderFlags(mat));
}
}
public override void OnChildOnGUI()
{
if (Context == null)
{
Context = new NBShaderGUIContext(this);
SyncService = new NBShaderSyncService(this);
}
Context.Refresh();
if (IsInit)
{
_toolBar = new NBShaderGUIToolBar(this);
_modeBlock = new ModeBigBlockItem(this, null);
_baseBlock = new BaseOptionBigBlockItem(this, null);
_mainTexBlock = new MainTexBigBlockItem(this, null);
_lightBlock = new LightBigBlockItem(this, null);
_featureBlock = new FeatureBigBlockItem(this, null);
_taBlock = new TABigBlockItem(this, null);
_particleVertexStreamsItem = new ParticleVertexStreamsItem(this, null);
}
bool syncMaterialState = IsInit;
EditorGUI.BeginChangeCheck();
_toolBar ??= new NBShaderGUIToolBar(this);
_toolBar.DrawToolbar();
_modeBlock.OnGUI();
_baseBlock.OnGUI();
_mainTexBlock.OnGUI();
if (Context.UIEffectEnabled == MixedBool.False)
{
_lightBlock.OnGUI();
}
_featureBlock.OnGUI();
_taBlock.OnGUI();
if (EditorGUI.EndChangeCheck())
{
syncMaterialState = true;
}
if (syncMaterialState)
{
SyncService.SyncMaterialState();
}
_particleVertexStreamsItem.OnGUI();
}
public void ExecuteResetAllItems()
{
_modeBlock?.ExecuteReset(true);
_baseBlock?.ExecuteReset(true);
_mainTexBlock?.ExecuteReset(true);
_lightBlock?.ExecuteReset(true);
_featureBlock?.ExecuteReset(true);
_taBlock?.ExecuteReset(true);
}
public System.Collections.Generic.IEnumerable<ShaderGUIItem> GetToolbarResetRootItems()
{
if (_baseBlock != null)
{
yield return _baseBlock;
}
if (_mainTexBlock != null)
{
yield return _mainTexBlock;
}
if (_lightBlock != null)
{
yield return _lightBlock;
}
if (_featureBlock != null)
{
yield return _featureBlock;
}
if (_taBlock != null)
{
yield return _taBlock;
}
}
}
}

View File

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

View File

@@ -0,0 +1,335 @@
# NBShaderGUI Rule
## Purpose
This rule defines the structure constraints for `NBShaders2/Editor/NBShaderGUI` and shared `ShaderGUIItems`.
## Core Principles
- Keep the GUI structure minimal and explicit.
- Do not add wrapper abstractions without a clear responsibility.
- `FoldOut` behavior and `parent-child composition` are two different concerns and must not be mixed.
- Common drawing items live in `XuanXuanRenderUtility/Editor/ShaderGUIItems`.
- Shared item names must not use the `NBShader` prefix.
## Shared Item Rules
All common material-property drawing items must live in `XuanXuanRenderUtility/Editor/ShaderGUIItems`, not in `NBShaders2/Editor/ShaderGUIItems`.
Use shared items for common material property drawing:
- `ToggleItem`
- `ColorItem`
- `TextureItem`
- `Vector2LineItem`
- `VectorComponentItem`
- `HelpBoxItem`
Vector-related shared item classes should stay in one `VectorItem.cs` file.
Do not create NBShader-prefixed wrappers for common drawing behavior. These names are not allowed for shared/general controls:
- `NBShaderTogglePropertyItem`
- `NBShaderColorPropertyItem`
- `NBShaderTexturePropertyItem`
- `NBShaderVector2LinePropertyItem`
- `NBShaderVectorComponentPropertyItem`
- `NBShaderHelpBoxItem`
Do not create wrappers that only set `PropertyName`, `GuiContent`, ranges, or visibility around an existing shared item. Prefer using the shared item directly, or create a concrete business item when there is real shader-specific behavior.
Pure configuration items should be instantiated directly inside the owning block constructor.
Use direct shared item construction for cases that only assign:
- `PropertyName`
- `GuiContent` or `GUIContent` provider
- `RangePropertyName`
- `Min` / `Max`
- simple visibility predicates
Example pattern:
```csharp
_alphaAllItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_AlphaAll",
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("base.alphaAll", "Overall Alpha"),
RangePropertyName = "AlphaAllRangeVec"
};
_alphaAllItem.InitTriggerByChild();
```
Do not create a named class for this pattern, such as `AlphaAllItem`, unless it adds real behavior.
A concrete item class is justified only when it owns shader-specific behavior, such as:
- overriding `OnGUI`, `DrawBlock`, `OnEndChange`, `CheckIsPropertyModified`, or `ExecuteReset`
- synchronizing keywords, render queue, blend state, pass state, runtime flags, or context
- implementing a reusable layout/control behavior that belongs in shared `ShaderGUIItems`
Current examples:
- `ZTestItem` is allowed because it forces UIEffect depth behavior.
- `AddToPreMultiplySlider` is allowed because its reset default depends on `BlendMode`.
- Popup items are allowed when they update `Context`, keywords, render state, or child visibility.
- `BaseColorIntensityItem`, `AlphaAllItem`, and `CutOffSlider` are not allowed as named wrappers because they only configure shared float/slider items.
Shared items must not reference:
- `NBShaderRootItem`
- `NBShaderInspectorLocalization`
- NBShader-specific keyword, pass, or flag logic
NBShader-specific labels should be passed into shared items through `GUIContent` providers from the call site.
## Localization Rules
NBShader Inspector user-facing text must go through `NBShaderInspectorLocalization`.
- Use CSV keys in `NBShaders2/Editor/Localization/NBShaderInspectorLocalization.csv`.
- CSV format is `key,zh-CN,en-US,zh-CN-tip,en-US-tip`.
- Tooltip text belongs to the same row as its label key. If a row has no tooltip, leave the tip columns empty.
- Legacy `.tip` rows are only compatibility fallback for existing non-label message reads. New label tooltips must not create a separate `.tip` key.
- Language selection is project-wide and stored by `NBFXProjectSettings` in `ProjectSettings/NB_FXSettings.asset`.
- Language selection is edited through Project Settings > Project > NB_FX, not through Unity menu items.
Fallback order:
- current language
- `zh-CN`
- code fallback
Key conventions:
- normal labels use `inspector.<block>.<feature>.<name>.label`
- label tooltips use the same key as the label and read the `<language>-tip` column
- standalone tooltip/help text that is not attached to a `GUIContent` should use `.message` or another explicit text key
- pure messages use `inspector.<block>.<feature>.<name>.message`
- buttons use `inspector.<block>.<feature>.<name>.button`
- popup options use `inspector.<block>.<feature>.<name>.option.<index>`
Code conventions:
- Normal controls should call `NBShaderInspectorLocalization.MakeInspectorContent(key, fallback, tip)` or pass a provider that calls it. The helper reads the label from `inspector.<key>.label` and the tooltip from the same CSV row first.
- HelpBox/message strings should call `NBShaderInspectorLocalization.GetInspectorText(key, fallback)`.
- Popup options should call `NBShaderInspectorLocalization.GetInspectorOptions(key, fallbackArray)` or update `PopUpNames` from an options provider.
- Shared `XuanXuanRenderUtility/Editor/ShaderGUIItems` must not reference `NBShaderInspectorLocalization`.
- Shared items that draw visible labels should expose `GUIContent` providers; NBShader call sites provide localized content.
- Technical identifiers stay untranslated unless they are deliberately shown as UI copy: shader property names, keyword names, pass names, enum protocol values, render queue numbers, and stencil config keys remain stable.
## NBShaders2 Item Rules
`NBShaders2/Editor/ShaderGUIItems` should only contain NBShader business structure:
- top-level blocks
- secondary business blocks
- shader-specific popup items with side effects
- composite layout items such as the main texture layout
- feature-specific items that synchronize NBShader keywords, pass state, or runtime flags
NBShader-specific item names are acceptable only when the item has NBShader business meaning. They must not be used for generic drawing controls.
## Inheritance Rules
### 1. `ShaderGUIItem`
`ShaderGUIItem` is the base class for normal GUI items.
Use it for:
- leaf controls
- composite layout items
- parent-child grouping items without foldout
- texture layout parent items
Important:
- parent-child composition already belongs to `ShaderGUIItem`
- do not introduce extra “control base class” layers just to express parent-child grouping
### 2. `BlockItem`
`BlockItem` exists only to provide `FoldOut` behavior.
Responsibilities:
- owns `FoldOutPropertyName`
- owns foldout open/close lifecycle
- draws foldout title row
- draws children inside foldout content area
It must not be used for:
- non-foldout layout items
- generic feature/control wrappers
### 3. `BigBlockItem`
`BigBlockItem` inherits from `BlockItem`.
Responsibilities:
- defines the visual style of top-level blocks
- bold title
- spacing
- separator line
`BigBlockItem` is a style specialization of `BlockItem`, not a different composition system.
## Top-Level Block Rules
These top-level sections should inherit `BigBlockItem`:
- `ModeBigBlockItem`
- `BaseOptionBigBlockItem`
- `MainTexBigBlockItem`
- `LightBigBlockItem`
- `FeatureBigBlockItem`
- `TABigBlockItem`
These are first-level inspector sections and should use persisted foldout state.
## Secondary Block Rules
Only use `BlockItem` for a secondary section when:
- it has its own foldout state
- it is semantically a collapsible section
- it contains a group of child items
If a section is only doing layout and grouping, it must stay on `ShaderGUIItem`.
## Layout Rules
All normal inspector row layout must be owned by `ShaderGUIItem`.
Do not calculate label/control/reset positions independently in leaf items. Use the base rect pipeline:
- `GetRect()`
- `ApplyGlobalRectCompensation()`
- `SplitLineRect()`
- `SplitControlAndResetRect()`
Standard row responsibilities:
- `BaseRect` is the compensated full row rect.
- `LabelRect` uses `GetLabelWidth(BaseRect)`.
- `GetLabelWidth()` has a fixed minimum (`MinLabelWidth`) and then grows by `LabelWidthRatio` once the inspector row is wide enough.
- Do not read or hardcode a fixed label width in business items. If a custom layout needs the normal label/control split, call `SplitLineRect()`.
- `ControlRect` starts after `LabelRect` and reserves reset space.
- `ResetRect` is fixed to the right side and uses `ResetButtonSize`.
- `ControlResetGap` is the only standard gap between control and reset.
Do not add local magic numbers for reset width, reset gap, or standard control expansion in business items. If a layout constant is needed by more than one item, add it to `ShaderGUIItem`.
Global row compensation:
- `GlobalRectXOffset` shifts the whole row left/right.
- `GlobalRectWidthExpansion` expands the whole row width.
- These constants compensate meaningless inspector-side margin and must be applied at the rect entry point, before splitting label/control/reset.
Any item that calls `EditorGUILayout.GetControlRect()` directly must immediately pass the result through `ApplyGlobalRectCompensation()`, unless there is a specific documented reason not to.
Editor indent rules:
- `EditorGUI.indentLevel` is only a hierarchy level counter.
- Do not introduce a separate per-block indent-count constant.
- Unity's internal per-level indent width is represented by `UnityEditorGUIIndentWidth`.
- The desired NBShader GUI visual indent width is represented by `EditorGUIIndentWidth`.
- `ApplyLabelIndentWidth()` converts Unity's built-in `EditorGUI.LabelField` indent width into the desired visual indent width for the NBShader GUI rect system.
- Direct `GUI.Label`, `GUI.Toggle`, texture preview rects, and other non-`EditorGUI.LabelField` labels do not get Unity's built-in label indent. Use `ApplyDirectLabelIndentWidth()` for their label start.
- Foldout arrows must be positioned from the final visual label text x, not from `BaseRect.x`. Use `ShaderGUIFoldOutHelper` / `GetEditorLabelTextX()` and do not call `EditorGUI.Foldout()` directly in business items.
- Do not hardcode a local texture or foldout indent width. Three-line texture groups must use `ApplyDirectLabelIndentWidth()` for the texture preview left edge and `SplitLineRect()` for Tilling/Offset control/reset positions.
Control indent compensation:
- `ControlIndentCompensation` is not the same thing as row indent.
- It only adjusts `ControlRect` by moving `x` left and increasing `width`.
- Use it only to compensate controls whose Unity internal drawing is shifted right inside the passed rect.
- Do not apply it to controls that draw exactly inside the passed rect, such as single-line `ColorField`; call `GetRect(false)` or `SplitLineRect(..., false)` for those rows.
- `EditorGUI.ColorField` draws the visible swatch through `EditorStyles.colorField.padding.Remove(position)`. Labeled color rows may compensate this padding inside `ColorItem`; no-label color rows keep their own local inset. Do not add Color-only constants to `ShaderGUIItem`.
- Keep `LabelRect` and `ResetRect` independent from this compensation.
- Composite layouts may disable it with `applyControlIndentCompensation: false` and then apply a local compensation only to the actual control rect when needed.
Full-width or no-label rows:
- Rows such as full-width color bars should not automatically use label/control semantics.
- If a row has no label, call `SplitControlAndResetRect()` directly and disable control compensation when the row must preserve its left edge.
- Reset alignment should still come from `SplitControlAndResetRect()`.
Texture rows:
- All texture object inputs should use the shared three-row texture layout (`TexturePropertyGroupItem` through `TextureItem`) instead of `MaterialEditor.TexturePropertySingleLine()`.
- Texture rows without editable Tilling/Offset should still reserve the three-row texture object area and leave the Tilling/Offset rows empty.
- Texture color rows remain separate no-label color rows after the three-row texture object group.
## Animated Property Rules
Animated property highlight must follow Unity's native material inspector behavior.
Do not manually set animated controls to a fixed color such as `Color.red`.
Use the shared `ShaderGUIItem` animated scope helpers:
- `BeginAnimatedPropertyBackground(Rect totalPosition, MaterialProperty property)`
- `EndAnimatedPropertyBackground(bool scopeActive)`
These helpers must use `MaterialEditor.BeginAnimatedCheck()` and `MaterialEditor.EndAnimatedCheck()`. They must not implement their own color decision with `AnimationMode.IsPropertyAnimated()`.
Reason:
- Unity's original `MaterialEditor.ShaderProperty()` wraps controls with `BeginAnimatedCheck()` / `EndAnimatedCheck()`.
- Unity chooses between animated, recorded, and candidate colors internally.
- Unity restores the previous `GUI.backgroundColor` through a stack, so nested drawing does not leak color state.
Standard item rule:
- Normal leaf items that use `ShaderGUIItem.OnGUI()` should rely on the base animated scope around `DrawController()`.
Custom `OnGUI()` rule:
- If an item overrides `OnGUI()` or draws multiple independent controls manually, it must explicitly wrap each actual editable control with the correct `MaterialProperty`.
- Do not wrap a composite row with one property if the row contains controls backed by different properties.
- Always call `EndAnimatedPropertyBackground()` in the same draw path after the control is drawn.
Multi-property control rule:
- `ShaderGUISliderItem` with `RangePropertyName` must wrap the min/max fields with the range vector property and the slider with the main float property.
- Texture scale/offset controls must wrap their `Vector2Field` controls with the texture property when editing `textureScaleAndOffset`, or with the vector property when editing a vector ST property.
Animation refresh rule:
- `ShaderGUIRootItem` must update incoming `MaterialProperty[]` into `PropertyInfoDic` every `OnGUI`.
- In animation mode, the material inspector should repaint so animated values and highlight state refresh while scrubbing or recording.
- Do not cache animated-state booleans. Caching property path strings is allowed for diagnostics or non-background queries.
## Texture GUI Rules
For texture-related GUI:
- the texture layout parent item should inherit `ShaderGUIItem`
- it is a layout/composition item, not a `BlockItem`
- texture object field, texture color, and texture `Tilling/Offset` are separate GUI items
- the parent texture layout item is responsible only for arranging these child items
- texture layout must not move label text as a side effect of control compensation
- for `Tilling/Offset`, calculate label rects from the uncompensated vector rect first, then apply control compensation only to the `Vector2Field` rect if visual control alignment requires it
- texture, texture label, texture color, `Tilling/Offset`, and reset buttons must still use shared `ShaderGUIItem` layout constants where applicable
- texture ST animated highlight must use Unity's texture `MaterialProperty` animated check, not manual `_ST.x/y/z/w` color logic
Required structure:
- texture parent layout item
- texture object field item
- texture color item
- texture `Tilling/Offset` item
## Anti-Rules
Do not introduce these kinds of abstractions again unless there is a concrete need:
- generic `ControlItem` base classes with no real behavior
- generic `FeatureItem` base classes with no real semantics
- wrapper layers that only rename existing base classes
If an abstraction does not define a stable responsibility boundary, do not keep it.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0faa7bb86fa23764794c77e95761379e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,691 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using NBShaderEditor;
using UnityEditor;
using UnityEngine;
namespace NBShaders2.Editor
{
[InitializeOnLoad]
internal static class ParticleBaseMigrationSettingsProvider
{
static ParticleBaseMigrationSettingsProvider()
{
NBFXProjectSettings.RegisterSettingsSection(
"ParticleBaseMigration",
() => new GUIContent(Text("particleBaseMigration.providerLabel", "ParticleBase Migration")),
OnGUI,
new[]
{
"ParticleBase",
"NBShader2",
"Migration",
"Material",
"Shader GUID"
},
95);
}
private static void OnGUI(string searchContext)
{
EditorGUILayout.HelpBox(
Text(
"particleBaseMigration.settingsHelp",
"Scan material assets that reference the legacy ParticleBase shader GUID and migrate them to NBShader2 after confirmation. Back up assets or commit to version control before converting."),
MessageType.Warning);
if (GUILayout.Button(ButtonContent("particleBaseMigration.openWindow", "Open ParticleBase Migration Window")))
{
ParticleBaseMigrationWindow.Open();
}
}
private static GUIContent ButtonContent(string key, string fallback)
{
return NBShaderInspectorLocalization.MakeContent("inspector." + key + ".button", fallback);
}
private static string Text(string key, string fallback)
{
return NBShaderInspectorLocalization.GetInspectorText(key, fallback);
}
}
internal sealed class ParticleBaseMigrationWindow : EditorWindow
{
private const string LegacyShaderGuidFallback = "7184a95c20fc1a441a8815af4c795ccd";
private const string NBShader2Guid = "7787bfdacec31472ca6644d6e3616bd4";
private const string LegacyShaderAssetPath = "Packages/com.xuanxuan.nb.fx/NBShaders/Shader/ParticleBase.shader";
private const string NBShader2AssetPath = "Packages/com.xuanxuan.nb.fx/NBShaders2/Shader/NBShader.shader";
private const string LegacyShaderName = "Effects/NBShader(Legacy)";
private const string UndoNameFallback = "Migrate ParticleBase Materials To NBShader2";
private static readonly string[] LegacyFoldoutProperties =
{
"_W9ParticleShaderGUIFoldToggle",
"_W9ParticleShaderGUIFoldToggle1",
"_W9ParticleShaderGUIFoldToggle2"
};
private static readonly string[] NBShader2FoldoutProperties =
{
"_NBShaderGUIFoldToggle",
"_NBShaderGUIFoldToggle1",
"_NBShaderGUIFoldToggle2"
};
private readonly List<MaterialMigrationEntry> _entries = new List<MaterialMigrationEntry>();
private Vector2 _scrollPosition;
private bool _scanned;
private string _statusMessage;
public static void Open()
{
var window = GetWindow<ParticleBaseMigrationWindow>(Text("particleBaseMigration.windowTitle", "ParticleBase Migration"));
window.minSize = new Vector2(760f, 420f);
window.Show();
}
private void OnGUI()
{
titleContent = new GUIContent(Text("particleBaseMigration.windowTitle", "ParticleBase Migration"));
EditorGUILayout.LabelField(Text("particleBaseMigration.title", "ParticleBase -> NBShader2"), EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
Text(
"particleBaseMigration.windowWarning",
"This operation changes material shader assignments and synchronized material state. Back up assets or commit to version control before converting. The tool does not provide an automatic rollback."),
MessageType.Warning);
DrawToolbar();
DrawStatus();
DrawMaterialList();
DrawConvertButton();
}
private void DrawToolbar()
{
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(ButtonContent("particleBaseMigration.scan", "Scan ParticleBase Materials"), GUILayout.Height(24f)))
{
ScanMaterials();
}
EditorGUI.BeginDisabledGroup(_entries.Count == 0);
if (GUILayout.Button(ButtonContent("particleBaseMigration.selectAll", "Select All"), GUILayout.Width(96f), GUILayout.Height(24f)))
{
SetAllSelected(true);
}
if (GUILayout.Button(ButtonContent("particleBaseMigration.selectNone", "Select None"), GUILayout.Width(96f), GUILayout.Height(24f)))
{
SetAllSelected(false);
}
EditorGUI.EndDisabledGroup();
}
}
private void DrawStatus()
{
if (!string.IsNullOrEmpty(_statusMessage))
{
EditorGUILayout.HelpBox(_statusMessage, MessageType.Info);
}
else if (!_scanned)
{
EditorGUILayout.HelpBox(
Text(
"particleBaseMigration.scanPrompt",
"Click Scan to find .mat assets that reference the ParticleBase shader asset GUID. Shader name is only used as a fallback."),
MessageType.Info);
}
else if (_entries.Count == 0)
{
EditorGUILayout.HelpBox(
Text("particleBaseMigration.noMaterials", "No ParticleBase material assets were found."),
MessageType.Info);
}
}
private void DrawMaterialList()
{
if (_entries.Count == 0)
{
return;
}
EditorGUILayout.Space();
EditorGUILayout.LabelField(
FormatText("particleBaseMigration.listSummary", "Found {0} material asset(s). Selected: {1}", _entries.Count, CountSelected()),
EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
GUILayout.Label("", GUILayout.Width(24f));
GUILayout.Label(Text("particleBaseMigration.column.material", "Material"), GUILayout.Width(240f));
GUILayout.Label(Text("particleBaseMigration.column.match", "Match"), GUILayout.Width(160f));
GUILayout.Label(Text("particleBaseMigration.column.path", "Path"), GUILayout.MinWidth(260f));
}
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
for (int i = 0; i < _entries.Count; i++)
{
DrawMaterialRow(_entries[i]);
}
EditorGUILayout.EndScrollView();
}
private static void DrawMaterialRow(MaterialMigrationEntry entry)
{
using (new EditorGUILayout.HorizontalScope())
{
entry.selected = EditorGUILayout.Toggle(entry.selected, GUILayout.Width(24f));
EditorGUILayout.ObjectField(entry.material, typeof(Material), false, GUILayout.Width(240f));
GUILayout.Label(entry.matchSource, EditorStyles.miniLabel, GUILayout.Width(160f));
if (GUILayout.Button(ButtonContent("particleBaseMigration.ping", "Ping"), GUILayout.Width(48f)))
{
PingAsset(entry.assetPath);
}
EditorGUILayout.SelectableLabel(
entry.assetPath,
EditorStyles.miniLabel,
GUILayout.Height(EditorGUIUtility.singleLineHeight),
GUILayout.MinWidth(220f));
}
}
private void DrawConvertButton()
{
EditorGUILayout.Space();
EditorGUI.BeginDisabledGroup(CountSelected() == 0);
if (GUILayout.Button(ButtonContent("particleBaseMigration.convertSelected", "Convert Selected Materials To NBShader2"), GUILayout.Height(30f)))
{
ConvertSelectedMaterials();
}
EditorGUI.EndDisabledGroup();
}
private void ScanMaterials()
{
_entries.Clear();
_scanned = true;
_statusMessage = null;
string legacyShaderGuid = ResolveShaderGuid(LegacyShaderAssetPath, LegacyShaderGuidFallback);
Shader legacyShader = LoadShaderByGuidOrPath(legacyShaderGuid, LegacyShaderAssetPath);
string[] materialGuids = AssetDatabase.FindAssets("t:Material");
var seenPaths = new HashSet<string>(StringComparer.Ordinal);
bool canceled = false;
try
{
for (int i = 0; i < materialGuids.Length; i++)
{
if (EditorUtility.DisplayCancelableProgressBar(
Text("particleBaseMigration.windowTitle", "ParticleBase Migration"),
FormatText("particleBaseMigration.progress.scanning", "Scanning materials {0}/{1}", i + 1, materialGuids.Length),
materialGuids.Length > 0 ? (float)i / materialGuids.Length : 1f))
{
canceled = true;
break;
}
string path = AssetDatabase.GUIDToAssetPath(materialGuids[i]);
if (string.IsNullOrEmpty(path) ||
!path.EndsWith(".mat", StringComparison.OrdinalIgnoreCase) ||
!seenPaths.Add(path))
{
continue;
}
Material material = AssetDatabase.LoadAssetAtPath<Material>(path);
string matchSource;
if (!IsLegacyParticleBaseMaterial(path, material, legacyShaderGuid, legacyShader, out matchSource))
{
continue;
}
_entries.Add(new MaterialMigrationEntry
{
assetPath = path,
material = material,
selected = true,
matchSource = matchSource
});
}
}
finally
{
EditorUtility.ClearProgressBar();
}
_entries.Sort((a, b) => string.CompareOrdinal(a.assetPath, b.assetPath));
_statusMessage = canceled
? FormatText("particleBaseMigration.scanCanceled", "Scan canceled. Found {0} material asset(s) before canceling.", _entries.Count)
: FormatText("particleBaseMigration.scanComplete", "Scan complete. Found {0} ParticleBase material asset(s).", _entries.Count);
}
private void ConvertSelectedMaterials()
{
List<MaterialMigrationEntry> selectedEntries = GetSelectedEntries();
if (selectedEntries.Count == 0)
{
return;
}
Shader targetShader = LoadShaderByGuidOrPath(NBShader2Guid, NBShader2AssetPath);
if (targetShader == null)
{
EditorUtility.DisplayDialog(
Text("particleBaseMigration.nbShader2Missing.title", "NBShader2 Missing"),
Text("particleBaseMigration.nbShader2Missing.message", "Could not load NBShader2 shader asset. Migration cannot continue."),
Text("particleBaseMigration.dialog.ok", "OK"));
return;
}
if (!ConfirmConversion(selectedEntries.Count))
{
return;
}
string legacyShaderGuid = ResolveShaderGuid(LegacyShaderAssetPath, LegacyShaderGuidFallback);
Shader legacyShader = LoadShaderByGuidOrPath(legacyShaderGuid, LegacyShaderAssetPath);
int convertedCount = 0;
bool canceled = false;
var failures = new List<string>();
int undoGroup = Undo.GetCurrentGroup();
bool assetEditingStarted = false;
string undoName = Text("particleBaseMigration.undo", UndoNameFallback);
Undo.SetCurrentGroupName(undoName);
try
{
AssetDatabase.StartAssetEditing();
assetEditingStarted = true;
for (int i = 0; i < selectedEntries.Count; i++)
{
MaterialMigrationEntry entry = selectedEntries[i];
if (EditorUtility.DisplayCancelableProgressBar(
Text("particleBaseMigration.windowTitle", "ParticleBase Migration"),
FormatText("particleBaseMigration.progress.converting", "Converting {0}/{1}: {2}", i + 1, selectedEntries.Count, entry.assetPath),
selectedEntries.Count > 0 ? (float)i / selectedEntries.Count : 1f))
{
canceled = true;
break;
}
if (ConvertMaterialEntry(entry, targetShader, legacyShaderGuid, legacyShader, undoName, failures))
{
convertedCount++;
}
}
}
finally
{
if (assetEditingStarted)
{
AssetDatabase.StopAssetEditing();
}
EditorUtility.ClearProgressBar();
Undo.CollapseUndoOperations(undoGroup);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
if (failures.Count > 0)
{
Debug.LogWarning(
Text("particleBaseMigration.failuresLogged", "ParticleBase migration completed with failures:") +
"\n" +
string.Join("\n", failures.ToArray()));
}
_statusMessage = BuildConversionStatus(convertedCount, selectedEntries.Count, canceled, failures.Count);
}
private static bool ConvertMaterialEntry(
MaterialMigrationEntry entry,
Shader targetShader,
string legacyShaderGuid,
Shader legacyShader,
string undoName,
List<string> failures)
{
try
{
Material material = AssetDatabase.LoadAssetAtPath<Material>(entry.assetPath);
if (material == null)
{
failures.Add(FormatText("particleBaseMigration.failure.loadMaterial", "{0}: material could not be loaded.", entry.assetPath));
return false;
}
string matchSource;
if (!IsLegacyParticleBaseMaterial(entry.assetPath, material, legacyShaderGuid, legacyShader, out matchSource))
{
failures.Add(FormatText("particleBaseMigration.failure.noLongerParticleBase", "{0}: skipped because it no longer references ParticleBase.", entry.assetPath));
return false;
}
int[] legacyFoldoutValues = CaptureLegacyFoldoutValues(material, entry.assetPath);
Undo.RecordObject(material, undoName);
material.shader = targetShader;
ApplyNBShader2FoldoutValues(material, legacyFoldoutValues);
NBShaderSyncService.SyncMaterialState(material);
EditorUtility.SetDirty(material);
AssetDatabase.SaveAssetIfDirty(material);
entry.material = material;
entry.matchSource = Text("particleBaseMigration.match.converted", "Converted");
entry.selected = false;
return true;
}
catch (Exception ex)
{
failures.Add(FormatText("particleBaseMigration.failure.exception", "{0}: {1}", entry.assetPath, ex.Message));
return false;
}
}
private static bool ConfirmConversion(int count)
{
return EditorUtility.DisplayDialog(
Text("particleBaseMigration.confirm.title", "Confirm ParticleBase Migration"),
FormatText(
"particleBaseMigration.confirm.message",
"You are about to convert {0} material asset(s) from ParticleBase to NBShader2.\n\nBack up assets or commit to version control before continuing. This tool does not provide an automatic rollback.",
count),
Text("particleBaseMigration.dialog.convert", "Convert"),
Text("particleBaseMigration.dialog.cancel", "Cancel"));
}
private static string BuildConversionStatus(int converted, int selected, bool canceled, int failureCount)
{
string status = canceled
? FormatText("particleBaseMigration.conversionCanceled", "Conversion canceled. Converted {0}/{1} selected material asset(s).", converted, selected)
: FormatText("particleBaseMigration.conversionComplete", "Conversion complete. Converted {0}/{1} selected material asset(s).", converted, selected);
if (failureCount > 0)
{
status += " " + FormatText("particleBaseMigration.conversionFailures", "{0} failure(s) were logged to the Console.", failureCount);
}
return status;
}
private static int[] CaptureLegacyFoldoutValues(Material material, string assetPath)
{
var values = new int[LegacyFoldoutProperties.Length];
for (int i = 0; i < LegacyFoldoutProperties.Length; i++)
{
values[i] = int.MinValue;
if (material != null && material.HasProperty(LegacyFoldoutProperties[i]))
{
values[i] = material.GetInteger(LegacyFoldoutProperties[i]);
continue;
}
int serializedValue;
if (TryReadSerializedIntegerProperty(assetPath, LegacyFoldoutProperties[i], out serializedValue))
{
values[i] = serializedValue;
}
}
return values;
}
private static void ApplyNBShader2FoldoutValues(Material material, int[] legacyValues)
{
if (material == null || legacyValues == null)
{
return;
}
int count = Math.Min(legacyValues.Length, NBShader2FoldoutProperties.Length);
for (int i = 0; i < count; i++)
{
if (legacyValues[i] == int.MinValue || !material.HasProperty(NBShader2FoldoutProperties[i]))
{
continue;
}
material.SetInteger(NBShader2FoldoutProperties[i], legacyValues[i]);
}
}
private static bool IsLegacyParticleBaseMaterial(
string assetPath,
Material material,
string legacyShaderGuid,
Shader legacyShader,
out string matchSource)
{
if (SerializedMaterialReferencesShaderGuid(assetPath, legacyShaderGuid))
{
matchSource = Text("particleBaseMigration.match.shaderGuid", "Shader GUID");
return true;
}
if (material != null && material.shader != null)
{
if (legacyShader != null && material.shader == legacyShader)
{
matchSource = Text("particleBaseMigration.match.shaderObject", "Shader object");
return true;
}
if (string.Equals(material.shader.name, LegacyShaderName, StringComparison.Ordinal))
{
matchSource = Text("particleBaseMigration.match.shaderNameFallback", "Shader name fallback");
return true;
}
}
matchSource = null;
return false;
}
private static bool SerializedMaterialReferencesShaderGuid(string assetPath, string shaderGuid)
{
if (string.IsNullOrEmpty(assetPath) || string.IsNullOrEmpty(shaderGuid))
{
return false;
}
string physicalPath;
if (!TryGetPhysicalPath(assetPath, out physicalPath) || !File.Exists(physicalPath))
{
return false;
}
try
{
string content = File.ReadAllText(physicalPath);
return content.IndexOf("m_Shader:", StringComparison.Ordinal) >= 0 &&
content.IndexOf("guid: " + shaderGuid, StringComparison.OrdinalIgnoreCase) >= 0;
}
catch
{
return false;
}
}
private static bool TryReadSerializedIntegerProperty(string assetPath, string propertyName, out int value)
{
value = 0;
if (string.IsNullOrEmpty(assetPath) || string.IsNullOrEmpty(propertyName))
{
return false;
}
string physicalPath;
if (!TryGetPhysicalPath(assetPath, out physicalPath) || !File.Exists(physicalPath))
{
return false;
}
try
{
string prefix = "- " + propertyName + ":";
using (var reader = new StringReader(File.ReadAllText(physicalPath)))
{
string line;
while ((line = reader.ReadLine()) != null)
{
string trimmed = line.Trim();
if (!trimmed.StartsWith(prefix, StringComparison.Ordinal))
{
continue;
}
string rawValue = trimmed.Substring(prefix.Length).Trim();
return int.TryParse(rawValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value);
}
}
}
catch
{
return false;
}
return false;
}
private static bool TryGetPhysicalPath(string assetPath, out string physicalPath)
{
physicalPath = null;
if (string.IsNullOrEmpty(assetPath))
{
return false;
}
string normalizedPath = assetPath.Replace('\\', '/');
if (normalizedPath.StartsWith("Assets/", StringComparison.Ordinal) ||
string.Equals(normalizedPath, "Assets", StringComparison.Ordinal))
{
string projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
physicalPath = Path.Combine(projectRoot, normalizedPath.Replace('/', Path.DirectorySeparatorChar));
return true;
}
if (!normalizedPath.StartsWith("Packages/", StringComparison.Ordinal))
{
return false;
}
var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(normalizedPath);
if (packageInfo == null || string.IsNullOrEmpty(packageInfo.resolvedPath))
{
return false;
}
string packageRoot = "Packages/" + packageInfo.name + "/";
if (!normalizedPath.StartsWith(packageRoot, StringComparison.Ordinal))
{
return false;
}
string relativePath = normalizedPath.Substring(packageRoot.Length).Replace('/', Path.DirectorySeparatorChar);
physicalPath = Path.Combine(packageInfo.resolvedPath, relativePath);
return true;
}
private static string ResolveShaderGuid(string assetPath, string fallbackGuid)
{
string guid = AssetDatabase.AssetPathToGUID(assetPath);
return string.IsNullOrEmpty(guid) ? fallbackGuid : guid;
}
private static Shader LoadShaderByGuidOrPath(string guid, string fallbackAssetPath)
{
string assetPath = string.IsNullOrEmpty(guid) ? null : AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty(assetPath))
{
assetPath = fallbackAssetPath;
}
return AssetDatabase.LoadAssetAtPath<Shader>(assetPath);
}
private void SetAllSelected(bool selected)
{
for (int i = 0; i < _entries.Count; i++)
{
_entries[i].selected = selected;
}
}
private int CountSelected()
{
int count = 0;
for (int i = 0; i < _entries.Count; i++)
{
if (_entries[i].selected)
{
count++;
}
}
return count;
}
private List<MaterialMigrationEntry> GetSelectedEntries()
{
var selectedEntries = new List<MaterialMigrationEntry>();
for (int i = 0; i < _entries.Count; i++)
{
if (_entries[i].selected)
{
selectedEntries.Add(_entries[i]);
}
}
return selectedEntries;
}
private static void PingAsset(string assetPath)
{
UnityEngine.Object asset = AssetDatabase.LoadMainAssetAtPath(assetPath);
if (asset == null)
{
return;
}
Selection.activeObject = asset;
EditorGUIUtility.PingObject(asset);
}
private static GUIContent ButtonContent(string key, string fallback)
{
return NBShaderInspectorLocalization.MakeContent("inspector." + key + ".button", fallback);
}
private static string Text(string key, string fallback)
{
return NBShaderInspectorLocalization.GetInspectorText(key, fallback);
}
private static string FormatText(string key, string fallback, params object[] args)
{
return string.Format(Text(key, fallback), args);
}
private sealed class MaterialMigrationEntry
{
public string assetPath;
public Material material;
public string matchSource;
public bool selected;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,450 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using NBShader;
namespace NBShaderEditor
{
public enum RenderFace
{
Front = 2,
Back = 1,
Both = 0
}
public enum ForceZWriteMode
{
Default = 0,
ForceOn = 1,
ForceOff = 2
}
public class BaseOptionBigBlockItem : BigBlockItem
{
private readonly NBShaderRootItem _nbRootItem;
private readonly ShaderGUIFloatItem _baseColorIntensityItem;
private readonly ShaderGUISliderItem _alphaAllItem;
private readonly BlockItem _colorAdjustmentBlock;
private readonly ToggleItem _colorAdjustmentOnlyMainTexItem;
private readonly PropertyToggleBlockItem _hueShiftBlock;
private readonly ShaderGUISliderItem _hueShiftSlider;
private readonly CustomDataSelectItem _hueShiftCustomDataItem;
private readonly PropertyToggleBlockItem _saturabilityBlock;
private readonly ShaderGUISliderItem _saturabilitySlider;
private readonly CustomDataSelectItem _saturabilityCustomDataItem;
private readonly PropertyToggleBlockItem _contrastBlock;
private readonly ColorItem _contrastMidColorItem;
private readonly ShaderGUISliderItem _contrastSlider;
private readonly CustomDataSelectItem _contrastCustomDataItem;
private readonly PropertyToggleBlockItem _baseMapColorRefineBlock;
private readonly VectorComponentItem _baseMapColorRefineA;
private readonly VectorComponentItem _baseMapColorRefineBPower;
private readonly VectorComponentItem _baseMapColorRefineBMultiply;
private readonly VectorComponentItem _baseMapColorRefineLerp;
private readonly ToggleItem _colorMultiAlphaItem;
private readonly ZTestItem _zTestItem;
private readonly CullModeItem _cullItem;
private readonly ToggleItem _backFirstPassItem;
private readonly ForceZWriteItem _forceZWriteItem;
private readonly ToggleItem _affectsShadowsItem;
private readonly ToggleItem _transparentShadowDitherItem;
private readonly PropertyToggleBlockItem _baseBackColorBlock;
private readonly ColorItem _baseBackColorItem;
private readonly PropertyToggleBlockItem _distanceFadeBlock;
private readonly Vector2LineItem _fadeRangeItem;
private readonly PropertyToggleBlockItem _softParticlesBlock;
private readonly Vector2LineItem _softParticleFadeItem;
private readonly ToggleItem _stencilWithoutPlayerItem;
private readonly ToggleItem _ignoreVertexColorItem;
private readonly ShaderGUISliderItem _fogIntensityItem;
public BaseOptionBigBlockItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem) :
base(
rootItem,
parentItem,
"_BaseOptionBigBlockItemFoldOut",
() => Content("block.base", "Base Options", "Global controls"))
{
_nbRootItem = rootItem;
_baseColorIntensityItem = new ShaderGUIFloatItem(rootItem, this)
{
PropertyName = "_BaseColorIntensityForTimeline",
GuiContent = Content("base.colorIntensity", "Base Color Intensity")
};
_baseColorIntensityItem.InitTriggerByChild();
_alphaAllItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_AlphaAll",
GuiContent = Content("base.alphaAll", "Overall Alpha"),
RangePropertyName = "AlphaAllRangeVec"
};
_alphaAllItem.InitTriggerByChild();
_colorAdjustmentBlock = new BlockItem(
rootItem,
this,
"_BaseColorAdjustmentFoldOut",
() => Content("base.colorAdjustment", "Color Adjustment"));
_colorAdjustmentOnlyMainTexItem = new ToggleItem(
rootItem,
_colorAdjustmentBlock,
"_ColorAdjustmentOnlyAffectMainTex",
() => Content("base.colorAdjustment.onlyMainTex", "Only Affect Main Texture"),
enabled => rootItem.SyncService.ApplyToggleFlag(
NBShaderFlags.FLAG_BIT_PARTICLE_COLOR_ADJUSTMENT_ONLY_AFFECT_MAINTEX,
enabled));
_hueShiftBlock = new PropertyToggleBlockItem(
rootItem,
_colorAdjustmentBlock,
"_HueShiftFoldOut",
"_HueShift_Toggle",
() => Content("base.hueShift", "Hue Shift"),
NBShaderFlags.FLAG_BIT_HUESHIFT_ON);
_hueShiftSlider = new ShaderGUISliderItem(rootItem, _hueShiftBlock)
{
PropertyName = "_HueShift",
GuiContent = Content("base.hueShift.value", "Hue"),
Min = 0f,
Max = 1f
};
_hueShiftSlider.InitTriggerByChild();
_hueShiftCustomDataItem = new CustomDataSelectItem(
rootItem,
_hueShiftBlock,
NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_HUESHIFT,
0,
() => Content("base.hueShift.customData", "Hue Custom Data"),
IsParticleMode);
_saturabilityBlock = new PropertyToggleBlockItem(
rootItem,
_colorAdjustmentBlock,
"_SaturabilityFoldOut",
"_ChangeSaturability_Toggle",
() => Content("base.saturability", "Saturation"),
NBShaderFlags.FLAG_BIT_SATURABILITY_ON);
_saturabilitySlider = new ShaderGUISliderItem(rootItem, _saturabilityBlock)
{
PropertyName = "_Saturability",
GuiContent = Content("base.saturability.value", "Saturation"),
RangePropertyName = "SaturabilityRangeVec"
};
_saturabilitySlider.InitTriggerByChild();
_saturabilityCustomDataItem = new CustomDataSelectItem(
rootItem,
_saturabilityBlock,
NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_SATURATE,
1,
() => Content("base.saturability.customData", "Saturation Custom Data"),
IsParticleMode);
_contrastBlock = new PropertyToggleBlockItem(
rootItem,
_colorAdjustmentBlock,
"_ContrastFoldOut",
"_Contrast_Toggle",
() => Content("base.contrast", "Contrast"),
NBShaderFlags.FLAG_BIT_PARTICLE_1_MAINTEX_CONTRAST,
1);
_contrastMidColorItem = new ColorItem(rootItem, _contrastBlock, "_ContrastMidColor", () => Content("base.contrast.mid", "Contrast Mid Color"));
_contrastSlider = new ShaderGUISliderItem(rootItem, _contrastBlock)
{
PropertyName = "_Contrast",
GuiContent = Content("base.contrast.value", "Contrast"),
Min = 0f,
Max = 5f
};
_contrastSlider.InitTriggerByChild();
_contrastCustomDataItem = new CustomDataSelectItem(
rootItem,
_contrastBlock,
NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_MAINTEX_CONTRAST,
2,
() => Content("base.contrast.customData", "Contrast Custom Data"),
IsParticleMode);
_baseMapColorRefineBlock = new PropertyToggleBlockItem(
rootItem,
_colorAdjustmentBlock,
"_BaseMapColorRefineFoldOut",
"_BaseMapColorRefine_Toggle",
() => Content("base.colorRefine", "Color Refine"),
NBShaderFlags.FLAG_BIT_PARTICLE_1_MAINTEX_COLOR_REFINE,
1);
_baseMapColorRefineA = new VectorComponentItem(rootItem, _baseMapColorRefineBlock, "_BaseMapColorRefine", 0, () => Content("base.colorRefine.a", "A Main Color Multiply"), false);
_baseMapColorRefineBPower = new VectorComponentItem(rootItem, _baseMapColorRefineBlock, "_BaseMapColorRefine", 1, () => Content("base.colorRefine.bPower", "B Main Color Power"), false);
_baseMapColorRefineBMultiply = new VectorComponentItem(rootItem, _baseMapColorRefineBlock, "_BaseMapColorRefine", 2, () => Content("base.colorRefine.bMultiply", "B After Power Multiply"), false);
_baseMapColorRefineLerp = new VectorComponentItem(rootItem, _baseMapColorRefineBlock, "_BaseMapColorRefine", 3, () => Content("base.colorRefine.lerp", "A/B Lerp"), true, 0f, 1f);
_colorMultiAlphaItem = new ToggleItem(
rootItem,
_colorAdjustmentBlock,
"_ColorMultiAlpha",
() => Content("base.colorMultiAlpha", "Color Multiply Alpha"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_COLOR_MULTI_ALPHA, enabled));
_zTestItem = new ZTestItem(rootItem, this);
_cullItem = new CullModeItem(rootItem, this);
_backFirstPassItem = new ToggleItem(
rootItem,
this,
"_BackFirstPassToggle",
() => Content("base.backFirstPass", "Back First Pass"),
OnBackFirstPassChanged,
() => Is3DTransparent());
_forceZWriteItem = new ForceZWriteItem(rootItem, this);
_affectsShadowsItem = new ToggleItem(
rootItem,
this,
"_AffectsShadows",
() => Content("base.affectsShadows", "Affects Shadows"),
_ => rootItem.SyncService.SyncMaterialState(),
Is3DMode);
_transparentShadowDitherItem = new ToggleItem(
rootItem,
this,
"_TransparentShadowDitherToggle",
() => Content("base.transparentShadowDither", "Transparent Dither Shadows"),
_ => rootItem.SyncService.SyncMaterialState(),
ShouldDrawTransparentShadowDither);
_baseBackColorBlock = new PropertyToggleBlockItem(
rootItem,
this,
"_BaseBackColorFoldOut",
"_BaseBackColor_Toggle",
() => Content("base.backColor", "Back Color"),
NBShaderFlags.FLAG_BIT_PARTICLE_BACKCOLOR,
0,
isVisible: Is3DMode);
_baseBackColorItem = new ColorItem(rootItem, _baseBackColorBlock, "_BaseBackColor", () => Content("base.backColor.color", "Back Color"));
_distanceFadeBlock = new PropertyToggleBlockItem(
rootItem,
this,
"_DistanceFadeFoldOut",
"_DistanceFade_Toggle",
() => Content("base.distanceFade", "Distance Fade"),
keyword: "_DISTANCE_FADE",
isVisible: Is3DMode);
_fadeRangeItem = new Vector2LineItem(rootItem, _distanceFadeBlock, "_Fade", true, () => Content("base.distanceFade.range", "Fade Range"));
_softParticlesBlock = new PropertyToggleBlockItem(
rootItem,
this,
"_SoftParticlesFoldOut",
"_SoftParticlesEnabled",
() => Content("base.softParticles", "Soft Particles"),
keyword: "_SOFTPARTICLES_ON",
isVisible: Is3DMode);
_softParticleFadeItem = new Vector2LineItem(rootItem, _softParticlesBlock, "_SoftParticleFadeParams", true, () => Content("base.softParticles.range", "Near/Far Fade"));
_stencilWithoutPlayerItem = new NBShaderKeywordToggleItem(
rootItem,
this,
"_StencilWithoutPlayerToggle",
"_STENCIL_WITHOUT_PLAYER",
() => Content("base.stencilWithoutPlayer", "Stencil Without Player"),
OnStencilWithoutPlayerChanged,
Is3DMode);
_ignoreVertexColorItem = new ToggleItem(
rootItem,
this,
"_IgnoreVetexColor_Toggle",
() => Content("base.ignoreVertexColor", "Ignore Vertex Color"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_1_IGNORE_VERTEX_COLOR, enabled, 1),
Is3DMode);
_fogIntensityItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_fogintensity",
GuiContent = Content("base.fogIntensity", "Fog Intensity"),
Min = 0f,
Max = 1f
};
_fogIntensityItem.InitTriggerByChild();
InitTriggerByChild();
}
public override void DrawBlock()
{
_baseColorIntensityItem.OnGUI();
_alphaAllItem.OnGUI();
_colorAdjustmentBlock.OnGUI();
_zTestItem.OnGUI();
_cullItem.OnGUI();
_backFirstPassItem.OnGUI();
DrawBackFirstPassWarning();
_forceZWriteItem.OnGUI();
_affectsShadowsItem.OnGUI();
_transparentShadowDitherItem.OnGUI();
_baseBackColorBlock.OnGUI();
_distanceFadeBlock.OnGUI();
_softParticlesBlock.OnGUI();
_stencilWithoutPlayerItem.OnGUI();
_ignoreVertexColorItem.OnGUI();
if (Is3DMode())
{
_fogIntensityItem.OnGUI();
}
else if (_nbRootItem.PropertyInfoDic.ContainsKey("_fogintensity"))
{
_nbRootItem.PropertyInfoDic["_fogintensity"].Property.floatValue = 0f;
}
}
private bool Is3DMode()
{
return _nbRootItem.Context.UIEffectEnabled == MixedBool.False;
}
private bool Is3DTransparent()
{
return Is3DMode() && _nbRootItem.Context.TransparentMode == TransparentMode.Transparent;
}
private bool IsParticleMode()
{
return _nbRootItem.Context.ParticleMode == MixedBool.True;
}
private bool ShouldDrawTransparentShadowDither()
{
return Is3DTransparent() &&
_nbRootItem.PropertyInfoDic.TryGetValue("_AffectsShadows", out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
info.Property.floatValue > 0.5f;
}
private void DrawBackFirstPassWarning()
{
if (!Is3DTransparent() ||
!_nbRootItem.PropertyInfoDic.ContainsKey("_BackFirstPassToggle") ||
_nbRootItem.PropertyInfoDic["_BackFirstPassToggle"].Property.hasMixedValue ||
_nbRootItem.PropertyInfoDic["_BackFirstPassToggle"].Property.floatValue <= 0.5f)
{
return;
}
DrawLayoutHelpBox(
NBShaderInspectorLocalization.GetInspectorText(
"base.backFirstPass.warning",
"预渲染反面会导致打断动态合批,请谨慎使用。"),
MessageType.Warning);
}
private void OnBackFirstPassChanged(bool enabled)
{
_nbRootItem.SyncService.ApplyShaderPass("SRPDefaultUnlit", enabled);
if (enabled && _nbRootItem.PropertyInfoDic.ContainsKey("_Cull"))
{
_nbRootItem.PropertyInfoDic["_Cull"].Property.floatValue = (float)RenderFace.Front;
}
}
private void OnStencilWithoutPlayerChanged(bool enabled)
{
_nbRootItem.SyncService.ApplyStencilPreset(enabled ? "ParticleWithoutPlayer" : "ParticleBaseDefault");
if (_nbRootItem.PropertyInfoDic.ContainsKey("_CustomStencilTest"))
{
_nbRootItem.PropertyInfoDic["_CustomStencilTest"].Property.floatValue = enabled ? 1f : 0f;
}
}
private static GUIContent Content(string key, string fallback, string tip = "")
{
return NBShaderInspectorLocalization.MakeInspectorContent(key, fallback, tip);
}
}
public class ZTestItem : ShaderGUIPopUpItem
{
private static readonly string[] Options = Enum.GetNames(typeof(CompareFunction));
public ZTestItem(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem: parentItem)
{
PropertyName = "_ZTest";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("base.ztest", "ZTest");
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("base.ztest", Options);
InitTriggerByChild();
}
public override void OnGUI()
{
if (RootItem is NBShaderRootItem nbRootItem)
{
if (nbRootItem.Context.UIEffectEnabled == MixedBool.True)
{
if (!Mathf.Approximately(PropertyInfo.Property.floatValue, (float)CompareFunction.LessEqual))
{
PropertyInfo.Property.floatValue = (float)CompareFunction.LessEqual;
}
return;
}
if (nbRootItem.Context.UIEffectEnabled == MixedBool.Mixed)
{
return;
}
}
base.OnGUI();
}
}
public class CullModeItem : ShaderGUIPopUpItem
{
private static readonly string[] Options = { "Both", "Back", "Front" };
public CullModeItem(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem)
{
PropertyName = "_Cull";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("base.cull", "Cull");
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("base.cull", Options);
InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
}
}
public class ForceZWriteItem : ShaderGUIPopUpItem
{
private static readonly string[] Options = { "Default", "Force On", "Force Off" };
public ForceZWriteItem(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem)
{
PropertyName = "_ForceZWriteToggle";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("base.forceZWrite", "Force ZWrite");
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("base.forceZWrite", Options);
InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
}
public override void OnEndChange()
{
base.OnEndChange();
if (RootItem is NBShaderRootItem nbRootItem)
{
nbRootItem.SyncService.SyncMaterialState();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 135aa1fd916c4155b15cada119fdf3fd
timeCreated: 1758549245

View File

@@ -0,0 +1,136 @@
namespace NBShaderEditor
{
public class FeatureBigBlockItem : BigBlockItem
{
public FeatureBigBlockItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_FeatureBigBlockItemFoldOut",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.block.feature.label",
"特效功能",
"inspector.block.feature.tip",
"遮罩、扭曲、溶解等特效功能"))
{
new MaskFeatureItem(rootItem, this);
new NoiseAndDistortFeatureItem(rootItem, this);
new ChromaticAberrationFeatureItem(rootItem, this);
new EmissionFeatureItem(rootItem, this);
new ColorBlendFeatureItem(rootItem, this);
new RampColorFeatureItem(rootItem, this);
new DissolveFeatureItem(rootItem, this);
new ProgramNoiseFeatureItem(rootItem, this);
new SharedUVFeatureItem(rootItem, this);
new FresnelFeatureItem(rootItem, this);
new VertexOffsetFeatureItem(rootItem, this);
new DepthFeatureItem(rootItem, this);
new ParallaxFeatureItem(rootItem, this);
new PortalFeatureItem(rootItem, this);
new FlipbookFeatureItem(rootItem, this);
new VatFeatureItem(rootItem, this);
InitTriggerByChild();
}
public override void DrawBlock()
{
for (int i = 0; i < ChildrenItemList.Count; i++)
{
ShaderGUIItem child = ChildrenItemList[i];
if (IsFeatureItemAllowed(child))
{
child.OnGUI();
}
}
}
private bool IsFeatureItemAllowed(ShaderGUIItem item)
{
if (item is DepthFeatureItem)
{
var rootItem = (NBShaderRootItem)RootItem;
return rootItem.Context == null ||
rootItem.Context.IsAnyKeywordAllowed("_DEPTH_DECAL", "_DEPTH_OUTLINE");
}
string keyword = GetFeatureKeyword(item);
return string.IsNullOrEmpty(keyword) || ((NBShaderRootItem)RootItem).Context.IsKeywordAllowed(keyword);
}
private static string GetFeatureKeyword(ShaderGUIItem item)
{
if (item is MaskFeatureItem)
{
return "_MASKMAP_ON";
}
if (item is NoiseAndDistortFeatureItem)
{
return "_NOISEMAP";
}
if (item is ChromaticAberrationFeatureItem)
{
return "_CHROMATIC_ABERRATION";
}
if (item is EmissionFeatureItem)
{
return "_EMISSION";
}
if (item is ColorBlendFeatureItem)
{
return "_COLORMAPBLEND";
}
if (item is RampColorFeatureItem)
{
return "_COLOR_RAMP";
}
if (item is DissolveFeatureItem)
{
return "_DISSOLVE";
}
if (item is ProgramNoiseFeatureItem)
{
return "_PROGRAM_NOISE";
}
if (item is SharedUVFeatureItem)
{
return "_SHARED_UV";
}
if (item is FresnelFeatureItem)
{
return "_FRESNEL";
}
if (item is ParallaxFeatureItem)
{
return "_PARALLAX_MAPPING";
}
if (item is VatFeatureItem)
{
return "_VAT";
}
if (item is FlipbookFeatureItem)
{
return "_FLIPBOOKBLENDING_ON";
}
if (item is VertexOffsetFeatureItem)
{
return "_VERTEX_OFFSET";
}
return null;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,28 @@
using NBShader;
namespace NBShaderEditor
{
internal sealed class ChromaticAberrationFeatureItem : FeatureToggleFoldOutItem
{
public ChromaticAberrationFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_ChromaticAberrationFoldOut",
"_Distortion_Choraticaberrat_Toggle",
"色散",
keyword: "_CHROMATIC_ABERRATION")
{
ShaderGUIItem chromaticNoiseAffect = new NoiseAffectItem(rootItem, this);
new ToggleItem(
rootItem,
chromaticNoiseAffect,
"_Distortion_Choraticaberrat_WithNoise_Toggle",
() => Content("色散强度受扭曲强度影响"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_NOISE_CHORATICABERRAT_WITH_NOISE, enabled));
new VectorComponentItem(rootItem, this, "_DistortionDirection", 2, () => Content("色散强度"), false);
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_CHORATICABERRAT_INTENSITY, 0, () => Content("色散强度自定义曲线"));
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,29 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class ColorBlendFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] OnOffNames = { "关闭", "开启" };
public ColorBlendFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_ColorBlendBlockFoldOut", "_ColorBlendMap_Toggle", "渐变(颜色相乘)", keyword: "_COLORMAPBLEND")
{
AddTextureWithWrap(rootItem, this, "_ColorBlendMap", "颜色渐变贴图", NBShaderFlags.FLAG_BIT_WRAPMODE_COLORBLENDMAP, "_ColorBlendColor");
new UVModeSelectItem(rootItem, this, "_ColorBlendUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_COLOR_BLEND_MAP, 0, () => Content("颜色渐变贴图UV来源"), "_ColorBlendMap");
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_COLOR_BLEND_OFFSET_X, 3, () => Content("颜色渐变贴图X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_COLOR_BLEND_OFFSET_Y, 3, () => Content("颜色渐变贴图Y轴偏移自定义曲线"));
new VectorComponentItem(rootItem, this, "_ColorBlendVec", 3, () => Content("颜色渐变贴图旋转"), true, 0f, 360f);
new Vector2LineItem(rootItem, this, "_ColorBlendMapOffset", true, () => Content("颜色渐变贴图偏移速度"));
ShaderGUIItem colorBlendNoiseAffect = new NoiseAffectItem(rootItem, this);
new VectorComponentItem(rootItem, colorBlendNoiseAffect, "_ColorBlendVec", 0, () => Content("颜色渐变扭曲强度"), true);
new FeaturePopupItem(rootItem, this, "_ColorBlendAlphaMultiplyMode", () => Content("颜色渐变图Alpha作用"), OnOffNames,
property => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_COLOR_BLEND_ALPHA_MULTIPLY_MODE, property.floatValue > 0.5f));
new VectorComponentItem(rootItem, this, "_ColorBlendVec", 2, () => Content("颜色渐变图Alpha强度"), true);
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,64 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class DepthFeatureItem : ShaderGUIItem
{
public DepthFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem)
{
new DepthOutlineFeatureItem(rootItem, this);
new ToggleItem(
rootItem,
this,
"_DepthDecal_Toggle",
() => FeatureToggleFoldOutItem.Content("深度贴花"),
rootItem.SyncService.ApplyDepthDecalEnabled,
FeatureToggleFoldOutItem.TierVisible(
rootItem,
"_DEPTH_DECAL",
() => rootItem.Context.UIEffectEnabled != MixedBool.True));
InitTriggerByChild();
}
public override void OnGUI()
{
for (int i = 0; i < ChildrenItemList.Count; i++)
{
ChildrenItemList[i].OnGUI();
}
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
HasModified = false;
for (int i = 0; i < ChildrenItemList.Count; i++)
{
HasModified |= ChildrenItemList[i].HasModified;
}
ParentItem?.CheckIsPropertyModified(true);
}
}
internal sealed class DepthOutlineFeatureItem : FeatureToggleFoldOutItem
{
public DepthOutlineFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_DepthOutlineBlockFoldOut",
"_DepthOutline_Toggle",
"深度描边",
keyword: "_DEPTH_OUTLINE",
isVisible: () => rootItem.Context.UIEffectEnabled != MixedBool.True)
{
new ColorItem(rootItem, this, "_DepthOutline_Color", () => Content("深度描边颜色"));
new Vector2LineItem(rootItem, this, "_DepthOutline_Vec", true, () => Content("深度描边距离"));
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,83 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class DissolveFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] RampSourceNames = { "渐变", "贴图" };
private static readonly string[] BlendModeNames = { "叠加", "相乘" };
private static readonly string[] DissolveMaskModeNames = { "Process Dissolve", "Dissolve Mask" };
public DissolveFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_DissolveBlockFoldOut", "_Dissolve_Toggle", "溶解", keyword: "_DISSOLVE")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_Dissolve",
"NB_DEBUG_DISSOLVE",
() => Content("溶解度黑白值测试"),
isVisible: null);
TextureRelatedFoldOutItem dissolveMapRelatedFoldOut = AddTextureWithRelatedFoldOut(rootItem, this, "_DissolveMap", "溶解贴图", "_DissolveMapFoldOut", NBShaderFlags.FLAG_BIT_WRAPMODE_DISSOLVE_MAP);
new ColorChannelSelectItem(rootItem, dissolveMapRelatedFoldOut, NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_DISSOLVE_MAP, 0, () => Content("溶解贴图通道选择"));
new CustomDataSelectItem(rootItem, dissolveMapRelatedFoldOut, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_DISSOLVE_OFFSET_X, 1, () => Content("溶解贴图X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, dissolveMapRelatedFoldOut, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_DISSOLVE_OFFSET_Y, 1, () => Content("溶解贴图Y轴偏移自定义曲线"));
new UVModeSelectItem(rootItem, dissolveMapRelatedFoldOut, "_DissolveUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_DISSOLVE_MAP, 0, () => Content("溶解贴图UV来源"), "_DissolveMap");
new Vector2LineItem(rootItem, dissolveMapRelatedFoldOut, "_DissolveOffsetRotateDistort", true, () => Content("溶解贴图偏移速度"));
new VectorComponentItem(rootItem, dissolveMapRelatedFoldOut, "_DissolveOffsetRotateDistort", 2, () => Content("溶解贴图旋转"), true, 0f, 360f);
new PNoiseBlendModeItem(rootItem, this, NBShaderFlags.FLAG_BIT_PNOISE_BLEND_POS_0_DISSOLVE, "_DissolvePNoiseBlendOpacity", () => Content("溶解程序噪波混合"),
() => rootItem.Context.ProgramNoiseEnabled == MixedBool.True);
new VectorComponentItem(rootItem, this, "_Dissolve", 1, () => Content("溶解值Pow"), true, 0.001f, 10f);
new VectorComponentRangeSliderItem(rootItem, this, "_Dissolve", 0, "DissolveXRangeVec", () => Content("溶解强度"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_DISSOLVE_INTENSITY, 0, () => Content("溶解强度自定义曲线"));
new VectorComponentItem(rootItem, this, "_Dissolve", 3, () => Content("溶解硬软度"), true, 0.001f, 1f);
ShaderGUIItem dissolveNoiseAffect = new NoiseAffectItem(rootItem, this);
new VectorComponentItem(rootItem, dissolveNoiseAffect, "_DissolveOffsetRotateDistort", 3, () => Content("溶解贴图扭曲强度"), false);
PropertyToggleBlockItem lineBlock = ToggleBlock(rootItem, "_DissolveLineFoldOut", "_DissolveLineMaskToggle", "溶解描边",
NBShaderFlags.FLAG_BIT_PARTICLE_1_DISSOLVE_LINE_MASK, 1, parent: this);
new ColorItem(rootItem, lineBlock, "_DissolveLineColor", () => Content("溶解描边颜色"));
new VectorComponentRangeSliderItem(rootItem, lineBlock, "_Dissolve_Vec2", 0, "Dissolve2XRangeVec", () => Content("描边位置"));
new VectorComponentRangeSliderItem(rootItem, lineBlock, "_Dissolve_Vec2", 1, "Dissolve2YRangeVec", () => Content("描边软硬"));
PropertyToggleBlockItem rampBlock = ToggleBlock(rootItem, "_DissolveRampFoldOut", "_Dissolve_useRampMap_Toggle", "溶解Ramp图功能",
parent: this, keyword: "_DISSOLVE_RAMP",
onValueChanged: _ => rootItem.SyncService.SyncMaterialState());
Func<bool> isDissolveRampMapVisible = TierVisible(rootItem, "_DISSOLVE_RAMP_MAP", () => IsPropertyMode(rootItem, "_DissolveRampSourceMode", 1));
new FeaturePopupItem(rootItem, rampBlock, "_DissolveRampSourceMode", () => Content("溶解Ramp模式"), RampSourceNames,
_ => rootItem.SyncService.SyncMaterialState(),
keyword: "_DISSOLVE_RAMP_MAP");
AddTextureWithWrap(rootItem, rampBlock, "_DissolveRampMap", "溶解Ramp图", NBShaderFlags.FLAG_BIT_WRAPMODE_DISSOLVE_RAMPMAP, "_DissolveRampColor",
isDissolveRampMapVisible);
AddGradient(rootItem, rampBlock, "Ramp颜色", "_DissolveRampCount", "_DissolveRampColor", "_DissolveRampAlpha", hdr: true,
isVisible: () => IsPropertyMode(rootItem, "_DissolveRampSourceMode", 0));
new TextureScaleOffsetItem(rootItem, rampBlock, "_DissolveRampMap", false, () => IsPropertyMode(rootItem, "_DissolveRampSourceMode", 0), TillingContent, OffsetContent);
new ColorItem(rootItem, rampBlock, "_DissolveRampColor", () => Content("Ramp颜色叠加"), () => IsPropertyMode(rootItem, "_DissolveRampSourceMode", 0));
new WrapModeItem(rootItem, rampBlock, NBShaderFlags.FLAG_BIT_WRAPMODE_DISSOLVE_RAMPMAP, () => Content("溶解RampUV Wrap"), 2,
() => IsPropertyMode(rootItem, "_DissolveRampSourceMode", 0));
new FeaturePopupItem(rootItem, rampBlock, "_DissolveRampColorBlendMode", () => Content("溶解Ramp混合模式"), BlendModeNames,
property => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_1_DISSOLVE_RAMP_MULITPLY, property.floatValue > 0.5f, 1));
PropertyToggleBlockItem maskBlock = ToggleBlock(rootItem, "_DissolveMaskFoldOut", "_DissolveMask_Toggle", "溶解遮罩图(过程溶解)",
parent: this, keyword: "_DISSOLVE_MASK");
new FeaturePopupItem(rootItem, maskBlock, "_DissolveMaskMode", () => Content("溶解遮罩模式"), DissolveMaskModeNames);
AddTextureWithWrap(rootItem, maskBlock, "_DissolveMaskMap", "溶解遮罩图", NBShaderFlags.FLAG_BIT_WRAPMODE_DISSOLVE_MASKMAP);
new UVModeSelectItem(rootItem, maskBlock, "_DissolveMaskUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_DISSOLVE_MASK_MAP, 0, () => Content("溶解遮罩图UV来源"), "_DissolveMaskMap");
new ColorChannelSelectItem(rootItem, maskBlock, NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_DISSOLVE_MASK_MAP, 0, () => Content("溶解遮罩图通道选择"));
new VectorComponentItem(rootItem, maskBlock, "_Dissolve", 2, () => Content("溶解遮罩强度"), false, isVisible: () => !IsDissolveMaskStrengthSlider(rootItem));
new VectorComponentItem(rootItem, maskBlock, "_Dissolve", 2, () => Content("溶解遮罩强度"), true, 0f, 2f, () => IsDissolveMaskStrengthSlider(rootItem));
new CustomDataSelectItem(rootItem, maskBlock, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_DISSOLVE_MASK_INTENSITY, 1, () => Content("溶解遮罩图强度自定义曲线"));
InitTriggerByChild();
}
private static bool IsDissolveMaskStrengthSlider(NBShaderRootItem rootItem)
{
return rootItem.PropertyInfoDic.TryGetValue("_DissolveMaskMode", out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
info.Property.floatValue > 0.5f;
}
}
}

View File

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

View File

@@ -0,0 +1,42 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class EmissionFeatureItem : FeatureToggleFoldOutItem
{
public EmissionFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_EmissionBlockFoldOut", "_EmissionEnabled", "流光(颜色相加)", keyword: "_EMISSION")
{
AddTextureWithWrap(rootItem, this, "_EmissionMap", "流光贴图", NBShaderFlags.FLAG_BIT_WRAPMODE_EMISSIONMAP, "_EmissionMapColor");
new UVModeSelectItem(rootItem, this, "_EmissionUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_EMISSION_MAP, 0, () => Content("流光贴图UV来源"), "_EmissionMap");
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_EMISSION_OFFSET_X, 3, () => Content("流光贴图X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_EMISSION_OFFSET_Y, 3, () => Content("流光贴图Y轴偏移自定义曲线"));
ShaderGUISliderItem emissionMapUVRotationItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_EmissionMapUVRotation",
GuiContent = Content("流光贴图旋转"),
Min = 0f,
Max = 360f
};
emissionMapUVRotationItem.InitTriggerByChild();
new Vector2LineItem(rootItem, this, "_EmissionMapUVOffset", true, () => Content("流光贴图偏移速度"));
ShaderGUIItem emissionNoiseAffect = new NoiseAffectItem(rootItem, this);
ShaderGUIFloatItem emissionDistortionIntensityItem = new ShaderGUIFloatItem(rootItem, emissionNoiseAffect)
{
PropertyName = "_Emi_Distortion_intensity",
GuiContent = Content("流光贴图扭曲强度")
};
emissionDistortionIntensityItem.InitTriggerByChild();
ShaderGUIFloatItem emissionMapColorIntensityItem = new ShaderGUIFloatItem(rootItem, this)
{
PropertyName = "_EmissionMapColorIntensity",
GuiContent = Content("流光颜色强度")
};
emissionMapColorIntensityItem.InitTriggerByChild();
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,175 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class NoiseAffectItem : ShaderGUIItem
{
private readonly NBShaderRootItem _nbRootItem;
public NoiseAffectItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem)
{
_nbRootItem = rootItem;
}
public override void OnGUI()
{
bool previousMixedValue = EditorGUI.showMixedValue;
bool noiseEnabledHasMixedValue = _nbRootItem.Context.NoiseEnabled == MixedBool.Mixed;
using (new InheritedControlDisabledScope(_nbRootItem.Context.NoiseEnabled == MixedBool.False))
{
for (int i = 0; i < ChildrenItemList.Count; i++)
{
EditorGUI.showMixedValue = noiseEnabledHasMixedValue;
ChildrenItemList[i].OnGUI();
}
}
EditorGUI.showMixedValue = previousMixedValue;
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
HasModified = false;
for (int i = 0; i < ChildrenItemList.Count; i++)
{
HasModified |= ChildrenItemList[i].HasModified;
}
ParentItem?.CheckIsPropertyModified(true);
}
}
internal sealed class FlipbookFeatureItem : ToggleItem
{
private readonly NBShaderRootItem _nbRootItem;
public FlipbookFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_FlipbookBlending",
() => FeatureToggleFoldOutItem.Content("序列帧融帧(丝滑)"),
rootItem.SyncService.ApplyFlipbookEnabled)
{
_nbRootItem = rootItem;
}
public override void DrawBlock()
{
if (PropertyInfo.Property.hasMixedValue || PropertyInfo.Property.floatValue <= 0.5f)
{
return;
}
if (_nbRootItem.Context.MeshSourceMode == MeshSourceMode.Particle ||
_nbRootItem.Context.MeshSourceMode == MeshSourceMode.UIParticle)
{
if (HasSpecialUVChannel())
{
using (ParentControlDisabledScope())
{
DrawLayoutHelpBox(
FeatureToggleFoldOutItem.Text(
"feature.flipbook.specialUvWarning.message",
"序列帧融帧和特殊UV通道同时开启粒子序列帧应该影响UV0和UV1两个通道特殊通道只能使用UV3原始UV"),
MessageType.Warning);
}
}
else
{
using (ParentControlDisabledScope())
{
DrawLayoutHelpBox(
FeatureToggleFoldOutItem.Text(
"feature.flipbook.particleInfo.message",
"AnimationSheet的AffectUVChannel需要有UV0和UV1"),
MessageType.Info);
}
}
return;
}
if (_nbRootItem.Context.MeshSourceMode == MeshSourceMode.Mesh)
{
using (ParentControlDisabledScope())
{
DrawLayoutHelpBox(
FeatureToggleFoldOutItem.Text(
"feature.flipbook.meshInfo.message",
"需要添加AnimationSheetHelper脚本"),
MessageType.Info);
}
}
}
private bool HasSpecialUVChannel()
{
for (int i = 0; i < _nbRootItem.ShaderFlags.Count; i++)
{
if (_nbRootItem.ShaderFlags[i] is NBShaderFlags flags &&
flags.CheckIsUVModeOn(NBShaderFlags.UVMode.SpecialUVChannel))
{
return true;
}
}
return false;
}
}
internal sealed class VatFrameCustomDataItem : CustomDataSelectItem
{
private readonly Func<bool> _isVisible;
private readonly Func<bool> _anyVatFrameCustomDataVisible;
public VatFrameCustomDataItem(
NBShaderRootItem rootItem,
ShaderGUIItem parentItem,
Func<GUIContent> contentProvider,
Func<bool> isVisible,
Func<bool> anyVatFrameCustomDataVisible)
: base(rootItem, parentItem, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_VAT_FRAME, 2, contentProvider)
{
_isVisible = isVisible;
_anyVatFrameCustomDataVisible = anyVatFrameCustomDataVisible;
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
if (_anyVatFrameCustomDataVisible == null || !_anyVatFrameCustomDataVisible())
{
ClearVatFrameCustomData();
}
return;
}
base.OnGUI();
}
private void ClearVatFrameCustomData()
{
for (int i = 0; i < RootItem.ShaderFlags.Count; i++)
{
if (RootItem.ShaderFlags[i] is NBShaderFlags flags && flags.material != null)
{
if (flags.GetCustomDataFlag(NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_VAT_FRAME, 2) !=
NBShaderFlags.CutomDataComponent.Off)
{
flags.SetCustomDataFlag(
NBShaderFlags.CutomDataComponent.Off,
NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_VAT_FRAME,
2);
}
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,276 @@
using System;
using System.Collections.Generic;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal abstract class FeatureToggleFoldOutItem : PropertyToggleBlockItem
{
private const string LocalizationTableName = NBShaderInspectorLocalization.TableName;
private static readonly Dictionary<string, GUIContent> ContentCache =
new Dictionary<string, GUIContent>(StringComparer.Ordinal);
private static readonly Dictionary<string, string[]> PopupOptionsCache =
new Dictionary<string, string[]>(StringComparer.Ordinal);
private static string s_CacheLanguage;
protected FeatureToggleFoldOutItem(
NBShaderRootItem rootItem,
ShaderGUIItem parentItem,
string foldOutPropertyName,
string togglePropertyName,
string label,
int flagBits = 0,
int flagIndex = 0,
string keyword = null,
Action<bool> onValueChanged = null,
Func<bool> isVisible = null,
bool bold = true)
: base(
rootItem,
parentItem,
foldOutPropertyName,
togglePropertyName,
() => Content(label),
flagBits,
flagIndex,
keyword,
onValueChanged: onValueChanged,
isVisible: isVisible,
bold: bold)
{
}
protected TextureRelatedFoldOutItem AddTextureWithRelatedFoldOut(
NBShaderRootItem rootItem,
ShaderGUIItem parent,
string texturePropertyName,
string label,
string foldOutPropertyName,
int wrapFlag,
string colorPropertyName = null,
Func<bool> isVisible = null)
{
new TextureItem(
rootItem,
parent,
texturePropertyName,
() => Content(label),
colorPropertyName,
isVisible: isVisible,
tillingContentProvider: TillingContent,
offsetContentProvider: OffsetContent);
TextureRelatedFoldOutItem relatedFoldOut = new TextureRelatedFoldOutItem(
rootItem,
parent,
foldOutPropertyName,
texturePropertyName,
() => Content(label + "相关功能"),
isVisible);
new WrapModeItem(rootItem, relatedFoldOut, wrapFlag, () => Content(label + " Wrap"), 2);
return relatedFoldOut;
}
protected void AddTextureWithWrap(
NBShaderRootItem rootItem,
ShaderGUIItem parent,
string texturePropertyName,
string label,
int wrapFlag,
string colorPropertyName = null,
Func<bool> isVisible = null)
{
new TextureItem(
rootItem,
parent,
texturePropertyName,
() => Content(label),
colorPropertyName,
isVisible: isVisible,
tillingContentProvider: TillingContent,
offsetContentProvider: OffsetContent);
new WrapModeItem(rootItem, parent, wrapFlag, () => Content(label + " Wrap"), 2, isVisible);
}
protected PropertyToggleBlockItem ToggleBlock(
NBShaderRootItem rootItem,
string foldOutPropertyName,
string togglePropertyName,
string label,
int flagBits = 0,
int flagIndex = 0,
ShaderGUIItem parent = null,
string keyword = null,
Action<bool> onValueChanged = null,
Func<bool> isVisible = null,
bool bold = false)
{
return new PropertyToggleBlockItem(
rootItem,
parent ?? this,
foldOutPropertyName,
togglePropertyName,
() => Content(label),
flagBits,
flagIndex,
keyword,
onValueChanged: onValueChanged,
isVisible: isVisible,
bold: bold);
}
protected static void AddGradient(
NBShaderRootItem rootItem,
ShaderGUIItem parent,
string label,
string countPropertyName,
string colorPrefix,
string alphaPrefix,
bool hdr = false,
Func<bool> isVisible = null)
{
new GradientItem(
rootItem,
parent,
countPropertyName,
6,
BuildPropertyNames(colorPrefix, 6),
BuildPropertyNames(alphaPrefix, 3),
() => Content(label),
hdr,
ColorSpace.Gamma,
isVisible);
}
protected static string[] BuildPropertyNames(string prefix, int count)
{
string[] names = new string[count];
for (int i = 0; i < count; i++)
{
names[i] = prefix + i;
}
return names;
}
protected static bool IsPropertyMode(NBShaderRootItem rootItem, string propertyName, int expectedMode)
{
return rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
Mathf.RoundToInt(info.Property.floatValue) == expectedMode;
}
protected static bool IsPropertyMode(NBShaderRootItem rootItem, string propertyName, params int[] expectedModes)
{
if (!rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) ||
info.Property.hasMixedValue)
{
return false;
}
int value = Mathf.RoundToInt(info.Property.floatValue);
for (int i = 0; i < expectedModes.Length; i++)
{
if (value == expectedModes[i])
{
return true;
}
}
return false;
}
internal static GUIContent Content(string label)
{
EnsureCacheLanguage();
if (ContentCache.TryGetValue(label, out GUIContent cachedContent))
{
return cachedContent;
}
cachedContent = NBShaderInspectorLocalization.MakeInspectorContent("feature." + label, label);
ContentCache[label] = cachedContent;
return cachedContent;
}
protected static GUIContent TillingContent()
{
return LocalizedInspectorContent(LocalizationTableName, "common.tilling", "Tilling");
}
protected static GUIContent OffsetContent()
{
return LocalizedInspectorContent(LocalizationTableName, "common.offset", "Offset");
}
internal static string Text(string key, string fallback)
{
return LocalizedText(LocalizationTableName, key, fallback);
}
internal static string[] PopupOptions(string propertyName, string[] fallback)
{
EnsureCacheLanguage();
if (PopupOptionsCache.TryGetValue(propertyName, out string[] cachedOptions))
{
return cachedOptions;
}
cachedOptions = NBShaderInspectorLocalization.GetInspectorOptions("feature.popup." + propertyName, fallback);
PopupOptionsCache[propertyName] = cachedOptions;
return cachedOptions;
}
private static void EnsureCacheLanguage()
{
string currentLanguage = NBShaderInspectorLocalization.CurrentLanguage;
if (string.Equals(s_CacheLanguage, currentLanguage, StringComparison.Ordinal))
{
return;
}
s_CacheLanguage = currentLanguage;
ContentCache.Clear();
PopupOptionsCache.Clear();
}
internal static bool IsTierKeywordAllowed(NBShaderRootItem rootItem, string keyword)
{
return string.IsNullOrEmpty(keyword) ||
rootItem == null ||
rootItem.Context == null ||
rootItem.Context.IsKeywordAllowed(keyword);
}
internal static Func<bool> TierVisible(NBShaderRootItem rootItem, string keyword, Func<bool> isVisible = null)
{
return () => IsTierKeywordAllowed(rootItem, keyword) && (isVisible == null || isVisible());
}
}
internal sealed class FeaturePopupItem : ShaderGUIPopUpItem
{
public FeaturePopupItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
string propertyName,
Func<GUIContent> contentProvider,
string[] popupNames,
Action<MaterialProperty> onValueChanged = null,
Func<bool> isVisible = null,
string keyword = null)
: base(
rootItem,
parentItem,
propertyName,
contentProvider,
() => FeatureToggleFoldOutItem.PopupOptions(propertyName, popupNames),
onValueChanged,
string.IsNullOrEmpty(keyword)
? isVisible
: FeatureToggleFoldOutItem.TierVisible(rootItem as NBShaderRootItem, keyword, isVisible))
{
}
}
}

View File

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

View File

@@ -0,0 +1,50 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class FresnelFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] FresnelModeNames = { "颜色", "透明" };
public FresnelFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_FresnelBlockFoldOut", "_fresnelEnabled", "菲涅尔", keyword: "_FRESNEL")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_Fresnel",
"NB_DEBUG_FRESNEL",
() => Content("菲涅尔测试颜色"),
isVisible: null);
new FeaturePopupItem(rootItem, this, "_FresnelMode", () => Content("菲涅尔模式"), FresnelModeNames,
property => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_FRESNEL_FADE_ON, property.floatValue > 0.5f));
Func<bool> isFresnelColorMode = () => IsPropertyMode(rootItem, "_FresnelMode", 0);
new ColorItem(rootItem, this, "_FresnelColor", () => Content("菲涅尔颜色"), isFresnelColorMode);
new VectorComponentItem(rootItem, this, "_FresnelUnit", 2, () => Content("菲涅尔强度"), true);
new VectorComponentItem(rootItem, this, "_FresnelUnit", 0, () => Content("菲涅尔位置"), true, -1f, 1f);
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_FRESNEL_OFFSET, 0, () => Content("菲涅尔位置自定义曲线"));
new VectorComponentItem(rootItem, this, "_FresnelUnit", 1, () => Content("菲涅尔范围Pow"), true, 0f, 10f);
new VectorComponentItem(rootItem, this, "_FresnelUnit", 3, () => Content("菲涅尔硬度"), true);
new ToggleItem(
rootItem,
this,
"_InvertFresnel_Toggle",
() => Content("翻转菲涅尔"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_FRESNEL_INVERT_ON, enabled));
new ToggleItem(
rootItem,
this,
"_FresnelColorAffectByAlpha",
() => Content("菲涅尔颜色受Alpha影响"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_FRESNEL_COLOR_AFFETCT_BY_ALPHA, enabled),
isFresnelColorMode);
new VectorComponentItem(rootItem, this, "_FresnelRotation", 0, () => Content("菲涅尔方向偏移X"), false);
new VectorComponentItem(rootItem, this, "_FresnelRotation", 1, () => Content("菲涅尔方向偏移Y"), false);
new VectorComponentItem(rootItem, this, "_FresnelRotation", 2, () => Content("菲涅尔方向偏移Z"), false);
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,171 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class MaskFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] TextureGradientNames = { "贴图", "渐变" };
public MaskFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_MaskBlockFoldOut", "_Mask_Toggle", "遮罩", keyword: "_MASKMAP_ON")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_Mask",
"NB_DEBUG_MASK",
() => Content("测试遮罩颜色"),
isVisible: null);
new VectorComponentItem(rootItem, this, "_MaskMapVec", 0, () => Content("遮罩强度"), true);
PropertyToggleBlockItem refineBlock = ToggleBlock(
rootItem,
"_MaskRefineFoldOut",
"_MaskRefineToggle",
"遮罩整体调整",
NBShaderFlags.FLAG_BIT_PARTICLE_1_MASK_REFINE,
1,
parent: this);
new VectorComponentItem(rootItem, refineBlock, "_MaskRefineVec", 0, () => Content("范围(Pow)"), false);
new VectorComponentItem(rootItem, refineBlock, "_MaskRefineVec", 1, () => Content("相乘"), false);
new VectorComponentItem(rootItem, refineBlock, "_MaskRefineVec", 2, () => Content("偏移(相加)"), false);
new PNoiseBlendModeItem(rootItem, this, NBShaderFlags.FLAG_BIT_PNOISE_BLEND_POS_0_MASK, "_MaskPNoiseBlendOpacity", () => Content("遮罩程序噪波混合"),
() => rootItem.Context.ProgramNoiseEnabled == MixedBool.True);
AddMaskMap(rootItem, this, "_MaskMap", "_MaskMapGradientToggle", "_MaskUVModeFoldOut", "遮罩",
NBShaderFlags.FLAG_BIT_WRAPMODE_MASKMAP,
NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_MASKMAP1,
NBShaderFlags.FLAG_BIT_UVMODE_POS_0_MASKMAP,
NBShaderFlags.FLAG_BIT_PARTICLE_1_MASKMAP_GRADIENT,
1,
"_MaskMapFoldOut");
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_MASK_OFFSET_X, 0, () => Content("Mask图X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_MASK_OFFSET_Y, 0, () => Content("Mask图Y轴偏移自定义曲线"));
new Vector2LineItem(rootItem, this, "_MaskMapOffsetAnition", true, () => Content("遮罩偏移速度"));
ShaderGUISliderItem maskMapUVRotationItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_MaskMapUVRotation",
GuiContent = Content("遮罩旋转"),
Min = 0f,
Max = 360f
};
maskMapUVRotationItem.InitTriggerByChild();
PropertyToggleBlockItem rotateBlock = ToggleBlock(
rootItem,
"_MaskRotationFoldOut",
"_Mask_RotationToggle",
"遮罩旋转速度",
NBShaderFlags.FLAG_BIT_PARTILCE_MASKMAPROTATIONANIMATION_ON,
parent: this);
ShaderGUIFloatItem maskMapRotationSpeedItem = new ShaderGUIFloatItem(rootItem, rotateBlock)
{
PropertyName = "_MaskMapRotationSpeed",
GuiContent = Content("旋转速度")
};
maskMapRotationSpeedItem.InitTriggerByChild();
ShaderGUIItem maskNoiseAffect = new NoiseAffectItem(rootItem, this);
ShaderGUISliderItem maskDistortionIntensityItem = new ShaderGUISliderItem(rootItem, maskNoiseAffect)
{
PropertyName = "_MaskDistortion_intensity",
GuiContent = Content("遮罩扭曲强度"),
RangePropertyName = "MaskDistortionIntensityRangeVec"
};
maskDistortionIntensityItem.InitTriggerByChild();
PropertyToggleBlockItem mask2Block = ToggleBlock(
rootItem,
"_Mask2BlockFoldOut",
"_Mask2_Toggle",
"遮罩2",
parent: this,
keyword: "_MASKMAP2_ON");
AddMaskMap(rootItem, mask2Block, "_MaskMap2", "_MaskMap2GradientToggle", "_Mask2UVModeFoldOut", "遮罩2",
NBShaderFlags.FLAG_BIT_WRAPMODE_MASKMAP2,
NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_MASKMAP2,
NBShaderFlags.FLAG_BIT_UVMODE_POS_0_MASKMAP_2,
NBShaderFlags.FLAG_BIT_PARTICLE_1_MASKMAP_2_GRADIENT,
1);
new VectorComponentItem(rootItem, mask2Block, "_MaskMapVec", 1, () => Content("遮罩2旋转"), false);
new Vector2LineItem(rootItem, mask2Block, "_MaskMapOffsetAnition", false, () => Content("遮罩2偏移速度"));
PropertyToggleBlockItem mask3Block = ToggleBlock(
rootItem,
"_Mask3BlockFoldOut",
"_Mask3_Toggle",
"遮罩3",
parent: this,
keyword: "_MASKMAP3_ON");
AddMaskMap(rootItem, mask3Block, "_MaskMap3", "_MaskMap3GradientToggle", "_Mask3UVModeFoldOut", "遮罩3",
NBShaderFlags.FLAG_BIT_WRAPMODE_MASKMAP3,
NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_MASKMAP3,
NBShaderFlags.FLAG_BIT_UVMODE_POS_0_MASKMAP_3,
NBShaderFlags.FLAG_BIT_PARTICLE_1_MASKMAP_3_GRADIENT,
1);
new VectorComponentItem(rootItem, mask3Block, "_MaskMapVec", 2, () => Content("遮罩3旋转"), false);
new Vector2LineItem(rootItem, mask3Block, "_MaskMap3OffsetAnition", true, () => Content("遮罩3偏移速度"));
InitTriggerByChild();
}
private void AddMaskMap(
NBShaderRootItem rootItem,
ShaderGUIItem parent,
string texturePropertyName,
string modePropertyName,
string uvFoldOutPropertyName,
string label,
int wrapFlag,
int colorChannelFlagPos,
int uvModeFlagPos,
int gradientFlag,
int gradientFlagIndex,
string textureFoldOutPropertyName = null)
{
new FeaturePopupItem(rootItem, parent, modePropertyName, () => Content(label + "模式"), TextureGradientNames,
property => rootItem.SyncService.ApplyToggleFlag(gradientFlag, property.floatValue > 0.5f, gradientFlagIndex));
ShaderGUIItem textureParent = parent;
if (string.IsNullOrEmpty(textureFoldOutPropertyName))
{
AddTextureWithWrap(rootItem, parent, texturePropertyName, label + "贴图", wrapFlag,
isVisible: () => IsPropertyMode(rootItem, modePropertyName, 0));
}
else
{
textureParent = AddTextureWithRelatedFoldOut(rootItem, parent, texturePropertyName, label + "贴图", textureFoldOutPropertyName, wrapFlag,
isVisible: () => IsPropertyMode(rootItem, modePropertyName, 0));
}
new ColorChannelSelectItem(rootItem, textureParent, colorChannelFlagPos, 0, () => Content(label + "通道选择"),
() => IsPropertyMode(rootItem, modePropertyName, 0));
AddAlphaGradient(rootItem, parent, label + "渐变", texturePropertyName + "GradientCount", texturePropertyName + "GradientFloat",
() => IsPropertyMode(rootItem, modePropertyName, 1));
new TextureScaleOffsetItem(rootItem, parent, texturePropertyName, false, () => IsPropertyMode(rootItem, modePropertyName, 1), TillingContent, OffsetContent);
new WrapModeItem(rootItem, parent, wrapFlag, () => Content(label + "UV Wrap"), 2,
() => IsPropertyMode(rootItem, modePropertyName, 1));
new UVModeSelectItem(rootItem, parent, uvFoldOutPropertyName, uvModeFlagPos, 0, () => Content(label + "UV来源"), texturePropertyName, forceEnable: true);
}
private static void AddAlphaGradient(
NBShaderRootItem rootItem,
ShaderGUIItem parent,
string label,
string countPropertyName,
string alphaPrefix,
Func<bool> isVisible = null)
{
new GradientItem(
rootItem,
parent,
countPropertyName,
6,
Array.Empty<string>(),
BuildPropertyNames(alphaPrefix, 3),
() => Content(label),
false,
ColorSpace.Gamma,
isVisible);
}
}
}

View File

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

View File

@@ -0,0 +1,519 @@
using System;
using System.Reflection;
using NBShader;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace NBShaderEditor
{
internal sealed class NoiseAndDistortFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] DistortModeNames = { "FlowMap/RG贴图", "折射率" };
private static readonly string[] ScreenDistortModeNames = { "No Screen Distort", "Deferred Distort", "Camera Opaque Distort" };
private const int ScreenDistortModeDeferred = 1;
private const int ScreenDistortModeCameraOpaque = 2;
private const string ScreenDistortKeyword = "_SCREEN_DISTORT_MODE";
private const string ScreenDistortModePropertyName = "_ScreenDistortModeToggle";
private const string RendererDataListPropertyName = "m_RendererDataList";
private const string LegacyRendererDataPropertyName = "m_RendererData";
private const string RendererFeaturesPropertyName = "m_RendererFeatures";
private const string OpaqueTexturePropertyName = "supportsCameraOpaqueTexture";
private const string OpaqueTextureSerializedPropertyName = "m_RequireOpaqueTexture";
private const string RendererFeatureActivePropertyName = "isActive";
private const string RendererFeatureActiveSerializedPropertyName = "m_Active";
private const string NBPostProcessTypeFullName = "NBShader.NBPostProcess";
private const string NBPostProcessTypeName = "NBPostProcess";
public NoiseAndDistortFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_NoiseBlockFoldOut", "_noisemapEnabled", "扭曲", keyword: "_NOISEMAP")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_Distort",
"NB_DEBUG_DISTORT",
() => Content("扭曲强度值测试"),
isVisible: null);
ShaderGUISliderItem noiseIntensityItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_NoiseIntensity",
GuiContent = Content("整体扭曲强度"),
RangePropertyName = "_NoiseIntensityRangeVec"
};
noiseIntensityItem.InitTriggerByChild();
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_NOISE_INTENSITY, 1, () => Content("扭曲强度自定义曲线"));
new FeaturePopupItem(rootItem, this, "_ScreenDistortModeToggle", () => Content("屏幕扰动模式"), ScreenDistortModeNames,
property => rootItem.SyncService.ApplyScreenDistortMode(Mathf.RoundToInt(property.floatValue)),
() => rootItem.Context.UIEffectEnabled != MixedBool.True,
ScreenDistortKeyword);
Func<bool> isDeferredDistortVisible = TierVisible(
rootItem,
ScreenDistortKeyword,
() => IsScreenDistortMode(rootItem, ScreenDistortModeDeferred));
Func<bool> isCameraOpaqueDistortVisible = TierVisible(
rootItem,
ScreenDistortKeyword,
() => IsScreenDistortMode(rootItem, ScreenDistortModeCameraOpaque));
Func<bool> isScreenDistortModeNeedsNBPostProcessVisible = () => isDeferredDistortVisible() || isCameraOpaqueDistortVisible();
Func<bool> isMissingNBPostProcessVisible = () => isScreenDistortModeNeedsNBPostProcessVisible() && !HasActiveNBPostProcessRendererFeature();
Func<bool> isMissingOpaqueTextureVisible = () => isCameraOpaqueDistortVisible() && !HasCameraOpaqueTextureCopyEnabled();
new PingableHelpBoxItem(
rootItem,
this,
() => Text(
"feature.screenDistort.missingNbPostProcess.message",
"Screen Distort requires an active NB Post Process Feature on at least one RendererData in the current URP Pipeline Asset."),
MessageType.Warning,
() => ButtonContent("feature.screenDistort.pingRendererData", "Ping Renderer"),
GetRendererDataForNBPostProcessPing,
isMissingNBPostProcessVisible);
new PingableHelpBoxItem(
rootItem,
this,
() => Text(
"feature.screenDistort.missingOpaqueTextureCopy.message",
"Camera Opaque Distort requires Opaque Texture to be enabled on the current URP Pipeline Asset."),
MessageType.Warning,
() => ButtonContent("feature.screenDistort.pingPipelineAsset", "Ping URP Asset"),
GetCurrentRenderPipelineAsset,
isMissingOpaqueTextureVisible);
ShaderGUISliderItem screenDistortIntensityItem = new ShaderGUISliderItem(
rootItem,
this,
TierVisible(
rootItem,
ScreenDistortKeyword,
() => rootItem.Context.UIEffectEnabled != MixedBool.True && IsPropertyGreater(rootItem, "_ScreenDistortModeToggle", 0.5f)))
{
PropertyName = "_ScreenDistortIntensity",
GuiContent = Content("屏幕扭曲强度"),
RangePropertyName = "_ScreenDistortIntensityRangeVec"
};
screenDistortIntensityItem.InitTriggerByChild();
new ToggleItem(
rootItem,
this,
"_DisableMainPassToggle",
() => Content("关闭主材质Pass"),
enabled =>
{
rootItem.SyncService.ApplyScreenDistortMode(GetIntProperty(rootItem, "_ScreenDistortModeToggle"));
},
TierVisible(
rootItem,
ScreenDistortKeyword,
() => rootItem.Context.UIEffectEnabled != MixedBool.True && IsPropertyGreater(rootItem, "_ScreenDistortModeToggle", 0.5f)));
PropertyToggleBlockItem screenAlphaBlock = ToggleBlock(
rootItem,
"_ScreenDistortAlphaFoldOut",
"_ScreenDistortAlphaRefineToggle",
"屏幕扭曲Alpha整体调整",
NBShaderFlags.FLAG_BIT_PARTICLE_1_SCREEN_DISTORT_ALPHA_REFINE,
1,
parent: this,
isVisible: TierVisible(
rootItem,
ScreenDistortKeyword,
() => rootItem.Context.UIEffectEnabled != MixedBool.True && IsPropertyGreater(rootItem, "_ScreenDistortModeToggle", 0.5f)));
ShaderGUIFloatItem screenDistortAlphaPowItem = new ShaderGUIFloatItem(rootItem, screenAlphaBlock)
{
PropertyName = "_ScreenDistortAlphaPow",
GuiContent = Content("范围(Pow)")
};
screenDistortAlphaPowItem.InitTriggerByChild();
ShaderGUIFloatItem screenDistortAlphaMultiItem = new ShaderGUIFloatItem(rootItem, screenAlphaBlock)
{
PropertyName = "_ScreenDistortAlphaMulti",
GuiContent = Content("相乘")
};
screenDistortAlphaMultiItem.InitTriggerByChild();
ShaderGUIFloatItem screenDistortAlphaAddItem = new ShaderGUIFloatItem(rootItem, screenAlphaBlock)
{
PropertyName = "_ScreenDistortAlphaAdd",
GuiContent = Content("偏移(相加)")
};
screenDistortAlphaAddItem.InitTriggerByChild();
new FeaturePopupItem(rootItem, this, "_DistortMode", () => Content("扭曲模式"), DistortModeNames,
property => rootItem.SyncService.ApplyToggleKeyword("_DISTORT_REFRACTION", property.floatValue > 0.5f),
keyword: "_DISTORT_REFRACTION");
TextureRelatedFoldOutItem noiseMapRelatedFoldOut = AddTextureWithRelatedFoldOut(rootItem, this, "_NoiseMap", "扭曲贴图", "_NoiseMapFoldOut", NBShaderFlags.FLAG_BIT_WRAPMODE_NOISEMAP,
isVisible: () => IsPropertyMode(rootItem, "_DistortMode", 0));
new UVModeSelectItem(rootItem, noiseMapRelatedFoldOut, "_NoiseUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_NOISE_MAP, 0, () => Content("扭曲贴图UV来源"), "_NoiseMap",
isVisible: () => IsPropertyMode(rootItem, "_DistortMode", 0));
new Vector2LineItem(rootItem, noiseMapRelatedFoldOut, "_DistortionDirection", true, () => Content("扭曲方向强度"), () => IsPropertyMode(rootItem, "_DistortMode", 0));
new CustomDataSelectItem(rootItem, noiseMapRelatedFoldOut, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_NOISE_DIRECTION_X, 2, () => Content("扭曲方向强度X自定义曲线"), () => IsPropertyMode(rootItem, "_DistortMode", 0));
new CustomDataSelectItem(rootItem, noiseMapRelatedFoldOut, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_NOISE_DIRECTION_Y, 2, () => Content("扭曲方向强度Y自定义曲线"), () => IsPropertyMode(rootItem, "_DistortMode", 0));
ShaderGUISliderItem noiseMapUVRotationItem = new ShaderGUISliderItem(rootItem, noiseMapRelatedFoldOut, () => IsPropertyMode(rootItem, "_DistortMode", 0))
{
PropertyName = "_NoiseMapUVRotation",
GuiContent = Content("扭曲旋转"),
Min = 0f,
Max = 360f
};
noiseMapUVRotationItem.InitTriggerByChild();
new Vector2LineItem(rootItem, noiseMapRelatedFoldOut, "_NoiseOffset", true, () => Content("扭曲偏移速度"), () => IsPropertyMode(rootItem, "_DistortMode", 0));
new ToggleItem(
rootItem,
noiseMapRelatedFoldOut,
"_DistortionBothDirection_Toggle",
() => Content("0.5为中值,双向扭曲"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_NOISEMAP_NORMALIZEED_ON, enabled),
() => IsPropertyMode(rootItem, "_DistortMode", 0));
ShaderGUISliderItem refractionIorItem = new ShaderGUISliderItem(
rootItem,
this,
TierVisible(rootItem, "_DISTORT_REFRACTION", () => IsPropertyMode(rootItem, "_DistortMode", 1)))
{
PropertyName = "_RefractionIOR",
GuiContent = Content("折射率"),
Min = 0f,
Max = 5f
};
refractionIorItem.InitTriggerByChild();
new PNoiseBlendModeItem(rootItem, this, NBShaderFlags.FLAG_BIT_PNOISE_BLEND_POS_0_DISTORT, "_DistortPNoiseBlendOpacity", () => Content("扭曲程序噪波混合"),
() => rootItem.Context.ProgramNoiseEnabled == MixedBool.True);
PropertyToggleBlockItem noiseMaskBlock = ToggleBlock(
rootItem,
"_NoiseMaskBlockFoldOut",
"_noiseMaskMap_Toggle",
"扭曲遮罩",
parent: this,
keyword: "_NOISE_MASKMAP");
AddTextureWithWrap(rootItem, noiseMaskBlock, "_NoiseMaskMap", "扭曲遮罩贴图", NBShaderFlags.FLAG_BIT_WRAPMODE_NOISE_MASKMAP);
new ColorChannelSelectItem(rootItem, noiseMaskBlock, NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_NOISE_MASK, 0, () => Content("扭曲遮罩图通道选择"));
new UVModeSelectItem(rootItem, noiseMaskBlock, "_NoiseMaskUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_NOISE_MASK_MAP, 0, () => Content("扭曲遮罩贴图UV来源"), "_NoiseMaskMap");
InitTriggerByChild();
}
private static int GetIntProperty(NBShaderRootItem rootItem, string propertyName)
{
return rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) && !info.Property.hasMixedValue
? Mathf.RoundToInt(info.Property.floatValue)
: 0;
}
private static bool IsPropertyGreater(NBShaderRootItem rootItem, string propertyName, float threshold)
{
return rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
info.Property.floatValue > threshold;
}
private static bool IsScreenDistortMode(NBShaderRootItem rootItem, int mode)
{
return rootItem.Context.UIEffectEnabled != MixedBool.True &&
IsPropertyMode(rootItem, ScreenDistortModePropertyName, mode);
}
private static bool HasActiveNBPostProcessRendererFeature()
{
try
{
RenderPipelineAsset pipelineAsset = GetCurrentRenderPipelineAsset();
if (pipelineAsset == null)
{
return false;
}
SerializedObject pipelineObject = new SerializedObject(pipelineAsset);
SerializedProperty rendererDataList = pipelineObject.FindProperty(RendererDataListPropertyName);
if (rendererDataList != null && rendererDataList.isArray)
{
for (int i = 0; i < rendererDataList.arraySize; i++)
{
UnityEngine.Object rendererData = rendererDataList.GetArrayElementAtIndex(i).objectReferenceValue;
if (RendererDataHasNBPostProcess(rendererData, requireActive: true))
{
return true;
}
}
return false;
}
SerializedProperty legacyRendererData = pipelineObject.FindProperty(LegacyRendererDataPropertyName);
return legacyRendererData != null && RendererDataHasNBPostProcess(legacyRendererData.objectReferenceValue, requireActive: true);
}
catch (Exception)
{
return false;
}
}
private static bool RendererDataHasNBPostProcess(UnityEngine.Object rendererData, bool requireActive)
{
if (rendererData == null)
{
return false;
}
SerializedObject rendererDataObject = new SerializedObject(rendererData);
SerializedProperty rendererFeatures = rendererDataObject.FindProperty(RendererFeaturesPropertyName);
if (rendererFeatures == null || !rendererFeatures.isArray)
{
return false;
}
for (int i = 0; i < rendererFeatures.arraySize; i++)
{
UnityEngine.Object rendererFeature = rendererFeatures.GetArrayElementAtIndex(i).objectReferenceValue;
if (IsNBPostProcessFeature(rendererFeature) &&
(!requireActive || IsRendererFeatureActive(rendererFeature)))
{
return true;
}
}
return false;
}
private static bool IsNBPostProcessFeature(UnityEngine.Object rendererFeature)
{
if (rendererFeature == null)
{
return false;
}
for (Type type = rendererFeature.GetType(); type != null; type = type.BaseType)
{
if (string.Equals(type.FullName, NBPostProcessTypeFullName, StringComparison.Ordinal) ||
string.Equals(type.Name, NBPostProcessTypeName, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
private static bool IsRendererFeatureActive(UnityEngine.Object rendererFeature)
{
if (rendererFeature == null)
{
return false;
}
if (TryGetBoolProperty(rendererFeature, RendererFeatureActivePropertyName, out bool isActive))
{
return isActive;
}
try
{
SerializedObject rendererFeatureObject = new SerializedObject(rendererFeature);
SerializedProperty activeProperty = rendererFeatureObject.FindProperty(RendererFeatureActiveSerializedPropertyName);
return activeProperty != null &&
activeProperty.propertyType == SerializedPropertyType.Boolean &&
activeProperty.boolValue;
}
catch (Exception)
{
return false;
}
}
private static bool HasCameraOpaqueTextureCopyEnabled()
{
try
{
RenderPipelineAsset pipelineAsset = GetCurrentRenderPipelineAsset();
if (pipelineAsset == null)
{
return false;
}
if (TryGetBoolProperty(pipelineAsset, OpaqueTexturePropertyName, out bool supportsCameraOpaqueTexture))
{
return supportsCameraOpaqueTexture;
}
SerializedObject pipelineObject = new SerializedObject(pipelineAsset);
SerializedProperty opaqueTextureProperty = pipelineObject.FindProperty(OpaqueTextureSerializedPropertyName);
return opaqueTextureProperty != null &&
opaqueTextureProperty.propertyType == SerializedPropertyType.Boolean &&
opaqueTextureProperty.boolValue;
}
catch (Exception)
{
return false;
}
}
private static UnityEngine.Object GetRendererDataForNBPostProcessPing()
{
try
{
RenderPipelineAsset pipelineAsset = GetCurrentRenderPipelineAsset();
if (pipelineAsset == null)
{
return null;
}
SerializedObject pipelineObject = new SerializedObject(pipelineAsset);
SerializedProperty rendererDataList = pipelineObject.FindProperty(RendererDataListPropertyName);
if (rendererDataList != null && rendererDataList.isArray)
{
return GetRendererDataForNBPostProcessPing(rendererDataList);
}
SerializedProperty legacyRendererData = pipelineObject.FindProperty(LegacyRendererDataPropertyName);
return legacyRendererData != null ? legacyRendererData.objectReferenceValue : null;
}
catch (Exception)
{
return null;
}
}
private static UnityEngine.Object GetRendererDataForNBPostProcessPing(SerializedProperty rendererDataList)
{
UnityEngine.Object firstRendererData = null;
UnityEngine.Object rendererDataWithInactiveFeature = null;
for (int i = 0; i < rendererDataList.arraySize; i++)
{
UnityEngine.Object rendererData = rendererDataList.GetArrayElementAtIndex(i).objectReferenceValue;
if (rendererData == null)
{
continue;
}
if (firstRendererData == null)
{
firstRendererData = rendererData;
}
if (RendererDataHasNBPostProcess(rendererData, requireActive: true))
{
return rendererData;
}
if (rendererDataWithInactiveFeature == null &&
RendererDataHasNBPostProcess(rendererData, requireActive: false))
{
rendererDataWithInactiveFeature = rendererData;
}
}
return rendererDataWithInactiveFeature != null ? rendererDataWithInactiveFeature : firstRendererData;
}
private static RenderPipelineAsset GetCurrentRenderPipelineAsset()
{
return QualitySettings.renderPipeline != null
? QualitySettings.renderPipeline
: GraphicsSettings.currentRenderPipeline;
}
private static bool TryGetBoolProperty(UnityEngine.Object target, string propertyName, out bool value)
{
value = false;
if (target == null)
{
return false;
}
try
{
PropertyInfo propertyInfo = target.GetType().GetProperty(
propertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (propertyInfo == null || propertyInfo.PropertyType != typeof(bool))
{
return false;
}
value = (bool)propertyInfo.GetValue(target, null);
return true;
}
catch (Exception)
{
return false;
}
}
private static GUIContent ButtonContent(string key, string fallback)
{
return NBShaderInspectorLocalization.MakeContent("inspector." + key + ".button", fallback);
}
private sealed class PingableHelpBoxItem : ShaderGUIItem
{
private const float HelpBoxPadding = 6f;
private const float HelpBoxButtonGap = 4f;
private const float MaxButtonWidth = 160f;
private static readonly GUIContent TempHelpContent = new GUIContent();
private readonly Func<string> _messageProvider;
private readonly MessageType _messageType;
private readonly Func<GUIContent> _buttonContentProvider;
private readonly Func<UnityEngine.Object> _targetProvider;
private readonly Func<bool> _isVisible;
public PingableHelpBoxItem(
ShaderGUIRootItem rootItem,
ShaderGUIItem parentItem,
Func<string> messageProvider,
MessageType messageType,
Func<GUIContent> buttonContentProvider,
Func<UnityEngine.Object> targetProvider,
Func<bool> isVisible) : base(rootItem, parentItem)
{
_messageProvider = messageProvider ?? (() => string.Empty);
_messageType = messageType;
_buttonContentProvider = buttonContentProvider ?? (() => GUIContent.none);
_targetProvider = targetProvider ?? (() => null);
_isVisible = isVisible;
}
public override void OnGUI()
{
if (_isVisible != null && !_isVisible())
{
return;
}
using (ParentControlDisabledScope())
{
string message = _messageProvider();
GUIContent buttonContent = _buttonContentProvider();
TempHelpContent.text = message;
float width = Mathf.Max(1f, EditorGUIUtility.currentViewWidth + GlobalRectWidthExpansion + GlobalRectXOffset);
float messageHeight = Mathf.Max(
EditorGUIUtility.singleLineHeight * 2f,
EditorStyles.helpBox.CalcHeight(TempHelpContent, width));
float buttonHeight = EditorGUIUtility.singleLineHeight;
float height = messageHeight + HelpBoxButtonGap + buttonHeight + HelpBoxPadding;
Rect rect = ApplyGlobalRectCompensation(LayoutRect(height));
EditorGUI.HelpBox(rect, message, _messageType);
float buttonWidth = Mathf.Min(
MaxButtonWidth,
Mathf.Max(90f, EditorStyles.miniButton.CalcSize(buttonContent).x + 18f));
buttonWidth = Mathf.Min(buttonWidth, Mathf.Max(0f, rect.width - HelpBoxPadding * 2f));
Rect buttonRect = new Rect(
rect.xMax - HelpBoxPadding - buttonWidth,
rect.yMax - HelpBoxPadding - buttonHeight,
buttonWidth,
buttonHeight);
UnityEngine.Object target = _targetProvider();
using (new EditorGUI.DisabledScope(target == null))
{
if (GUI.Button(buttonRect, buttonContent, EditorStyles.miniButton))
{
Selection.activeObject = target;
EditorGUIUtility.PingObject(target);
}
}
TempHelpContent.text = string.Empty;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,35 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class ParallaxFeatureItem : FeatureToggleFoldOutItem
{
public ParallaxFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_ParallaxBlockFoldOut", "_ParallaxMapping_Toggle", "遮蔽视差", keyword: "_PARALLAX_MAPPING", isVisible: () => rootItem.Context.UIEffectEnabled != MixedBool.True)
{
AddTextureWithWrap(rootItem, this, "_ParallaxMapping_Map", "视差贴图", NBShaderFlags.FLAG_BIT_WRAPMODE_PARALLAXMAPPINGMAP);
ShaderGUISliderItem parallaxMappingIntensityItem = new ShaderGUISliderItem(rootItem, this)
{
PropertyName = "_ParallaxMapping_Intensity",
GuiContent = Content("视差"),
RangePropertyName = "_ParallaxMapping_IntensityRangeVec"
};
parallaxMappingIntensityItem.InitTriggerByChild();
new VectorComponentItem(rootItem, this, "_ParallaxMapping_Vec", 0, () => Content("遮蔽视差最小层数"), true, 0f, 100f);
new VectorComponentItem(rootItem, this, "_ParallaxMapping_Vec", 1, () => Content("遮蔽视差最大层数"), true, 0f, 100f);
new HelpBoxItem(rootItem, this, () => Text("feature.parallax.layerWarning.message", "遮蔽视差层数过高将影响性能"), MessageType.Warning,
() => IsParallaxMaxLayerHigh(rootItem));
InitTriggerByChild();
}
private static bool IsParallaxMaxLayerHigh(NBShaderRootItem rootItem)
{
return rootItem.PropertyInfoDic.TryGetValue("_ParallaxMapping_Vec", out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
info.Property.vectorValue.y >= 20f;
}
}
}

View File

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

View File

@@ -0,0 +1,17 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class PortalFeatureItem : FeatureToggleFoldOutItem
{
public PortalFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_PortalBlockFoldOut", "_Portal_Toggle", "模板视差", onValueChanged: _ => rootItem.SyncService.ApplyPortalState(), isVisible: () => rootItem.Context.UIEffectEnabled != MixedBool.True)
{
new ToggleItem(rootItem, this, "_Portal_MaskToggle", () => Content("模板视差蒙版"), _ => rootItem.SyncService.ApplyPortalState());
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,58 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class ProgramNoiseFeatureItem : FeatureToggleFoldOutItem
{
public ProgramNoiseFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_ProgramNoiseBlockFoldOut", "_ProgramNoise_Toggle", "程序化噪波", keyword: "_PROGRAM_NOISE")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_PNoise",
"NB_DEBUG_PNOISE",
() => Content("程序化噪波测试颜色"),
isVisible: null);
new UVModeSelectItem(rootItem, this, "_ProgramNoiseUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_PROGRAM_NOISE, 0, () => Content("程序噪波UV来源"), forceEnable: true);
ShaderGUIFloatItem programNoiseRotateItem = new ShaderGUIFloatItem(rootItem, this)
{
PropertyName = "_ProgramNoise_Rotate",
GuiContent = Content("程序化噪波旋转")
};
programNoiseRotateItem.InitTriggerByChild();
PropertyToggleBlockItem simpleBlock = ToggleBlock(rootItem, "_ProgramNoiseSimpleFoldOut", "_ProgramNoise_Simple_Toggle", "Perlin噪波",
parent: this, keyword: "_PROGRAM_NOISE_SIMPLE");
new Vector2LineItem(rootItem, simpleBlock, "_DissolveVoronoi_Vec", true, () => Content("噪波1缩放"));
new VectorComponentItem(rootItem, simpleBlock, "_DissolveVoronoi_Vec2", 2, () => Content("噪波1速度"), false);
new Vector2LineItem(rootItem, simpleBlock, "_DissolveVoronoi_Vec4", true, () => Content("噪波1偏移"));
new Vector2LineItem(rootItem, simpleBlock, "_DissolveVoronoi_Vec3", true, () => Content("噪波1偏移速度"));
new CustomDataSelectItem(rootItem, simpleBlock, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_DISSOLVE_NOISE1_OFFSET_X, 2, () => Content("噪波1偏移速度X自定义曲线"));
new CustomDataSelectItem(rootItem, simpleBlock, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_DISSOLVE_NOISE1_OFFSET_Y, 2, () => Content("噪波1偏移速度Y自定义曲线"));
PropertyToggleBlockItem voronoiBlock = ToggleBlock(rootItem, "_ProgramNoiseVoronoiFoldOut", "_ProgramNoise_Voronoi_Toggle", "Voronoi噪波",
parent: this, keyword: "_PROGRAM_NOISE_VORONOI");
new Vector2LineItem(rootItem, voronoiBlock, "_DissolveVoronoi_Vec", false, () => Content("噪波2缩放"));
new VectorComponentItem(rootItem, voronoiBlock, "_DissolveVoronoi_Vec2", 3, () => Content("噪波2速度"), false);
new Vector2LineItem(rootItem, voronoiBlock, "_DissolveVoronoi_Vec4", false, () => Content("噪波2偏移"));
new Vector2LineItem(rootItem, voronoiBlock, "_DissolveVoronoi_Vec3", false, () => Content("噪波2偏移速度"));
new CustomDataSelectItem(rootItem, voronoiBlock, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_DISSOLVE_NOISE2_OFFSET_X, 2, () => Content("噪波2偏移速度X自定义曲线"));
new CustomDataSelectItem(rootItem, voronoiBlock, NBShaderFlags.FLAGBIT_POS_2_CUSTOMDATA_DISSOLVE_NOISE2_OFFSET_Y, 2, () => Content("噪波2偏移速度Y自定义曲线"));
new VectorComponentItem(rootItem, this, "_DissolveVoronoi_Vec2", 0, () => Content("噪波1和噪波2混合系数"), true);
new PNoiseBlendModeItem(
rootItem,
this,
NBShaderFlags.FLAG_BIT_PNOISE_BLEND_POS_0_BASE_BLEND,
"_ProgramNoiseBaseBlendOpacity",
() => Content("两种程序噪波混合"),
() => rootItem.Context.ProgramNoiseEnabled == MixedBool.True &&
rootItem.Context.IsToggleOn("_ProgramNoise_Simple_Toggle") &&
rootItem.Context.IsToggleOn("_ProgramNoise_Voronoi_Toggle"));
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,37 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class RampColorFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] RampSourceNames = { "渐变", "贴图" };
private static readonly string[] BlendModeNames = { "叠加", "相乘" };
public RampColorFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_RampColorBlockFoldOut", "_RampColorToggle", "颜色映射(Ramp)", keyword: "_COLOR_RAMP")
{
Func<bool> isRampMapVisible = TierVisible(rootItem, "_COLOR_RAMP_MAP", () => IsPropertyMode(rootItem, "_RampColorSourceMode", 1));
new FeaturePopupItem(rootItem, this, "_RampColorSourceMode", () => Content("Ramp来源模式"), RampSourceNames,
_ => rootItem.SyncService.SyncMaterialState(),
keyword: "_COLOR_RAMP_MAP");
AddTextureWithWrap(rootItem, this, "_RampColorMap", "颜色映射黑白图", NBShaderFlags.FLAG_BIT_WRAPMODE_RAMP_COLOR_MAP,
isVisible: isRampMapVisible);
new TextureScaleOffsetItem(rootItem, this, "_RampColorMap", false, () => IsPropertyMode(rootItem, "_RampColorSourceMode", 0), TillingContent, OffsetContent);
new WrapModeItem(rootItem, this, NBShaderFlags.FLAG_BIT_WRAPMODE_RAMP_COLOR_MAP, () => Content("颜色映射UV Wrap"), 2,
() => IsPropertyMode(rootItem, "_RampColorSourceMode", 0));
new ColorChannelSelectItem(rootItem, this, NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_RAMP_COLOR_MAP, 0, () => Content("颜色映射黑白图通道选择"),
isRampMapVisible);
new UVModeSelectItem(rootItem, this, "_RampColorUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_RAMP_COLOR_MAP, 0, () => Content("颜色映射黑白图UV来源"), "_RampColorMap", true);
new Vector2LineItem(rootItem, this, "_RampColorMapOffset", true, () => Content("颜色映射贴图偏移速度"));
new VectorComponentItem(rootItem, this, "_RampColorMapOffset", 3, () => Content("颜色映射贴图旋转"), true, 0f, 360f);
AddGradient(rootItem, this, "映射颜色", "_RampColorCount", "_RampColor", "_RampColorAlpha", hdr: true);
new FeaturePopupItem(rootItem, this, "_RampColorBlendMode", () => Content("Ramp颜色混合模式"), BlendModeNames,
property => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_RAMP_COLOR_BLEND_ADD, property.floatValue > 0.5f));
new ColorItem(rootItem, this, "_RampColorBlendColor", () => Content("颜色映射叠加颜色"));
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,24 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class SharedUVFeatureItem : FeatureToggleFoldOutItem
{
public SharedUVFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_SharedUVBlockFoldOut", "_SharedUVToggle", "公共UV", keyword: "_SHARED_UV")
{
new UVModeSelectItem(rootItem, this, "_SharedUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_SHAREDUV, 0, () => Content("公共UV来源"), forceEnable: true);
new Vector2LineItem(rootItem, this, "_SharedUV_ST", true, () => Content("公共UV Tiling"));
new Vector2LineItem(rootItem, this, "_SharedUV_ST", false, () => Content("公共UV Offset"));
new Vector2LineItem(rootItem, this, "_SharedUV_Vec", true, () => Content("公共UV偏移速度"));
new VectorComponentItem(rootItem, this, "_SharedUV_Vec", 2, () => Content("旋转"), false);
new VectorComponentItem(rootItem, this, "_SharedUV_Vec", 3, () => Content("旋转速度"), false);
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_SHARED_UV_OFFSET_X, 3, () => Content("公共UV X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_SHARED_UV_OFFSET_Y, 3, () => Content("公共UV Y轴偏移自定义曲线"));
InitTriggerByChild();
}
}
}

View File

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

View File

@@ -0,0 +1,428 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class VatFeatureItem : FeatureToggleFoldOutItem
{
private static readonly string[] VatModeNames = { "Houdini", "TyFlow" };
private static readonly string[] HoudiniVatSubModeNames =
{
"SoftBody (Deformation)",
"RigidBody (Pieces)",
"Dynamic Remeshing (Lookup)",
"Particle Sprites (Billboard)"
};
private static readonly string[] TyFlowVatSubModeNames =
{
"Absolute positions",
"Relative offsets",
"Skin (R)",
"Skin (PR)",
"Skin (PRSAVE)",
"Skin (PRSXYZ)"
};
public VatFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_VATBlockFoldOut", "_VAT_Toggle", "VAT顶点动画图", keyword: "_VAT", onValueChanged: rootItem.SyncService.ApplyVatEnabled)
{
new FeaturePopupItem(rootItem, this, "_VATMode", () => Content("VAT模式"), VatModeNames, _ => rootItem.SyncService.SyncMaterialState());
Func<bool> isHoudini = () => IsPropertyMode(rootItem, "_VATMode", (int)VATMode.Houdini);
Func<bool> isTyflow = () => IsPropertyMode(rootItem, "_VATMode", (int)VATMode.Tyflow);
Func<bool> hasVatFrameCustomData = () => IsVatFrameCustomDataVisible(rootItem);
ShaderGUIFloatItem floatItem;
new FeaturePopupItem(rootItem, this, "_HoudiniVATSubMode", () => Content("Houdini VAT Sub Mode"), HoudiniVatSubModeNames,
_ => rootItem.SyncService.SyncMaterialState(), isHoudini);
new HelpBoxItem(rootItem, this, () => Text("feature.vat.houdiniUnsupportedParticle.message", "该 Houdini VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。"), MessageType.Warning,
() => isHoudini() && HasUnsupportedHoudiniParticleMode(rootItem));
new SectionLabelItem(rootItem, this, () => Content("Playback"), isHoudini);
new ToggleItem(rootItem, this, "_B_autoPlayback", () => Content("Auto Playback"), isVisible: isHoudini);
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && ShouldDrawWhenFloatOff(rootItem, "_B_autoPlayback"))
{
PropertyName = "_displayFrame",
GuiContent = Content("Display Frame")
};
floatItem.InitTriggerByChild();
new VatFrameCustomDataItem(rootItem, this, () => Content("VAT Frame CustomData"), () => isHoudini() && hasVatFrameCustomData(), hasVatFrameCustomData);
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_gameTimeAtFirstFrame",
GuiContent = Content("Game Time at First Frame")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_playbackSpeed",
GuiContent = Content("Playback Speed")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_houdiniFPS",
GuiContent = Content("Houdini FPS")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_B_interpolate", () => Content("Interframe Interpolation"), isVisible: isHoudini);
new ToggleItem(rootItem, this, "_animateFirstFrame", () => Content("Animate First Frame"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 1));
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_frameCount",
GuiContent = Content("Frame Count")
};
floatItem.InitTriggerByChild();
new SectionLabelItem(rootItem, this, () => Content("Bounds Metadata"), isHoudini);
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMinX",
GuiContent = Content("Bound Min X")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMinY",
GuiContent = Content("Bound Min Y")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMinZ",
GuiContent = Content("Bound Min Z")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMaxX",
GuiContent = Content("Bound Max X")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMaxY",
GuiContent = Content("Bound Max Y")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, isHoudini)
{
PropertyName = "_boundMaxZ",
GuiContent = Content("Bound Max Z")
};
floatItem.InitTriggerByChild();
new SectionLabelItem(rootItem, this, () => Content("Textures"), isHoudini);
new TextureItem(rootItem, this, "_posTexture", () => Content("Position Texture"), drawScaleOffset: false, isVisible: isHoudini);
new TextureItem(rootItem, this, "_posTexture2", () => Content("Position Texture 2"), drawScaleOffset: false,
isVisible: () => isHoudini() && ShouldDrawWhenFloatOn(rootItem, "_B_LOAD_POS_TWO_TEX"));
new TextureItem(rootItem, this, "_rotTexture", () => Content("Rotation Texture"), drawScaleOffset: false,
isVisible: () => isHoudini() && ShouldDrawHoudiniRotationTexture(rootItem));
new TextureItem(rootItem, this, "_colTexture", () => Content("Color Texture"), drawScaleOffset: false,
isVisible: () => isHoudini() && ShouldDrawWhenFloatOn(rootItem, "_B_LOAD_COL_TEX"));
new TextureItem(rootItem, this, "_lookupTable", () => Content("Lookup Table"), drawScaleOffset: false,
isVisible: () => isHoudini() && (IsPropertyMode(rootItem, "_HoudiniVATSubMode", 2) || ShouldDrawWhenFloatOn(rootItem, "_B_LOAD_LOOKUP_TABLE")));
new SectionLabelItem(rootItem, this, () => Content("Scale"), () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 1, 3));
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 1, 3))
{
PropertyName = "_globalPscaleMul",
GuiContent = Content("Global Piece Scale Multiplier")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_B_pscaleAreInPosA", () => Content("Piece Scales in Position Alpha"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 1, 3));
new SectionLabelItem(rootItem, this, () => Content("Particle Sprite"), () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3));
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3))
{
PropertyName = "_widthBaseScale",
GuiContent = Content("Width Base Scale")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3))
{
PropertyName = "_heightBaseScale",
GuiContent = Content("Height Base Scale")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_B_hideOverlappingOrigin", () => Content("Hide Overlapping Origin"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3));
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3) && ShouldDrawWhenFloatOn(rootItem, "_B_hideOverlappingOrigin"))
{
PropertyName = "_originRadius",
GuiContent = Content("Origin Effective Radius")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_B_CAN_SPIN", () => Content("Particles Can Spin"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3));
new ToggleItem(rootItem, this, "_B_spinFromHeading", () => Content("Compute Spin from Heading"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3) && ShouldDrawWhenFloatOn(rootItem, "_B_CAN_SPIN"));
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3) && ShouldDrawWhenFloatOn(rootItem, "_B_CAN_SPIN") && ShouldDrawWhenFloatOff(rootItem, "_B_spinFromHeading"))
{
PropertyName = "_spinPhase",
GuiContent = Content("Particle Spin Phase")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3) && ShouldDrawWhenFloatOn(rootItem, "_B_CAN_SPIN"))
{
PropertyName = "_scaleByVelAmount",
GuiContent = Content("Scale by Velocity Amount")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3))
{
PropertyName = "_particleTexUScale",
GuiContent = Content("Particle Texture U Scale")
};
floatItem.InitTriggerByChild();
floatItem = new ShaderGUIFloatItem(rootItem, this, () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 3))
{
PropertyName = "_particleTexVScale",
GuiContent = Content("Particle Texture V Scale")
};
floatItem.InitTriggerByChild();
new SectionLabelItem(rootItem, this, () => Content("Flags"), isHoudini);
new ToggleItem(rootItem, this, "_B_LOAD_POS_TWO_TEX", () => Content("Positions Require Two Textures"), isVisible: isHoudini);
new ToggleItem(rootItem, this, "_B_UNLOAD_ROT_TEX", () => Content("Use Compressed Normals (no rotTex)"), isVisible: () => isHoudini() && ShouldDrawCompressedNormalsToggle(rootItem));
new ToggleItem(rootItem, this, "_B_LOAD_COL_TEX", () => Content("Load Color Texture"), isVisible: isHoudini);
new ToggleItem(rootItem, this, "_B_LOAD_LOOKUP_TABLE", () => Content("Load Lookup Table"), isVisible: () => isHoudini() && IsPropertyMode(rootItem, "_HoudiniVATSubMode", 2));
new TextureItem(rootItem, this, "_VATTex", () => Content("VAT texture"), drawScaleOffset: false, isVisible: isTyflow);
floatItem = new ShaderGUIFloatItem(rootItem, this, isTyflow)
{
PropertyName = "_ImportScale",
GuiContent = Content("ImportScale")
};
floatItem.InitTriggerByChild();
new FeaturePopupItem(rootItem, this, "_TyFlowVATSubMode", () => Content("TyFlow VAT Sub Mode"), TyFlowVatSubModeNames,
_ => rootItem.SyncService.SyncMaterialState(), isTyflow);
new HelpBoxItem(rootItem, this, () => Text("feature.vat.tyflowUnsupportedParticle.message", "该 TyFlow VAT 类型需要 Mesh 多 UV 数据,不支持 ParticleSystem VertexStream 模式。"), MessageType.Warning,
() => isTyflow() && HasUnsupportedTyflowParticleMode(rootItem));
new HelpBoxItem(rootItem, this, () => Text("feature.vat.tyflowUv2Conflict.message", "TyFlow VAT uses UV2 (TEXCOORD0.zw) as vertexIndex / vertexCount in ParticleSystem mode. Flipbook blending or Special UV (UV2) conflicts with it; VAT takes priority."), MessageType.Warning,
() => isTyflow() && !HasUnsupportedTyflowParticleMode(rootItem) && HasTyflowParticleUV2Conflict(rootItem));
new ToggleItem(rootItem, this, "_DeformingSkin", () => Content("Deforming skin"), isVisible: isTyflow);
floatItem = new ShaderGUIFloatItem(rootItem, this, isTyflow)
{
PropertyName = "_SkinBoneCount",
GuiContent = Content("Skin bone count")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_RGBAEncoded", () => Content("RGBA encoded"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_RGBAHalf", () => Content("RGBA half"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_LinearToGamma", () => Content("Gamma correction"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_VATIncludesNormals", () => Content("VAT includes normals"), isVisible: isTyflow);
floatItem = new ShaderGUIFloatItem(rootItem, this, isTyflow)
{
PropertyName = "_Frame",
GuiContent = Content("Frame")
};
floatItem.InitTriggerByChild();
new VatFrameCustomDataItem(rootItem, this, () => Content("VAT Frame CustomData"), () => isTyflow() && hasVatFrameCustomData(), hasVatFrameCustomData);
floatItem = new ShaderGUIFloatItem(rootItem, this, isTyflow)
{
PropertyName = "_Frames",
GuiContent = Content("Frames")
};
floatItem.InitTriggerByChild();
new ToggleItem(rootItem, this, "_FrameInterpolation", () => Content("Frame interpolation"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_Loop", () => Content("Loop"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_InterpolateLoop", () => Content("Interpolate loop"), isVisible: isTyflow);
new ToggleItem(rootItem, this, "_Autoplay", () => Content("Autoplay"), isVisible: isTyflow);
floatItem = new ShaderGUIFloatItem(rootItem, this, isTyflow)
{
PropertyName = "_AutoplaySpeed",
GuiContent = Content("AutoplaySpeed")
};
floatItem.InitTriggerByChild();
InitTriggerByChild();
}
private static bool ShouldDrawWhenFloatOn(NBShaderRootItem rootItem, string propertyName)
{
if (!rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info))
{
return false;
}
return info.Property.hasMixedValue || info.Property.floatValue > 0.5f;
}
private static bool ShouldDrawWhenFloatOff(NBShaderRootItem rootItem, string propertyName)
{
if (!rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info))
{
return false;
}
return info.Property.hasMixedValue || info.Property.floatValue <= 0.5f;
}
private static bool TryGetPropertyMode(NBShaderRootItem rootItem, string propertyName, out int mode)
{
mode = 0;
if (!rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) ||
info.Property.hasMixedValue)
{
return false;
}
mode = Mathf.RoundToInt(info.Property.floatValue);
return true;
}
private static bool ShouldDrawHoudiniRotationTexture(NBShaderRootItem rootItem)
{
return TryGetPropertyMode(rootItem, "_HoudiniVATSubMode", out int subMode) &&
subMode != 3 &&
ShouldDrawWhenFloatOff(rootItem, "_B_UNLOAD_ROT_TEX");
}
private static bool ShouldDrawCompressedNormalsToggle(NBShaderRootItem rootItem)
{
return TryGetPropertyMode(rootItem, "_HoudiniVATSubMode", out int subMode) && subMode != 3;
}
private static bool IsVatFrameCustomDataVisible(NBShaderRootItem rootItem)
{
return IsAnyHoudiniParticleModeEnabled(rootItem) || IsAnyTyflowParticleModeEnabled(rootItem);
}
private static bool HasTyflowParticleUV2Conflict(NBShaderRootItem rootItem)
{
if (rootItem.Mats == null || rootItem.ShaderFlags == null)
{
return false;
}
int count = Mathf.Min(rootItem.Mats.Count, rootItem.ShaderFlags.Count);
for (int i = 0; i < count; i++)
{
Material mat = rootItem.Mats[i];
if (!IsTyflowParticleModeEnabled(mat) ||
!(rootItem.ShaderFlags[i] is NBShaderFlags flags))
{
continue;
}
bool flipbook = mat.IsKeywordEnabled("_FLIPBOOKBLENDING_ON");
bool specialUVUsesUV2 = flags.CheckIsUVModeOn(NBShaderFlags.UVMode.SpecialUVChannel) &&
!flags.CheckFlagBits(NBShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD2, index: 1);
if (flipbook || specialUVUsesUV2)
{
return true;
}
}
return false;
}
private static bool IsAnyHoudiniParticleModeEnabled(NBShaderRootItem rootItem)
{
if (rootItem.Mats == null)
{
return false;
}
for (int i = 0; i < rootItem.Mats.Count; i++)
{
if (IsHoudiniParticleModeEnabled(rootItem.Mats[i]))
{
return true;
}
}
return false;
}
private static bool IsAnyTyflowParticleModeEnabled(NBShaderRootItem rootItem)
{
if (rootItem.Mats == null)
{
return false;
}
for (int i = 0; i < rootItem.Mats.Count; i++)
{
if (IsTyflowParticleModeEnabled(rootItem.Mats[i]))
{
return true;
}
}
return false;
}
private static bool HasUnsupportedHoudiniParticleMode(NBShaderRootItem rootItem)
{
if (rootItem.Mats == null)
{
return false;
}
for (int i = 0; i < rootItem.Mats.Count; i++)
{
Material mat = rootItem.Mats[i];
if (IsHoudiniParticleModeEnabled(mat) &&
GetMaterialInt(mat, "_HoudiniVATSubMode", 0) == 1)
{
return true;
}
}
return false;
}
private static bool HasUnsupportedTyflowParticleMode(NBShaderRootItem rootItem)
{
if (rootItem.Mats == null)
{
return false;
}
for (int i = 0; i < rootItem.Mats.Count; i++)
{
Material mat = rootItem.Mats[i];
if (IsVatParticleMode(mat, (int)VATMode.Tyflow) &&
GetMaterialInt(mat, "_TyFlowVATSubMode", 0) >= 2)
{
return true;
}
}
return false;
}
private static bool IsHoudiniParticleModeEnabled(Material mat)
{
return IsVatParticleMode(mat, (int)VATMode.Houdini);
}
private static bool IsTyflowParticleModeEnabled(Material mat)
{
return IsVatParticleMode(mat, (int)VATMode.Tyflow) &&
(!mat.HasProperty("_TyFlowVATSubMode") || Mathf.RoundToInt(mat.GetFloat("_TyFlowVATSubMode")) <= 1);
}
private static bool IsVatParticleMode(Material mat, int vatMode)
{
if (mat == null ||
!mat.HasProperty("_VAT_Toggle") ||
!mat.HasProperty("_VATMode") ||
!mat.HasProperty("_MeshSourceMode") ||
mat.GetFloat("_VAT_Toggle") <= 0.5f ||
Mathf.RoundToInt(mat.GetFloat("_VATMode")) != vatMode)
{
return false;
}
MeshSourceMode meshSourceMode = (MeshSourceMode)Mathf.RoundToInt(mat.GetFloat("_MeshSourceMode"));
return meshSourceMode == MeshSourceMode.Particle ||
meshSourceMode == MeshSourceMode.UIParticle;
}
private static int GetMaterialInt(Material mat, string propertyName, int defaultValue)
{
return mat != null && mat.HasProperty(propertyName)
? Mathf.RoundToInt(mat.GetFloat(propertyName))
: defaultValue;
}
}
}

View File

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

View File

@@ -0,0 +1,62 @@
using System;
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
internal sealed class VertexOffsetFeatureItem : FeatureToggleFoldOutItem
{
public VertexOffsetFeatureItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(rootItem, parentItem, "_VertexOffsetBlockFoldOut", "_VertexOffset_Toggle", "顶点偏移", keyword: "_VERTEX_OFFSET")
{
new NBShaderKeywordToggleItem(
rootItem,
this,
"_NB_Debug_VertexOffset",
"NB_DEBUG_VERTEX_OFFSET",
() => Content("顶点偏移方向测试"),
isVisible: null);
AddTextureWithWrap(rootItem, this, "_VertexOffset_Map", "顶点偏移贴图", NBShaderFlags.FLAG_BIT_WRAPMODE_VERTEXOFFSETMAP);
new UVModeSelectItem(rootItem, this, "_VertexOffsetUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_VERTEX_OFFSET_MAP, 0, () => Content("顶点偏移贴图UV来源"), "_VertexOffset_Map");
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_VERTEX_OFFSET_X, 1, () => Content("顶点扰动X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_VERTEX_OFFSET_Y, 1, () => Content("顶点扰动Y轴偏移自定义曲线"));
new Vector2LineItem(rootItem, this, "_VertexOffset_Vec", true, () => Content("顶点偏移动画"));
new VectorComponentItem(rootItem, this, "_VertexOffset_Vec", 2, () => Content("顶点偏移强度"), false);
new CustomDataSelectItem(rootItem, this, NBShaderFlags.FLAGBIT_POS_1_CUSTOMDATA_VERTEXOFFSET_INTENSITY, 1, () => Content("顶点扰动强度自定义曲线"));
new ToggleItem(
rootItem,
this,
"_VertexOffset_StartFromZero",
() => Content("顶点偏移从零开始"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_1_VERTEXOFFSET_START_FROM_ZERO, enabled, 1));
new ToggleItem(
rootItem,
this,
"_VertexOffset_NormalDir_Toggle",
() => Content("顶点偏移使用法线方向"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_VERTEX_OFFSET_NORMAL_DIR, enabled));
Func<bool> showCustomDirection = () => IsPropertyOff(rootItem, "_VertexOffset_NormalDir_Toggle");
new VectorComponentItem(rootItem, this, "_VertexOffset_CustomDir", 0, () => Content("顶点偏移本地方向X"), false, isVisible: showCustomDirection);
new VectorComponentItem(rootItem, this, "_VertexOffset_CustomDir", 1, () => Content("顶点偏移本地方向Y"), false, isVisible: showCustomDirection);
new VectorComponentItem(rootItem, this, "_VertexOffset_CustomDir", 2, () => Content("顶点偏移本地方向Z"), false, isVisible: showCustomDirection);
PropertyToggleBlockItem maskBlock = ToggleBlock(rootItem, "_VertexOffsetMaskBlockFoldOut", "_VertexOffset_Mask_Toggle", "顶点偏移遮罩",
parent: this, keyword: "_VERTEX_OFFSET_MASKMAP");
AddTextureWithWrap(rootItem, maskBlock, "_VertexOffset_MaskMap", "顶点偏移遮罩图", NBShaderFlags.FLAG_BIT_WRAPMODE_VERTEXOFFSET_MASKMAP);
new UVModeSelectItem(rootItem, maskBlock, "_VertexOffsetMaskUVModeFoldOut", NBShaderFlags.FLAG_BIT_UVMODE_POS_0_VERTEX_OFFSET_MASKMAP, 0, () => Content("顶点偏移遮罩图UV来源"), "_VertexOffset_MaskMap");
new CustomDataSelectItem(rootItem, maskBlock, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_VERTEX_OFFSET_MASK_X, 3, () => Content("顶点扰动遮罩X轴偏移自定义曲线"));
new CustomDataSelectItem(rootItem, maskBlock, NBShaderFlags.FLAGBIT_POS_3_CUSTOMDATA_VERTEX_OFFSET_MASK_Y, 3, () => Content("顶点扰动遮罩Y轴偏移自定义曲线"));
new Vector2LineItem(rootItem, maskBlock, "_VertexOffset_MaskMap_Vec", true, () => Content("顶点偏移遮罩动画"));
new VectorComponentItem(rootItem, maskBlock, "_VertexOffset_MaskMap_Vec", 2, () => Content("顶点偏移遮罩强度"), true);
InitTriggerByChild();
}
private static bool IsPropertyOff(NBShaderRootItem rootItem, string propertyName)
{
return rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info) &&
!info.Property.hasMixedValue &&
info.Property.floatValue <= 0.5f;
}
}
}

View File

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

View File

@@ -0,0 +1,358 @@
using NBShader;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
public enum FxLightMode
{
UnLit = 0,
BlinnPhong = 1,
HalfLambert = 2,
PBR = 3,
SixWay = 4,
UnKnownOrMixedValue = -1
}
public class LightBigBlockItem : BigBlockItem
{
private readonly NBShaderRootItem _nbRootItem;
private readonly FxLightModePopupItem _lightModeItem;
private readonly ToggleItem _specularToggleItem;
private readonly ColorItem _specularColorItem;
private readonly VectorComponentItem _specularSmoothnessItem;
private readonly VectorComponentItem _pbrMetallicItem;
private readonly VectorComponentItem _pbrSmoothnessItem;
private readonly PropertyToggleBlockItem _bumpBlock;
private readonly PropertyToggleBlockItem _matCapBlock;
private readonly TextureItem _sixWayPositiveItem;
private readonly TextureItem _sixWayNegativeItem;
private readonly ToggleItem _sixWayAbsorptionToggleItem;
private readonly VectorComponentItem _sixWayAbsorptionStrengthItem;
private readonly TextureItem _sixWayEmissionRampItem;
private readonly VectorComponentItem _sixWayEmissionPowItem;
private readonly ColorItem _sixWayEmissionColorItem;
public LightBigBlockItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_LightBigBlockItemFoldOut",
() => Content("block.light", "Light", "Normal, MatCap and light mode controls"))
{
_nbRootItem = rootItem;
_lightModeItem = new FxLightModePopupItem(rootItem, this);
_specularToggleItem = new NBShaderKeywordToggleItem(
rootItem,
this,
"_BlinnPhongSpecularToggle",
"_SPECULAR_COLOR",
() => Content("light.specular.toggle", "Specular"),
isVisible: () => IsBlinnOrHalf(rootItem));
_specularColorItem = new ColorItem(
rootItem,
this,
"_SpecularColor",
() => Content("light.specular.color", "Specular Color"),
() => IsToggleOn(rootItem, "_BlinnPhongSpecularToggle") && IsBlinnOrHalf(rootItem));
_specularSmoothnessItem = new VectorComponentItem(
rootItem,
this,
"_MaterialInfo",
1,
() => Content("light.specular.smoothness", "Smoothness"),
true,
0f,
1f,
() => IsToggleOn(rootItem, "_BlinnPhongSpecularToggle") && IsBlinnOrHalf(rootItem));
_pbrMetallicItem = new VectorComponentItem(
rootItem,
this,
"_MaterialInfo",
0,
() => Content("light.pbr.metallic", "Metallic"),
true,
0f,
1f,
() => rootItem.Context.FxLightMode == FxLightMode.PBR);
_pbrSmoothnessItem = new VectorComponentItem(
rootItem,
this,
"_MaterialInfo",
1,
() => Content("light.pbr.smoothness", "Smoothness"),
true,
0f,
1f,
() => rootItem.Context.FxLightMode == FxLightMode.PBR);
_bumpBlock = new PropertyToggleBlockItem(
rootItem,
this,
"_BumpToggleFoldOut",
"_BumpMapToggle",
() => Content("light.bump.toggle", "Normal Map"),
keyword: "_NORMALMAP",
isVisible: () => rootItem.Context.FxLightMode != FxLightMode.SixWay);
new TextureItem(
rootItem,
_bumpBlock,
"_BumpTex",
() => Content("light.bump.texture", "Normal Map"),
drawScaleOffset: true);
TextureRelatedFoldOutItem bumpTexRelatedFoldOut = new TextureRelatedFoldOutItem(
rootItem,
_bumpBlock,
"_BumpTexFoldOut",
"_BumpTex",
() => Content("light.bump.related", "Normal Map Related"));
new WrapModeItem(rootItem, bumpTexRelatedFoldOut, NBShaderFlags.FLAG_BIT_WRAPMODE_BUMPTEX, () => Content("light.bump.wrap", "Normal Map Wrap"));
new UVModeSelectItem(
rootItem,
bumpTexRelatedFoldOut,
"_BumpUVModeFoldOut",
NBShaderFlags.FLAG_BIT_UVMODE_POS_0_BUMPMAP,
0,
() => Content("light.bump.uvmode", "Normal Map UV Source"),
"_BumpTex");
new ToggleItem(
rootItem,
bumpTexRelatedFoldOut,
"_BumpMapMaskMode",
() => Content("light.bump.maskMode", "Normal Map Multi Channel"),
enabled => rootItem.SyncService.ApplyToggleFlag(NBShaderFlags.FLAG_BIT_PARTICLE_NORMALMAP_MASK_MODE, enabled));
ShaderGUISliderItem bumpScaleItem = new ShaderGUISliderItem(rootItem, bumpTexRelatedFoldOut)
{
PropertyName = "_BumpScale",
GuiContent = Content("light.bump.scale", "Normal Strength"),
RangePropertyName = "BumpScaleRangeVec"
};
bumpScaleItem.InitTriggerByChild();
_matCapBlock = new PropertyToggleBlockItem(
rootItem,
this,
"_MatCapFoldOut",
"_MatCapToggle",
() => Content("light.matcap.toggle", "MatCap"),
keyword: "_MATCAP",
isVisible: () => rootItem.Context.FxLightMode != FxLightMode.SixWay);
new TextureItem(rootItem, _matCapBlock, "_MatCapTex", () => Content("light.matcap.texture", "MatCap Texture"), "_MatCapColor", false);
new VectorComponentItem(rootItem, _matCapBlock, "_MatCapInfo", 0, () => Content("light.matcap.blend", "Add/Multiply Blend"), true, 0f, 1f);
_sixWayPositiveItem = new TextureItem(
rootItem,
this,
"_RigRTBk",
() => Content("light.sixway.positive", "SixWay Positive"),
drawScaleOffset: false,
isVisible: IsSixWay);
_sixWayNegativeItem = new TextureItem(
rootItem,
this,
"_RigLBtF",
() => Content("light.sixway.negative", "SixWay Negative"),
drawScaleOffset: false,
isVisible: IsSixWay);
_sixWayAbsorptionToggleItem = new NBShaderKeywordToggleItem(
rootItem,
this,
"_SixWayColorAbsorptionToggle",
"VFX_SIX_WAY_ABSORPTION",
() => Content("light.sixway.absorption.toggle", "Light Color Absorption"),
isVisible: IsSixWay);
_sixWayAbsorptionStrengthItem = new VectorComponentItem(
rootItem,
this,
"_SixWayInfo",
0,
() => Content("light.sixway.absorption.strength", "Absorption Strength"),
true,
0f,
1f,
() => IsSixWay() && IsToggleOn(rootItem, "_SixWayColorAbsorptionToggle"));
_sixWayEmissionRampItem = new TextureItem(
rootItem,
this,
"_SixWayEmissionRamp",
() => Content("light.sixway.ramp", "SixWay Emission Ramp"),
drawScaleOffset: false,
afterDraw: SyncSixWayRampFlag,
isVisible: IsSixWay);
_sixWayEmissionPowItem = new VectorComponentItem(
rootItem,
this,
"_SixWayInfo",
1,
() => Content("light.sixway.emissionPow", "SixWay Emission Pow"),
false,
isVisible: IsSixWay);
_sixWayEmissionColorItem = new ColorItem(
rootItem,
this,
"_SixWayEmissionColor",
() => Content("light.sixway.color", "SixWay Emission Color"),
IsSixWay);
InitTriggerByChild();
}
public override void DrawBlock()
{
if (IsAnyLightModeAllowed())
{
_lightModeItem.OnGUI();
}
if (IsTierAllowed("_SPECULAR_COLOR"))
{
_specularToggleItem.OnGUI();
_specularColorItem.OnGUI();
_specularSmoothnessItem.OnGUI();
}
if (IsTierAllowed("_FX_LIGHT_MODE_PBR"))
{
_pbrMetallicItem.OnGUI();
_pbrSmoothnessItem.OnGUI();
}
if (IsTierAllowed("_NORMALMAP"))
{
_bumpBlock.OnGUI();
}
if (IsTierAllowed("_MATCAP"))
{
_matCapBlock.OnGUI();
}
if (IsTierAllowed("_FX_LIGHT_MODE_SIX_WAY"))
{
_sixWayPositiveItem.OnGUI();
_sixWayNegativeItem.OnGUI();
DrawSixWayWarning();
_sixWayEmissionRampItem.OnGUI();
_sixWayEmissionPowItem.OnGUI();
_sixWayEmissionColorItem.OnGUI();
}
if (IsTierAllowed("VFX_SIX_WAY_ABSORPTION"))
{
_sixWayAbsorptionToggleItem.OnGUI();
_sixWayAbsorptionStrengthItem.OnGUI();
}
}
private bool IsTierAllowed(string keyword)
{
return _nbRootItem.Context == null || _nbRootItem.Context.IsKeywordAllowed(keyword);
}
private bool IsAnyLightModeAllowed()
{
return _nbRootItem.Context == null ||
_nbRootItem.Context.IsAnyKeywordAllowed(
"_FX_LIGHT_MODE_UNLIT",
"_FX_LIGHT_MODE_BLINN_PHONG",
"_FX_LIGHT_MODE_HALF_LAMBERT",
"_FX_LIGHT_MODE_PBR",
"_FX_LIGHT_MODE_SIX_WAY");
}
private bool IsSixWay()
{
return _nbRootItem.Context.FxLightMode == FxLightMode.SixWay;
}
private void DrawSixWayWarning()
{
if (!IsSixWay())
{
return;
}
DrawLayoutHelpBox(
NBShaderInspectorLocalization.GetInspectorText(
"light.sixway.uvWarning.message",
"六路UV跟随主贴图UV及颜色"),
MessageType.Warning);
}
private void SyncSixWayRampFlag(MaterialProperty rampProperty)
{
if (rampProperty.hasMixedValue)
{
return;
}
_nbRootItem.SyncService.ApplyToggleFlag(
NBShaderFlags.FLAG_BIT_PARTICLE_1_SIXWAY_RAMPMAP,
rampProperty.textureValue != null,
1);
}
private static bool IsToggleOn(NBShaderRootItem rootItem, string propertyName)
{
return rootItem.Context.IsToggleOn(propertyName);
}
private static bool IsBlinnOrHalf(NBShaderRootItem rootItem)
{
return rootItem.Context.FxLightMode == FxLightMode.BlinnPhong ||
rootItem.Context.FxLightMode == FxLightMode.HalfLambert;
}
private static GUIContent Content(string key, string fallback, string tip = "")
{
return NBShaderInspectorLocalization.MakeInspectorContent(key, fallback, tip);
}
}
public class FxLightModePopupItem : ShaderGUIPopUpItem
{
private static readonly string[] LightModeOptions =
{
"Unlit",
"BlinnPhong",
"HalfLambert",
"PBR",
"SixWay"
};
private readonly NBShaderRootItem _nbRootItem;
public FxLightModePopupItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem)
{
_nbRootItem = rootItem;
PropertyName = "_FxLightMode";
GuiContent = NBShaderInspectorLocalization.MakeContent("inspector.light.mode.label", "Light Mode");
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("light.mode", LightModeOptions);
InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
}
public override void OnEndChange()
{
base.OnEndChange();
_nbRootItem.SyncService.ApplyLightMode((FxLightMode)PropertyInfo.Property.floatValue);
_nbRootItem.Context.Refresh();
}
}
}

View File

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

View File

@@ -0,0 +1,260 @@
using UnityEditor;
using UnityEngine;
using NBShader;
namespace NBShaderEditor
{
public class MainTexBigBlockItem : BigBlockItem
{
private readonly NBShaderRootItem _nbRootItem;
private readonly TexturePropertyGroupItem _baseMapGroupItem;
private readonly TextureRelatedFoldOutItem _baseMapRelatedFoldOutItem;
private readonly ColorLineItem _uiColorItem;
private readonly TextureScaleOffsetItem _uiMainTexScaleOffsetItem;
private readonly ColorChannelSelectItem _alphaChannelItem;
private readonly WrapModeItem _baseMapWrapModeItem;
private readonly UVModeSelectItem _uvModeItem;
private readonly CustomDataSelectItem _offsetXCustomDataItem;
private readonly CustomDataSelectItem _offsetYCustomDataItem;
private readonly Vector2LineItem _baseMapOffsetSpeedItem;
private readonly ShaderGUISliderItem _baseMapRotationItem;
private readonly ShaderGUIFloatItem _baseMapRotationSpeedItem;
private readonly ShaderGUISliderItem _texDistortionIntensityItem;
private readonly PNoiseBlendModeItem _pNoiseBlendModeItem;
private readonly HelpBoxItem _graphicMainTexHelpBox;
public MainTexBigBlockItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_MainTexBigBlockItemFoldOut",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.block.maintex.label",
"Main Texture",
"inspector.block.maintex.tip",
"Main texture and base color controls"))
{
_nbRootItem = rootItem;
_baseMapGroupItem = new TexturePropertyGroupItem(
rootItem,
this,
"_BaseMap",
"_BaseColor",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.basemap.label",
"Main Texture"),
isVisible: () => rootItem.Context.UseGraphicMainTex == MixedBool.False,
tillingContentProvider: TillingContent,
offsetContentProvider: OffsetContent);
_baseMapRelatedFoldOutItem = new TextureRelatedFoldOutItem(
rootItem,
this,
"_BaseMapFoldOut",
"_BaseMap",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.basemap.related.label",
"Main Texture Related"),
() => rootItem.Context.UseGraphicMainTex == MixedBool.False);
_graphicMainTexHelpBox = new HelpBoxItem(
rootItem,
this,
() => NBShaderInspectorLocalization.Get(
"inspector.maintex.graphic.message",
"Current mode uses Graphic texture. Only color and ST remain editable."),
MessageType.Info);
_uiColorItem = new ColorLineItem(
rootItem,
this,
"_Color",
showLabel: false,
contentProvider: () => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.uicolor.label",
"Graphic Color"),
isVisible: () => rootItem.Context.UseGraphicMainTex == MixedBool.True);
_uiMainTexScaleOffsetItem = new TextureScaleOffsetItem(
rootItem,
this,
"_UI_MainTex_ST",
isVectorProperty: true,
isVisible: () => rootItem.Context.UseGraphicMainTex == MixedBool.True,
tillingContentProvider: TillingContent,
offsetContentProvider: OffsetContent);
_alphaChannelItem = new ColorChannelSelectItem(
rootItem,
_baseMapRelatedFoldOutItem,
NBShaderFlags.FLAG_BIT_COLOR_CHANNEL_POS_0_MAINTEX_ALPHA,
3,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.alphaChannel.label",
"Alpha Channel"));
_baseMapWrapModeItem = new WrapModeItem(
rootItem,
_baseMapRelatedFoldOutItem,
NBShaderFlags.FLAG_BIT_WRAPMODE_BASEMAP,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.wrap.label",
"Main Texture Wrap"),
2,
() => rootItem.Context.UseGraphicMainTex == MixedBool.False);
_uvModeItem = new UVModeSelectItem(
rootItem,
_baseMapRelatedFoldOutItem,
"_MainTexUVModeFoldOut",
NBShaderFlags.FLAG_BIT_UVMODE_POS_0_MAINTEX,
0,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.uvmode.label",
"Main Texture UV Source"),
forceEnable: true,
isVisible: () => rootItem.Context.MeshSourceMode != MeshSourceMode.UIEffectSprite);
_offsetXCustomDataItem = new CustomDataSelectItem(
rootItem,
_baseMapRelatedFoldOutItem,
NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_MAINTEX_OFFSET_X,
0,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.customdata.offsetx.label",
"Main Texture Offset X Custom Data"),
() => rootItem.Context.ParticleMode == MixedBool.True);
_offsetYCustomDataItem = new CustomDataSelectItem(
rootItem,
_baseMapRelatedFoldOutItem,
NBShaderFlags.FLAGBIT_POS_0_CUSTOMDATA_MAINTEX_OFFSET_Y,
0,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.customdata.offsety.label",
"Main Texture Offset Y Custom Data"),
() => rootItem.Context.ParticleMode == MixedBool.True);
_baseMapOffsetSpeedItem = new Vector2LineItem(
rootItem,
_baseMapRelatedFoldOutItem,
"_BaseMapMaskMapOffset",
true,
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.offsetspeed.label",
"Offset Speed"),
isVisible: () => rootItem.Context.UseGraphicMainTex == MixedBool.False);
_baseMapRotationItem = new ShaderGUISliderItem(rootItem, _baseMapRelatedFoldOutItem)
{
PropertyName = "_BaseMapUVRotation",
GuiContent = NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.rotation.label",
"Rotation"),
Min = 0f,
Max = 360f
};
_baseMapRotationItem.InitTriggerByChild();
_baseMapRotationSpeedItem = new ShaderGUIFloatItem(rootItem, _baseMapRelatedFoldOutItem)
{
PropertyName = "_BaseMapUVRotationSpeed",
GuiContent = NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.rotationspeed.label",
"Rotation Speed")
};
_baseMapRotationSpeedItem.InitTriggerByChild();
_texDistortionIntensityItem = new ShaderGUISliderItem(rootItem, _baseMapRelatedFoldOutItem)
{
PropertyName = "_TexDistortion_intensity",
GuiContent = NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.distortionIntensity.label",
"Main Texture Distortion"),
RangePropertyName = "TexDistortionintensityRangeVec"
};
_texDistortionIntensityItem.InitTriggerByChild();
_pNoiseBlendModeItem = new PNoiseBlendModeItem(
rootItem,
_baseMapRelatedFoldOutItem,
NBShaderFlags.FLAG_BIT_PNOISE_BLEND_POS_0_MAINTEX,
"_MainTexPNoiseBlendOpacity",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.maintex.pnoiseBlend.label",
"Main Texture Program Noise Blend"),
() => rootItem.Context.ProgramNoiseEnabled == MixedBool.True);
InitTriggerByChild();
}
public override void DrawBlock()
{
if (_nbRootItem.Context.UseGraphicMainTex == MixedBool.Mixed)
{
DrawLayoutHelpBox(
NBShaderInspectorLocalization.GetInspectorText(
"maintex.mixedMeshSource.message",
"Mixed mesh-source modes will show the matching texture controls per material state."),
MessageType.Info);
}
_baseMapGroupItem.OnGUI();
if (_nbRootItem.Context.UseGraphicMainTex == MixedBool.True)
{
_graphicMainTexHelpBox.OnGUI();
}
_uiColorItem.OnGUI();
_uiMainTexScaleOffsetItem.OnGUI();
if (_nbRootItem.Context.UseGraphicMainTex == MixedBool.False)
{
_baseMapRelatedFoldOutItem.OnGUI();
}
else
{
DrawMainTexRelatedItems();
}
}
private void DrawMainTexRelatedItems()
{
_alphaChannelItem.OnGUI();
_baseMapWrapModeItem.OnGUI();
_uvModeItem.OnGUI();
_offsetXCustomDataItem.OnGUI();
_offsetYCustomDataItem.OnGUI();
_baseMapOffsetSpeedItem.OnGUI();
if (_nbRootItem.Context.UseGraphicMainTex == MixedBool.False)
{
_baseMapRotationItem.OnGUI();
_baseMapRotationSpeedItem.OnGUI();
}
if (_nbRootItem.Context.UseGraphicMainTex == MixedBool.False)
{
bool previousMixedValue = EditorGUI.showMixedValue;
EditorGUI.showMixedValue = _nbRootItem.Context.NoiseEnabled == MixedBool.Mixed;
using (new InheritedControlDisabledScope(_nbRootItem.Context.NoiseEnabled == MixedBool.False))
{
_texDistortionIntensityItem.OnGUI();
}
EditorGUI.showMixedValue = previousMixedValue;
}
_pNoiseBlendModeItem.OnGUI();
}
private static GUIContent TillingContent()
{
return NBShaderInspectorLocalization.MakeInspectorContent("common.tilling", "Tilling");
}
private static GUIContent OffsetContent()
{
return NBShaderInspectorLocalization.MakeInspectorContent("common.offset", "Offset");
}
}
}

View File

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

View File

@@ -0,0 +1,377 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
public class ModeBigBlockItem : BigBlockItem
{
private readonly NBShaderRootItem _nbRootItem;
public ModeBigBlockItem(NBShaderRootItem rootItem, ShaderGUIItem parentItem)
: base(
rootItem,
parentItem,
"_BigBlockModeSettingFoldOut",
() => NBShaderInspectorLocalization.MakeContent(
"inspector.block.mode.label",
"模式设置",
"inspector.block.mode.tip",
"各种基础模式设置"))
{
_nbRootItem = rootItem;
_meshModePopUp = new MeshModePopUp(rootItem, this);
_transparentMode = new TransparentModePopUp(rootItem, this);
base.InitTriggerByChild();
}
private MeshModePopUp _meshModePopUp;
private TransparentModePopUp _transparentMode;
public override void DrawBlock()
{
_meshModePopUp.OnGUI();
_transparentMode.OnGUI();
}
}
public enum MeshSourceMode
{
Particle,
Mesh,
UIEffectRawImage,
UIEffectSprite,
UIEffectBaseMap,
UIParticle,
UnKnowOrMixed = -1
}
public class MeshModePopUp : ShaderGUIPopUpItem,IDisposable
{
public MeshSourceMode MeshSourceMode;
public static Dictionary<ShaderGUIRootItem,MeshModePopUp> MeshSourceModeDic = new Dictionary<ShaderGUIRootItem,MeshModePopUp>();
public MeshModePopUp(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) :
base(rootItem, parentItem: parentItem)
{
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("mode.meshSource", MeshSourceOptions);
PropertyName = "_MeshSourceMode";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("mode.meshSource", "Mesh Source Mode", "Matches the current object type.");
MeshSourceModeDic[rootItem] = this;
InitTriggerByChild();
}
public MixedBool UIEffectEnabled()
{
if ((int)MeshSourceMode >= 2)
{
return MixedBool.True;
}
else if (MeshSourceMode == MeshSourceMode.UnKnowOrMixed)
{
return MixedBool.Mixed;
}
else
{
return MixedBool.False;
}
}
public override void OnGUI()
{
base.OnGUI();
if (PropertyInfo.Property.hasMixedValue)
{
MeshSourceMode = MeshSourceMode.UnKnowOrMixed;
}
else
{
MeshSourceMode = (MeshSourceMode)PropertyInfo.Property.floatValue;
}
DrawParticleSystemMismatchWarning();
}
public override void OnEndChange()
{
base.OnEndChange();
if (RootItem is NBShaderRootItem nbRootItem)
{
nbRootItem.Context.Refresh();
}
}
public void Dispose()
{
MeshSourceModeDic.Remove(RootItem);
}
private void DrawParticleSystemMismatchWarning()
{
if (!(RootItem is NBShaderRootItem nbRootItem) ||
nbRootItem.Mats == null ||
nbRootItem.Mats.Count == 0 ||
nbRootItem.Context.ParticleMode == MixedBool.True ||
!nbRootItem.IsUsedByParticleSystem)
{
return;
}
DrawLayoutHelpBox(
NBShaderInspectorLocalization.GetInspectorText(
"mode.meshSource.particleModeMismatch",
"检测到材质用在粒子系统上,和设置不匹配"),
MessageType.Error);
}
private static readonly string[] MeshSourceOptions =
{
"粒子系统",
"模型(非粒子发射)",
"2D RawImage",
"2D 精灵",
"2D 材质贴图",
"2D UIParticle"
};
}
public enum TransparentMode
{
Opaque = 0,
Transparent = 1,
CutOff = 2,
UnKnowOrMixed = -1
}
public class TransparentModePopUp : ShaderGUIPopUpItem,IDisposable
{
public TransparentMode TransparentMode;
public static Dictionary<ShaderGUIRootItem,TransparentModePopUp> TransparentModeDic =
new Dictionary<ShaderGUIRootItem, TransparentModePopUp>();
public TransparentModePopUp(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) :
base(rootItem, parentItem: parentItem)
{
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("mode.transparent", TransparentOptions);
PropertyName = "_TransparentMode";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("mode.transparent", "Transparent Mode", "Controls opaque, transparent, and cutoff rendering.");
TransparentModeDic[RootItem] = this;
_cutOffSlider = new ShaderGUISliderItem(RootItem, this)
{
PropertyName = "_Cutoff",
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("mode.cutoff", "Cutoff", "0 keeps everything, 1 clips everything.")
};
_cutOffSlider.InitTriggerByChild();
_blendPopUp = new BlendPopUp(RootItem, this);
PropertyInfo = RootItem.PropertyInfoDic[PropertyName];
TransparentMode = (TransparentMode)PropertyInfo.Property.floatValue;
InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
if (PropertyInfo.Property.hasMixedValue)
{
TransparentMode = TransparentMode.UnKnowOrMixed;
}
else
{
TransparentMode = (TransparentMode)PropertyInfo.Property.floatValue;
}
}
private ShaderGUISliderItem _cutOffSlider;
private BlendPopUp _blendPopUp;
public override void DrawBlock()
{
if (TransparentMode== TransparentMode.CutOff)
{
_cutOffSlider.OnGUI();
}
if (TransparentMode == TransparentMode.Transparent)
{
_blendPopUp.OnGUI();
}
}
public override void OnEndChange()
{
TransparentMode = (TransparentMode)PropertyInfo.Property.floatValue;
switch (TransparentMode)
{
case TransparentMode.Opaque:
if (RootItem is NBShaderRootItem opaqueRootItem)
{
opaqueRootItem.SyncService.ApplyTransparentMode(TransparentMode);
}
_blendPopUp.PropertyInfo.Property.floatValue = (float)BlendMode.Opaque;
_blendPopUp.OnEndChange();
break;
case TransparentMode.Transparent:
if (RootItem is NBShaderRootItem transparentRootItem)
{
transparentRootItem.SyncService.ApplyTransparentMode(TransparentMode);
}
if (_blendPopUp.BlendMode == BlendMode.Opaque)
{
_blendPopUp.PropertyInfo.Property.floatValue = (float)BlendMode.Alpha;//如果设置错误则强制设置。
_blendPopUp.OnEndChange();
}
break;
case TransparentMode.CutOff:
if (RootItem is NBShaderRootItem cutOffRootItem)
{
cutOffRootItem.SyncService.ApplyTransparentMode(TransparentMode);
}
_blendPopUp.PropertyInfo.Property.floatValue = (float)BlendMode.Opaque;
_blendPopUp.OnEndChange();
break;
}
base.OnEndChange();
}
public void Dispose()
{
TransparentModeDic.Remove(RootItem);//回收时清掉相关引用。?会不会有时序问题
}
private static readonly string[] TransparentOptions =
{
"不透明Opaque",
"半透明Transparent",
"不透明裁剪CutOff"
};
}
public enum BlendMode
{
Alpha, // Old school alpha-blending mode, fresnel does not affect amount of transparency
Premultiply, // Physically plausible transparency mode, implemented as alpha pre-multiply
Additive,
Multiply,
Opaque,
UnKnowOrMixed = -1
}
public class BlendPopUp : ShaderGUIPopUpItem,IDisposable
{
public BlendMode BlendMode;
public static Dictionary<ShaderGUIRootItem,BlendPopUp> BlendModeDic = new Dictionary<ShaderGUIRootItem,BlendPopUp>();
public BlendPopUp(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem)
{
PropertyName = "_Blend";
PopUpNames = NBShaderInspectorLocalization.GetInspectorOptions("mode.blend", BlendOptions);
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("mode.blend", "Blend Mode");
BlendModeDic[rootItem] = this;
_addToPreMultiplySlider = new AddToPreMultiplySlider(rootItem, this);
InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
if (PropertyInfo.Property.hasMixedValue)
{
BlendMode = BlendMode.UnKnowOrMixed;
}
else
{
BlendMode = (BlendMode)PropertyInfo.Property.floatValue;
}
}
private AddToPreMultiplySlider _addToPreMultiplySlider;
public override void DrawBlock()
{
if (BlendMode == BlendMode.Additive || BlendMode == BlendMode.Premultiply)
{
_addToPreMultiplySlider.OnGUI();
}
}
public override void OnEndChange()
{
BlendMode = (BlendMode)PropertyInfo.Property.floatValue;
if (BlendMode == BlendMode.Additive)
{
_addToPreMultiplySlider.PropertyInfo.Property.floatValue = 0;
_addToPreMultiplySlider.OnEndChange();
}
if (BlendMode == BlendMode.Premultiply)
{
_addToPreMultiplySlider.PropertyInfo.Property.floatValue = 1;
_addToPreMultiplySlider.OnEndChange();
}
if (RootItem is NBShaderRootItem nbRootItem)
{
nbRootItem.SyncService.ApplyBlendMode(BlendMode);
}
base.OnEndChange();
}
public void Dispose()
{
BlendModeDic.Remove(RootItem);
}
private static readonly string[] BlendOptions =
{
"透明度混合AlphaBlend",
"预乘PreMultiply",
"叠加Additive",
"正片叠底Multiply"
};
}
public class AddToPreMultiplySlider : ShaderGUISliderItem
{
public AddToPreMultiplySlider(ShaderGUIRootItem rootItem, ShaderGUIItem parentItem) : base(rootItem, parentItem)
{
PropertyName = "_AdditiveToPreMultiplyAlphaLerp";
GuiContent = NBShaderInspectorLocalization.MakeInspectorContent("mode.additiveToPremultiply", "Additive To Premultiply", "0 is additive, 1 is premultiply.");
base.InitTriggerByChild();
}
public override void OnGUI()
{
base.OnGUI();
}
public override void CheckIsPropertyModified(bool isCallByChild = false)
{
float defaultValue = 0;
BlendPopUp blendPopUp = BlendPopUp.BlendModeDic[RootItem];
if (blendPopUp.BlendMode == BlendMode.Premultiply)
{
defaultValue = 1;
}
HasModified = !Mathf.Approximately(defaultValue,PropertyInfo.Property.floatValue);
ParentItem?.CheckIsPropertyModified(true);
}
public override void ExecuteReset(bool isCallByParent = false)
{
float defaultValue = 0;
BlendPopUp blendPopUp = BlendPopUp.BlendModeDic[RootItem];
if (blendPopUp.BlendMode == BlendMode.Premultiply)
{
defaultValue = 1;
}
PropertyInfo.Property.floatValue = defaultValue;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed09665b113c407dbfb8c818b74f48aa
timeCreated: 1758445745

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using NBShader;
using NBShaders2.Editor.FeatureLevel;
using UnityEditor;
using UnityEngine;
namespace NBShaderEditor
{
public class NBShaderGUIContext
{
private const string FeatureTierPropertyName = "_NBShaderFeatureTier";
private readonly NBShaderRootItem _rootItem;
private HashSet<string> _currentTierAllowedKeywords;
public NBShaderGUIContext(NBShaderRootItem rootItem)
{
_rootItem = rootItem;
}
public MeshSourceMode MeshSourceMode { get; private set; } = MeshSourceMode.UnKnowOrMixed;
public TransparentMode TransparentMode { get; private set; } = TransparentMode.UnKnowOrMixed;
public MixedBool UIEffectEnabled { get; private set; } = MixedBool.Mixed;
public MixedBool UseGraphicMainTex { get; private set; } = MixedBool.Mixed;
public MixedBool ParticleMode { get; private set; } = MixedBool.Mixed;
public MixedBool NoiseEnabled { get; private set; } = MixedBool.Mixed;
public MixedBool ProgramNoiseEnabled { get; private set; } = MixedBool.Mixed;
public MixedBool VatEnabled { get; private set; } = MixedBool.Mixed;
public MixedBool FlipbookEnabled { get; private set; } = MixedBool.Mixed;
public FxLightMode FxLightMode { get; private set; } = FxLightMode.UnKnownOrMixedValue;
public NBShaderFeatureTier CurrentTier { get; private set; } = NBShaderFeatureTier.Ultra;
public bool CurrentTierMixed { get; private set; }
public bool IsKeywordAllowed(string keyword)
{
if (!NBShaderFeatureCatalog.IsManagedKeyword(keyword))
{
return true;
}
if (CurrentTierMixed)
{
return true;
}
return _currentTierAllowedKeywords != null && _currentTierAllowedKeywords.Contains(keyword);
}
public bool AreKeywordsAllowed(params string[] keywords)
{
if (keywords == null)
{
return true;
}
for (int i = 0; i < keywords.Length; i++)
{
if (!IsKeywordAllowed(keywords[i]))
{
return false;
}
}
return true;
}
public bool IsAnyKeywordAllowed(params string[] keywords)
{
if (keywords == null || keywords.Length == 0)
{
return true;
}
for (int i = 0; i < keywords.Length; i++)
{
if (IsKeywordAllowed(keywords[i]))
{
return true;
}
}
return false;
}
public bool IsAnyKeywordAllowed(string keyword0, string keyword1)
{
return IsKeywordAllowed(keyword0) || IsKeywordAllowed(keyword1);
}
public bool IsAnyKeywordAllowed(
string keyword0,
string keyword1,
string keyword2,
string keyword3,
string keyword4)
{
return IsKeywordAllowed(keyword0) ||
IsKeywordAllowed(keyword1) ||
IsKeywordAllowed(keyword2) ||
IsKeywordAllowed(keyword3) ||
IsKeywordAllowed(keyword4);
}
public static bool IsCatalogKeyword(string keyword)
{
return NBShaderFeatureCatalog.IsManagedKeyword(keyword);
}
public bool HasProperty(string propertyName)
{
return _rootItem.PropertyInfoDic.ContainsKey(propertyName);
}
public MaterialProperty GetProperty(string propertyName)
{
return _rootItem.PropertyInfoDic[propertyName].Property;
}
public void Refresh()
{
RefreshFeatureTier();
if (HasProperty("_MeshSourceMode"))
{
MaterialProperty meshSourceModeProperty = GetProperty("_MeshSourceMode");
MeshSourceMode = meshSourceModeProperty.hasMixedValue
? MeshSourceMode.UnKnowOrMixed
: (MeshSourceMode)meshSourceModeProperty.floatValue;
}
if (HasProperty("_TransparentMode"))
{
MaterialProperty transparentModeProperty = GetProperty("_TransparentMode");
TransparentMode = transparentModeProperty.hasMixedValue
? TransparentMode.UnKnowOrMixed
: (TransparentMode)transparentModeProperty.floatValue;
}
if (MeshSourceMode == MeshSourceMode.UnKnowOrMixed)
{
UIEffectEnabled = MixedBool.Mixed;
UseGraphicMainTex = MixedBool.Mixed;
ParticleMode = MixedBool.Mixed;
}
else
{
UIEffectEnabled = (int)MeshSourceMode >= 2 ? MixedBool.True : MixedBool.False;
UseGraphicMainTex = MeshSourceMode == MeshSourceMode.UIEffectRawImage || MeshSourceMode == MeshSourceMode.UIEffectSprite
? MixedBool.True
: MixedBool.False;
ParticleMode = MeshSourceMode == MeshSourceMode.Particle || MeshSourceMode == MeshSourceMode.UIParticle
? MixedBool.True
: MixedBool.False;
}
if (HasProperty("_FxLightMode"))
{
MaterialProperty lightModeProperty = GetProperty("_FxLightMode");
FxLightMode = lightModeProperty.hasMixedValue
? FxLightMode.UnKnownOrMixedValue
: (FxLightMode)lightModeProperty.floatValue;
}
NoiseEnabled = IsKeywordAllowed("_NOISEMAP") ? GetToggleState("_noisemapEnabled") : MixedBool.False;
ProgramNoiseEnabled = IsKeywordAllowed("_PROGRAM_NOISE") ? GetToggleState("_ProgramNoise_Toggle") : MixedBool.False;
VatEnabled = IsKeywordAllowed("_VAT") ? GetToggleState("_VAT_Toggle") : MixedBool.False;
FlipbookEnabled = IsKeywordAllowed("_FLIPBOOKBLENDING_ON") ? GetToggleState("_FlipbookBlending") : MixedBool.False;
}
private void RefreshFeatureTier()
{
if (!HasProperty(FeatureTierPropertyName))
{
CurrentTier = NBShaderFeatureTier.Ultra;
CurrentTierMixed = false;
_currentTierAllowedKeywords =
NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForReadOnlyUse(CurrentTier);
return;
}
MaterialProperty tierProperty = GetProperty(FeatureTierPropertyName);
CurrentTierMixed = tierProperty.hasMixedValue;
CurrentTier = CurrentTierMixed
? NBShaderFeatureTier.Ultra
: ToFeatureTier(Mathf.RoundToInt(tierProperty.floatValue));
_currentTierAllowedKeywords = CurrentTierMixed
? null
: NBShaderFeatureLevelProjectSettings.instance.GetAllowedKeywordSetForReadOnlyUse(CurrentTier);
}
private static NBShaderFeatureTier ToFeatureTier(int value)
{
return Enum.IsDefined(typeof(NBShaderFeatureTier), value) && value >= 0
? (NBShaderFeatureTier)value
: NBShaderFeatureTier.Ultra;
}
public MixedBool GetToggleState(string propertyName)
{
if (!HasProperty(propertyName))
{
return MixedBool.False;
}
MaterialProperty property = GetProperty(propertyName);
if (property.hasMixedValue)
{
return MixedBool.Mixed;
}
return property.floatValue > 0.5f ? MixedBool.True : MixedBool.False;
}
public bool IsToggleOn(string propertyName)
{
return GetToggleState(propertyName) == MixedBool.True;
}
}
}

View File

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

View File

@@ -0,0 +1,715 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using NBShader;
using NBShaders2.Editor.FeatureLevel;
namespace NBShaderEditor
{
public class NBShaderGUIToolBar
{
private const float ButtonWidth = 30f;
private const float TierButtonWidth = 105f;
private const string FeatureTierPropertyName = "_NBShaderFeatureTier";
private const string HelpUrl = "https://owejt9diz2c.feishu.cn/wiki/BHz8wHHSjiYJagk7WrmcAcconlb?from=from_copylink";
private static readonly string[] SettingsIconNames =
{
"SettingsIcon",
"d_SettingsIcon",
"Settings",
"d_Settings"
};
private readonly NBShaderRootItem _rootItem;
private readonly GUIContent _tierContent = new GUIContent();
private readonly string _tierMixedLabel;
private readonly string _tierFormat;
private readonly string _tierTooltip;
private NBShaderFeatureTier _tierContentTier;
private bool _tierContentMixed;
private bool _tierContentInitialized;
private static readonly Dictionary<string, GUIContent> IconContentCache =
new Dictionary<string, GUIContent>(StringComparer.Ordinal);
private static readonly Dictionary<string, GUIContent> TextContentCache =
new Dictionary<string, GUIContent>(StringComparer.Ordinal);
private static GUIContent s_SettingsContent;
private static string s_ToolbarContentLanguage;
private static Material copiedMaterialSnapshot;
private static Shader copiedShader;
public NBShaderGUIToolBar(NBShaderRootItem rootItem)
{
_rootItem = rootItem;
_tierMixedLabel = Label("tierMixed", "Tier: Mixed");
_tierFormat = Label("tierFormat", "Tier: {0}");
_tierTooltip = Tip("tier", "NBShader feature tier");
}
public void DrawToolbar()
{
Rect toolbarRect = ShaderGUIItem.ApplyGlobalRectCompensation(
_rootItem.GetControlRect(EditorGUIUtility.singleLineHeight));
GUI.Box(toolbarRect, GUIContent.none, EditorStyles.toolbar);
Material material = MainMaterial;
bool hasMaterial = material != null;
float buttonX = toolbarRect.x;
using (new EditorGUI.DisabledScope(!hasMaterial))
{
if (ToolbarButton(toolbarRect, ref buttonX, IconContent("Material On Icon", "ping", "跳到当前材质")))
{
EditorGUIUtility.PingObject(material);
}
if (ToolbarButton(toolbarRect, ref buttonX, IconContent("TreeEditor.Trash", "cleanUnusedTextures", "清除没有使用的贴图")))
{
CleanUnusedTextures();
}
if (ToolbarButton(toolbarRect, ref buttonX, TextContent("copy", "C", "复制材质属性")))
{
CopyMaterial(material);
}
}
using (new EditorGUI.DisabledScope(!hasMaterial || !HasCopiedMaterial()))
{
if (ToolbarButton(toolbarRect, ref buttonX, TextContent("paste", "V", "粘贴材质属性")))
{
PasteMaterial();
}
}
using (new EditorGUI.DisabledScope(!hasMaterial))
{
if (ToolbarButton(toolbarRect, ref buttonX, TextContent("specialReset", "R", "特殊重置功能")))
{
ShowResetPopupMenu();
}
if (ToolbarButton(toolbarRect, ref buttonX, IconContent("d_UnityEditor.HierarchyWindow", "collapseAll", "折叠所有控件")))
{
CollapseAll();
}
}
float rightX = toolbarRect.xMax;
rightX -= ButtonWidth;
Rect helpRect = MakeToolbarButtonRect(toolbarRect, rightX);
if (GUI.Button(helpRect, IconContent("d__Help@2x", "help", "说明文档"), EditorStyles.toolbarButton))
{
Application.OpenURL(HelpUrl);
}
rightX -= ButtonWidth;
Rect settingsRect = MakeToolbarButtonRect(toolbarRect, rightX);
if (GUI.Button(settingsRect, SettingsContent(), EditorStyles.toolbarButton))
{
OpenProjectSettings();
}
rightX -= TierButtonWidth;
Rect tierRect = MakeToolbarButtonRect(toolbarRect, rightX, TierButtonWidth);
using (new EditorGUI.DisabledScope(!hasMaterial))
{
if (GUI.Button(tierRect, TierContent(), EditorStyles.toolbarButton))
{
ShowTierPopupMenu();
}
}
}
private static bool ToolbarButton(Rect toolbarRect, ref float buttonX, GUIContent content)
{
return ToolbarButton(toolbarRect, ref buttonX, content, ButtonWidth);
}
private static bool ToolbarButton(Rect toolbarRect, ref float buttonX, GUIContent content, float width)
{
Rect buttonRect = MakeToolbarButtonRect(toolbarRect, buttonX, width);
buttonX += width;
return GUI.Button(buttonRect, content, EditorStyles.toolbarButton);
}
private static Rect MakeToolbarButtonRect(Rect toolbarRect, float x)
{
return MakeToolbarButtonRect(toolbarRect, x, ButtonWidth);
}
private static Rect MakeToolbarButtonRect(Rect toolbarRect, float x, float width)
{
return new Rect(x, toolbarRect.y, width, toolbarRect.height);
}
private static GUIContent SettingsContent()
{
EnsureToolbarContentLanguage();
if (s_SettingsContent != null)
{
return s_SettingsContent;
}
Texture image = null;
for (int i = 0; i < SettingsIconNames.Length; i++)
{
GUIContent icon = EditorGUIUtility.IconContent(SettingsIconNames[i]);
if (icon != null && icon.image != null)
{
image = icon.image;
break;
}
}
s_SettingsContent = new GUIContent(image, Tip("settings", "NBShader Project Settings"));
return s_SettingsContent;
}
private static void OpenProjectSettings()
{
SettingsService.OpenProjectSettings(NBShaderFeatureLevelSettingsProvider.SettingsPath);
}
private static bool HasCopiedMaterial()
{
return copiedMaterialSnapshot != null;
}
private static void CopyMaterial(Material material)
{
if (copiedMaterialSnapshot != null)
{
UnityEngine.Object.DestroyImmediate(copiedMaterialSnapshot);
copiedMaterialSnapshot = null;
copiedShader = null;
}
if (material == null)
{
return;
}
copiedMaterialSnapshot = new Material(material)
{
hideFlags = HideFlags.HideAndDontSave
};
copiedShader = copiedMaterialSnapshot.shader;
}
private GUIContent TierContent()
{
bool mixed = _rootItem.Context != null && _rootItem.Context.CurrentTierMixed;
NBShaderFeatureTier tier = CurrentTier;
if (!_tierContentInitialized || _tierContentMixed != mixed || _tierContentTier != tier)
{
_tierContent.text = mixed
? _tierMixedLabel
: string.Format(_tierFormat, GetTierLabel(tier));
_tierContent.tooltip = _tierTooltip;
_tierContentTier = tier;
_tierContentMixed = mixed;
_tierContentInitialized = true;
}
return _tierContent;
}
private NBShaderFeatureTier CurrentTier
{
get
{
return _rootItem.Context != null ? _rootItem.Context.CurrentTier : NBShaderFeatureTier.Ultra;
}
}
private void ShowTierPopupMenu()
{
GenericMenu menu = new GenericMenu();
AddTierMenuItem(menu, NBShaderFeatureTier.Low);
AddTierMenuItem(menu, NBShaderFeatureTier.Medium);
AddTierMenuItem(menu, NBShaderFeatureTier.High);
AddTierMenuItem(menu, NBShaderFeatureTier.Ultra);
menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
}
private void AddTierMenuItem(GenericMenu menu, NBShaderFeatureTier tier)
{
bool isChecked = (_rootItem.Context == null || !_rootItem.Context.CurrentTierMixed) && CurrentTier == tier;
menu.AddItem(new GUIContent(GetTierLabel(tier)), isChecked, () => SetFeatureTier(tier));
}
private static string GetTierLabel(NBShaderFeatureTier tier)
{
switch (tier)
{
case NBShaderFeatureTier.Low:
return Label("tierLow", "Low");
case NBShaderFeatureTier.Medium:
return Label("tierMedium", "Medium");
case NBShaderFeatureTier.High:
return Label("tierHigh", "High");
case NBShaderFeatureTier.Ultra:
return Label("tierUltra", "Ultra");
default:
return tier.ToString();
}
}
private void SetFeatureTier(NBShaderFeatureTier tier)
{
RecordAllMaterials(UndoText("setTier", "Set NBShader Feature Tier"));
if (_rootItem.PropertyInfoDic.TryGetValue(FeatureTierPropertyName, out ShaderPropertyInfo info))
{
info.Property.floatValue = (float)tier;
}
foreach (Material mat in Materials)
{
if (mat.HasProperty(FeatureTierPropertyName))
{
mat.SetFloat(FeatureTierPropertyName, (float)tier);
}
NBShaderFeatureLevelMaterialApplier.Apply(mat, tier, false, true);
}
FinishFeatureTierMutation();
}
private void ShowResetPopupMenu()
{
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent(Label("resetAll", "重置所有")), false, ResetAll);
menu.AddItem(new GUIContent(Label("resetDisabledFeatureChildren", "重置关闭功能子属性")), false, ResetDisabledFeatureChildren);
menu.AddSeparator(string.Empty);
menu.AddItem(new GUIContent(Label("resetSpecialUV", "重置特殊UV通道")), false, ResetSpecialUVChannel);
menu.AddItem(new GUIContent(Label("resetTwirl", "重置旋转扭曲")), false, ResetTwirl);
menu.AddItem(new GUIContent(Label("resetPolar", "重置极坐标")), false, ResetPolar);
menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));
}
private void CleanUnusedTextures()
{
RecordAllMaterials(UndoText("cleanUnusedTextures", "清除没有使用的贴图"));
foreach (Material mat in Materials)
{
CleanUnusedTextureProperties(mat);
}
_rootItem.RequestClearUnusedTextureReferences();
MarkAllMaterialsDirty();
}
private void PasteMaterial()
{
Material material = MainMaterial;
if (material == null || !HasCopiedMaterial())
{
return;
}
Undo.RecordObject(material, UndoText("paste", "粘贴材质属性"));
if (copiedShader != null)
{
material.shader = copiedShader;
}
material.CopyPropertiesFromMaterial(copiedMaterialSnapshot);
EditorUtility.SetDirty(material);
_rootItem.IsInit = true;
_rootItem.Context?.Refresh();
_rootItem.SyncService?.SyncMaterialState();
_rootItem.Context?.Refresh();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
GUIUtility.ExitGUI();
}
private void ResetSpecialUVChannel()
{
RecordAllMaterials(UndoText("resetSpecialUV", "重置特殊UV通道"));
ResetSpecialUVChannelValues();
FinishMaterialMutation();
}
private void ResetTwirl()
{
RecordAllMaterials(UndoText("resetTwirl", "重置旋转扭曲"));
ResetTwirlValues();
FinishMaterialMutation();
}
private void ResetPolar()
{
RecordAllMaterials(UndoText("resetPolar", "重置极坐标"));
ResetPolarValues();
FinishMaterialMutation();
}
private void ResetAll()
{
RecordAllMaterials(UndoText("resetAll", "重置所有特殊功能"));
_rootItem.ExecuteResetAllItems();
ResetSpecialUVChannelValues();
ResetTwirlValues();
ResetPolarValues();
FinishMaterialMutation();
}
private void ResetDisabledFeatureChildren()
{
RecordAllMaterials(UndoText("resetDisabledFeatureChildren", "重置关闭功能子属性"));
foreach (ShaderGUIItem item in _rootItem.GetToolbarResetRootItems())
{
ResetDisabledFeatureChildren(item);
}
FinishMaterialMutation();
}
private static void ResetDisabledFeatureChildren(ShaderGUIItem item)
{
if (item == null)
{
return;
}
if (item is PropertyToggleBlockItem && IsExplicitlyDisabled(item))
{
ExecuteResetChildren(item);
item.CheckIsPropertyModified(true);
return;
}
for (int i = 0; i < item.ChildrenItemList.Count; i++)
{
ResetDisabledFeatureChildren(item.ChildrenItemList[i]);
}
item.CheckIsPropertyModified(true);
}
private static bool IsExplicitlyDisabled(ShaderGUIItem item)
{
MaterialProperty property = item.PropertyInfo?.Property;
return property != null &&
!property.hasMixedValue &&
property.floatValue <= 0.5f;
}
private static void ExecuteResetChildren(ShaderGUIItem item)
{
for (int i = 0; i < item.ChildrenItemList.Count; i++)
{
ExecuteResetSubtree(item.ChildrenItemList[i]);
}
}
private static void ExecuteResetSubtree(ShaderGUIItem item)
{
if (item == null)
{
return;
}
item.ExecuteReset(true);
for (int i = 0; i < item.ChildrenItemList.Count; i++)
{
ExecuteResetSubtree(item.ChildrenItemList[i]);
}
item.CheckIsPropertyModified(true);
}
private void ResetSpecialUVChannelValues()
{
float defaultValue = GetDefaultFloat("_SpecialUVChannelMode", 0f);
SetFloatProperty("_SpecialUVChannelMode", defaultValue);
bool useTexcoord1 = Mathf.RoundToInt(defaultValue) == 0;
for (int i = 0; i < _rootItem.ShaderFlags.Count; i++)
{
ShaderFlagsBase flags = _rootItem.ShaderFlags[i];
if (useTexcoord1)
{
flags.SetFlagBits(NBShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD1, index: 1);
flags.ClearFlagBits(NBShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD2, index: 1);
}
else
{
flags.ClearFlagBits(NBShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD1, index: 1);
flags.SetFlagBits(NBShaderFlags.FLAG_BIT_PARTICLE_1_USE_TEXCOORD2, index: 1);
}
}
}
private void ResetTwirlValues()
{
float enabled = GetDefaultFloat("_UTwirlEnabled", 0f);
SetFloatProperty("_UTwirlEnabled", enabled);
SetVectorProperty("_TWParameter", GetDefaultVector("_TWParameter", new Vector4(0.5f, 0.5f, 0f, 0f)));
SetFloatProperty("_TWStrength", GetDefaultFloat("_TWStrength", 1f));
ApplyFlag(NBShaderFlags.FLAG_BIT_PARTICLE_UTWIRL_ON, enabled > 0.5f, 0);
}
private void ResetPolarValues()
{
float enabled = GetDefaultFloat("_PolarCoordinatesEnabled", 0f);
SetFloatProperty("_PolarCoordinatesEnabled", enabled);
SetVectorProperty("_PCCenter", GetDefaultVector("_PCCenter", new Vector4(0.5f, 0.5f, 1f, 0f)));
ApplyFlag(NBShaderFlags.FLAG_BIT_PARTICLE_POLARCOORDINATES_ON, enabled > 0.5f, 0);
}
private void CollapseAll()
{
RecordAllMaterials(UndoText("collapseAll", "折叠所有控件"));
foreach (KeyValuePair<string, ShaderPropertyInfo> pair in _rootItem.PropertyInfoDic)
{
if (!pair.Key.EndsWith("FoldOut", StringComparison.Ordinal))
{
continue;
}
MaterialProperty property = pair.Value.Property;
ShaderPropertyType propertyType = ShaderGUIUnityCompat.GetPropertyType(property);
if (propertyType == ShaderPropertyType.Float ||
propertyType == ShaderPropertyType.Range)
{
property.floatValue = 0f;
}
}
MarkAllMaterialsDirty();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
private void CleanUnusedTextureProperties(Material mat)
{
if (mat == null || mat.shader == null)
{
return;
}
Shader shader = mat.shader;
var shaderTexProps = new HashSet<string>();
int count = shader.GetPropertyCount();
for (int i = 0; i < count; i++)
{
if (shader.GetPropertyType(i) == ShaderPropertyType.Texture)
{
shaderTexProps.Add(shader.GetPropertyName(i));
}
}
string[] texturePropertyNames = mat.GetTexturePropertyNames();
foreach (string propertyName in texturePropertyNames)
{
if (shaderTexProps.Contains(propertyName) || mat.GetTexture(propertyName) == null)
{
continue;
}
mat.SetTexture(propertyName, null);
Debug.LogFormat(
mat,
NBShaderInspectorLocalization.Get(
"inspector.toolbar.cleanUnusedTextures.log",
"清理 {0} 的无效贴图属性: {1}"),
mat.name,
propertyName);
}
}
private void FinishMaterialMutation()
{
_rootItem.Context?.Refresh();
_rootItem.SyncService?.SyncMaterialState();
_rootItem.SyncService?.NotifyKeywordsMayHaveChanged();
_rootItem.Context?.Refresh();
MarkAllMaterialsDirty();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
private void FinishFeatureTierMutation()
{
_rootItem.Context?.Refresh();
_rootItem.SyncService?.NotifyKeywordsMayHaveChanged();
_rootItem.Context?.Refresh();
MarkAllMaterialsDirty();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
private void ApplyFlag(int flagBits, bool enabled, int flagIndex)
{
for (int i = 0; i < _rootItem.ShaderFlags.Count; i++)
{
ShaderFlagsBase flags = _rootItem.ShaderFlags[i];
if (enabled)
{
flags.SetFlagBits(flagBits, index: flagIndex);
}
else
{
flags.ClearFlagBits(flagBits, index: flagIndex);
}
}
}
private float GetDefaultFloat(string propertyName, float fallback)
{
return _rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info)
? _rootItem.Shader.GetPropertyDefaultFloatValue(info.Index)
: fallback;
}
private Vector4 GetDefaultVector(string propertyName, Vector4 fallback)
{
return _rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info)
? _rootItem.Shader.GetPropertyDefaultVectorValue(info.Index)
: fallback;
}
private void SetFloatProperty(string propertyName, float value)
{
if (_rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info))
{
info.Property.floatValue = value;
}
foreach (Material mat in Materials)
{
if (mat.HasProperty(propertyName))
{
mat.SetFloat(propertyName, value);
}
}
}
private void SetVectorProperty(string propertyName, Vector4 value)
{
if (_rootItem.PropertyInfoDic.TryGetValue(propertyName, out ShaderPropertyInfo info))
{
info.Property.vectorValue = value;
}
foreach (Material mat in Materials)
{
if (mat.HasProperty(propertyName))
{
mat.SetVector(propertyName, value);
}
}
}
private void RecordAllMaterials(string undoName)
{
var objects = new List<UnityEngine.Object>();
foreach (Material mat in Materials)
{
objects.Add(mat);
}
if (objects.Count > 0)
{
Undo.RecordObjects(objects.ToArray(), undoName);
}
}
private void MarkAllMaterialsDirty()
{
foreach (Material mat in Materials)
{
EditorUtility.SetDirty(mat);
}
}
private IEnumerable<Material> Materials
{
get
{
if (_rootItem.Mats == null)
{
yield break;
}
for (int i = 0; i < _rootItem.Mats.Count; i++)
{
Material mat = _rootItem.Mats[i];
if (mat != null)
{
yield return mat;
}
}
}
}
private Material MainMaterial
{
get
{
return _rootItem.Mats != null && _rootItem.Mats.Count > 0 ? _rootItem.Mats[0] : null;
}
}
private static GUIContent IconContent(string iconName, string key, string fallbackTooltip)
{
EnsureToolbarContentLanguage();
if (IconContentCache.TryGetValue(key, out GUIContent cachedContent))
{
return cachedContent;
}
GUIContent icon = EditorGUIUtility.IconContent(iconName);
var content = new GUIContent(icon != null ? icon.image : null, Tip(key, fallbackTooltip));
IconContentCache[key] = content;
return content;
}
private static void EnsureToolbarContentLanguage()
{
string currentLanguage = NBShaderInspectorLocalization.CurrentLanguage;
if (string.Equals(s_ToolbarContentLanguage, currentLanguage, StringComparison.Ordinal))
{
return;
}
s_ToolbarContentLanguage = currentLanguage;
s_SettingsContent = null;
IconContentCache.Clear();
TextContentCache.Clear();
}
private static GUIContent TextContent(string key, string fallbackLabel, string fallbackTooltip)
{
EnsureToolbarContentLanguage();
if (TextContentCache.TryGetValue(key, out GUIContent cachedContent))
{
return cachedContent;
}
cachedContent = NBShaderInspectorLocalization.MakeInspectorContent("toolbar." + key, fallbackLabel, fallbackTooltip);
TextContentCache[key] = cachedContent;
return cachedContent;
}
private static string Label(string key, string fallback)
{
return NBShaderInspectorLocalization.Get("inspector.toolbar." + key + ".label", fallback);
}
private static string Tip(string key, string fallback)
{
return NBShaderInspectorLocalization.Get("inspector.toolbar." + key + ".tip", fallback);
}
private static string UndoText(string key, string fallback)
{
return NBShaderInspectorLocalization.Get("inspector.toolbar." + key + ".undo", fallback);
}
}
}

View File

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

Some files were not shown because too many files have changed in this diff Show More