美文网首页
案例-逐顶点漫反射光照

案例-逐顶点漫反射光照

作者: JervieQin | 来源:发表于2018-07-08 12:52 被阅读0次

码前须知

在标准光照模型中将进入摄像机的光线分为了4个部分:
自发光
给定一个方向,该表面本身向该方向发射的辐射量。
高光反射
光线照射表面发生完全镜面反射方向散发的辐射量。
漫反射
光线照射表面向每个方向散射的辐射量。
环境光
其他所有的间接光照。

计算方式

光照模型的计算方式有两种:逐顶点计算、逐像素计算。

  • 逐像素计算方式中使用的是Phong着色技术,以像素为基础,得到它的法线(可以对顶点法线插值得到 或者 从法线纹理中采样得到),然后对光照模型进行计算。
  • 逐顶点计算方式中使用的是一种高洛德着色技术:在每个顶点上计算光照,然后在渲染图元内部进行线性插值,最后输出像素颜色。往往顶点数量比像素数量要少,所以这种方式的计算量更小。但是,当光照模型种出现非线性计算时(例如高光反射),会出现棱角现象。

案例

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

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

Shader "Learning/chapter6/DiffuseVertexLevel"{
    Properties{
        //属性值末尾不需要添加分号。如果是纹理类型要加默认值和{option},至少{}
        _Diffuse("DiffuseColor",Color) = (1,1,1,1)   //控制反射颜色       
    }
    SubShader{
        /*
           subshader tags用来告诉渲染器什么时候、用什么方式来进行渲染自身。
           之前的文章也说过了,tags其实就是键值对。
           详情:https://docs.unity3d.com/Manual/SL-SubShaderTags.html
        */
        Tags{ }
        /*
        就unity的渲染管线而言,着色器定义对象本身的外观(其材质属性)以及它对光的反应。
        详情:https://docs.unity3d.com/Manual/SL-RenderPipeline.html
        */
        pass{
            /*
              1. 如何应用光照以及使用着色器的哪些Pass取决于使用哪个 Rendering Path。不同的渲染路径影响光照和阴影。
                 在“Graphics Settings”中选择项目使用的渲染路径。此外,您可以为每个摄像头覆盖它。
                 详情:https://docs.unity3d.com/Manual/RenderingPaths.html
                 简单的说一下rendering path 保真度由高到低分别是:延迟着色渲染、前向渲染、顶点渲染
              2. 着色器中的每个 pass 都通过Pass Tags传递其光照类型。但是此处的tags不同于上面的,应用范围不一样,作用也不一样。
                 详情:https://docs.unity3d.com/Manual/SL-PassTags.html
                 
            */
            //LightMode定义PASS在uinty流水光照线中的角色。
            //ForwardBase,在正向渲染中使用,应用环境光,主方向光,顶点/ SH光和光照贴图。
            //只有定义了正确得LightMode才能获取Unity内置光照变量,例如_LightColor0
            Tags{ "LightMode"= "ForwardBase"}    

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            //因为要使用unity内置得光照变量 _LightColor0要导入"Lighting.cginc"
            #include "Lighting.cginc" 
            #include "UnityCG.cginc"     

            fixed3 _Diffuse;
 
            //定义顶点着色器阶段输入结构
            struct a2v{
                float4 vertex:POSITION;
                float3 normal:NORMAL;
            };
            //定义顶点着色器阶段输出结构和片元着色器阶段输入结构
            struct v2f{
                float4 pos:SV_POSITION;
                fixed3 color : COLOR;
            };

            v2f vert(a2v v){
                v2f f;
                f.pos = UnityObjectToClipPos(v.vertex);   //顶点着色器的基本任务

                //获取环境光颜色
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                
                //将表面法线从模型空间转换到世界空间下
                //_World2Object是unity内置矩阵,用来将顶点/矢量从世界空间转到模型空间
                //通过调换矩阵相乘顺序,达到
                fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));

                //获取世界坐标下的光照方向
                //_WorldSpaceLightPos0是Unity内置变量,用来访问光源方向
                //下面获取光源方向的方法只适用于场景中为单光源并且为平行光的情况,并不能够处理多光源且复杂光源的情况。
                fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
                
                //计算漫反射公式:   漫反射颜色 = 光源颜色 * 材质颜色 * 点积(表面法线,光源方向)
                //saturate 函数 是CG函数, 作用是防止点积结果为负数
                //_LightColor0是unity内置变量,用来访问pass处理的光源颜色和强度信息,使用前必须定义LightMode
                fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

                f.color = ambient + diffuse;

                return f;
            }

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

结果

左球为材质效果,右球为原始对比

相关文章

网友评论

      本文标题:案例-逐顶点漫反射光照

      本文链接:https://www.haomeiwen.com/subject/digryftx.html