zoukankan      html  css  js  c++  java
  • 【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert

    【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert


    转载请注明出处:http://www.cnblogs.com/-867259206/p/5598185.html

    写作本系列文章时使用的是Unity5.3。
    写代码之前:

    1. 当然啦,如果Unity都没安装的话肯定不会来学Unity Shaders吧?

    2. 阅读本系列文章之前你需要有一些编程的概念。

    3. 在VS里面,Unity Shaders是没有语法高亮显示和智能提示的,VS党可以参考一下这篇文章使代码高亮显示,也可以下载shaderlabvsNShader之类的插件使代码高亮显示。

    4. 这是针对小白的Unity Shaders的基础知识,如果你已经有了基础或者你是大神,那么这些文章不适合你。

    5. 由于作者水平的局限,文中或许会有谬误之处,恳请指出。


    还记得前面说的创建Surface Shader的方法吗?按照之前的方法,新建一个Shader,命名为BasicDiffuse。

    1. 先将修改Properties里的内容:

    Properties {
            _EmissiveColor ("Emissive Color", Color) = (1,1,1,1)
            _AmbientColor ("Ambient Color", Color) = (1,1,1,1)
            _MySliderValue ("This is a Slider", Range(0,10)) = 2.5
        }
    
    1. #pragma surface surf Standard fullforwardshadows改为:

    #pragma surface surf BasicDiffuse
    

    这说明我们要用BasicDiffuse光照模型,这是我们自定义的一个光照模型。

    1. 定义在Properties里声明过的变量:

    float4 _EmissiveColor;
    float4 _AmbientColor;
    float _MySliderValue;
    
    1. 修改你的surf函数:

    void surf (Input IN, inout SurfaceOutput o){
        float4 c;
        c = pow((_EmissiveColor+_AmbientColor), _MySliderValue);
        o.Albedo = c.rgb;
        o.Alpha = c.a;
    }
    

    注意输出结构的类型,做了修改。

    1. 添加下面这个函数,这就是我们自定义的光照模型:

    inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten){
        float difLight = max(0, dot (s.Normal, lightDir));
        float4 col;
        col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
        col.a = s.Alpha;
        return col;
    }
    

    解释

    1. 在surf函数里,我们将自发光颜色和漫反射颜色相加的和作为底数,然后将_MySliderValue的值作为次幂,进行幂运算得到四元浮点向量c,输出的反射值等于c的RGB颜色,输出的透明通道等于c的透明通道。这其实就是将自发光颜色和漫反射颜色进行了一定的混合。

    2. 自定义的光照模型的命名规则是“Lighting”+“自定义的光照名称”。这样就定义了一个光照模型。
      光照模型有5种原型:

      half4 LightingName (SurfaceOutput s, fixed3 lightDir, half atten);
      half4 LightingName (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, half atten);
      half4 LightingName_PrePass (SurfaceOutput s, half4 light);
      half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal);
      half4 LightingName_DirLightmap(SurfaceOutput s, fixed4 color, fixed4 scale, fixed3 viewDir, bool surfFuncWritesNormal,out half3 specColor);
      

      这里我们用的就是第一种原型。第一个参数是输出结构,第二个参数是光线方向,也就是光源到物体表面上的点的向量,是单位向量,第三个参数衰减度,attenuation的缩写,因为光线被物体反射之后,会有能量损失,所以会有衰减。我们看到,这个参数没有被赋值,所以它是Unity内置的一个参数,我们知道它表示衰减就可以了。
      函数里第一句计算的是漫反射的光强。dot是点乘。将表面的法向量和光线角度点乘,也就是光线和法向量的夹角越大,光线在法向量方向的分量越小,即反射的光越弱。因为夹角超过90度的时候,是负值,所以用max函数使结果大于0。max(x,y)就是取x,y中的最大值。
      第三句的意思就是颜色值=反射值×平行光的颜色×漫反射光强×衰减度×2.
      _LightColor0也是Unity内置的一个变量,它在不同的render path和pass里的意义不同,在这里就是平行光的颜色。
      后面的这个2应该是个经验数值,可以根据自己想要的效果修改。
      这就是基本漫反射的计算方法。
      我们来看一下它的效果:
      新建一个Sphere,将BasicDiffuse材质赋给它。将Slider的数值调为0.不出意外的话,你看到的效果是这样的:
      enter description here
      更改自发光的颜色,然后调节Slider,我们发现,Slider数值越大,自发光颜色越明显:
      enter description hereenter description here
      现在将自发光改回白色,更改漫反射的颜色,然后调节Slider:
      不出意外的话,看到的效果和自发光一样,Slider=0时,阴影是灰色的,自发光和漫反射的颜色不起作用,数值越大,则自发光和漫反射的颜色越明显。
      接下来,同时更改自发光和漫反射的颜色,比如红色和绿色,我们看到球变成了黄色,也就是红光和绿光混合的效果:
      enter description here
      你还可以自己再调节其他颜色试试看,看看都会有些什么效果。
      还有那个函数里的数值2,你也可以改改试试看哟~

    HalfLambert

    接下来再学习一个经典的光照模型——HalfLambert(半兰伯特)。
    很简单,我们先把光照模型改名为HalfLambert,也就是修改光照函数和#pragma。
    先修改一句:

    float difLight = dot (s.Normal, lightDir);
    

    然后添加一句:

    float hLambert = 0.5 * difLight + 0.5;
    

    再改一句:

     col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
    

    原先difLight区间[-1,0]的部分变成了[0,0.5],如果直接用max函数使结果大于0的话,小于0的部分都会等于0,也就是背光面都会是黑色。如果用半兰伯特公式的话,小于0的部分就会从0渐变到0.5,颜色的灰度是会有变化。同时,亮部的亮度也提高了。
    HalfLambert是由Valve公司提出的技术,是一种用于在低光照区域照亮物体的技术。它用来防止某个物体的背光面丢失形状并且显得太过平面化。这个技术是没有任何物理原理的,是一种感性的视觉增强。


    附:代码清单

    Shader "Custom/BasicDiffuse" {
        Properties {
            _EmissiveColor ("Emissive Color", Color) = (1,1,1,1)
            _AmbientColor ("Ambient Color", Color) = (1,1,1,1)
            _MySliderValue ("This is a Slider", Range(0,10)) = 2.5
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
            
            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf BasicDiffuse
    
            // Use shader model 3.0 target, to get nicer looking lighting
            #pragma target 3.0
    
            float4 _EmissiveColor;
            float4 _AmbientColor;
            float _MySliderValue;
    
            struct Input{
                float2 uv_MainTex;
            };
    
            void surf (Input IN, inout SurfaceOutput o){
                float4 c;
                c = pow((_EmissiveColor+_AmbientColor), _MySliderValue);
                o.Albedo = c.rgb;
                o.Alpha = c.a;
            }
    
            inline float4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten){
            float difLight = max(0, dot (s.Normal, lightDir));
            float4 col;
            col.rgb = s.Albedo * _LightColor0.rgb * (difLight * atten * 2);
            col.a = s.Alpha;
            return col;
            }
    
            ENDCG
        }
        FallBack "Diffuse"
    }
    

    HalfLambert光照模型函数:

    inline float4 LightingHalfLambert (SurfaceOutput s, fixed3 lightDir, fixed atten){
        float difLight = dot (s.Normal, lightDir);
        float hLambert = 0.5 * difLight + 0.5;
        float4 col;
        col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
        col.a = s.Alpha;
        return col;
    }
    
  • 相关阅读:
    js的红黑树
    javaScript实现平衡树
    使用javaScript实现一个二叉树,实现插入节点,删除节点,查询节点,最大最小值查询,中序,前序,后序遍历功能
    使用javaScript实现散列表的线性探查法
    使用javaScript实现处理散列表的冲突的方法之分离链接
    使用javaScript实现一个字典
    使用javaScript实现集合
    使用javaScript实现一个堆链表
    使用javaScript实现一个双端链表
    kmp
  • 原文地址:https://www.cnblogs.com/-867259206/p/5598185.html
Copyright © 2011-2022 走看看