文章

shader入门基础-更复杂光照

shader入门基础-更复杂光照

渲染路径

  • 前向渲染路径(Forward Rendering Path)
  • 延迟渲染路径(Defferred Rendering Path)
  • 顶点照明渲染路径(Vertex Lit Rendering Path)

通过设置 Pass 的 LightMode 标签实现

1
2
3
    Pass{
        Tags {"LightMode"="ForwardBase"}
    }

LightMode 标签支持的渲染路径设置选项

标签名描述
Always不管使用哪种渲染路径,该 Pass 总是会被渲染,但不会计算任何光照
ForwardBase用于前向渲染,该 pass 会计算环境光,最重要的平行光,逐顶点/SH 光源和 Lightmaps
ForwardAdd用于前向渲染,该 pass 会计算额外的逐像素光源,每个 pass 对应一个光源
Deferred用于延迟渲染,该 pass 会渲染 G 缓冲 G-buffer
ShadowCaster把物体的深度信息渲染到阴影映射纹理(shadowmap)或一张深度纹理中
PrepassBase用于遗留的延迟渲染,该 pass 会渲染法线和高光反射的指数部分
PrepassFinal用于遗留的延迟渲染,该 pass 通过合并纹理、光照和自发光来渲染得到最后的颜色
Vertex、VertexLMRGBM 和 VertexLM用于遗留的顶点照明渲染

前向渲染路径的原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Pass{
    for (each primitive in this model){
        for (each fragment covered by this primitive)
        {
            if (failed in depth test)
            {
                //如果没有通过深度测试,则该片元时不可见
                discard;
            }
            else{
                //如果片元可见就记性光照机选
                float4 color = Shading(materialinfo,pos,normal,lightDir,viewDir);
                //更新帧缓冲
                writeFrameBuffer(fragment,color);
            }
        }
    }
}

对于每个逐像素光源,我们都需要进行上面一次完整的渲染流程。如果一个物体在多个逐像素光源的影响区域内,那么该物体就需要执行多个 Pass, 每个 Pass 计算一个逐像素光源的光照结果,然后在帧缓冲中把这些光照结果混合起来得到最终的颜色值。假设场景中有个 N 个物体,每个物体受 M 个光源的 影响,那么要渲染整个场景一共需要 N*M 个 pass。

Unity 中的前向渲染

前向渲染路径有 3 种光照处理方式:

  • 逐顶点处理
  • 逐像素处理
  • 球谐函数(Spherical Harmonics,SH)

unity 会根据场景中各个光源的设置以及这些光源对物体影响程度,对这些光源进行一个重要度排序。 其中,一定数目光源按逐像素方式处理,最多 4 个光源会按逐顶点方式处理,剩下按 SH 方式处理。 Unity 排序规则

  • 场景中最亮的平行光总是按逐像素处理
  • 渲染模式被设置成 Not Important 的光源,会按逐顶点或者 SH 处理。
  • 渲染模式被设置成 Important 的光源,会按照逐像素处理。
  • 如果根据以上规则得到的逐像素官员数量小于 Quality Setting 中的逐像素光源数量,会有更多的光源以逐像素的方式进项渲染。

前向渲染的两种 Pass alphatest

延迟渲染原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Pass 1 {
    //第一个pass不进行真正的光照计算
    //仅仅把光照计算需要的信心存储到G缓冲中
    for(each primitive in this model)
    {
        for(each fragment covered by this privitive)
        {
            if(failed in depth test)
            {
                //如果没有通过深度测试,说明该片元是不可见
                discard;
            }else{
                //如果该片元可见
                //就把需要的信息存储到G缓冲中
                writeGBuffer(materialInfo,pos,normal);
            }
        }
    }
}

Pass 2{
    //利用G缓冲中的信息进行真正的光照计算
    for(each pixel in the screen)
    {
        if(the pixel is valid)
        {
            //如果该像素是有效地
            //读取它对应的G缓冲中的信息
            readGBuffer(pixel,materialInfo,pos,normal);
            //根据读取到的信息进行光照计算
            float4 color = Shading(materialInfo,pos,normal,lightDir,viewDir);
            //更新帧缓冲
            writeFrameBuffer(pixel,color);
        }
    }
}

延迟渲染使用的 Pass 数目通常就是两个,延迟渲染的效率不依赖于场景的复杂度,而是和我们使用的屏幕空间的大小有关。

Unity 中的延迟渲染

延迟渲染路径适合场景中光源数量较多、使用前向渲染路径会造成性能瓶颈的情况下使用,延迟渲染中的每个光源都可以按逐像素的方式进行处理。 延迟渲染缺点:

  • 不支持真正的抗锯齿(anti-aliasing)功能
  • 不能处理半透明物体(延迟渲染需要深度写入)
  • 对显卡有一定要求 Unity 中使用延迟渲染路径,需要提供两个 Pass。 第一个 Pass 用于渲染 G 缓冲,在该 Pass 中将物体漫反射、高光反射、颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的 G 缓冲区,因此,延迟渲染路径的效率不依赖与场景是否复杂,而是屏幕的分辨率高低。对于每个物体来说,这个 Pass 仅会执行一次。 第二个 Pass 用于计算真正的光照模型。这个 Pass 使用上一个 Pass 中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。 默认的 G 缓冲区包括以下渲染纹理(Render Texture):

  • RT0:ARGB,RGB 通道存储漫反射颜色,A 通道未使用
  • RT1:ARGB,RGB 通道存储高光反射颜色,A 通道存储高光反射的指数部分(Gloss)
  • RT2:ARGB,RGB 通道存储法线,A 通道未使用
  • RT3:ARGB,存储自发光+lightmap+反射探针
  • 深度缓冲和模板缓冲

光源类型

常用的光源属性有光源的位置,方向,颜色,强度,衰减。

  • 平行光 没有位置,只有方向,不会衰减。
  • 点光源 球形,球心处光照强度最强,球体边界处最弱,衰减值可以由一个函数定义。
  • 聚光灯 锥形
  • 面光源
本文由作者按照 CC BY 4.0 进行授权