zoukankan      html  css  js  c++  java
  • [Unity3D]降低向Shader中传值的开销

    Unity3D中提供了很多API用于向shader传值,这篇文章对比测试了两类不同的使用方法的性能。

    正文

    Unity3D中,通过C#代码向shader传值有两种方式。 
    一种是面向具体的material,另一种是面向所有的material。 
    以上两种方式分别对应下面两类API:

    • Material.SetXXX();
    • Shader.SetGlobalXXX();

    例如,现在的需求是,需要每帧向shader传递一个offset、一个scale、和一个alpha。

    普通的做法是:

    在shader中添加:

        float _Offset;
        float _Scale;
        float _Alpha;

    在C#中通过以下方式进行传值:

        Shader.SetGlobalFloat("_Offset", offset);
        Shader.SetGlobalFloat("_Scale", scale);
        Shader.SetGlobalFloat("_Alpha", alpha);

    以上写法可以正常工作,但是更好的方法是下面这种:

    Shader中:

        float4 _Parameter;

    C#中:

        Vector4 parameter = new Vector4(offset, scale, alpha, 0);
        Shader.SetGlobalVector("_Parameter", parameter );

    第二种方法在GPU寄存器的使用方面会优于第一种方法,因为不论是SetFloat还是SetVector,都会占用一个寄存器。CPU和GPU通信次数越少性能开销也就越少。 
    用下面的方法做一下测试,可以发现两种方式在CPU方面开销变化很明显,在我的电脑上,万次循环一帧大约可以节省2ms左右。

    void Update()
    {
        for (int i = 0; i < 10000; i++)
        {
            if (_switcher)
            {
                Shader.SetGlobalVector("_Parameter", new Vector4(1, 0, 0, 1));
            }
            else
            {
                Shader.SetGlobalFloat("_R", 0);
                Shader.SetGlobalFloat("_G", 1);
                Shader.SetGlobalFloat("_B", 1);
                Shader.SetGlobalFloat("_A", 1);
            }
        }
    }

    最后

    其实这个技巧也不仅仅局限于Unity3d,在dx和gl中也应该是这样,思想是通用的,如果谁能分享一些不是非常难的结合代码的GPU和CPU通信的学习资料大普通将be very appreciate。

  • 相关阅读:
    已知用经纬度表示的两点,求两点之间的直线距离
    linux 管道--转
    Five ways to maximize Java NIO and NIO.2--reference
    java获取当前方法
    事务策略: 了解事务陷阱--转
    实例详解 EJB 中的六大事务传播属性--转
    全面分析 Spring 的编程式事务管理及声明式事务管理--转
    Spring 事务管理高级应用难点剖析--转
    Java NIO——Selector机制源码分析---转
    Java NIO类库Selector机制解析--转
  • 原文地址:https://www.cnblogs.com/lancidie/p/7832933.html
Copyright © 2011-2022 走看看