unity-LOD优化

LOD, 也就是 Level of Detail
lod 主要是为了在 摄像机 离 物体 不同距离的情况, 显示 模型不同精细级别. 近距离 显示 丰富细节的模型, 远距离 显示 简单的模型. 可以有效减少绘制量, 减少模型顶点数量 (也就是可以减少 shader vertex 阶段的执行量). 缺点是 需要制作多个模型, 会增大包体.


前篇


使用

  1. 建一个 空对象a, 丢上需要显示不同级别的模型

  2. 对象a 上挂一个 LOD Group 组件, 然后把不同级别模型拖进去, 这里 我把两个 sphere 丢进 LOD0, 是为了体现这个级别需要两个dc.

    调整 lod 百分比可以调整与 摄像机触发距离

  3. 然后拖动摄像机离 对象a 的距离, 就可以看到效果.


shader 中的 lod

相关资料

对于TA来说,Shader LOD其实就是根据设备性能的不同编译不同版本的Shader。

这种编译方式最早是为了适应不同时代的显卡而准备的。主机端本来就不存在这个问题,而现在在PC端上想找到上古级别的显卡也不太容易。所以目前这玩意儿最大的用途也就是为了适配高低配置不同的手机(以上为个人意见)。

使用Shader LOD,要编写多个SubShader,格式大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Shader "YY/Cube" 
{
Properties {
...
}

SubShader
{
Tags { "RenderType"="Opaque" "IgnoreProjector"="True"}
LOD 100
UsePass "YY/BasicShaders/UNLIGHT"
}

SubShader
{
Tags { "RenderType"="Opaque" "IgnoreProjector"="True"}
LOD 50
UsePass "YY/BasicShaders/UNLIGHTNOFOG"
}

FallBack "Diffuse"
}

shader 的 lod 定义

Built-in shaders in Unity have their LODs set up this way:

  • VertexLit kind of shaders = 100
  • Decal, Reflective VertexLit = 150
  • Diffuse = 200
  • Diffuse Detail, Reflective Bumped Unlit, Reflective Bumped VertexLit = 250
  • Bumped, Specular = 300
  • Bumped Specular = 400
  • Parallax = 500
  • Parallax Specular = 600

shader 的 lod 设置

在脚本中,我们可以用 Shader.globalMaximumLOD = 100 来全局设置 lod 值,激活使用相对应的 SubShader。
我们也可以用 _shader.maximumLOD 来单独设置一个 shader 的 lod。

根据这个特性,我们就可以在一个 shader 里写一出组 SubShader ,分别设置不同的 lod ,lod 越大的对应性能越好,越低的性能越差。然后我们就可以用设置 lod 的方法来控制游戏画面的渲染质量。

Project Setting->QualitySettings 中的 Maximum LODLevel 可以设置最大LOD等级,Shader的LOD值是小于所设定的LOD值,才会被编译使用。Maximum LODLevel的等级可以设置7个级别,例如设置为1,则表示把最大LOD值设置为100,等级2,则最大LOD值为200,以此类推,若设置为0,则表示不进行LOD判断,任何LOD值的Shader都会被使用。

实际测试情况

参考: ShaderLod.cs

很重要 : shader 需要动态控制使用 subshader 的话, subshader 的顺序 从上到下 必须按 Lod 的 大到小 来写, 才可以动态控制. 如果 从小到大 来写, 只要命中了 小的, 就不会再变了

  • shader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Shader "test/testShaderLod" {
    Properties {
    _MainTex ("Base (RGB)", 2D) = "white" {}
    }

    SubShader
    {
    Tags { "RenderType"="Opaque" "IgnoreProjector"="True"}
    LOD 600
    UsePass "test/PassNameBase/PassNameBase02" // green
    }

    SubShader
    {
    Tags { "RenderType"="Opaque" "IgnoreProjector"="True"}
    LOD 500
    UsePass "test/PassNameBase/PassNameBase01" // red
    }
    }
  • csharp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class testShaderLod : MonoBehaviour {
    Material mat;
    void Start() {
    mat = transform.GetComponent<Renderer>().sharedMaterial;
    }

    void Update() {
    if (Input.GetKeyDown(KeyCode.A)) {
    mat.shader.maximumLOD = 500;
    Debug.LogFormat("--- maximumLOD = 500");
    }

    if (Input.GetKeyDown(KeyCode.B)) {
    mat.shader.maximumLOD = 600;
    Debug.LogFormat("--- maximumLOD = 600");
    }
    }
    }
  • 效果


插件 Simple LOD v1.6

看了下这个插件的使用, 貌似不能达到减少 dc 的效果, 因为生产 lod 时, 知识 把 mesh 合并了一下, 减少了顶点, 但是还是和原来一样的 材质数量,贴图数量, 没有减少 dc. 所以还是 unity 内置的中 lod 能达到减少 dc 的效果.