zoukankan      html  css  js  c++  java
  • unity shader矩阵相关优化

    https://chengkehan.github.io/MulOptimizing.html

    总结:推荐用o.vertex = UnityObjectToClipPos(v.vertex); 而不是o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);

    因为后者会拆分为:

    当开启 GPU Instancing 时,UNITY_MATRIX_MVP 会被解释为 mul(UNITY_MATRIX_VP, unity_ObjectToWorld),而 unity_ObjectToWorld 又会被解释为 unity_ObjectToWorldArray[unity_InstanceID]。这样 UNITY_MATRIX_MVP 不再是一个 uniform 常量,而变成了两个矩阵相乘,所以就需要像最开始的代码那样进行优化。

    因为:

    定义两个矩阵:

    uniform float4x4 mat0;
    uniform float4x4 mat1;

    利用这两个的累积变换,对一个点进行变换操作,可以是类似下面这样:

    o.vertex = mul(mat0, mul(mat1, v.vertex));

    也可以是这样:

    o.vertex = mul(mul(mat0, mat1), v.vertex);

    这两种方式得到的结果是一样的,但是计算量却相差很大。最简单的验证方式就是手工计算一遍,就能体会到了。另一种更直观的方式,可以看一下对应的 glsl。

    第一种:

    // cg
    o.vertex = mul(mat0, mul(mat1, v.vertex));
    // glsl
    u_xlat0 = in_POSITION0.yyyy * hlslcc_mtx4x4mat1[1];
    u_xlat0 = hlslcc_mtx4x4mat1[0] * in_POSITION0.xxxx + u_xlat0;
    u_xlat0 = hlslcc_mtx4x4mat1[2] * in_POSITION0.zzzz + u_xlat0;
    u_xlat0 = hlslcc_mtx4x4mat1[3] * in_POSITION0.wwww + u_xlat0;
    u_xlat1 = u_xlat0.yyyy * hlslcc_mtx4x4mat0[1];
    u_xlat1 = hlslcc_mtx4x4mat0[0] * u_xlat0.xxxx + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[2] * u_xlat0.zzzz + u_xlat1;
    gl_Position = hlslcc_mtx4x4mat0[3] * u_xlat0.wwww + u_xlat1;

    第二种:

    // cg
    o.vertex = mul(mul(mat0, mat1), v.vertex);
    // glsl
    u_xlat0 = hlslcc_mtx4x4mat0[1] * hlslcc_mtx4x4mat1[1].yyyy;
    u_xlat0 = hlslcc_mtx4x4mat0[0] * hlslcc_mtx4x4mat1[1].xxxx + u_xlat0;
    u_xlat0 = hlslcc_mtx4x4mat0[2] * hlslcc_mtx4x4mat1[1].zzzz + u_xlat0;
    u_xlat0 = hlslcc_mtx4x4mat0[3] * hlslcc_mtx4x4mat1[1].wwww + u_xlat0;
    u_xlat0 = u_xlat0 * in_POSITION0.yyyy;
    u_xlat1 = hlslcc_mtx4x4mat0[1] * hlslcc_mtx4x4mat1[0].yyyy;
    u_xlat1 = hlslcc_mtx4x4mat0[0] * hlslcc_mtx4x4mat1[0].xxxx + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[2] * hlslcc_mtx4x4mat1[0].zzzz + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[3] * hlslcc_mtx4x4mat1[0].wwww + u_xlat1;
    u_xlat0 = u_xlat1 * in_POSITION0.xxxx + u_xlat0;
    u_xlat1 = hlslcc_mtx4x4mat0[1] * hlslcc_mtx4x4mat1[2].yyyy;
    u_xlat1 = hlslcc_mtx4x4mat0[0] * hlslcc_mtx4x4mat1[2].xxxx + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[2] * hlslcc_mtx4x4mat1[2].zzzz + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[3] * hlslcc_mtx4x4mat1[2].wwww + u_xlat1;
    u_xlat0 = u_xlat1 * in_POSITION0.zzzz + u_xlat0;
    u_xlat1 = hlslcc_mtx4x4mat0[1] * hlslcc_mtx4x4mat1[3].yyyy;
    u_xlat1 = hlslcc_mtx4x4mat0[0] * hlslcc_mtx4x4mat1[3].xxxx + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[2] * hlslcc_mtx4x4mat1[3].zzzz + u_xlat1;
    u_xlat1 = hlslcc_mtx4x4mat0[3] * hlslcc_mtx4x4mat1[3].wwww + u_xlat1;
    gl_Position = u_xlat1 * in_POSITION0.wwww + u_xlat0;

    这样很直观的可以看到指令数量上的差别,指令越多也就意味着计算量越大,GPU 的压力也越大,但是两种方法得到的结果是一样的,所以这一点在优化时需要注意了。

  • 相关阅读:
    .NET Core: 在.NET Core中进行单元测试
    .NET: 使用.NET Core CLI开发应用程序
    .NET: 谈谈C#中的扩展方法
    WPF: WPF 中的 Triggers 和 VisualStateManager
    WPF: 只读依赖属性的介绍与实践
    XAML: 自定义控件中事件处理的最佳实践
    .NET: 谈谈共享项目 (Shared Project) 的使用
    UWP: 实现 UWP 应用自启动
    UWP: 通过命令行启动 UWP 应用
    在 .NET中,一种更方便操作配置项的方法
  • 原文地址:https://www.cnblogs.com/Shaojunping/p/12726818.html
Copyright © 2011-2022 走看看