zoukankan      html  css  js  c++  java
  • Unity Shader 之 基础光照

    摄像机是如何看这个世界的

      游戏中摄像机所看到的世界与我们现实中所看到的几乎是一样的。

    • 首先,光线从光源中发射出来。
    • 然后,光线和场景中的一些物体相交(散射,吸收)。
    • 最后,摄像机吸收了一些光,产生一张图像。

      光线与物体相交的结果有两个:散射(scattering)和吸收(absorption)

    • 散射:只改变光线的方向,但不改变光线的密度和颜色,有两种方向:内部与外部,对应折射与反射。
      • 折射(refraction):散射到物体内部,用漫反射(diffuse)模型来计算。
      • 反射(reflection):散射的物体外部,用高光反射(specular)模型来计算。
    • 吸收:只改变光线的密度和颜色,但不改变光线的方向。

      用不同的光照模型来计算两种不同的散射方向:漫反射模型和高光反射模型。

    • 漫反射:表示有多少光线会被折射、吸收和散射出表面。
    • 高光反射:表示物体表面是如何反射光线的。

    标准光照模型 (以下粗体都表示向量)

      把进入到摄像机内的光线分为4个部分,每个部分使用一种方法来计算它的贡献度。

    • 自发光(emissive):当给定一个方向时,一个表面本身会发射多少辐射量。(并不能照亮周围的物体,只是显得亮而已)
    • 高光反射(specular):当光线从光源照射到模型表面时,该表面会在完全镜面反射方向散射多少辐射量。
    • 漫反射(diffuse):当光线从光源照射到模型表面时,该表面会向每个方向散射多少辐射量。
    • 环境光(ambient):描述其他所有的间接光照。

      自发光

      直接采用了该材质的自发光颜色。

      高光反射

      Phong模型公式

        specular = (light · shininess)max(0, v · r)^gloss

      • light:光源颜色
      • shininess:反光度  
      • v:物体到摄像机的方向向量
      • r:光线的反射方向向量(利用法线方向和光线入射方向可以计算出来,公式为:r = l - 2(n · l)n, Cg中计算反射方向的函数reflect)
      • gloss:光泽度(数值越大亮点越小)

      Blinn-Phong模型公式

      注意:如果摄像机和光源距离模型足够远的话,Blinn模型速度快于Phone模型,因为,此时可以认为vl都为定值,因此h将是一个常量。但是当vl不是定值时,Phone模型反而更快。

        specular = (light · shininess)max(0, n · h)^gloss

      • light:光源颜色  
      • shininess:反光度    
      • n:表面法线方向    
      • h:对vl取平均后再归一化,公式:h = (v + l) / | v + l |
      • gloss:光泽度(数值越大亮点越小)  

      漫反射

      兰伯特定律  

        diffuse = (light · diffuseColor)max(0, n · l)

      • light:光源颜色    
      • diffuseColor:材质漫反射颜色    
      • n:表面法线方向      
      • l:光源的单位矢量
      • 注意:max函数是为了防止法线和光源方向点乘的结果为负值。

      半兰伯特定律

        diffuse = (light · diffuseColor)(0.5 * max(0, n · l) + 0.5)

        没有任何的物理依据,仅仅是视觉加强技术

    代码示例(环境光+漫反射+高光反射)

    Shader "Unity My Shader/Diffuse Light"
    {
        Properties
        {
            _Color("Color", Color) = (1,1,1,1)       // 模型颜色
            _Specular("Specular", Color) = (1,1,1,1) // 高光颜色
            _Gloss("Gloss", Range(8.0, 256)) = 20    // 控制高光区域大小
        }
        SubShader
        {
            Pass
            {
                Tags{"LightMode"="ForwardBase"}      // 定义该Pass在Unity流水线中用于前向渲染
    
                CGPROGRAM                            // 于ENGCG配对用于包裹Cg代码片
                #pragma vertex vert                  // 利用#pragma告诉Unity顶点着色器的名字叫vert
                #pragma fragment frag                // 同上
                
                #include "UnityCG.cginc"             // 引入内置文件
                #include "Lighting.cginc"
    
                fixed4 _Color;                       // 定义于Properties中相匹配的变量
                fixed4 _Specular;
                float _Gloss;
    
                struct a2v                           // 顶点着色器的输入结构体
                {
                    float4 vertex : POSITION;        // 模型的顶点位置信息(基于模型空间)
                    float3 normal : NORMAL;          // 模型的顶点法线信息(基于模型空间)
                };
    
                struct v2f                           // 顶点着色器的输出结构体和片元着色器的输入结构体
                {
                    float4 pos : SV_POSITION;        // 模型的顶点信息(基于裁剪空间)
                    float3 worldPos : TEXCOORD0;     // 模型的顶点信息(基于世界空间)
                    float3 worldNormal : TEXCOORD1;  // 模型的法线信息(基于世界空间)
                };
                
                v2f vert (a2v v)
                {
                    v2f o;
    
                    o.pos = UnityObjectToClipPos(v.vertex); // 顶点位置从模型空间转换到裁剪空间
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex); // 模型坐标顶点转换世界坐标顶点
                    o.worldNormal = UnityObjectToWorldNormal(v.normal); // 模型坐标法线转换世界坐标法线
    
                    return o;
                }
                
                fixed4 frag (v2f i) : SV_Target
                {
                    fixed3 worldNormal = normalize(i.worldNormal); // 法线方向
                    fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 光照方向
                    fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // 视角方向
    
                    fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz; //环境光
    
                    fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal, worldLightDir)); // 漫反射
    
                    fixed3 halfDir = normalize(worldViewDir + worldLightDir); // Blinn模型 计算
                    fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); // 高光反射
    
                    return fixed4(ambient + diffuse + specular, 1); // 相加后输出颜色
                }
                ENDCG
            }
        }
    }
  • 相关阅读:
    时间戳
    MD5加密、字节与字符串转换、对ToString("X2 ")的理解
    JWT(JSON Web Token)简介
    Entity Framework 通过主键查询提高效率
    C# switch语句与枚举类型
    对象映射库【AutoMapper】所支持场景
    关于EF框架EntityState的几种状态
    EF底层操作注意点、批量操作、更新
    linq:求分组后的每组最大值、最小值、平均值等、Aggregate聚合函数
    Flask——Request(2)
  • 原文地址:https://www.cnblogs.com/SHOR/p/7872024.html
Copyright © 2011-2022 走看看