找回密码
 立即注册
查看: 326|回复: 0

【unity Shader 学习笔记】5-4 GI(全局光照)

[复制链接]
发表于 2023-3-30 20:48 | 显示全部楼层 |阅读模式
全局光照,(Global Illumination,简称 GI),。
或被称为 Indirect Illumination, 间接光照,是指既考虑场景中直接来自光源的光照(Direct Light)又考虑经过场景中其他物体反射后的光照 (Indirect Light)的一种渲染技术。使用全局光照能够有效地增强场景的真实感。
即可以理解为:全局光照 = 直接光照(Direct Light) + 间接光照(Indirect Light)


【05.渲染中光和材质的数学魔法 | GAMES104-现代游戏引擎:从入门到实践】 【精准空降到 31:48】
说白了其实就是计算环境内的所有光照,如果只是单纯计算直接光照,那么看起来就不真实。现实生活中,光会在各种物体间折射和反射,这个计算是十分复杂的,所以也就有了平常常听的光线追踪这类的名词。
对于一般的游戏来说,实时计算GI是件非常耗性能的事情。所以一般来说会先进行预计算,也就是提前将场景的光照烘焙到一张名为LightMap 的贴图中,用来记录光照信息以及一些阴影的信息。
unityt中的GI

烘焙GI

在unity 中,选择 Window -> Rendering -> Lighting




将场景中需要烘焙的物体勾上 static标签,点击Lighting 中的计算,会生成对应场景的光照数据以及光照贴图。
如何使用GI




关闭场景光源,显示烘焙好的阴影

先直接贴代码
Shader "Study/Chapter5/MyGlobalGI"
{
    Properties
    {
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

                        // 引入变体 是否使用光照贴图
                        #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #include "UnityCG.cginc"
                        #include "AutoLight.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal :NORMAL;
                // 当Back GI 或 Realtime GI 开启时则进行定义 (静态或者动态GI的时候)
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 texcoord1 : TEXCOORD1;
                #endif
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldPos : TEXCOORD0;
                half3 worldNormal : TEXCOORD2;
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                float4 lightmapUV : TEXCOORD1;
                #endif
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                #if defined(LIGHTMAP_ON)
                o.lightmapUV.xy = v.texcoord1 * unity_LightmapST.xy + unity_LightmapST.zw;
                #endif

                #if defined(DYNAMICLIGHTMAP_ON)
                o.lightmapUV.zw = v.texcoord1 * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
                #endif
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                SurfaceOutput o;
                // UNITY_INITIALIZE_OUTPUT 将类型的参数都初始化为0 (type,name) -> (类型,变量名)
                UNITY_INITIALIZE_OUTPUT(SurfaceOutput,o)
                o.Normal = i.worldNormal;
                o.Albedo = 1;

                UnityGI gi;
                UNITY_INITIALIZE_OUTPUT(UnityGI,gi)
                gi.light.color = _LightColor0;
                gi.light.dir = _WorldSpaceLightPos0;   // 光照方向
                gi.indirect.diffuse = 0;  //漫反射
                gi.indirect.specular = 0;   // 高光

                UnityGIInput giInput;
                UNITY_INITIALIZE_OUTPUT(UnityGIInput,giInput)
                giInput.light = gi.light;  // 世界光照的颜色
                giInput.worldPos = i.worldPos;  // 当前世界坐标
                giInput.worldViewDir = normalize(_WorldSpaceCameraPos - i.worldPos);    //世界坐标到摄像机位置归一向量
                giInput.atten = 1;  //光照衰减 平行光默认为1
                giInput.ambient = 0; //  周围光照(环境光?)
                #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
                    giInput.lightmapUV = i.lightmapUV; // lightmapUV 只在烘焙的时候使用
                #endif

                // GI间接光照计算,数据存储在gi中
                gi = UnityGI_Base(giInput,1,o.Normal);
                fixed4 c = LightingLambert(o,gi);
                return c;
            }
            ENDCG
        }
    }
}
一般情况下,unity 内置的 Standard 材质,几乎是满足绝大部分的一些材质需求,当然这个也使得材质十分的臃肿,以及过多的变体。不过,如果需要找具体某些功能,还是能够从里面去拆解自己需要的部分。
如果觉得Standard嵌套太多,还可以看下表面着色器生成的代码。表面着色器生成后的代码虽然冗长,但是还是能从中找到需要的内容。



表面着色器shader

Shader "Standard"{
......
Pass
        {
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }
            .......
            #pragma vertex vertBase
            #pragma fragment fragBase
            #include "UnityStandardCoreForward.cginc"

            ENDCG
        }Standard.shader ->  UnityStandardCoreForward.cginc
#include "UnityStandardConfig.cginc"

#if UNITY_STANDARD_SIMPLE
    #include "UnityStandardCoreForwardSimple.cginc"
    VertexOutputBaseSimple vertBase (VertexInput v) { return vertForwardBaseSimple(v); }
    VertexOutputForwardAddSimple vertAdd (VertexInput v) { return vertForwardAddSimple(v); }
    half4 fragBase (VertexOutputBaseSimple i) : SV_Target { return fragForwardBaseSimpleInternal(i); }
    half4 fragAdd (VertexOutputForwardAddSimple i) : SV_Target { return fragForwardAddSimpleInternal(i); }UnityStandardCoreForward.cginc -> UnityStandardCoreForwardSimple.cginc
half4 fragForwardBaseSimpleInternal (VertexOutputBaseSimple i)
{
   ......
   UnityGI gi = FragmentGI (s, occlusion, i.ambientOrLightmapUV, atten, mainLight);
}UnityStandardCoreForwardSimple.cginc -> UnityStandardCore.cginc
inline UnityGI FragmentGI(......)
{
   .......
   return UnityGlobalIllumination
}UnityStandardCore.cginc  ->  UnityGlobalIllumination.cginc
inline UnityGI UnityGlobalIllumination(......)
{
    UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
}一顿操作,终于翻到最后需要的内容  UnityGI_Base。具体再解析需要的结构数据,一步步传入,最后返回获取的GI数据。
环境光遮蔽 Ambient Occlusion

环境光遮蔽(Ambient Occlusion,简称 AO)是全局光照明的一种近似替代品,可以产生重要 的视觉明暗效果,通过描绘物体之间由于遮挡而产生的阴影, 能够更好地捕捉到场景中的细 节,可以解决漏光,阴影漂浮等问题,改善场景中角落、锯齿、裂缝等细小物体阴影不清晰 等问题,增强场景的深度和立体感。
可以说,环境光遮蔽在直观上给玩家的主要感觉体现在画面的明暗程度上,未开启环境光遮 蔽特效的画面光照稍亮一些;而开启环境光遮蔽特效之后, 局部的细节画面尤其是暗部阴影会更加明显一些。


而且大部分游戏实际会将阴影直接画在贴图上,或者是额外的贴图做阴影高光等特殊的处理。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-15 07:09 , Processed in 0.100624 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表