如何在Unity中实现基于物理的材质系统(PBR)?

Number of views 94

请说明PBR的工作原理,并提供一个Unity ShaderLab实现。

1 Answers

物理基础渲染(PBR)是一种流行的渲染技术,它基于物理定律来模拟表面反射。PBR材质可以根据光线的角度、环境和材质属性计算出正确的颜色,使得渲染结果更加真实。

PBR的基本原理

PBR材质主要考虑以下两个因素:

  1. 漫反射:光线照射到物体表面后,会均匀地散射开来。漫反射的颜色通常由物体的基础颜色决定。
  2. 镜面反射:光线照射到物体表面后,一部分光线会被反射回去。这部分反射光的颜色取决于光照条件以及材质表面的光滑程度。

在PBR中,材质表面的属性通常包括:

  • 金属度(Metallic):表示物体表面是否具有金属特性。金属的反射光颜色通常是由物体的基础颜色决定的,而非金属则更倾向于白色。
  • 粗糙度(Roughness):控制反射光的模糊程度。粗糙度越低,反射光越清晰;反之,反射光越模糊。
  • 法线贴图(Normal Map):增加表面细节,使表面看起来更复杂。

Unity ShaderLab实现

下面是一个简单的PBR Shader示例:

Shader "Custom/PBRShader"
{
    Properties
    {
        _BaseColor("Base Color", Color) = (1, 1, 1, 1)
        _Metallic("Metallic", Range(0, 1)) = 0.5
        _Roughness("Roughness", Range(0, 1)) = 0.5
        _MainTex ("Texture", 2D) = "white" {}
        _NormalMap("Normal Map", 2D) = "bump" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;
        sampler2D _NormalMap;
        float4 _BaseColor;
        half _Metallic;
        half _Roughness;

        struct Input
        {
            float2 uv_MainTex;
            float2 uv_NormalMap;
        };

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb * _BaseColor.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = 1 - _Roughness;
            o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));
        }
        ENDCG
    }
    FallBack "Diffuse"
}

这个Shader使用了Unity内置的Standard光照模型,通过Properties定义了材质的基本属性,如基础颜色、金属度、粗糙度等。surf函数中,我们根据这些属性设置了表面输出的Albedo(基础颜色)、Metallic(金属度)、Smoothness(光滑度)和Normal(法线)。

要使用这个Shader,只需将其分配给任何Unity中的材质,并调整其属性即可。