Unity3D 面试经典:PBR渲染流程详解

前言
PBR(Physically Based Rendering)是一种基于物理光学原理的渲染技术,它能够更加真实地模拟物体表面的光照反射和折射效果。在Unity3D中,PBR渲染已经成为了主流的渲染方式,因此掌握PBR的渲染流程对于Unity3D开发者来说是非常重要的。本文将详细介绍Unity3D中PBR渲染的流程,包括BRDF模型、环境光遮蔽、全局光照、间接光照等内容,并给出相应的代码实现。

对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!

BRDF模型
BRDF(Bidirectional Reflectance Distribution Function)是指反射分布函数,它描述了物体表面对于入射光的反射特性。在PBR渲染中,常用的BRDF模型有两种:Lambertian模型和Cook-Torrance模型。

Lambertian模型是一种最简单的BRDF模型,它假设物体表面是完全粗糙的,入射光在物体表面上随机反射,反射光强度与入射光强度成正比。在Unity3D中,Lambertian模型对应的Shader代码如下:

Shader “Custom/Lambertian” {
Properties {
_MainTex (“Texture”, 2D) = “white” {}
}
SubShader {
Tags { “RenderType”=“Opaque” }
LOD 100

    CGPROGRAM
    #pragma surface surf Lambert
    sampler2D _MainTex;

    struct Input {
        float2 uv_MainTex;
    };

    void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    }
    ENDCG
}
FallBack "Diffuse"

}
Cook-Torrance模型是一种更加复杂的BRDF模型,它考虑了物体表面的粗糙度和镜面反射。在Unity3D中,Cook-Torrance模型对应的Shader代码如下:

Shader “Custom/Cook-Torrance” {
Properties {
_MainTex (“Texture”, 2D) = “white” {}
_Metallic (“Metallic”, Range(0,1)) = 0
_Glossiness (“Smoothness”, Range(0,1)) = 0.5
}
SubShader {
Tags { “RenderType”=“Opaque” }
LOD 100

    CGPROGRAM
    #pragma surface surf Standard
    sampler2D _MainTex;
    float _Metallic;
    float _Glossiness;

    struct Input {
        float2 uv_MainTex;
    };

    void surf (Input IN, inout SurfaceOutputStandard o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
    }
    ENDCG
}
FallBack "Standard"

}
环境光遮蔽
环境光遮蔽(Ambient Occlusion)是指由于物体表面几何形状的遮挡而导致的阴影效果。在PBR渲染中,环境光遮蔽可以通过计算物体表面与周围环境的遮蔽程度来模拟这种阴影效果。在Unity3D中,可以通过使用AmbientOcclusion贴图来实现环境光遮蔽。AmbientOcclusion贴图包含了物体表面每个像素点的环境遮蔽程度信息,通过在Shader中使用该贴图来实现环境光遮蔽效果。在Unity3D中,可以通过如下代码来实现环境光遮蔽:

Shader “Custom/Cook-Torrance-AO” {
Properties {
_MainTex (“Texture”, 2D) = “white” {}
_Metallic (“Metallic”, Range(0,1)) = 0
_Glossiness (“Smoothness”, Range(0,1)) = 0.5
_Occlusion (“Occlusion”, 2D) = “white” {}
}
SubShader {
Tags { “RenderType”=“Opaque” }
LOD 100

    CGPROGRAM
    #pragma surface surf Standard
    sampler2D _MainTex;
    sampler2D _Occlusion;
    float _Metallic;
    float _Glossiness;

    struct Input {
        float2 uv_MainTex;
        float2 uv_Occlusion;
    };

    void surf (Input IN, inout SurfaceOutputStandard o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        o.Metallic = _Metallic;
        o.Smoothness = _Glossiness;
        o.Occlusion = tex2D (_Occlusion, IN.uv_Occlusion).r;
    }
    ENDCG
}
FallBack "Standard"

}
全局光照
全局光照(Global Illumination)是指由于光线在场景中的多次反射和折射而导致的间接光照效果。在PBR渲染中,全局光照可以通过使用Unity3D内置的光照系统来实现。Unity3D内置的光照系统包括了实时光照和预计算光照两种方式。

实时光照是指在运行时计算光照效果,它可以实现实时的动态光照效果。在Unity3D中,可以通过使用Lighting模块来实现实时光照。Lighting模块包括了实时光照、实时阴影、实时反射等功能,可以通过在场景中添加Lighting组件来启用这些功能。在Unity3D中,可以通过如下代码来启用实时光照:

void Start () {
Light light = GetComponent();
light.type = LightType.Directional;
light.color = Color.white;
light.intensity = 1.0f;
light.shadows = LightShadows.Soft;
light.shadowStrength = 0.7f;
light.shadowBias = 0.05f;
light.shadowNormalBias = 0.4f;
light.shadowNearPlane = 0.1f;
light.renderMode = LightRenderMode.ForcePixel;
light.cullingMask = 1 << LayerMask.NameToLayer(“Default”);
light.useOcclusionCulling = true;
light.bounceIntensity = 0;
light.lightmapBakeType = LightmapBakeType.Realtime;
light.flare = null;
}
预计算光照是指在编辑器中对场景进行光照计算,然后将计算结果保存到Lightmap中,最终在运行时加载Lightmap来实现光照效果。在Unity3D中,可以通过使用Lightmapping模块来实现预计算光照。Lightmapping模块包括了Lightmap的生成和加载功能,可以通过在场景中添加Lightmap组件来启用这些功能。在Unity3D中,可以通过如下代码来启用预计算光照:

void Start () {
LightmapData[] lightmaps = new LightmapData[2];
lightmaps[0] = new LightmapData();
lightmaps[0].lightmapColor = Resources.Load(“Lightmap-0”);
lightmaps[1] = new LightmapData();
lightmaps[1].lightmapColor = Resources.Load(“Lightmap-1”);
LightmapSettings.lightmaps = lightmaps;
}
间接光照
间接光照(Indirect Lighting)是指由于光线在场景中的多次反射和折射而导致的间接光照效果。在PBR渲染中,间接光照可以通过使用Unity3D内置的全局光照系统来实现。Unity3D内置的全局光照系统包括了实时全局光照和预计算全局光照两种方式。

实时全局光照是指在运行时计算场景中物体的间接光照效果,它可以实现实时的动态间接光照效果。在Unity3D中,可以通过使用Realtime Global Illumination(RGI)来实现实时全局光照。RGI包括了实时光照、实时间接光照、实时反射等功能,可以通过在场景中添加Lighting组件来启用这些功能。在Unity3D中,可以通过如下代码来启用实时全局光照:

void Start () {
LightProbes probes = new LightProbes();
probes.count = 1;
probes.bakedProbes = new SphericalHarmonicsL2[1];
probes.bakedProbes[0] = new SphericalHarmonicsL2();
probes.bakedProbes[0][0] = new Vector3(1, 0, 0);
probes.bakedProbes[0][1] = new Vector3(0, 1, 0);
probes.bakedProbes[0][2] = new Vector3(0, 0, 1);
probes.bakedProbes[0][3] = new Vector3(0, 0, 0);
probes.bakedProbes[0][4] = new Vector3(0, 0, 0);
probes.bakedProbes[0][5] = new Vector3(0, 0, 0);
probes.bakedProbes[0][6] = new Vector3(0, 0, 0);
probes.bakedProbes[0][7] = new Vector3(0, 0, 0);
LightmapSettings.lightProbes = probes;
}
预计算全局光照是指在编辑器中对场景进行全局光照计算,然后将计算结果保存到Lightmap中,最终在运行时加载Lightmap来实现全局光照效果。在Unity3D中,可以通过使用Baked Global Illumination(BGI)来实现预计算全局光照。BGI包括了Lightmap的生成和加载功能,可以通过在场景中添加Lightmap组件来启用这些功能。在Unity3D中,可以通过如下代码来启用预计算全局光照:

void Start () {
LightmapData[] lightmaps = new LightmapData[2];
lightmaps[0] = new LightmapData();
lightmaps[0].lightmapColor = Resources.Load(“Lightmap-0”);
lightmaps[0].lightmapDir = Resources.Load(“Lightmap-0-dir”);
lightmaps[1] = new LightmapData();
lightmaps[1].lightmapColor = Resources.Load(“Lightmap-1”);
lightmaps[1].lightmapDir = Resources.Load(“Lightmap-1-dir”);
LightmapSettings.lightmaps = lightmaps;
}
总结

本文详细介绍了Unity3D中PBR渲染的流程,包括BRDF模型、环境光遮蔽、全局光照、间接光照等内容,并给出了相应的代码实现。掌握PBR渲染的流程可以帮助Unity3D开发者更好地实现真实的渲染效果。

附:视频教程
Unity / 面试专区 面试经典:PBR渲染流程详解

猜你喜欢

转载自blog.csdn.net/weixin_49669470/article/details/131005844