Unity高级开发-优化(一)-渲染

01-网格合并

  • 使用gameobject的static属性设置
    注意的是,所谓静态就是静止的,你如果要改变它位置,就不是静态了,静态物体在脚本加载的时候就开始渲染,不随着update 每侦更新,你如果要移动物体,就必然要重新刷新,就是动态了 。

所有被勾选了“Static”的GameObject,其中的Mesh Filter中的mesh都会被合并到 "Combined Mesh (root: scene)" 中。


Unity高级开发-优化(一)-渲染_第1张图片
Static
  • 使用代码合并

合并网格有利于性能最优化。如果mergeSubMeshes为true,所有的网格会被结合成一个单个子网格。否则每一个网格都将变成单个不同的子网格。如果所有的网格共享同一种材质,设定它为真。如果useMatrices为false,在CombineInstance结构中的变换矩阵将被忽略。

using UnityEngine;

public class MashTest : MonoBehaviour {

    
    void Start () {
        MeshFilter[] meshfies = GetComponentsInChildren();
        CombineInstance[] combine = new CombineInstance[meshfies.Length];
        int i = 0;
        while (i < meshfies.Length)
        {
            combine[i].mesh = meshfies[i].sharedMesh;
            combine[i].transform = meshfies[i].transform.localToWorldMatrix;
            meshfies[i].gameObject.SetActive(false);
            i++;
        }

        transform.GetComponent().mesh = new Mesh();
        transform.GetComponent().mesh.CombineMeshes(combine);
        transform.gameObject.SetActive(true);
    }
}
using UnityEditor;
using UnityEngine;

public class MashTool : MonoBehaviour {

    
    [MenuItem("Tools/Save Combine Mesh")]
    public static void SaveMesh()
    {
        Mesh m = Selection.activeGameObject.GetComponent().sharedMesh;
        AssetDatabase.CreateAsset(m, "Assets/Test/cmbMesh.asset");
        AssetDatabase.SaveAssets();
    }
}
Unity高级开发-优化(一)-渲染_第2张图片
保存后的mash

使用Linear还是Gamma

官方文档

概述

线性渲染就是渲染场景所有输入都是线性的。一般来说存在的纹理都是经过Gamma矫正了的,也就是说当纹理被采样到一个材质上时,颜色值已经不是线性的了。如果这些纹理用通常的计算方式去计算光照和图片效果,在非线性空间计算,这将导致轻微的偏差。(而这种偏差就是需要Gamma矫正的原因)

线性渲染保证了在shader中输入与输出都是在正确的颜色空间得出更正确的结果。

Gamma矫正

所谓伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比度效果。计算机绘图领域惯以此屏幕输出电压与对应亮度的转换关系曲线,称为伽玛曲线(Gamma Curve)。以传统CRT(Cathode Ray Tube)屏幕的特性而言,它的输入电压和显示出来的亮度关系不是线性的,而是一个类似幂律(pow-law)曲线的关系,而这个关系又恰好跟人眼对光的敏感度是相反的。这个巧合意味着,虽然CRT显示关系是非线性的,但对人类来说感知上很可能是一致的。

Gamma 校正补偿了不同输出设备存在的颜色显示差异,从而使图像在不同的监视器上呈现出相同的效果。

保存颜色信息本身矫正称为encoding gamma,显示器对颜色的矫正称为display gamma,所以一个完整的图形系统中需要两个Gamma值,两次矫正刚好在一定程度上抵消(但一般不是完全抵消)。

Gamma管线(Gamma Pipeline)

在Gamma渲染管线中,所有颜色和纹理在Gamma空间被采样,在shader应用了之后前,不会对shader输入做任何处理。即使这些值是在Gamma空间中的,所有shader计算对待他们输入都当做在线性空间,此外,当把shader输出写到内存中时,没有对最终像素应用Gamma矫正。很多时候是可以接受两次偏差一定程度上相互抵消。但是这是不正确的。

两种情况:

  1. 线性输入
    输入颜色值在线性空间下,而在shader中按照线性空间下的计算,这些都是正确的,但最终输出的时候也没有做任何处理(主要Gamma矫正),所以在屏幕显示时,屏幕进行了一次display gamma,这样的转换后得到非预期的亮度,通常表现为整个场景比较昏暗。

  2. 非线性输入
    输入颜色值在非线性空间下(通常表现为纹理),而在shader中把该值当成是线性空间下计算的(产生了偏差),这是不正确的,在最终输出的时候也没有做任何处理,但在屏幕显示时,进行了display gamma,虽然这样产生两次偏差会在一定程度上进行抵消,但这样的抵消是不正确的。

为了直接显示时可以正确显示,大多数图像文件都进行了提前的校正,即已经使用了一个encoding gamma对像素值编码。

线性管线(Linear Pipeline)

如果开启了线性渲染(Linear Rendering),Unity会背地里把输入纹理设置为sRGB模式,这种模式下硬件在对纹理进行采样时会自动将其转换到线性空间中;并且,也会设置一个sRGB格式的buffer,此时GPU会在shader写入color buffer前自动进行伽马校正。如果此时开启了混合(像我们之前的那样),在每次混合是,之前buffer中存储的颜色值会先重新转换回线性空间中,然后再进行混合,完成后再进行伽马校正,最后把校正后的混合结果写入color buffer中。这里需要注意,Alpha通道是不会参与伽马校正的。

sRGB模式是在近代的GPU上才有的东西。如果不支持sRGB,我们就需要自己在shader中进行伽马校正。
对非线性输入纹理的校正通常代码如下:

float3 diffuseCol = pow(tex2D(diffTex, texCoord), 2.2);

在最后输出前,对输出像素值的校正代码通常长下面这样:

fragColor.rgb = pow(fragColor.rgb, 1.0/2.2);
return fragColor;

但是,手工对输出像素进行伽马校正在使用混合的时候会出现问题。这是因为,校正后导致写入color buffer的颜色是非线性的,这样混合就发生在非线性空间中。一种解决方法时,在中间计算时不要对输出进行伽马校正,在最后进行一个屏幕后处理操作对最后的输出进行伽马校正,但很显然这会造成性能问题。 还有一些细节问题,例如在进行屏幕后处理的时候,要小心我们目前正在处理的图像到底是不是已经伽马校正后的。

总之,一切工作都是为了“保证所有的输入都转换到线性空间,并在线性空间下做各种光照计算,最后的输出(最最最最后的输出)进行伽马校正后再显示”。

Linear Rendering 和 Gamma Rendering的区别

Linear Rendering就是在shader中所有计算会在线性空间下进行,Gamma Rendering就是在shader中不进行转换到线性空间下,直接计算。然就是计算方程式不同,也就意味例如光照表面会有不同的响应曲线和图片效果,表现不相同。

  • Light Falloff
    光照表现一般受光源的距离和法线两个因素影响(在同等光强下)。首先当我们用Linear Rendering时,执行Gamma矫正将会使光照范围变大。第二种会使边缘模糊,分不清界限。这更准确的表现了表面光照强度下降。


    Unity高级开发-优化(一)-渲染_第3张图片
    image.png
  • 表面响应强度

随着光强的增加,非线性方式计算的表面会更亮一些。这导致了光照在表面很多地方曝光过度,而且给场景模型一个褪色(变白色了)的感觉。当你用线性渲染时,表面颜色仍然随着光照强度线性增加的,这样就使表面材质和颜色更接近现实


Unity高级开发-优化(一)-渲染_第4张图片
Linear与Gamma
  • 混合

混合是在帧缓冲区发生的,当使用Gamma Rendering,这表示颜色之间混合是在非线性空间下计算的。然而这是不正确的。
下图在Linear Space中混合结果,颜色之间过度不是很明显。


Unity高级开发-优化(一)-渲染_第5张图片
image.png

下图在Gamma Space中混合结果,颜色交界处出现了明显的其它颜色,颜色更亮,出现褪色的现象。


Unity高级开发-优化(一)-渲染_第6张图片
image.png
  • Mipmaps

计算纹理Mipmap是种线性计算,需要对某个方形区域内像素取平均值,如果纹理存储在非线性空间,那么计算时也是在非线性空间里计算,这样就会得到错误的结果。正确的做法是先转换到线性空间在计算mipmap。

  • Lightmapping

切换linear 和gamma方式,需要重新烘焙相关的Lightmapping。

你可能感兴趣的:(Unity高级开发-优化(一)-渲染)