UnityShader之五 表面着色器基础

UnityShader系列文章转载于 @浅墨_毛星云,为本人的学习笔记,转载请注明出处。

文章链接:https://blog.csdn.net/poem_qianmo/article/details/42215079

表面着色器的标准输出结构

    定义一个“表面函数(surface function)”,需要输入相关的UV信息或数据信息,并在输出结构中填充SurfaceOutput。SurfaceOutput基本上描述了表面的特性(光照的颜色反射率、法线、散射、镜面等)。其实还是需要用CG或者HLSL编写此部分的代码。

 

    我们其实是通过表面着色器(Surface Shader)来编译这段CG或者HLSL代码的,然后计算出需要填充输入什么,输出什么等相关信息,并产生真实的顶点(Vertex)&像素(pixel)着色器,以及把渲染路径传递到正向或延时渲染路径。

 

表面着色器(Surface Shader)的标准输出结构

struct SurfaceOutput{

    half3 Albedo;        //反射率,也就是纹理颜色值(r,g,b)

    half3 Normal;        //法线,法向量(x,y,z)

    half3 Emission;        //自发光颜色值(r,g,b)

    half3 Specular;        //镜面反射度

    half Gloss;            //光泽度

    half Alpha;            //透明度

}

表面着色器的编译指令

    表面着色器放在CGPROGRAM .. ENDCG块里面。表面着色器必须嵌在子着色器(SubShader)块里面,而不是Pass{}里面。因为表面着色器(Surface Shader)将在多重通道(multiple passes)内编译自己,而不是放在某个Pass中。

 

声明表面着色器

#pragma surface surfaceFunction lightMode[optionalparams]

  • surfaceFunction 

    • 表示指定名称的Cg函数中有表面着色器(surface shader)代码。这个函数的格式应该是这样:void surf(Input IN,inout SurfaceOutput o),其中Input是我们自己定义的结构。Input结构中应该包含所需的纹理坐标(texture coordinates)和表面函数(surfaceFunction)所需要的额外的必须变量。

  • LightModel 

    •  使用的光照模式。内置的是Lambert(diffuse)和BlingPhong(specular)两种,一般习惯使用Lambert。

  • 可选参数

    • alpha - 透明(Alpha)混合模式。使用它可以写出半透明的着色器。

    • alphaTest:VariableName - 透明(Alpha)测试模式。使用它可以写出镂空效果的着色器。镂空大小的变量(VariableName)是一个float型的变量。

    • vertex:VertexFunction - 自定义的顶点函数(Vertex function)。

    • finalcolor:ColorFunction - 自定义的最终颜色函数(final color function).

#pragma surface surf Lambert finalcolor:mycolor

  • exclude_path:prepass 或者 exclude_path:forward - 使用指定的渲染路径,不需要生成通道。

  • addshadow - 添加阴影投射&收集通道(collector passes).通常用自定义顶点修改,使阴影也能投射在任何程序的顶点动画上。

  • dualforward - 在正向(forward)渲染路径中使用双重光照贴图(dual lightmaps).

  • fullforwardshadows - 在正向(forward)渲染路径中支持所有阴影类型。

  • decal:add - 添加贴图着色器(decal shader)(例如:terrain AddPass)。

  • softvegetation - 使表面着色器(surface shader)仅能在soft Vegetation打开时渲染

  • noambient - 不适用于任何环境光照(ambient lighting)或者球面调和光照(spherical harmonics lights)

  • novertexlights - 在正向渲染(Forward rendering)中不适用于球面调和光照(spherical harmonics lights)或者每个顶点光照(per-vertex lights)

  • nolightmap - 在这个着色器上禁用光照贴图(lightmap)

  • nodirlightmap - 在这个着色器上禁用方向光照贴图(directional lightmaps)

  • noforwardadd - 禁用正向渲染添加通道(Forward rendering additive pass)。这会使这个着色器支持一个完整的方向光和所有光照的per-vertex/SH计算。

  • approxview - 着色器需要计算标准视图的每个顶点(per-vertex)方向而不是每个像素(per-pixel)方向。这样更快,但是视图方向不完全是当前摄像机所接近的表面。

  • halfasview - 在光照函数(lighting function)中传递进来的half-direction向量,而不是视图方向(view-direction)向量。Half-direction会计算且会把每个顶点(per vertex)标准化。

 

表面着色器输入结构

    Input这个输入结构通常拥有着色器需要的所有纹理坐标(texture coordinates).纹理坐标(Texture coordinates)必须被命名为 “uv”后接纹理名称。

 

    输入结构候选值

  • float3 viewDir

    • 视图方向(view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim ligihting)等,需要包含视图方向(view direction)值。

  • float4 with COLOR semantic

    • 每个顶点(per-vertex)颜色的插值

  • float4 screenPos

    • 屏幕空间中的位置。为了反射效果,需要包含屏幕空间中的位置信息。比如在Dark Unity中所使用的WetStreet着色器

  • float3 worldPos

    • 世界空间中的位置

  • float3 worldRefl

    • 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。

  • float3 worldNormal

    • 世界空间中的法线向量(normal vector)。如果表面着色器不写入法线(o.Normal)参数,将包含这个参数。

  • float3 worldRefl;INTERNAL_DATA

    • 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图(per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector(IN,o.Normal))

  • float3 worldNormal;INTERNAL_DATA

    • 世界空间中的法线向量(normal vector)。如果表面着色器不写入法线(o.Normal)参数,将包含这个参数。为了获得获得基于每个顶点法线贴图(per-pixel normal map)的法线向量(normal vector)需要使用世界法线向量(WorldNormalVector(IN,o.Normal))

 

CG函数讲解

 

    UnpackNormal()函数

        UnpackNormal接受一个fixed4的输入,并将其转换为所对应的法线值(fixed3),并将其赋值给输出的Normal,就可以参与到光线运算中完成接下来的的渲染工作。

 

        调用示例

o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));

 

    saturate()函数

        saturate函数的作用是将取值转化为[0,1]之内的一个值。其可选的原型如下:

float saturate(float x);

float1 saturate(float1 x);

float2 saturate(float2 x);

float3 saturate(float3 x);

float4 saturate(float4 x);

half saturate(half x);

half1 saturate(half1 x);

half2 saturate(half2 x);

half3 saturate(half3 x);

half4 saturate(half4 x);

fixed saturate(fixed x);

fixed1 saturate(fixed1 x);

fixed2 saturate(fixed2 x);

fixed3 saturate(fixed3 x);

fixed4 saturate(fixed4 x);

 

 

        返回值:

  • 如果x取值小于0,则返回值为0

  • 如果x取值大于1,则返回值为1

  • 若x在0到1之间,则直接返回x的值

 

dot()函数

    dot函数的作用用于返回两个向量的标量积,可选原型如下:

float dot(float a, float b);

float dot(float1 a, float1 b);

float dot(float2 a, float2 b);

float dot(float3 a, float3 b);

float dot(float4 a, float4 b);

half dot(half a, half b);

half dot(half1 a, half1 b);

half dot(half2 a, half2 b);

half dot(half3 a, half3 b);

half dot(half4 a, half4 b);

fixed dot(fixed a, fixed b);

fixed dot(fixed1 a, fixed1 b);

fixed dot(fixed2 a, fixed2 b);

fixed dot(fixed3 a, fixed3 b);

fixed dot(fixed4 a, fixed4 b);

 

tex2D()函数

    该函数用于2D纹理采样,其可选原型有

float4 tex2D(sampler2D samp, float2 s)

float4 tex2D(sampler2D samp, float2 s, inttexelOff)

float4 tex2D(sampler2D samp, float3 s)

float4 tex2D(sampler2D samp, float3 s, inttexelOff)

float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy)

float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)

float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy)

float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy, int texelOff)

int4 tex2D(isampler2D samp, float2 s)

int4 tex2D(isampler2D samp, float2 s, inttexelOff)

int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy)

int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)

unsigned int4 tex2D(usampler2D samp, float2s)

unsigned int4 tex2D(usampler2D samp, float2s, int texelOff)

unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy)

unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy,int texelOff)

    参数简介

  • samp -  需要查找采样的对象

  • s - 需进行查找的纹理坐标

  • dx -  预计算的沿x轴方向的导数

  • dy  -  预计算的沿y轴方向的导数

  • texeloff - 添加给最终纹理的偏移量

    其返回值为查找到的纹理

 

综合应用

 

Shader "typedef/Volume4/9.凹凸纹理+颜色可调+边缘发光+细节纹理" {

        Properties {

               _MainTex("【主纹理】RGB",2D) = "white"{}

               _BumpMap("【凹凸纹理】RGB",2D) = "white"{}

               _DetailTex("【细节纹理】",2D) = "gray"{}

               _ColorTint("【色泽】",Color) = (0.5,0.6,0.5,1)

               _RimColor("【边缘颜色】",Color) = (0.3,1,0.7,0)

               _RimPower("【边缘颜色强度】",Range(0.6,9))=3.0

        }

        SubShader {

               //着色器标签

               Tags{"RenderType" = "Opaque"}

               //开始CG编程语言段

               CGPROGRAM

               //声明光照模式:兰伯特光照模式+自定义颜色

               #pragma surface surf Lambert finalcolor:setcolor

               //声明变量

               sampler2D _MainTex;

               sampler2D _BumpMap;

               sampler2D _DetailTex;

               fixed4 _ColorTint;

               fixed4 _RimColor;

               float _RimPower;

               //输入结构体

               struct Input{

                       //主纹理的uv坐标值

                       float2 uv_MainTex;

                       //凹凸纹理的uv坐标值

                       float2 uv_BumpMap;

                       //细节纹理的uv坐标值

                       float2 uv_DetailTex;

                       //当前坐标的视线方向

                       float3 viewDir;

               };

               //表面着色函数

               void surf(Input IN,inout SurfaceOutput o){

                       //设置主纹理的rgb值

                       o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;

                       //设置细节纹理

                       o.Albedo *= tex2D(_DetailTex,IN.uv_DetailTex).rgb*3;

                       //设置凹凸纹理

                       o.Normal = UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));

                       //获得自发光强度系数

                       //获得射线方向与法线方向的点积,求点积就是求夹角的cos值

                       //将上面的值转化为[0,1]的一个值

                       half rim = 1.0 - saturate(dot(normalize(IN.viewDir),o.Normal));

                       //设置边缘发光颜色

                       o.Emission = _RimColor * pow(rim,_RimPower);

               }

               //自定义颜色函数

               void setcolor(Input IN,SurfaceOutput o, inout fixed4 color){

                       color *= _ColorTint;

               }

               //结束CG编程语言段

               ENDCG

        }

        FallBack "Diffuse"

}

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值