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

来源:互联网 发布:知乎live怎么免费听 编辑:程序博客网 时间:2024/06/10 16:29

“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    }}

接下来上效果图进行对比,图片来自网络
这里写图片描述
这里写图片描述

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ㄒ)/~~

0 0