本系列文章由@浅墨_毛星云 出品,转载请注明出处。  
文章链接: http://blog.csdn.net/poem_qianmo/article/details/50878538
作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442
本文工程使用的Unity3D版本: 5.2.1 

本次更新放出的Shader为透明系列的3个Shader和标准的镜面高光Shader的两个Shader。由易到难,由入门级到应用级,难度梯度合理。

依然是先放出游戏场景的exe和运行截图。

本期用的模型为妙蛙草。

【可运行的本文配套exe游戏场景请点击这里下载】

OK,直奔主题吧。

一、单色透明Shader

在上篇文章中单色透明的基础上进行改造,加入alpha混合,构成了这篇文章的第一个Shader——单色透明Shader。具体代码如下:

//透明单色ShaderShader "浅墨Shader编程/Volume13/1.SimpleAlphaShader"
{//------------------------------------【唯一的子着色器】------------------------------------SubShader{  //设置Queue为透明,在所有非透明几何体绘制之后再进行绘制Tags{ "Queue" = "Transparent" }Pass{//不写入深度缓冲,为了不遮挡住其他物体ZWrite Off//选取Alpha混合方式Blend  SrcAlpha SrcAlpha//Blend SrcAlpha OneMinusSrcAlpha//===========开启CG着色器语言编写模块============CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert #pragma fragment frag//--------------------------------【顶点着色函数】-----------------------------// 输入:POSITION语义(坐标位置)// 输出:SV_POSITION语义(像素位置)//---------------------------------------------------------------------------------float4 vert(float4 vertexPos : POSITION) : SV_POSITION{//坐标系变换//输出的顶点位置(像素位置)为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口return mul(UNITY_MATRIX_MVP, vertexPos);}//--------------------------------【片段着色函数】-----------------------------// 输入:无// 输出:COLOR语义(颜色值)//---------------------------------------------------------------------------------float4 frag(void) : COLOR{//返回单色return float4(0.3, 1.0, 0.1, 0.6);}//===========结束CG着色器语言编写模块===========ENDCG}}
}

将其施用于材质之上的效果如下:

实景效果如下:

二、颜色可以调版单色透明Shader

老规矩,让颜色可调,来一个Properties属性块,替换掉Hard encoding硬编码的颜色。所以,代码如下:

//颜色可以调版单色透明ShaderShader "浅墨Shader编程/Volume13/2.ColorChangeAlpha"
{//------------------------------------【属性值】------------------------------------Properties{//颜色值_ColorWithAlpha("ColorWithAlpha", Color) = (0.9, 0.1, 0.1, 0.5)}//------------------------------------【唯一的子着色器】------------------------------------SubShader{//设置Queue为透明,在所有非透明几何体绘制之后再进行绘制Tags{ "Queue" = "Transparent" }//--------------------------------唯一的通道-------------------------------Pass{//不写入深度缓冲,为了不遮挡住其他物体ZWrite Off//选取Alpha混合方式Blend  SrcAlpha SrcAlpha//Blend SrcAlpha OneMinusSrcAlpha//===========开启CG着色器语言编写模块============CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert #pragma fragment frag//变量声明uniform float4 _ColorWithAlpha;//--------------------------------【顶点着色函数】-----------------------------// 输入:POSITION语义(坐标位置)// 输出:SV_POSITION语义(像素位置)//---------------------------------------------------------------------------------float4 vert(float4 vertexPos : POSITION) : SV_POSITION{//坐标系变换//输出的顶点位置(像素位置)为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口return mul(UNITY_MATRIX_MVP, vertexPos);}//--------------------------------【片段着色函数】-----------------------------// 输入:无// 输出:COLOR语义(颜色值)//---------------------------------------------------------------------------------float4 frag(void) : COLOR{//返回自定义的RGBA颜色return _ColorWithAlpha;}//===========结束CG着色器语言编写模块===========ENDCG}}
}

将其施用于材质之上的效果如下:

这边的调色板中,,除了RGB三色,还有Alpha值可以进行调节。

实景效果如下:

三、双面双色颜色可以调版透明Shader

我们可以利用Cull语句,分别在两个Pass中Cull Front和Cull Back,以让材质的正面和反面显示出不同的颜色。代码实现如下:

//双面双色颜色可以调版透明ShaderShader "浅墨Shader编程/Volume13/3.TwoSideColorChangeAlpha"
{//------------------------------------【属性值】------------------------------------Properties{//正面颜色值_ColorWithAlpha_Front("ColorWithAlpha_Front", Color) = (0.9, 0.1, 0.1, 0.5)//背面颜色值_ColorWithAlpha_Back("ColorWithAlpha_Back", Color) = (0.1, 0.3, 0.9, 0.5)}//------------------------------------【唯一的子着色器】------------------------------------SubShader{//设置Queue为透明,在所有非透明几何体绘制之后再进行绘制Tags{ "Queue" = "Transparent" }//------------------------【通道1:渲染正面】-------------------------Pass{//剔除背面,渲染正面Cull Back//不写入深度缓冲,为了不遮挡住其他物体ZWrite Off //选取Alpha混合方式Blend SrcAlpha OneMinusSrcAlpha//Blend  SrcAlpha SrcAlpha//===========开启CG着色器语言编写模块============CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert #pragma fragment frag//变量声明uniform float4 _ColorWithAlpha_Front;//--------------------------------【顶点着色函数】-----------------------------// 输入:POSITION语义(坐标位置)// 输出:SV_POSITION语义(像素位置)//---------------------------------------------------------------------------------float4 vert(float4 vertexPos : POSITION) : SV_POSITION{//坐标系变换//输出的顶点位置(像素位置)为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口return mul(UNITY_MATRIX_MVP, vertexPos);}//--------------------------------【片段着色函数】-----------------------------// 输入:无// 输出:COLOR语义(颜色值)//---------------------------------------------------------------------------------float4 frag(void) : COLOR{//返回自定义的RGBA颜色return _ColorWithAlpha_Front;}//===========结束CG着色器语言编写模块===========ENDCG}//------------------------【通道2:渲染背面】-------------------------Pass{//剔除正面,渲染背面Cull Front//不写入深度缓冲,为了不遮挡住其他物体ZWrite Off//选取Alpha混合方式Blend SrcAlpha OneMinusSrcAlpha//Blend  SrcAlpha SrcAlpha//===========开启CG着色器语言编写模块============CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert #pragma fragment frag//变量声明uniform float4 _ColorWithAlpha_Back;//--------------------------------【顶点着色函数】-----------------------------// 输入:POSITION语义(坐标位置)// 输出:SV_POSITION语义(像素位置)//---------------------------------------------------------------------------------float4 vert(float4 vertexPos : POSITION) : SV_POSITION{//坐标系变换//输出的顶点位置(像素位置)为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口return mul(UNITY_MATRIX_MVP, vertexPos);}//--------------------------------【片段着色函数】-----------------------------// 输入:无// 输出:COLOR语义(颜色值)//---------------------------------------------------------------------------------float4 frag(void) : COLOR{//返回自定义的RGBA颜色return _ColorWithAlpha_Back;}//===========结束CG着色器语言编写模块===========ENDCG}}
}

将其施用于材质之上的效果如下:

可以看到,有两个可供调节的颜色选项,分别表示材质正面和反面的透明颜色,而材质最终表现出来的透明颜色,是这两种颜色的混合。

在实景表现中,从物体外部和内部,可以看到其显示出了不同的颜色。

从物体外部看:

从物体内部看:

四、镜面反射(Specular)Shader

上篇文章中讲到了Diffuse光照(漫反射光照)与实现它的Shader,经常与其相提并论的是Specular光照(镜面反射光照,或称高光)。这里,接着我们来放出镜面反射光照的Shader。其具体的原理翻开任何一本图形学的书都可以找到,这边就不多讲,直接放出详细注释的实现代码:

//镜面反射Shader(specular shader )Shader "浅墨Shader编程/Volume13/4.Specular"
{//------------------------------------【属性值】------------------------------------Properties{//主颜色_Color("Main Color", Color) = (1, 1, 1, 1)//镜面反射颜色_SpecColor("Specular Color", Color) = (1, 1, 1, 1)//镜面反射光泽度_SpecShininess("Specular Shininess", Range(1.0, 100.0)) = 10.0}//------------------------------------【唯一的子着色器】------------------------------------SubShader{//渲染类型设置:不透明Tags{ "RenderType" = "Opaque" }//--------------------------------唯一的通道-------------------------------Pass{//光照模型ForwardBaseTags{ "LightMode" = "ForwardBase" }//===========开启CG着色器语言编写模块===========CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert#pragma fragment frag//顶点着色器输入结构struct appdata{float4 vertex : POSITION;//顶点位置float3 normal : NORMAL;//法线向量坐标};//顶点着色器输出结构struct v2f{float4 pos : SV_POSITION;//像素位置float3 normal : NORMAL;//法线向量坐标float4 posWorld : TEXCOORD0;//在世界空间中的坐标位置};//变量的声明float4 _LightColor0;float4 _Color;float4 _SpecColor;float _SpecShininess;//--------------------------------【顶点着色函数】-----------------------------// 输入:顶点输入结构体// 输出:顶点输出结构体//---------------------------------------------------------------------------------//顶点着色函数v2f vert(appdata IN){//【1】声明一个输出结构对象v2f OUT;//【2】填充此输出结构//输出的顶点位置为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口OUT.pos = mul(UNITY_MATRIX_MVP, IN.vertex);//获得顶点在世界空间中的位置坐标OUT.posWorld = mul(_Object2World, IN.vertex);//获取顶点在世界空间中的法线向量坐标OUT.normal = mul(float4(IN.normal, 0.0), _World2Object).xyz;//【3】返回此输出结构对象return OUT;}//--------------------------------【片段着色函数】-----------------------------// 输入:顶点输出结构体// 输出:float4型的像素颜色值//---------------------------------------------------------------------------------fixed4 frag(v2f IN) : COLOR{//【1】先准备好需要的参数//获取法线的方向float3 normalDirection = normalize(IN.normal);//获取入射光线的方向float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);//获取视角方向float3 viewDirection = normalize(_WorldSpaceCameraPos - IN.posWorld.xyz);//【2】计算出漫反射颜色值  Diffuse=LightColor * MainColor * max(0,dot(N,L))float3 diffuse = _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDirection, lightDirection));//【3】计算镜面反射颜色值 float3 specular;//若是法线方向和入射光方向大于180度,镜面反射值为0if (dot(normalDirection, lightDirection) < 0.0){specular = float3(0.0, 0.0, 0.0);}//否则,根据公式进行计算 Specular =LightColor * SpecColor *pow(max(0,dot(R,V)),Shiness),R=reflect(-L,N)else{float3 reflectDirection = reflect(-lightDirection, normalDirection);specular = _LightColor0.rgb * _SpecColor.rgb * pow(max(0.0, dot(reflectDirection, viewDirection)), _SpecShininess);}//【4】合并漫反射、镜面反射、环境光的颜色值float4 diffuseSpecularAmbient = float4(diffuse, 1.0) + float4(specular, 1.0) + UNITY_LIGHTMODEL_AMBIENT;//【5】将漫反射-镜面反射-环境光的颜色值返回return diffuseSpecularAmbient;}//===========结束CG着色器语言编写模块===========ENDCG}}
}

将其施用于材质之上的效果如下:

其中的Specular Shininess滑条用于调节高光的衰减级数。

OK,我们将颜色调节一下,看看新的效果:

五、带纹理载入的specular shader

当然要支持纹理载入,不然实用性太低。Properties中加入纹理属性,其他的地方进行相应的变化,便可以得到支持纹理载入的specular shader:

//支持纹理载入的specular shader Shader "浅墨Shader编程/Volume13/5.Specular with Shader"
{//------------------------------------【属性值】------------------------------------Properties{//主纹理_MainTex("Texture", 2D) = "white" {}//主颜色_Color("Main Color", Color) = (1, 1, 1, 1)//镜面反射颜色_SpecColor("Specular Color", Color) = (1, 1, 1, 1)//镜面反射光泽度_SpecShininess("Specular Shininess", Range(1.0, 100.0)) = 10.0}//------------------------------------【唯一的子着色器】------------------------------------SubShader{//渲染类型设置:不透明Tags{ "RenderType" = "Opaque" }//--------------------------------唯一的通道-------------------------------Pass{//光照模型ForwardBaseTags{ "LightMode" = "ForwardBase" }//===========开启CG着色器语言编写模块===========CGPROGRAM//编译指令:告知编译器顶点和片段着色函数的名称#pragma vertex vert#pragma fragment frag//顶点着色器输入结构struct appdata{float4 vertex : POSITION;//顶点位置float3 normal : NORMAL;//法线向量坐标float2 texcoord : TEXCOORD0;//一级纹理坐标};//顶点着色器输出结构struct v2f{float4 pos : SV_POSITION;//像素位置float3 normal : NORMAL;//法线向量坐标float2 texcoord : TEXCOORD0;//一级纹理坐标float4 posWorld : TEXCOORD1;//在世界空间中的坐标位置};//变量的声明float4 _LightColor0;float4 _Color;sampler2D _MainTex;float4 _SpecColor;float _SpecShininess;//--------------------------------【顶点着色函数】-----------------------------// 输入:顶点输入结构体// 输出:顶点输出结构体//---------------------------------------------------------------------------------//顶点着色函数v2f vert(appdata IN){//【1】声明一个输出结构对象v2f OUT;//【2】填充此输出结构//输出的顶点位置为模型视图投影矩阵乘以顶点位置,也就是将三维空间中的坐标投影到了二维窗口OUT.pos = mul(UNITY_MATRIX_MVP, IN.vertex);//获得顶点在世界空间中的位置坐标OUT.posWorld = mul(_Object2World, IN.vertex);//获取顶点在世界空间中的法线向量坐标OUT.normal = mul(float4(IN.normal, 0.0), _World2Object).xyz;//输出的纹理坐标也就是输入的纹理坐标OUT.texcoord = IN.texcoord;//【3】返回此输出结构对象return OUT;}//--------------------------------【片段着色函数】-----------------------------// 输入:顶点输出结构体// 输出:float4型的像素颜色值//---------------------------------------------------------------------------------fixed4 frag(v2f IN) : COLOR{//【1】先准备好需要的参数//获取纹理颜色float4 texColor = tex2D(_MainTex, IN.texcoord);//获取法线的方向float3 normalDirection = normalize(IN.normal);//获取入射光线的方向float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);//获取视角方向float3 viewDirection = normalize(_WorldSpaceCameraPos - IN.posWorld.xyz);//【2】计算出漫反射颜色值  Diffuse=LightColor * MainColor * max(0,dot(N,L))float3 diffuse = _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDirection, lightDirection));//【3】计算镜面反射颜色值 float3 specular;//若是法线方向和入射光方向大于180度,镜面反射值为0if (dot(normalDirection, lightDirection) < 0.0){specular = float3(0.0, 0.0, 0.0);}//否则,根据公式进行计算 Specular =LightColor * SpecColor *pow(max(0,dot(R,V)),Shiness),R=reflect(-L,N)else{float3 reflectDirection = reflect(-lightDirection, normalDirection);specular = _LightColor0.rgb * _SpecColor.rgb * pow(max(0.0, dot(reflectDirection, viewDirection)), _SpecShininess);}//【4】合并漫反射、镜面反射、环境光的颜色值float4 diffuseSpecularAmbient = float4(diffuse, 1.0) + float4(specular, 1.0) + UNITY_LIGHTMODEL_AMBIENT;//【5】将漫反射-镜面反射-环境光的颜色值乘以纹理颜色值之后返回return diffuseSpecularAmbient * texColor;}//===========结束CG着色器语言编写模块===========ENDCG}}
}

将其施用于材质之上的效果如下:

将此Shader施于妙蛙草的模型之上,得到的便是如端游《剑灵》一般油腻腻的画风感觉:

本文Shader的全家福:

最后,依然是放出加入特效后的场景截图。

OK,本篇的内容大致如此,下次更新见。

附1: 本博文相关资源下载链接清单

【百度云】博文游戏场景exe下载

【百度云】博文示例场景资源和源码工程下载   ( PS:工程所用Unity版本为5.2.1)

【Github】本文全部Shader源码

附2:Reference

[1] http://docs.unity3d.com/Manual/SL-Reference.html

[2] https://en.wikibooks.org/wiki/Cg_Programming

【Unity3D Shader编程】之十三 单色透明Shader 标准镜面高光Shader相关推荐

  1. 【Unity3D Shader编程】之十三 单色透明Shader 标准镜面高光Shader

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  2. 【Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  3. Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  4. 【浅墨Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法. 在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照模 ...

  5. 【浅墨Unity3D Shader编程】之一 游戏场景的创建 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...

  6. 【Unity3D Shader编程】之六 暗黑城堡篇 表面着色器 Surface Shader 的写法 一

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由@浅墨 ...

  7. Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法颜色、光照与材质

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨) ...

  8. 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 amp; 纹理混合...

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接: http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星 ...

  9. 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...

最新文章

  1. linux nvme分区,这些 loop 分区是什么鬼东西?
  2. OpenSwitch操作系统成为Linux基金会官方项目
  3. java 通配符 类_关于类:具有多个类的Java泛型通配符
  4. 蓝书3.7 欧拉回路
  5. poj2965 【枚举】
  6. dr.com linux源码安装,Linux在不采用坑爹的Dr.com客户端下的连网方式(亲测可行 ,简单易行)...
  7. python会不会出4_无极4网人生苦短,Python会不会被取代?国外网友
  8. VS2019 更新MSDN并创建快捷方式
  9. 香农编码二叉树c语言,shannon码的编码实验总结.docx
  10. 【测试工具】在linux测试环境访问禅道数据库
  11. NatureGenetics:所有五个异源四倍体棉花起源被厘清
  12. HDU 4694: Important Sisters(支配树)
  13. OC小实例关于init方法不小心的错误
  14. 系统分析师考试经验分享
  15. 进制转换表与课程内容
  16. 颜色不透明度16进制对照表
  17. html5数独游戏设计,数独游戏的前端实现
  18. (个人记录)安装pycocotools库出现Could not build wheels for pycocotools which use PEP 517 and cannot be install
  19. java 上传文件-生成文件首页缩略图 生成pdf 抓取图片
  20. 技术解读 | 科大讯飞语音技术最新进展之二:语音识别与语音合成

热门文章

  1. 匈牙利算法解决二分图匹配问题
  2. 【FAQ】接入HMS Core应用内支付服务过程中一些常见问题总结(2)
  3. LTE Initial Attach 的过程以及相关消息的具体解析 (二)
  4. 视频抽帧及将图片合成视频
  5. php劳保管理系统,劳保管理软件,劳保发放管理,劳保发放记录,石开劳保发放管理系统...
  6. AOJ-problem-849
  7. 四款超级好用的终端文件管理器,提高你的使用效率!
  8. redis重启失败原因
  9. CAD中插入外部参照字体会变繁体_CAD外部参照的附加型和覆盖型有什么区别?
  10. C++字符串定义与操作