【问题标题】:Avoiding String properties in Unity Shaders在 Unity 着色器中避免字符串属性
【发布时间】:2020-11-09 03:50:59
【问题描述】:

在 Unity 中创建着色器时,您可以向其添加一个可以从不同脚本内部调用的属性。为此,可以使用以下行调用并设置 Vector3 属性名称_vector3:

materialName.SetVector("_vector3", new Vector3(1, 1, 1));

这很好,但真的没有办法避免使用“魔法”字符串吗?似乎是一种非常混乱且容易出错的方法。我知道也许你可以在顶部定义它,这样它就不是一个“神奇”的字符串,但它仍然是一个字符串变量,在进行任何更改时需要从着色器传递到脚本。

这里有一个非常基本的问题:有没有办法在 Unity 中调用变量时避免使用“魔法”字符串?

【问题讨论】:

  • 似乎有一个重载需要一个 ID:docs.unity3d.com/ScriptReference/Material.SetVector.html 您仍然需要将一个字符串传递给 Shader.PropertyToID 以将名称解析为 id,但只需一次,看起来这是首选方法,根据文档。 ID可以保存到变量中,如vector3_id等
  • @CoolBots 很确定这只是为了优化目的。根据我发现的所有内容,您可以在脚本顶部使用它来避免多次发生转换。不过,您仍然需要为初始转换提供字符串名称。所以它并不能真正帮助解决我对字符串的抱怨,还是我错过了什么?
  • @Jee 不,这是为了优化目的,你是对的 ^^
  • 没有办法避免这些神奇的字符串,但是你可以将它们定义为 const,这样它们就不会是神奇的了 ^^

标签: c# unity3d graphics shader


【解决方案1】:

不,没有办法摆脱字符串标识符。 当然,您可以在一个地方添加一些包含着色器属性标识符的辅助类,以提高可维护性。

public static class ShaderProps
{
    public static class MyShaderA
    {
        public const string SomeProperty = "_vector3";
    }
}

// Usage
public class MyBehaviour : MonoBehaviour
{
    private void Update 
    {
        material.SetVector(ShaderProps.MyShaderA.SomeProperty, ...);
    }
}

您应该使用Shader.PropertyToID(string name) 并缓存结果,因为它更有效。每次您使用字符串标识符重复调用字符串(例如在Update)时,Unity 都会在后台调用它。

【讨论】:

  • 我倾向于使用enum而不是字符串,但同样。
  • @Immersive 你有什么理由建议使用枚举而不是字符串?
  • @Jee 没什么具体的。如果可以的话,我会将 ID 缓存在字典中,并且更喜欢枚举(int)而不是字符串作为键。它主要是对效率的认可,比较一个 int 和一个字符串。不过,为了可维护性而使用 const 字符串是有争议的。
【解决方案2】:

遗憾的是,没有办法避免这种情况。有一个优雅的解决方案,考虑到 ID 以提高性能

public static class MyShader
{
    public static readonly int _MyPropertyName = 
        Shader.PropertyToID(nameof(_MyPropertyName));

}

用法

void myShaderMethod()
{
    materialName.SetVector(MyShader._MyPropertyName, new Vector3(1, 1, 1));
}

【讨论】:

    【解决方案3】:

    您可以简单地使用 Shader.PropertyToID:

    private static readonly int shaderProperty;
    
    void Start(){
        shaderProperty = Shader.PropertyToID("propertyName");
    }
    

    然后

    materialName.SetVector(shaderProperty, new Vector3(1, 1, 1));
    

    这样会更有效率。

    【讨论】:

    • 效率更高,没错,但它解决了魔术字符串问题吗?
    • 好吧,在着色器参数中插入一个字符串作为名称。这将被散列为一个整数值并存储。 Shader.PropertyToID 做同样的事情,接受一个字符串并将其散列为一个整数值。而且我想它背后没有“神奇”的东西,因为字符串是必需的,而不是可选的。所以不行。您无法避免插入字符串。否则如何匹配参数名称?
    猜你喜欢
    • 1970-01-01
    • 2017-09-03
    • 2019-07-15
    • 1970-01-01
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-14
    相关资源
    最近更新 更多