Surface Shader Lighting Examples

2018-06-21  本文已影响80人  passiony

表面着色器光照示例

下面的这些例子是表面着色器(Surface Shaders)中的自定义光照模式(custom lighting models)。普通光照模式的表面着色器在这页

因为延时光照(Deferred lighting)不能与一些自定义 per-material 光照模式(lighting model)很好的运行,在下面大部分例子中我们只在着色器的正向渲染(Forward Rendering)中编译。

Diffuse 漫反射

Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) )
Tip:cosθ = 光方向· 法线方向
我们从内置的Lambert光照模式(lighting model)开始:

  Shader "Example/Diffuse Texture" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

下面是效果一个有纹理(texture)和一个没有真实的纹理(texture)。(在场景中有一个方向光):

image image

现在,让我们来做一个完全一样的。但,是我们自己编写的光照模式(lighting model)而不是使用内置的Lambert。 表面着色器光照模式(Surface Shader Lighting Models)仅仅是需要我们编写的一些函数。下面是一个简单的Lambert。注意:"着色器部分"自身并没有改变(即下面的灰色部分)。

  Shader "Example/Diffuse Texture" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf SimpleLambert

      half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
          fixed diff = max (0, dot (s.Normal, lightDir));
          fixed4 c;
          c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten*2);
          c.a = s.Alpha;
          return c;
      }

      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

就这样我们这个点单的漫反射光照模式(Diffuse lighting model)是一个名叫LightingSimpleLambert的函数。它计算的是表面法线(surface normal)与灯光方向(light direction)的点积。然后应用于光线衰减和颜色。

Diffuse Wrap 漫反射遮蔽

下面是遮蔽的漫反射-漫反射光照的一种改进。照明"环绕(wraps around)"在物体的边缘。它对于假冒子表面(subsurface)散射效果(scattering effect)非常有用。同样的"着色器部分"自身并没有改变(即下面的灰色部分)。我们仅仅用了不同的光照函数(黑体字部分)。

  Shader "Example/Diffuse Wrapped" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf WrapLambert

      half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) {
          half NdotL = dot (s.Normal, lightDir);
          half diff = NdotL * 0.5 + 0.5;
          half4 c;
          c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
          c.a = s.Alpha;
          return c;
      }

      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }
image image

Toon Ramp 卡通渐变

下面是一个"渐变(Ramp)"光照模式。他使用一个纹理(texture)定义渐变怎样在表面做出反应,反应角度通过光照方向和法线求得。导入卡通光照(Toon lighting)可以实现多种效果。

  Shader "Example/Toon Ramp" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _Ramp ("Shading Ramp", 2D) = "gray" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Ramp

      sampler2D _Ramp;

      half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
          half NdotL = dot (s.Normal, lightDir);
          half diff = NdotL * 0.5 + 0.5;
          half3 ramp = tex2D (_Ramp, float2(diff,diff)).rgb;
          half4 c;
          c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
          c.a = s.Alpha;
          return c;
      }

      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }
image image image

Simple Specular 简单的高光

Specular = 直射光*pow(max(cosθ,0),高光的参数)
Tips: θ:是反射光方向和视野方向的夹角
Tips: θ:是半角向量与法线向量的夹角
下面是一个简单的高光光照模式(specular lighting model)。它是内置的BlinnPhong,实际上做起来非常简单。放在这里仅仅是为了说明它是如何工作的。

  Shader "Example/Simple Specular" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf SimpleSpecular

      half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {         
          half diff = max (0, dot (s.Normal, lightDir));

          //phong模型
          //光线的反射方向.点到摄像机
          // half3 reflectDir = normalize(reflect(-lightDir, s.Normal));  
          // float nh = max (0, dot (reflectDir, viewDir));

          //Blinn-phong
          //半角向量.发线向量
          //1.半角向量:求(点到光源+点到摄像机)的单位向量,他们的中间平均值
          half3 h = normalize (lightDir + viewDir);
          //2.高光底数【半角向量与法线向量的余弦值】
          float nh = max (0, dot (s.Normal, h));
          //3.高光系数:根据高光低数和高光指数求得
          float spec = pow (nh, _Spec);

          half4 c;
          c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
          c.a = s.Alpha;
          return c;
      }

      struct Input {
          float2 uv_MainTex;
      };
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }
image image
上一篇下一篇

猜你喜欢

热点阅读