zoukankan      html  css  js  c++  java
  • Unity3D学习(六):《Unity Shader入门精要》——Unity的基础光照

    前言
    光学中,我们是用辐射度来量化光。
    光照按照不同的散射方向分为:漫反射(diffuse)和高光反射(specular)。高光反射描述物体是如何反射光线的,漫反射则表示有多少光线会被折射、吸收和散射出表面。根据入射光线的数量和方向,我们可以计算出射光线的数量和方向,通常使用出射度描述它。辐射度和出射度之间是线性关系的,它们之间的比值就是材质的漫反射和高光反射属性。
    BRDF模型
    早期的游戏引擎一般只有一个光照模型,BRDF模型,即标准光照模型(Bidirectional Reflectance Distribution Function),又称Phong模型。
    它的基本方法是,把进入到摄像机内的光线分为4部分,每部分使用一种方法来计算它的贡献度。
    • 自发光  描述当给定一个方向时,一个表面本身会向该方向发射多少辐射量。注意,如果没有使用全局光照,这些自发光的表面并不会照亮周围的物体,只是他本体看起来更亮而已。
    • 高光反射(金属之类的)  描述当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
    • 漫反射  该表面会向四周散射多少辐射量
    • 环境光  描述其他所有的间接光照(就是其他物体的发射的光线)。 
    兰伯特定律
    发射光线的强度与表面法线和光源方向之间的夹角余弦值成正比。
     
    漫发射的计算公式
       C = (c * m) * max( 0 , n * l )。
    小写c为光源颜色,m为漫反射颜色,n是表面法线,l是指向光源的单位矢量。需要注意应该防止发现和光源点乘的结果为负值(避免物体被从后面来的光源照亮),所以用max函数限制其为正数。
     
    高光反射的计算公式
    •   r = 2(n * l)n - l
    •  C = (c * m) * (max(0,v * r)) ^ gloss
    n,l代表意义与漫反射公式相同,r为光的反射方向矢量,m为高光反射颜色, v 为 视角方向矢量,gloss为材质的光泽度,gloss越大亮点就越小。
     
     
    Blinn模型的高光反射计算公式
      与上述Phong模型不同的是,Blinn模型引入了一个新矢量h,通过对 v 和 l的取平均后再归一化得到:h = ( v + l ) / | v + l |。
      公式为:C = ( c * m) * (max( 0, n * h ))^gloss
     
    逐像素与逐顶点光照
     在片元着色器中计算,称为逐像素光照。在顶点着色器中计算,称为逐顶点光照(高罗德着色)。逐顶点光照是在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出成像素颜色。由于顶点数目小于像素数目,所以其计算量小于逐像素光照,因此在阴影交界处会出现锯齿,精细度不如逐像素光照。
     
    Unity的环境光和自发光
    环境光可以通过Shader的内置变量UNITY_LIGHTMODEL_AMBIENT访问
    自发光只需要在片元着色器输出最后的颜色之前,把材质的自发光颜色添加到输出颜色上就行。
     
    漫反射和高光反射的Shader实现
    漫反射光照模型(逐顶点)
    Shader "Unity Shader Book/Chapter6/Diffuse Vertex-Level"
    {
           Properties
           {
                 _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
           }
           SubShader
           {
                 Tags { "LightMode"="ForwardBase" }   
     
                 Pass
                 {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        
                        #include "Lighting.cginc"
     
                        fixed4 _Diffuse;
                        struct appdata
                        {
                              float4 vertex : POSITION; //顶点在模型空间的坐标
                              float3 normal : NORMAL;  //法线
                        } ;
     
                        struct v2f
                        {
                              fixed3 color : COLOR;  //输出颜色
                              float4 pos : SV_POSITION;  //输出位置
                        } ;
     
                        
                        v2f vert (appdata v)
                        {
                              v2f o;
                              o.pos = UnityObjectToClipPos(v.vertex);  //模型空间转换到裁剪空间
     
                              fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;  //环境光
     
                              fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); //法线方向n
     
                              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
                 }
           }
    }
    
    高光反射模型(逐顶点)
    Shader "Unity Shader Book/Chapter6/SpecularVertexLevel"
    {
           Properties
           {
                 _Diffuse("Diffuse",Color) = (1.0,1.0,1.0,1.0)
                 _Specular("Specular",Color) = (1.0,1.0,1.0,1.0)
                 _Gloss("Gloss",Range(8.0,256)) = 20 //size of specular area
           }
           SubShader
           {
                 Tags { "LightMode"="ForwardBase" }   //Be careful ,The light direction will be opposite without this
     
                 Pass
                 {
                        CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag
                        
                        #include "Lighting.cginc"
     
                        fixed4 _Diffuse;
                        fixed4 _Specular;
                        float  _Gloss;
                        struct appdata
                        {
                              float4 vertex : POSITION;
                              float3 normal : NORMAL;
                        } ;
     
                        struct v2f
                        {
                              float3 color: COLOR;
                              float4 pos : SV_POSITION;
                        } ;
                        
                        v2f vert (appdata v)
                        {
                              v2f o;
                              o.pos = UnityObjectToClipPos(v.vertex);
                              //equal to "o.pos = mul(UNITY_MATRIX_MVP,v.vertex);"
     
                              fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
     
                              fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
                              // or use UnityObjectToWorldNormal(v.normal)
                              fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
     
                              fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLightDir));
     
                              fixed3 reflectDir = normalize(reflect(-worldLightDir,worldNormal)); //反射方向矢量r
     
                              fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz); //视线方向
     
                              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
                 }
           }
    }
    

      

  • 相关阅读:
    字符串的基本操作
    PHP & Delphi 語法
    Delphi项目构成之单元文件PAS
    Delphi项目构成之项目文件DPR
    Delphi项目的构成
    關於那我的編程歷史..
    點擊Button,在Label1顯示HelloWorld!。
    開博客了, 因為搞Delphi 開發的關於Delphi學習
    Java 基础知识(一)
    关于多线程对于全局变量的资源竞争问题
  • 原文地址:https://www.cnblogs.com/0kk470/p/8206051.html
Copyright © 2011-2022 走看看