zoukankan      html  css  js  c++  java
  • Unity Shader 漫反射的实现

    模型的漫反射可以在两个函数中实现,一个是顶点函数,另外一个就是片元函数。而这两个函数的区别又决定了漫反射实现出来的效果,那就是精细度。

    因为顶点函数是逐顶点调用,漫反射在顶点函数实现时,对于在一个三角面(三个顶点包含的面)中的像素值是通过插值得到的。所以模型显示的每个像素不是最细化的。

    而片元函数是逐像素调用的,若漫反射在片元函数中调用,则会仔细涉及到每个像素,漫反射出来的效果也会更好一些。

    下面我就直接放两种Shader代码的实现了。在这里我在片元函数的漫反射直接使用了半兰伯特光照模型。

    顶点函数的漫反射(兰伯特光照模型)

     1 // 顶点函数漫反射的编写
     2 // 兰伯特光照模型
     3 // Diffuse = 直射光颜色 * max(cos(反射光,法线),0)
     4 Shader "TMoon/02-Diffuse Vertex" {
     5     Properties{
     6         _Diffuse("Diffuse Color",Color) = (1,1,1,1)
     7     }
     8 
     9     SubShader{
    10 
    11         Pass{
    12         
    13             Tags {"LightMode" = "ForwardBase"}
    14 
    15             CGPROGRAM
    16               
    17             // 类似C#的 using 引用类库或者文件
    18             // 这里引用了Unity内置的光照的类库
    19             // 配合"LightMode" = "ForwarBase"得到Unity场景中的光照信息
    20             #include "Lighting.cginc"
    21 
    22             #pragma vertex vert
    23             #pragma fragment frag
    24             
    25             //获得面板参数
    26             fixed4 _Diffuse;
    27 
    28             // 这里使用第二种方法传值 结构体
    29             // application to vertex
    30             // 由应用程序传递给顶点函数的参数
    31             struct a2v {
    32                 float4 vertex : POSITION; //应用程序将模型的顶点坐标填充到vertex
    33                 float3 normal : NORMAL; //应用程序将模型的顶点法线填充到normal
    34             };
    35 
    36             // vertex to fragment
    37             // 由顶点函数传递给片元函数的参数
    38             struct v2f {
    39                 float4 position : SV_POSITION; //模型裁剪空间下的顶点坐标
    40                 float3 color : COLOR0;    //COLOR0,COLOR1...这些类型一般是中介,用于存储和传递数据,有时并没有什么实际意义,就是中介而已。
    41             };
    42 
    43             v2f vert(a2v v) {
    44                 v2f f;
    45                 // 将模型顶点坐标变换到裁剪空间的坐标并赋值给v2f.position
    46                 f.position = mul(UNITY_MATRIX_MVP, v.vertex);
    47 
    48                 // UNITY_LIGHTMODEL_AMBIENT用来获取环境光
    49                 // 获取Unity环境光的颜色值
    50                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rag;
    51 
    52                 // 将模型顶点的法线转换到空间坐标下,方便一致计算
    53                 // UnityObjectToWorldNormal 把法线方向 模型空间 ——> 世界空间
    54                 fixed3 normalDir = normalize(UnityObjectToWorldNormal(v.normal));
    55 
    56                 // _WorldSpaceLightPos0 空间坐标下光的方向
    57                 // 对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光
    58                 // 在这里我直接理解为了反射光
    59                 fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    60 
    61                 // 兰伯特光照模型
    62                 // _LightColor0.rab 直射光颜色
    63                 fixed3 diffuse = _LightColor0.rab * max(dot(normalDir, lightDir),0) * _Diffuse.rgb;
    64 
    65                 // 将漫反射加上环境光的影响
    66                 f.color = diffuse + ambient;
    67 
    68                 return f;
    69             }
    70 
    71             float4 frag(v2f f) : SV_Target{
    72                 return fixed4(f.color,1);
    73             }
    74 
    75             ENDCG
    76         }
    77     }
    78 
    79     Fallback "VertexLit"
    80 }
    Diffuse Vertex

    片元函数的漫反射(半兰伯特光照模型)

     1 // 片元函数漫反射的编写  细节更多 边缘过渡更顺    可以对比顶点函数漫反射
     2 // 半兰伯特光照模型  阴影部分不会全黑,如果全黑对玩家不太友好  可以对比兰伯特光照模型  在02-Diffuse Vertex把环境光去掉即可明显对比
     3 // Diffuse = 直射光颜色 * (cos(反射光,法线)*0.5+0.5)
     4 Shader "TMoon/03-Diffuse Fragment" {
     5     Properties{
     6         _Diffuse("Diffuse Color",Color) = (1,1,1,1)
     7     }
     8 
     9     SubShader{
    10 
    11         Pass{
    12         
    13             Tags {"LightMode" = "ForwardBase"}
    14 
    15             CGPROGRAM
    16               
    17             // 类似C#的 using 引用类库或者文件
    18             // 这里引用了Unity内置的光照的类库
    19             // 配合"LightMode" = "ForwarBase"得到Unity场景中的光照信息
    20             #include "Lighting.cginc"
    21 
    22             #pragma vertex vert
    23             #pragma fragment frag
    24             
    25             //获得面板参数
    26             fixed4 _Diffuse;
    27 
    28             // application to vertex
    29             // 由应用程序传递给顶点函数的参数
    30             struct a2v {
    31                 float4 vertex : POSITION; //应用程序将模型的顶点坐标填充到vertex
    32                 float3 normal : NORMAL; //应用程序将模型的顶点法线填充到normal
    33             };
    34 
    35             // vertex to fragment
    36             // 由顶点函数传递给片元函数的参数
    37             struct v2f {
    38                 float4 position : SV_POSITION; //模型裁剪空间下的顶点坐标
    39                 float3 worldNormalDir : COLOR0;    //COLOR0,COLOR1...这些类型一般是中介,用于存储和传递数据,有时并没有什么实际意义,就是中介而已。
    40             };
    41 
    42             v2f vert(a2v v) {
    43                 v2f f;
    44 
    45                 // 将模型顶点坐标变换到裁剪空间的坐标并赋值给v2f.position
    46                 f.position = mul(UNITY_MATRIX_MVP, v.vertex);
    47 
    48                 // 将模型顶点的法线转换到空间坐标下,方便一致计算
    49                 // UnityObjectToWorldNormal 把法线方向 模型空间 ——> 世界空间
    50                 f.worldNormalDir = normalize(UnityObjectToWorldNormal(v.normal));
    51 
    52                 return f;
    53             }
    54 
    55             float4 frag(v2f f) : SV_Target{
    56 
    57                 // 反射光
    58                 fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    59 
    60                 // 半兰伯特光照模型
    61                 fixed3 diffuse = _LightColor0.rab * (dot(f.worldNormalDir, lightDir)*0.5+0.5) * _Diffuse.rgb;
    62 
    63                 return fixed4(diffuse,1);
    64             }
    65 
    66             ENDCG
    67         }
    68     }
    69 
    70     Fallback "VertexLit"
    71 }
    Diffuse Fragment

    这里通过截图显示一下兰伯特光照模型和半兰伯特光照模型的区别。

    通过背面就很明显看得出了。这篇文章就到这里了。

  • 相关阅读:
    获取目录下所有文件名
    毕业论文endnote使用
    CoinChange
    sublime3个人配置
    2015-12-31
    2015-12-09
    #define DEBUG用法
    fiddler介绍
    app测试模块
    android SDK_安装配置_使用
  • 原文地址:https://www.cnblogs.com/SeaSwallow/p/6894449.html
Copyright © 2011-2022 走看看