Basic Lighting in Unity

Generally speaking, when we want to simulate a real lighting environment to generate an image, we need to consider three physical phenomena.

First, light is emitted from the light source.

The light then intersects with some objects in the scene: some light is absorbed by the objects, while others are scattered in other directions.

Finally, the camera absorbs some light, producing an image.

light source

In real-time rendering, we usually treat the light source as a point without volume, and use L to represent her direction. So, how do we measure how much light a light source emits? That is, how do we quantify light, in optics we use irradiance to quantify light. For parallel light, its irradiance can be obtained by calculating the energy passing through a unit time in a unit area perpendicular to L. When calculating the illumination model, we need to know the irradiance of the surface of an object, and the surface of the object is often not perpendicular to L, so how to calculate such a surface irradiance? You can get it using the cosine of the angle between the light's direction L and the surface normal n. It should be noted that the modulus of the default direction vector here is all 1. 

Absorption and Scattering

After the light is emitted by the light source, it will intersect with some objects. Usually, there are two results of the intersection, scattering and absorption.

Scattering only changes the direction of light. After the light is scattered on the surface of the object, there are two directions: one will scatter into the object, this phenomenon is called refraction or transmission; the other will scatter to the outside, this phenomenon is called reflection. For opaque objects, the light rays refracted into the interior of the object will continue to intersect with the internal particles, some of which will eventually be re-emitted from the surface of the object, and some will be absorbed by the object. The light re-emitted from the surface of these objects will have a different directional distribution and color than the incident light. 

In order to distinguish between the two different scattering methods, we use different parts in the lighting model to calculate them: the specular part shows how the surface reflects the light, and the diffuse part shows how much light is refracted, absorbed and Scattered out of the surface. From the number and direction of incoming rays, we can calculate the number and direction of outgoing rays, which we usually describe using the degree of outgoing. There is a linear relationship between irradiance and emittance, and the ratio between them is the material and specular reflection properties.

Coloring

Shading refers to the process of using an equation based on material properties and light source information to calculate the radiance along a certain viewing direction. We also refer to this equation as the lighting model. Different lighting models have different purposes.

BRDF lighting model

When the position and direction of the light source and the viewing angle are known, we need to know that a surface is interacting with the light. For example, when light hits a surface from a certain direction, how much is reflected? What are the directions of reflections? And BRDF is used to answer these questions. When given a point on the model surface, the BRDF contains a complete description of the point's appearance. In graphics, BRDF is mostly represented by a mathematical formula, and provides some parameters to adjust the material properties. Generally speaking, when the direction and irradiance of the incident light are given, the BRDF can give a certain output direction. The light energy distribution on the .

The first law of computer graphics: if he looks right, he is right.

Standard Lighting Model

The standard lighting model only cares about direct lighting, that is, those rays that are directly emitted from the light source and irradiated on the surface of the object, and then go directly to the camera through a reflection from the surface of the object.

His basic method is to divide the light entering the camera into 4 parts, each part uses a method to calculate its contribution, the four parts are;

The emissive part. This section is used to describe how much radiation a surface itself emits back in that direction when given a direction. It's important to note that without the use of global illumination, these emissive surfaces don't actually illuminate the surrounding objects, they just appear brighter.

The specular section describes how much radiation is scattered by the surface in the fully specular direction when light hits the model surface from a light source.

The diffuse section describes how much radiation the surface scatters in each direction when light hits the model surface from a light source.

The ambient section is used to describe all other indirect lighting.

ambient light

While the standard lighting model focuses on describing direct lighting, in the real world objects can also be illuminated by introductory lighting. Indirect lighting means that the light usually bounces between multiple objects and finally enters the camera, that is, the light passes through more than one object reflection before it enters the camera.

In the standard lighting model, we approximate indirect lighting using a part called the environment view. The calculation of ambient light is very simple, it is usually a global variable, that is, all objects in the scene use this ambient light.

Self-luminous

Light can also be emitted directly into the camera by the light source, rather than having to be reflected by anything. The standard lighting model uses self-illumination to calculate the contribution of this part.

Usually self-illuminating surfaces in real-time rendering often do not illuminate surrounding surfaces, that is, the object is not used as a light source.

diffuse reflection

Diffuse lighting is used to model the radiance that is randomly scattered in all directions by the surface of an object. In diffuse reflection, the position of the viewing angle is not important because the reflection is completely random, so the part can be considered the same in any direction of the reflection. However, the incident ray angle is important.

Diffuse reflection is compounded by Lambert's law: the intensity of the reflected light is proportional to the cosine of the angle between the surface normal and the direction of the light source.

Specular reflection

The specular here is an empirical model, that is, it does not exactly match the specular phenomenon in the real world. It can be used to calculate rays that are reflected along a fully specular direction, which can make objects appear shiny, such as metals.

The calculation of specular reflection requires more information, such as the normal of the incoming surface, the viewing angle direction, the light source direction, the reflection direction, etc.

per-pixel or per-vertex

Where do we calculate the lighting model from? Generally speaking, we have two options: compute in the fragment shader, also known as per-pixel lighting; compute in the vertex shader, also known as per-vertex lighting.

In per-pixel lighting, we get its normal on a per-pixel basis, and then do the calculation of the care simulation. This technique of interpolating vertex normals between patches is called Phong shading, also known as Phong interpolation or normal interpolation shading technique. This is different from the Phong lighting model we talked about earlier.

The opposite is per-vertex care, also known as Golord shading. In per-vertex lighting, we compute the lighting on each vertex, then linearly interpolate within the render primitive, and output the pixel color. Since the number of vertices is often much smaller than the number of pixels, per-vertex lighting is often less computationally expensive than per-pixel lighting. However, since per-vertex lighting relies on linear interpolation to get pixel lighting, per-vertex lighting can be problematic when there are non-linear calculations in the lighting model.

Summarize

Although the standard lighting mode is only an empirical mode, that is, it does not fully match the lighting in the real world. However, due to its ease of use, better calculation speed and better results, it is still widely used. Second, because of its wide availability, this standard lighting mode has many different names, also known as Phong lighting mode.

But this model has many limitations. First, there are many important physical phenomena that cannot be represented by this model, such as Fresnel reflections. Secondly, this model is isotropic, that is, when we rotate the surface with a fixed viewing angle and light source direction, the reflection does not change in any way. But some surfaces have anisotropic reflection properties, such as brushed metal, hair, etc.

Ambient light and self-illumination in Unity

ambient light

 Self-luminous

 Diffuse Lighting Model

 From left to right, per-vertex lighting, per-pixel lighting, half-Lambert model

per-vertex lighting

Shader "Custom/manfanse"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass{
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag 
            #include "Lighting.cginc"
            fixed4 _Diffuse;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 color:COLOR;
            };


            v2f vert(a2v v){
                v2f o;
                //模型空间转到裁剪空间
                o.pos=UnityObjectToClipPos(v.vertex);
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLight));

                o.color=ambient+diffuse;
                return o;

            }

            fixed4 frag(v2f i):SV_TARGET{
                return fixed4(i.color,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

per-pixel lighting

Shader "Custom/manfanse"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass{
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag 
            #include "Lighting.cginc"
            fixed4 _Diffuse;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 worldNormal:TEXCOORD0;
            };


            v2f vert(a2v v){
                v2f o;
                //模型空间转到裁剪空间
                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                return o;

            }

            fixed4 frag(v2f i):SV_TARGET{
              fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;

              fixed3 worldNormal=normalize(i.worldNormal);

              fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);

              fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLightDir));

              fixed3 color=ambient+diffuse;

              return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

half-Lambert model

Shader "Custom/manfanse"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
    }
    SubShader
    {
        Pass{
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag 
            #include "Lighting.cginc"
            fixed4 _Diffuse;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 worldNormal:TEXCOORD0;
            };


            v2f vert(a2v v){
                v2f o;
                //模型空间转到裁剪空间
                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                return o;

            }

            fixed4 frag(v2f i):SV_TARGET{
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;

                fixed3 worldNormal=normalize(i.worldNormal);

                fixed3 worldLightDir=normalize(_WorldSpaceLightPos0.xyz);

                fixed halfLambert=dot(worldNormal,worldLightDir)*0.5+0.5;

                fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*halfLambert;

                fixed3 color=ambient+diffuse;

                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Specular Reflection Model

  From left to right, per-vertex lighting, per-pixel lighting, Blinn-Phong lighting model

per-vertex lighting

Shader "Custom/gaoguagn"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8.0,256))=20
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 color:COLOR;
            };

            v2f vert(a2v v){
                v2f o;

                o.pos=UnityObjectToClipPos(v.vertex);
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                fixed3 woeldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse =_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,woeldLightDir));
                fixed3 refletDir=normalize(reflect(-woeldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-mul(unity_ObjectToWorld,v.vertex).xyz);
                fixed3 specular= _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(refletDir,viewDir)),_Gloss);

                o.color=ambient+diffuse+specular;

                return o;
            }

            fixed4 frag(v2f i):SV_TARGET{
                return fixed4 (i.color ,1.0);
            }

            ENDCG
        }
    }
    Fallback "Specular"
}

per-pixel lighting

Shader "Custom/gaoguagn"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8.0,256))=20
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 worldNormal :TEXCOORD0;
                float3 worldPos:TEXCOORD1;
            };

            v2f vert(a2v v){
                v2f o;

                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;

                return o;


            }

            fixed4 frag(v2f i):SV_TARGET{
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(i.worldNormal);
                fixed3 woeldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse =_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,woeldLightDir));
                fixed3 refletDir=normalize(reflect(-woeldLightDir,worldNormal));
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                fixed3 specular= _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(refletDir,viewDir)),_Gloss);

                return fixed4(ambient+diffuse+specular,1.0);
            }

            ENDCG
        }
    }
    Fallback "Specular"
}

Blinn-Phong lighting model

Shader "Custom/gaoguagn_2"
{
    Properties
    {
        _Diffuse("Diffuse",Color)=(1,1,1,1)
        _Specular("Specular",Color)=(1,1,1,1)
        _Gloss("Gloss",Range(8.0,256))=20
    }
    SubShader
    {
        Pass
        {
            Tags{"LightMode"="ForwardBase"}

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "Lighting.cginc"

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

            struct a2v{
                float4 vertex :POSITION;
                float3 normal:NORMAL;
            };

            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 worldNormal :TEXCOORD0;
                float3 worldPos:TEXCOORD1;
            };

            v2f vert(a2v v){
                v2f o;

                o.pos=UnityObjectToClipPos(v.vertex);
                o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
                o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;

                return o;

            }

            fixed4 frag(v2f i):SV_TARGET{
                fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz;
                fixed3 worldNormal=normalize(i.worldNormal);
                fixed3 woeldLightDir=normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse =_LightColor0.rgb*_Diffuse.rgb*max(0,dot(worldNormal,woeldLightDir));
 
                fixed3 viewDir=normalize(_WorldSpaceCameraPos.xyz-i.worldPos.xyz);
                fixed3 halfDir=normalize(woeldLightDir*viewDir);
                fixed3 specular= _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(worldNormal,halfDir)),_Gloss);

                return fixed4(ambient+diffuse+specular,1.0);
            }

            ENDCG
        }
    }
    Fallback "Specular"
}

Guess you like

Origin blog.csdn.net/f402455894/article/details/122718662
Recommended