【问题标题】:Change camera shader property更改相机着色器属性
【发布时间】:2018-10-22 00:59:06
【问题描述】:

我需要设置一个着色器的变量,而没有环绕它的材质。

我会解释问题以及为什么它不像问题“How can I access shader variables from script?”。

问题

我的着色器与此类似(删除了 99% 的不相关样板代码):

Shader "Hidden/XShader"
{
    Properties
    {
        _x ("", float) = 0
    }

    SubShader
    {
        Pass
        {
            float _x;

            half4 frag(v2f i) : SV_Target
            {
                // "col" and "wpos" have been correctly defined

                if (wpos.x >= _x)
                {
                    col.r = 1;
                } else {
                    col.r = 0;
                }

                return col;
            }
        }
    }
}

这个着色器是通过Edit->Project Settings->Graphics->Deferred 选项设置的。它是主相机使用的默认着色器。

现在我需要从附加到相机的代码中设置_x 值:

public class XCameraController : MonoBehaviour
{
    public float x;

    void Update()
    {
        <something>.SetFloat("_x", x);
    }
}

&lt;something&gt; 占位符通常是一种材质,因为在那里定义了 SetFloat()。但是相机和着色器没有材质。 material 的概念甚至不适用于默认着色器。

我已经在网上和文档中搜索了几个小时。我承认我失败了,在这里不知所措。我想它一定很简单,但我找不到任何文档。

我不指望一个已实施的解决方案,我可以找到帮助的指针就足够了!

【问题讨论】:

    标签: c# unity3d shader


    【解决方案1】:

    但是相机和着色器没有材质。的概念 材质甚至不适用于默认着色器。

    是的,但是材质只是从着色器中公开所有属性,因此在这里很重要,因为您想更改着色器属性。

    您有一个自定义着色器,但它不用于渲染游戏对象,而是用于渲染相机。 更改着色器仍需要材质。 如果您不想使用材质,则可以使用Shader.SetGlobalXXX 函数,例如Shader.SetGlobalFloat("_x", 3),但它会更改所有着色器属性。这是不现实的。


    正确的方法是创建一个临时材质,您将使用它来修改着色器,更改着色器属性,然后更新相机正在使用的着色器。为此,您必须:

    查找着色器或使用公共变量获取着色器的引用:

    Shader camShader = Shader.Find("Hidden/XShader");
    

    从着色器创建材质

    Material camMat = new Material(camShader);
    

    根据需要修改属性

    camMat.SetFloat("_x", 3);
    

    将修改后的着色器属性应用到相机

    Camera.main.SetReplacementShader(camShader, "RenderType");
    

    如果您手动渲染相机,请使用Camera.main.RenderWithShader(camShader, "RenderType") 而不是Camera.main.SetReplacementShader(camShader, "RenderType")

    【讨论】:

    • 哇,谢谢!这是个好消息!但我还有两个问题。这个临时替换着色器......它是一个“着色器实例”吗?还是我混淆了什么?而且,更重要的是,为每一帧将着色器加载/编译到硬件中:这是否比 SetGlobal*() 替代方案更好?周围有很多全局变量看起来没有那么问题,我可以嵌套名称(shader1.tex1shader2.col)。我担心连续加载着色器时的性能。这很可能表明我知道的很少:-)
    • 不知道SetGlobalXXX的性能如何。以前没用过。有了这个名字,我认为使用它不是一个好主意。它看起来像是在寻找所有着色器并尝试更改其他一些着色器上不存在的属性。使用材质法。
    • 好吧,我会盲目相信你!再次,非常感谢!
    • 对于您的其他问题,ShaderMaterial 都是 classes,它们是引用类型,因此每次创建它们的新实例都是昂贵的。我提供的只是一个例子。您应该将camShadercamMat 变量设为全局变量,然后在AwakeStart 函数中将它们初始化一次。您可以在需要时在相机上设置属性或更新它,而不会影响性能或不会导致 GC。正在回答您评论中的其他问题,但不客气!
    • 忘了说点什么。既然您谈到了性能,您应该使用string 重载,而是使用int 一个nameID。每个着色器或材质函数都有一个int 重载,这就是您应该使用的。这也涉及Shader.PropertyToID。有关完整示例,请参阅 this
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-30
    • 2011-05-21
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多