Unity3D:将着色器关键字与 C# 脚本结合使用
推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生
将着色器关键字与 C# 脚本结合使用
您可以启用或禁用着色器关键字。启用或禁用着色器关键字时,Unity 会渲染相应的着色器变体。
本页包含以下信息:
- 本地和全局着色器关键字
- 启用和禁用着色器关键字
- 在运行时管理关键字集
本地和全局着色器关键字
当 Unity 在 C# 中表示着色器关键字时,它使用本地着色器关键字和全局着色器关键字的概念。
本地着色器关键字包含在着色器源文件中声明的所有关键字。本地着色器关键字会影响单个着色器或计算着色器。本地关键字可以具有本地或全局范围,这会影响它们是否可以被全局着色器关键字覆盖。
全局着色器关键字充当本地着色器关键字的替代。不要在着色器源文件中声明这些;它们仅存在于 C# 代码中。全局着色器关键字可以同时影响多个着色器和计算着色器。
本地着色器关键字
在着色器源文件中声明着色器关键字时,Unity 在 C# 中使用 LocalKeyword 结构表示此关键字。这称为本地着色器关键字。
的 isOverridable 属性指示关键字是在源文件中使用全局范围还是局部范围声明的。如果关键字是用全局范围声明的,因此可以被具有相同名称的全局着色器关键字覆盖。如果关键字是使用本地范围声明的,因此不能被具有相同名称的全局着色器关键字覆盖。LocalKeywordtruefalse
Unity 将影响着色器或计算着色器的所有本地着色器关键字存储在 LocalKeywordSpace 结构中。对于图形着色器,您可以使用Shader.keywordSpace访问它。对于计算着色器,您可以使用 ComputeShader-keywordSpace 访问它。
全局着色器关键字
除了您在源文件中声明的本地着色器关键字之外,Unity 还维护一个单独的全局着色器关键字列表。不要在着色器源文件中声明这些;相反,它们是在 C# 中使用的本地着色器关键字的运行时重写。全局着色器关键字可以同时影响多个着色器和计算着色器。
Unity 表示具有全局关键字结构的全局着色器关键字。
当您需要为许多材质和计算着色器启用或禁用相同的着色器关键字时,设置全局着色器关键字会很方便。但是,它具有以下潜在的缺点:
- 如果着色器意外定义了具有相同名称的关键字,则设置关键字的全局状态可能会导致意外后果。可以通过声明具有本地范围的关键字或以降低冲突可能性的方式命名关键字来防止这种情况。
- 创建新的 时,Unity 会更新此时加载的所有着色器和计算着色器的全局和本地关键字空间之间的内部映射。这可能是 CPU 密集型操作。若要减少此操作的影响,请尝试在应用程序启动后不久创建所有全局关键字,同时加载应用程序。
GlobalKeyword
本地和全局着色器关键字如何交互
当具有相同名称的全局和局部着色器关键字具有不同的状态时,Unity 将使用 的属性来确定是针对单个材质或计算着色器启用还是禁用关键字。 如果关键字是使用全局作用域声明的,并且是使用本地作用域声明的,则为 true。isOverridableLocalKeywordisOverridablefalse
- 何时为 :如果存在并启用了同名的全局关键字,Unity 将使用全局关键字的状态。否则,Unity 将使用本地关键字的状态。
isOverridabletrue
- 何时是:Unity 始终使用本地关键字的状态。
isOverridablefalse
因此,要了解是为单个材质或计算着色器启用还是禁用着色器关键字,必须检查属性的状态以及全局和/或局部关键字状态。isOverridable
此示例演示如何检查 Unity 是否认为为材质启用或禁用了关键字:
using UnityEngine;
using UnityEngine.Rendering;
public class KeywordExample : MonoBehaviour
{
public Material material;
void Start()
{
CheckShaderKeywordState();
}
void CheckShaderKeywordState()
{
// Get the instance of the Shader class that the material uses
var shader = material.shader;
// Get all the local keywords that affect the Shader
var keywordSpace = shader.keywordSpace;
// Iterate over the local keywords
foreach (var localKeyword in keywordSpace.keywords)
{
// If the local keyword is overridable (i.e., it was declared with a global scope),
// and a global keyword with the same name exists and is enabled,
// then Unity uses the global keyword state
if (localKeyword.isOverridable && Shader.IsKeywordEnabled(localKeyword.name))
{
Debug.Log("Local keyword with name of " + localKeyword.name + " is overridden by a global keyword, and is enabled");
}
// Otherwise, Unity uses the local keyword state
else
{
var state = material.IsKeywordEnabled(localKeyword) ? "enabled" : "disabled";
Debug.Log("Local keyword with name of " + localKeyword.name + " is " + state);
}
}
}
}
启用和禁用着色器关键字
若要检查是否为图形着色器启用了本地关键字,请使用 Material.IsKeywordEnabled 或 Material.EnableKeyword。对于计算着色器,请使用 ComputeShader.IsKeywordEnabled 或 ComputeShader.EnableKeyword。
若要检查是否启用了全局关键字,请使用 Shader.IsKeywordEnabled 或 Shader.EnableKeyword 或 ComputeShader.enabledKeywords。
若要启用或禁用图形着色器的本地着色器关键字,请使用 Material.SetKeyword、Material.EnableKeyword 或 Material.DisableKeyword。对于计算着色器,请使用 ComputeShader.SetKeyword、ComputeShader.EnableKeyword 或 ComputeShader.DisableKeyword。
要启用或禁用全局着色器关键字,请使用 Shader.SetKeyword、ComputeShader.EnableKeyword 或 ComputeShader.DisableKeyword。
若要使用命令缓冲区启用或禁用本地或全局关键字,请使用 CommandBuffer.EnableKeyword 或 CommandBuffer.DisableKeyword 。
注意:启用或禁用适用于着色器变体的关键字时,Unity 会使用不同的着色器变体。在运行时更改着色器变体可能会影响性能。如果关键字中的更改需要首次使用变体,则在图形驱动程序准备着色器程序时可能会导致卡顿。对于大型或复杂着色器,或者如果全局关键字状态更改影响多个着色器,这可能是一个特殊问题。为避免这种情况,如果将关键字与着色器变体一起使用,请确保在着色器加载和预热策略中考虑关键字变体。有关详细信息,请参阅着色器加载。
在运行时管理关键字集
创作着色器时,可以在集合中声明关键字。集合包含互斥关键字。
在运行时,Unity 没有这些集的概念。它允许您独立启用或禁用任何关键字,并且启用或禁用关键字不会影响任何其他关键字的状态。这意味着可以启用同一集中的多个关键字,也可以禁用集中的所有关键字。
当一个集中启用了多个关键字或一个集中没有启用任何关键字时,Unity 会选择它认为“足够好”匹配的变体。无法保证究竟发生了什么,它可能会导致意想不到的结果。最好通过仔细管理关键字状态来避免这种情况。
由3D建模学习工作室整理翻译,转载请注明出处!