Shader6-基础光照

 

光学概念简单介绍

1.辐射照度

量化光的单位(W/m²)

2.光线与物体相交,要么被散射要么被吸收

1.散射:(改变光线方向,不改变光线密度和颜色)

  • 散射到物体内部,称为折射或透射。折射到物体内部的光线,有些还会重新发射出物体表面。

  • 另一种散射到物体外部,称为反射。

2.吸收:(改变光线密度和颜色,不改变光线方向)


光照模型

1.标准光照模型(Blinn Phong)

把进入摄像机范围内的光线分为4个部分:

1.1 自发光(C_{missive}) - 物体表面向某个方向发射的辐射量,如果没有全局光照技术,自发光表面不会照亮周围物体,只是本身看起来更亮而已。标准光照模型中

                                 C_{missive}m_{emissive}(材质自发光颜色)

1.2 高光反射(C_{specular}) - 当光源光线照到模型表面时,该表面在完全镜面反射方向散射的辐射量。

求反射光线:

Phong模型计算高光反射:

                             

\large m_{gloss} = 光泽度(gloss) or 反光度(shininess)      \large m_{spscular} = 材质高光反射颜色      \large C_{light} = 光源颜色和强度

计算反射光线耗时,Blinn提出用 I 和 v取平均后,再归一化得到。

 

Blinn模型计算高光反射:

                          

1.3 漫反射(C_{diffuse}) - 当光源光线照到模型表面时,该表面向每个方向散射的辐射量。

兰伯特光照模型:反射光线强度和物体表面法线与光源方向的余弦值成正比。防止点乘为负,加个max限制一下

                          

半兰伯特光照模型:使用a和b参数将n和I的点积从[-1,1]映射到[0,1]范围内。

                       

 C_{light} = 光源颜色     m_{diffuse} = 漫反射颜色       n表面法线       I指向光源的单位矢量   

1.4 环境光(C_{ambient}) - 描述其他间接光照。标准光照模型中所有物体都使用一个环境光

                                         C_{ambient} = g_{ambient}

Unity设置环境光,Shader设置通过变量可直接获取,UNITY_LIGHTMODEL_AMBIENT

逐像素光照(Phong着色) 

基于每像素,用每个像素的法线进行光照计算,每个像素的法向量是通过顶点的法向量插值得到的。

逐顶点光照(高洛德着色 Gouraud)

基于顶点计算光照计算,然后计算得到的颜色插值顶点所在三角面。


实践1

1.兰伯特逐顶点计算的漫反射

Shader "Chan/Chapter6_DiffuseVertexLevel" {
    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));
                //世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
                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"
}

2.兰伯特逐像素计算的漫反射

Shader "Chan/Chapter6_DiffusePixelLevel" {
    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;
                float3 worldNormal:TEXCOORD0;
            };

            //顶点着色器
            v2f vert(a2v v)
            {
                v2f o;
                //顶点从模型空间转换到裁剪空间
                o.pos = UnityObjectToClipPos(v.vertex);
                //顶点法线转换到模型空间转化到世界空间 
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                return o;
            }

            //片元着色器 - 输出顶点颜色
            fixed4 frag(v2f i):SV_Target
            {
                //获取环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //世界空间下归一化的法线
                fixed3 worldNormal = normalize(i.worldNormal);
                //兰伯特光照模型计算漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
                fixed3 color = ambient + diffuse;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

3.半兰伯特逐像素计算的漫反射

 

Shader "Chan/Chapter6_HalfLambert" {
    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;
                float3 worldNormal:TEXCOORD0;
            };

            //顶点着色器
            v2f vert(a2v v)
            {
                v2f o;
                //顶点从模型空间转换到裁剪空间
                o.pos = UnityObjectToClipPos(v.vertex);
                //顶点法线转换到模型空间转化到世界空间 
                o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                return o;
            }

            //片元着色器 - 输出顶点颜色
            fixed4 frag(v2f i):SV_Target
            {
                //获取环境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                //世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                //世界空间下归一化的法线
                fixed3 worldNormal = normalize(i.worldNormal);
                //
                fixed halfLambert = dot(worldNormal,worldLight) * 0.5 + 0.5;
                //半兰伯特光照模型计算漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
                fixed3 color = ambient + diffuse;
                return fixed4(color,1.0);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

 

实践2

1.逐顶点的Phong光照模型计算

Shader "Chan/Chapter6_SpecularVertexLevel" {
    Properties {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)//高光反射系数
        _Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
    }
    SubShader {
        Pass
        {
            Tags{"LightMode" = "Forwardbase"}
            
            CGPROGRAM
            #include "Lighting.cginc"

            #pragma vertex vert
            #pragma fragment frag

            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));
                //世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                //兰伯特光照模型计算漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
                //光源方向和法线,求得反射光线方向 
                //-----worldLightDir = 交点指向光源方向,公式需要光源指向交点,因此取反-----
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
                //世界空间下的摄像机座标 - 世界空间下的顶点座标 = 顶点的的视角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz);
                //Phong光照模型高光反射
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                //环境光 + 漫反射 + 高光反射 = 最终颜色
                o.color = ambient + diffuse + specular;
                return o;
            }

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

2.逐像素的Phong光照模型

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'

Shader "Chan/Chapter6_SpecularPixelLevel" {
    Properties {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)//高光反射系数
        _Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
    }
    SubShader {
        Pass
        {
            Tags{"LightMode" = "Forwardbase"}
            
            CGPROGRAM
            #include "Lighting.cginc"

            #pragma vertex vert
            #pragma fragment frag

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

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

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

            v2f vert(a2v v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                //得到世界空间下的法线和顶点
                //unity_WorldToObject = 模型空间到世界空间的变换矩阵的逆矩阵
                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;
                float3 worldNormal = normalize(i.worldNormal);
                //世界空间下的光源方向 _WorldSpaceLightPos0(只有一个光源,并且是平行光时)
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                //兰伯特光照模型计算漫反射
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
                //光源方向和法线,求得反射光线方向 
                //-----worldLightDir = 交点指向光源方向,公式需要光源指向交点,因此取反-----
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));
                //世界空间下的摄像机座标 - 世界空间下的顶点座标 = 顶点的的视角方向
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
                //Phong光照模型高光反射
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir,viewDir)),_Gloss);
                //环境光 + 漫反射 + 高光反射 = 最终颜色
                return fixed4(ambient + diffuse + specular,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

实践3

1.Binn-Phong光照模型

Shader "Chan/Chapter6_BlinnPhong" {
    Properties {
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _Specular("Specular",Color) = (1,1,1,1)//高光反射系数
        _Gloss("Gloss",Range(8,256)) = 20//光泽度or反光度
    }
    SubShader {
        Pass
        {
            Tags{"LightMode" = "Forwardbase"}
            
            CGPROGRAM
            #include "Lighting.cginc"

            #pragma vertex vert
            #pragma fragment frag

            fixed4 _Diffuse;
            fixed4 _Specular;
            float _Gloss;

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

            struct v2f
            {
                float4 pos:SV_POSITION;
                float3 worldNormal:TEXCOORD0;
                fixed3 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;
                float3 worldNormal = normalize(i.worldNormal);
                fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
                fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal));         
                fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);          
                fixed3 halfDir = normalize(worldLightDir + viewDir);
                
                //Blinn-Phong光照模型高光反射
                fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(worldNormal,halfDir)),_Gloss);

                return fixed4(ambient + diffuse + specular,1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章