UnityShader官方案例讲解——SurfaceShader(3)

“Focus on where you’re going and you’ll know what steps to take. Focus on the steps you’re taking and you won’t know where you’re going.”

– Simon Sinek, Inspirational Speaker

step1
接下来实现的是将细节纹理显示在游戏对象上

Shader"Example / AutisticPatient SurfaceShader5"
{
    Properties
    {
        _MainTex("MainTex",2D) = "white"{}
        _Bump("Bump",2D) = "Bump"{}
        _Detail("Detail",2D) = "gray"{}
    }

    SubShader
    {   
        //子着色器标签,表示这个子着色器渲染非透明物体
        Tags{"RenderType" = "Opaque"}
        CGPROGRAM
        //定义表面着色器,并指定光照模型Lambert
        #pragma surface surf Lambert

        //真的 这些没什么可说的  简单带过吧
        //输入结构体,存放各个纹理的uv坐标值
        struct Input 
        {
          float2 uv_MainTex;
          float2 uv_Bump;
          float2 uv_Detail;
        };

        sampler2D _MainTex;
        sampler2D _Bump;
        sampler2D _Detail;

        void surf(Input IN,inout SurfaceOutput o)
        {
            //着色器会找到贴图上对应的UV坐标点,直接使用这个点的颜色信息rgb来进行着色.
            o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;

            //很上边同理,只不过这行处理的是细节纹理,将颜色值扩大了2倍,大家可以试试扩大4倍的效果
            o.Albedo *= tex2D(_Detail,IN.uv_Detail).rgb * 2;

            //unpcakNormal是接受fixed4类型的变量,然后转化为三维法线向量(fixed3)再赋值给标准输出结构体的Normal
            o.Normal = UnpackNormal(tex2D(_Bump,IN.uv_Bump));
        }



        ENDCG

    }
}

接下来上效果图进行对比,图片来自网络
UnityShader官方案例讲解——SurfaceShader(3)_第1张图片
UnityShader官方案例讲解——SurfaceShader(3)_第2张图片

step2

屏幕空间中的细节纹理 (Detail Texture)

其实主要就是讲内置变量screenPos的作用

Shader "Example / AutisticPatient SurfaceShader6" 
{
    Properties
    {
      //跟上面相比只是去掉了法线贴图
      _MainTex ("Texture", 2D) = "white" {}
      _Detail ("Detail", 2D) = "gray" {}
    }
    SubShader 
    {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input 
      {
          float2 uv_MainTex;

          //关于screenPos:screenPos是一个三维点,但是用齐次坐标的形式表示出来就是(x,y,z,w)
          //根据齐次坐标的性质。(x,y,z,w)的齐次坐标对应三维点(x/w,y/w,z/w).
          //因此把w值除掉可以看来是一种Normalize的作法,这样就取出了实际的屏幕xy的UV值.
          //这个说法是网上的一个前辈解释的,更加接近原理
          //如果大家感觉难理解的话,就把它当成“屏幕坐标”后面随着用法的深入,大家会有自己的理解的.
          float4 screenPos;
      };
      sampler2D _MainTex;
      sampler2D _Detail;

      void surf (Input IN, inout SurfaceOutput o)
      {
          //着色器会找到贴图上对应的UV坐标点,直接使用这个点的颜色信息rgb来进行着色.
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;

          //ok这里所做的就是刚才上面所说的了
          //取出屏幕xy的UV值,怎么取呢?
          //就是将xy坐标除以w.
          float2 screenUV = IN.screenPos.xy / IN.screenPos.w;

          //对screenUV进行倍增
          //x轴扩大8倍,y轴扩大6倍
          screenUV *= float2(8,6);
          o.Albedo *= tex2D (_Detail, screenUV).rgb * 2;
      }
      ENDCG
    } 
    Fallback "Diffuse"

 }

效果图大家可以自己找模型搞搞,我找的模型实在是看不出太大的区别,就不上图了

step3

立方体贴图反射
这里使用了一个新的内置变量,
worldRefl:世界空间的反射向量,使用它可以方便的对CubeMap进行采样

Cube : Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样.不理解?上代码就理解了,在properties里它的作用跟2D一样的

  Shader"Example / AutisticPatient SurfaceShader7"
  {
    Properties
    {
      _MainTex ("Texture", 2D) = "white" {}
      //这里官方加入了法线贴图的影响,加入法线贴图印象所必须的代码都将用//NM 注释
      //为什么要用法线贴图?如果希望模拟一个被雪花覆盖的物体,或者是一个凹凸不平的反射面
      //我们是可以通过其他方式模拟出来的,但是这么做的话,占用的资源就大了很多,游戏的帧数就会受到影响
      //现在我们可以用法线贴图来“假装”这种效果
      _Bump("Bump",2D) = "Bump"{}
      //立方体贴图,和2D纹理贴图在代码中的操作相似,但是功能不一样
      _Cube ("Cubemap", CUBE) = "" {}
    }
    SubShader 
    {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
      struct Input 
      {
          //NM    unity的内置结构(struct),它的作用是获取修改后的法线信息
          //换句话说:有了它我们可以访问经过法线贴图修改后的平面的法线信息
          INTERNAL_DATA;
          float2 uv_MainTex;
          //NM
          float2 uv_Bump;           
          float3 worldRefl;
      };

      //NM
      sampler2D _Bump;
      sampler2D _MainTex;
      //这里生命同名变量进行关联
      samplerCUBE _Cube;


      //不需要法线贴图版的surf
      void surf (Input IN, inout SurfaceOutput o) 
      {
          //对纹理采样,将UV坐标点的颜色值 * 0.5 后赋值给输出结构体的颜色属性
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;

          //这里是对立方体贴图进行纹理采样,可对照上一行代码理解
          //texCUBE是对立方体贴图(CubeMap)进行采样的函数,
          //参数1(CubeMap参数2(采样点)
          //然后对输出结构的Emission进行填充,输出
          o.Emission = texCUBE (_Cube, IN.worldRefl).rgb;

      }


      //NM 需要法线贴图版的surf
      void surf(Input IN, inout SurfaceOutput o)
      {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb * 0.5;

        //我们想要使用逐像素的法线贴图来修改反射贴图
        //为了这个目的,需要得带物体的平面法线信息
        o.Normal = UnpackNormal(tex2D(_Bump,IN.uv_Bump));


        //这里面的WorldReflectionVertor函数是新接触的
        //它的作用:获得在使用法线贴图的情况下,逐像素的获取世界空间的反射向量,这个解释比较模糊
        //其实在执行完上一行代码后,物体的平面法线已经被修改了,然后我们就可以就它来影响反射。
        //在结构体中已经声明了INTERVAL_DATA来访问修改后的法线信息.
        //然后使用WorldReflectionVertor函数去查找CubMap中对应的反射信息(反射向量).
        o.Emission = texCUBE(_Cube,WorldReflectionVertor(IN,o.Normal)).rgb;
      }




      ENDCG
    } 
    Fallback "Diffuse"
  }

*吐槽*

一大篇的大白话和病句搞得我看着有点尴尬了

以后的解释中太基础的东西就偏术语化了

非常影响代码的美感呀/(ㄒoㄒ)/~~

你可能感兴趣的:(unity3d特效)