http://www.cnblogs.com/guxin/p/unity-diffuse-shader-demo.html

在上文中已经学习了漫反射Diffuse Shader和环境光,现在再在此基础上加入高光反射Specular Shader。

高光反射的计算公式:

高光反射Specular = 直射光 * pow(max(0, cos(反射光方向和视野方向的夹角)), 高光反射参数)

当然中间的max(0, cos(反射光方向和视野方向的夹角)部分也可以改用半兰伯特模型以增强背光面的光照效果。


逐顶点高光反射

Shader "Custom/07-Specular Vertex" { // 逐顶点高光反射
Properties{
_Diffuse("Diffuse Color", Color) = (,,,) // 可在编辑器面板定义材质自身色彩
_Gloss("Gloss", Range(,)) = // 高光的参数
}
SubShader{
Pass { // 只有定义了正确的LightMode才能得到一些Unity的内置光照变量
Tags{"LightMode" = "ForwardBase"} CGPROGRAM // 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment frag fixed4 _Diffuse; // 使用属性
half _Gloss; struct a2v
{
float4 vertex : POSITION; // 告诉Unity把模型空间下的顶点坐标填充给vertex属性
float3 normal : NORMAL; // 告诉Unity把模型空间下的法线方向填充给normal属性
}; struct v2f
{
float4 position : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
float3 color : COLOR; // 用于传递计算出来的漫反射颜色
}; // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间
// 环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
// 法线方向。把法线方向从模型空间转换到世界空间
fixed3 normalDir = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); // 反过来相乘就是从模型到世界,否则是从世界到模型
// 光照方向。
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 对于每个顶点来说,光的位置就是光的方向,因为光是平行光
/*
* 漫反射Diffuse = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩
*/
fixed3 diffuse = _LightColor0.rgb * max(, dot(normalDir, lightDir)) * _Diffuse.rgb; // 颜色融合用乘法 // 反射光的方向
fixed3 reflectDir = normalize(reflect(-lightDir, normalDir)); // 参数:平行光的入射方向,法线方向。而lightDir光照方向是从模型表面到光源的,所以取负数。
// 视野方向 = 摄像机的位置 - 当前点的位置
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex, unity_WorldToObject).xyz);
/*
* 高光反射Specular = 直射光 * pow(max(0, cos(反射光方向和视野方向的夹角)), 高光反射参数)
*/
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir, viewDir), ), _Gloss); // 最终颜色 = 漫反射 + 环境光 + 高光反射
f.color = diffuse + ambient + specular; // 颜色叠加用加法(亮度通常会增加) return f;
} // 计算每个像素点的颜色值
fixed4 frag(v2f f) : SV_Target
{
return fixed4(f.color, ); // f.color是float3已经包含了三个数值
} ENDCG
} }
FallBack "Diffuse"
}

逐像素高光反射

Shader "Custom/08-Specular Fragment" { // 逐像素高光反射
Properties{
_Diffuse("Diffuse Color", Color) = (,,,) // 可在编辑器面板定义材质自身色彩
_Gloss("Gloss", Range(,)) = // 高光的参数
}
SubShader{
Pass { // 只有定义了正确的LightMode才能得到一些Unity的内置光照变量
Tags{"LightMode" = "ForwardBase"} CGPROGRAM // 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment frag fixed4 _Diffuse; // 使用属性
half _Gloss; struct a2v
{
float4 vertex : POSITION; // 告诉Unity把模型空间下的顶点坐标填充给vertex属性
float3 normal : NORMAL; // 告诉Unity把模型空间下的法线方向填充给normal属性
}; struct v2f
{
float4 position : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标
float3 worldNomal : TEXCOORD0;
float3 worldVertex : TEXCOORD1;
}; // 计算顶点坐标从模型坐标系转换到裁剪面坐标系
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间 // 法线方向。把法线方向从模型空间转换到世界空间
f.worldNomal = mul(v.normal, (float3x3)unity_WorldToObject); // 反过来相乘就是从模型到世界,否则是从世界到模型
f.worldVertex = mul(v.vertex, unity_WorldToObject).xyz;
return f;
} // 计算每个像素点的颜色值
fixed4 frag(v2f f) : SV_Target
{
// 环境光
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
// 法线方向。
fixed3 normalDir = normalize(f.worldNomal); // 单位向量
// 光照方向。
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 对于每个顶点来说,光的位置就是光的方向,因为光是平行光
// 漫反射Diffuse颜色 = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩
fixed3 diffuse = _LightColor0 * max(, dot(normalDir, lightDir)) * _Diffuse.rgb; // 颜色融合用乘法 // 反射光的方向
fixed3 reflectDir = normalize(reflect(-lightDir, normalDir)); // 参数:平行光的入射方向,法线方向。而lightDir光照方向是从模型表面到光源的,所以取负数。
// 视野方向 = 摄像机的位置 - 当前点的位置
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertex);
/*
* 高光反射Specular = 直射光 * pow(max(0, cos(反射光方向和视野方向的夹角)), 高光反射参数)
*/
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir, viewDir), ), _Gloss); // 最终颜色 = 漫反射 + 环境光 + 高光反射
fixed3 tempColor = diffuse + ambient + specular; // 颜色叠加用加法(亮度通常会增加) return fixed4(tempColor, ); // tempColor是float3已经包含了三个数值
} ENDCG
} }
FallBack "Diffuse"
}

效果比较

如下图,左边是逐顶点计算,右边是逐像素计算。能明显看出来逐顶点计算的光斑块状明显,效果不如逐像素计算的好。


使用Blinn-Phong光照模型

Blinn光照模型:
Specular = 直射光  * pow( max(cosθ,0),10)  θ:是反射光方向和视野方向的夹角
Blinn-Phong光照模型:
Specular = 直射光  * pow( max(cosθ,0),10)  θ:是法线和x的夹角  x:是平行光和视野方向的平分线

所以只需修改上面例子中的公式计算部分即可。

// 光照方向和视野方向的夹角的平分线
fixed3 halfDir = normalize(lightDir + viewDir); fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir, halfDir), ), _Gloss);

改用Blinn-Phong光照模型后能看到高光光斑变得更圆了一些,效果如下图:

下图左边是Blinn-Phong模型,背光面不会出现高光,感觉效果更好。


学习资料:

【Unity Shader】四、高光反射Specular Shader例子的更多相关文章

  1. 【Unity Shader学习笔记】Unity光照基础-高光反射

    1.原理 1.1.Phong模型 计算高光反射需要表面法线.视角方向.光源方向.反射方向等. 在这四个矢量中,我们实际上只需要知道其中3个矢量即可,而第4个矢量(反射方向r)可以通过其他信息计算得到: ...

  2. 【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现

    [Unity Shader](三) ---------------- 光照模型原理及漫反射和高光反射的实现 [Unity Shader](四) ------ 纹理之法线纹理.单张纹理及遮罩纹理的实现 ...

  3. Unity shader学习之高光反射光照模型

    高光反射光照模型的公式如下: Cspecular = Clight * mspecular * max(0, dot(v, r))gloss 要计算高光反射需要知道4个参数:入射光线颜色Cspecul ...

  4. Unity Shader (三)Surface Shader机制

    转自:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的机制一直是 ...

  5. 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...

  6. 【Unity Shaders】Shader学习资源和Surface Shader概述

    写在前面 写这篇文章的时候,我断断续续学习Unity Shader半年了,其实还是个门外汉.我也能体会很多童鞋那种想要学好Shader却无从下手的感觉.在这个期间,我找到一些学习Shader的教程以及 ...

  7. Phong & BlinnPhong Specular Shader

    [Phong Specular Shader] 如果物体离摄像机很远,或者不需要高精度镜面反射,则Phong模型适用. Phong模型如下: 使用前必须指定使用自定义Phong. [BlinnPhon ...

  8. 关于Unity中的模型描边与Shader切换(专题二)

    模型描边 1: LOL里面的模型描边效果,点击防御塔会有描边的效果,被攻击的时候模型也要描边凸显一下2: 网上可以找到模型描边的Shader,可以直接下载使用,一组第三方的Shader, 帮我们解决了 ...

  9. Unity GeometryShader(从一个线框渲染的例子开始)

    GeometryShader这个概念,已经出现很久了,但由于性能不佳,所以使用的并不多.甚至移动平台根本就不支持.移动平台的硬件更新速度也是越来越快,GS的应用普及应该不会太远.就现阶段而言,GS来做 ...

随机推荐

  1. Android中五种常用的menu

    Android Menu在手机的应用中起着导航的作用,作者总结了5种常用的Menu. 1.左右推出的Menu 前段时间比较流行,我最早是在海豚浏览器中看到的,当时耳目一新.最早使用左右推出菜单的,听说 ...

  2. EndNote 输出样式模板(根据国家标准制订)

    EndNote 输出样式模板(根据国家标准制定)   EndNote 相当于一个数据库,将添加/导入的文献存档.需要引用文献的时候就从中选择一个插入到文档中,EndNote 会自动给你编号.在文档末尾 ...

  3. cnetos7最小化安装ifconfig命令找不到怎么办

    我们在安装完centos7最小化系统安装完成后,执行ifconfig命令会报命令未找到.实际上在centos7上,使用“ip addr”和“ip link”命令来查找网卡详情.ifconfig命令已经 ...

  4. java Web的MVC最基础暂定分层包

    数据封装 entity, 数据访问对象  Dao, 业务逻辑 servlet, ----- 网页显示层 jsp 加上 jsp附带技术 el表达式和jstl ,jsp 标记库语言, el表达式 ${us ...

  5. unity, Collider2D.bounds的一个坑

    Note that this will be an empty bounding box if the collider is disabled or the game object is inact ...

  6. href="javascript:void(0)" 的用法

    href=”javascript:void(0);”这个的含义是,让超链接去执行一个js函数,而不是去跳转到一个地址,而void(0)表示一个空的方法,也就是不执行js函数. 为什么要使用href=” ...

  7. 发布Asp.net core到nginx 使用nginx代理

    In this guide, we will cover setting up a production-ready ASP.NET environment on an Ubuntu 16.04 Se ...

  8. JDK1.6新特性,网络增强(Networking features and enhancements)

    参考: http://docs.oracle.com/javase/6/docs/technotes/guides/net/enhancements-6.0.html http://blog.csdn ...

  9. 两种屏幕HUD区域限制的做法(矩形,弧形)

    HUD区域限制算是比较常用到的功能,方形的HUD区域限制多见于小地图,弧形或者椭圆多见于屏幕范围约束. 我没有研究倒角矩形做法,而是将椭圆和矩形进行插值得到一个弧度比较高的形状: 当插值为0时限制范围 ...

  10. Zend Studio 12 windows 无限期试用

    安装: 1.下载最新版本Zend Studio:http://downloads.zend.com/studio-eclipse/12.0.0/ZendStudio-12.0.0-win32.win3 ...