【Aladdin Unity3D Shader编程】之三 光照模型(二)
高光反射模型
Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角

编写高光反射Shader
Shader "AladdinShader/07 Specular Vertex Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
};
struct v2f
{
float4 position:SV_POSITION;
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色
//反射光方向
fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//视野方向
//相机是在世界空间下
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex,unity_WorldToObject).xyz);
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),10);
f.color = diffuse + adbient + specular;
return f;
}
fixed4 frag(v2f f):SV_Target
{
return fixed4(f.color, 1);
}
ENDCG
}
}
FallBack "VertexLit"
}
效果图:

添加_Gloss和SpecularColor控制高光大小和高光颜色
添加一个Range属性,将X次幂的值改成Range属性,做如下修改:
_Gloss("Gloss",Range(8,200)) = 10
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss);
就会看到高光光圈随着_Gloss改变而改变


想要改变高光部分的颜色控制,我们添加一个颜色变量然后将高光颜色与我们设置的颜色属性进行融合计算就会得到新的高光部分的颜色
Shader "AladdinShader/07 Specular Vertex Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
};
struct v2f
{
float4 position:SV_POSITION;
fixed3 color:COLOR;
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色
//反射光方向
fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//视野方向
//相机是在世界空间下
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(v.vertex,unity_WorldToObject).xyz);
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss) * _Specular.rgb;
f.color = diffuse + adbient + specular;
return f;
}
fixed4 frag(v2f f):SV_Target
{
return fixed4(f.color, 1);
}
ENDCG
}
}
FallBack "VertexLit"
}
效果图:


实现逐像素的高光反射
Shader "AladdinShader/08 Specular Fragment Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
};
struct v2f
{
float4 position:SV_POSITION;
float3 worldNormal:TEXCOORD0;//世界空间下的法线方向
float3 worldVertext:TEXCOORD1;//时间空间下的顶点坐标
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
f.worldVertext = mul(v.vertex , unity_WorldToObject).xyz;
return f;
}
fixed4 frag(v2f f):SV_Target
{
fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(f.worldNormal);
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色
//反射光方向
fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//视野方向
//相机是在世界空间下
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss) * _Specular.rgb;
fixed3 tempColor = diffuse + adbient + specular;
return fixed4(tempColor, 1);
}
ENDCG
}
}
FallBack "VertexLit"
}
效果图:

会比逐顶点高光效果更好一些,背光面可以考虑之前说的半兰伯特来处理,这样就不会显示全黑效果不好的情况。
使用Blinn-Phong光照模型
Specular=直射光颜色*pow(max(cosθ,0),10) θ:是发现和x的夹角 x是平行光和视野方向的平分线
Shader "AladdinShader/09 Specular Fragment Blinn Phong Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
};
struct v2f
{
float4 position:SV_POSITION;
float3 worldNormal:TEXCOORD0;//世界空间下的法线方向
float3 worldVertext:TEXCOORD1;//时间空间下的顶点坐标
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
f.worldVertext = mul(v.vertex , unity_WorldToObject).xyz;
return f;
}
fixed4 frag(v2f f):SV_Target
{
fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(f.worldNormal);
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色
//反射光方向
//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//视野方向
//相机是在世界空间下
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);
//平分线
fixed3 halfDir = normalize(viewDir + lightDir); //视野方向和光照方向的平分线
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss) * _Specular.rgb;
fixed3 tempColor = diffuse + adbient + specular;
return fixed4(tempColor, 1);
}
ENDCG
}
}
FallBack "VertexLit"
}

会发现高光部分会显得更大了,这也是平时用的比较多的高光反射模型。
如何使用Unity的内置函数
UnityCG.cginc中一些常用的函数
//摄像机方向(视野方向)
- float3 WorldSpaceViewDir(float4 v) 根据模型空间中的顶点坐标得到(世界空间)从这个点到摄像机的观察方向
- float3 UnityWorldSpaceViewDir(float4 v) 世界空间中的顶点坐标=>世界空间从这个点到摄像机的观察方向
- float3 ObjSpaceViewDir(float4 v) 模型空间中的顶点坐标=>模型空间从这个点到摄像机的观察方向
//光源方向
- float3 WorldSpaceLightDir(float4 v) 模型空间中的顶点坐标=>世界空间中从这个点到光源的方向
- float3 UnityWorldSpaceLightDir(float4 v) 世界空间中的顶点坐标=>世界空间中从这个点到光源的方向
- float3 ObjSpaceLightDir(float4 v) 模型空间中的顶点坐标=>模型空间中从这个点到光源的方向
//方向转换
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向 模型空间=>世界空间
float3 UnityObjectToWorldDir(float3 dir) 把方向 模型空间=>世界空间
float3 UnityWorldToObjectDir(float3 dir) 把方向 世界空间=>模型空间
上面BP模型修改:
Shader "AladdinShader/09 Specular Fragment Blinn Phong Shader"
{
Properties
{
_Diffuse("Diffuse",Color)=(1,1,1,1) //添加自身的颜色
_Specular("Specular",Color)=(1,1,1,1)
_Gloss("Gloss",Range(8,200)) = 10
}
SubShader {
Pass
{
Tags{"LightMode"="ForwardBase"}
CGPROGRAM
#include "Lighting.cginc" //引用一些写好的程序块 会包含一些获取光照的信息
//_LightColor0 取得第一个直射光的颜色
//_WorldSpaceLightPos0
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
struct a2v
{
float4 vertex:POSITION;
float3 normal:NORMAL; //模型空间下法线
};
struct v2f
{
float4 position:SV_POSITION;
float3 worldNormal:TEXCOORD0;//世界空间下的法线方向
float4 worldVertext:TEXCOORD1;//时间空间下的顶点坐标
};
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);
//法线从模型空间转成世界空间下
// f.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
f.worldNormal = UnityObjectToWorldNormal(v.normal); //使用内置方法转换
f.worldVertext = mul(v.vertex , unity_WorldToObject);
return f;
}
fixed4 frag(v2f f):SV_Target
{
fixed3 adbient = UNITY_LIGHTMODEL_AMBIENT.rgb;
fixed3 normalDir = normalize(f.worldNormal);
//光源方向
// fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//对于每个顶点来说 光的位置就是光的方向 因为是平行光
fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertext).xyz); //模型空间中的顶点坐标=>世界空间中从这个点到光源的方向
fixed3 diffuse = _LightColor0.rgb * max(dot(normalDir,lightDir), 0) * _Diffuse.rgb;//取得漫反射的颜色
//反射光方向
//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//视野方向
//相机是在世界空间下
// fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - f.worldVertext);
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertext));
//平分线
fixed3 halfDir = normalize(viewDir + lightDir); //视野方向和光照方向的平分线
//高光反射
fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss) * _Specular.rgb;
fixed3 tempColor = diffuse + adbient + specular;
return fixed4(tempColor, 1);
}
ENDCG
}
}
FallBack "VertexLit"
}

运行效果还是跟上面效果一样,BP模型是常用的模型,会发现背光面并没有一些奇怪的光斑,更符合生活常理。
漫反射和高光反射统一实现
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "AladdinShader/10 Diffuse Specular Shader"
{
Properties
{
_Diffuse("Diffuse Color", Color)=(1,1,1,1)
_Specular("Specular Color", Color)=(1,1,1,1)
_Gloss("Gloss",Range(10,200))=20
}
SubShader {
Pass{
//只有正确定义Tags 才能获取跟光相关的属性
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
fixed4 _Specular;
half _Gloss;
//顶点函数参数
struct a2v{
float4 vertex:POSITION; //顶点位置
float3 normal:NORMAL; //模型空间下的法线
};
struct v2f{
float4 svPos:SV_POSITION;
fixed3 worldNormal:TEXCOORD0;//世界空间下的法线
float4 worldVertex:TEXCOORD1;
};
v2f vert(a2v v)
{
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP,v.vertex); //模型空间位置到剪裁空间的顶点位置的转换
f.worldNormal = UnityObjectToWorldNormal(v.normal); //模型空间的法线转成时间空间下的法线
f.worldVertex = mul(v.vertex,unity_WorldToObject);
return f;
}
//片元函数返回颜色
fixed4 frag(v2f f):SV_Target{
//漫反射
//漫反射颜色 先不管透明度
//_LightColor0 平行光的颜色 cos夹角 光的方向和视野的夹角
fixed3 normalDir = normalize(f.worldNormal);
//光的方向
fixed3 lightDir = normalize(WorldSpaceLightDir(f.worldVertex));
//漫反射的颜色
fixed3 diffuse = _LightColor0.rgb *_Diffuse.rgb * max(dot(normalDir, lightDir),0);
//相机方向
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(f.worldVertex));
//光和相机方向的平分线
fixed3 halfDir = normalize(lightDir + viewDir);
//高光反射
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss);
//环境光
fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rgb;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Specular"
}
以上这一段一定要熟练敲熟并且弄懂。效果图也跟上面效果是差不多的。
Shader学习交流群:
316977780
【Aladdin Unity3D Shader编程】之三 光照模型(二)的更多相关文章
- 【Aladdin Unity3D Shader编程】之二 光照模型(一)
光照模型 光照模型就是一个公式,使用这个公式来计算在某个点的光照效果. 在标准光照模型里面,我们把进入摄像机的光分为下面四个部分: 自发光 类似生活中的萤火虫等自己能够发光 高光反射 类似生活中的镜子 ...
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨) ...
- 【Aladdin Unity3D Shader编程】之一 基本入门
OpenGL.DirectX以及GLSL.HLSL.CG OpenGL和DirectX是图像应用编程接口,用于渲染二维或者三维图形. GLSL着色语言是用来在OpenGL中着色编程的语言,有点在于跨平 ...
- 【Aladdin Unity3D Shader编程】之四 贴图纹理
关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...
- 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- 转 猫都能学会的Unity3D Shader入门指南(二)
猫都能学会的Unity3D Shader入门指南(二) 关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己 ...
- 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- Unity3D Shader入门指南(二)
关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果 ...
随机推荐
- 【转】 IntelliJ IDEA像Eclipse一样打开多个项目
http://blog.csdn.net/zht666/article/details/47831893 我们做项目实际中经常会遇到这样的情况,创建一个common项目(Maven项目)作为公用项目, ...
- TCP/IP(七)之玩转HTTP协议
前言 前面一篇的博文简单的介绍了一下属于应用层的HTTP协议,这一篇我将详细的学习HTTP协议,这也是做Web开发中一定要用到的协议.虽然我是做大数据的,但是多学习一点肯定是 没有坏处的.国庆放假7天 ...
- [SDOI2009]晨跑
又是一道山东省选的题目,居然题目又十分水100行的代码就随随便便AC了. Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止 ...
- 【JAVA零基础入门系列】Day2 Java集成开发环境IDEA
开发环境搭建好之后,还需要一个集成开发环境也就是IDE来进行编程.这里推荐的IDE是IDEA,那个老掉牙的Eclipse还是先放一边吧,(手动滑稽). IDEA的下载地址:http://www.jet ...
- FastDFS的安装步骤
1.安装相关环境 yum install -y gcc-c++ yum -y install libevent yum install -y pcre pcre-devel yum install - ...
- 考了3年,工作四年,零基础在职终于拿到CFA证书
大家都知道CFA Charterholder是独有的全球公认的投资管理从业人员高职业水平和道德水准的有力证明,是金融界卓越专业成就的象征:CFA资格强调和遵循极其严格的职业操守和道德准则,世界各主要发 ...
- 退出psql时,报psql_history的错
数据库版本:Enterprisedb 9.2(postgreSQL) 错误如下所示: postgres=# exitcould not save history to file "/opt/ ...
- clone github报Permission denied (publickey) 解决方案
问题描述 问题产生的原因,不是很清楚,就不管了.在执行git clone git@github.com:****.git 的时候报了Permission denied (publickey). War ...
- JAVA提高二:枚举
JDK5.0中有一个非常有用的特性:枚举,这个特性以前在C语言中出现过,后来JDK出现后,开始觉得没有必要,但随着使用JAVA语言的人数增多,发现大家对枚举的需求非常大,于是又加入了此特性,下面我们来 ...
- 学习札记 ----wind7下如何安装SqlServer数据库
1.控制面板 ---找到程序和功能选项 如下图所示: 2.打开程序和功能后进入如下图所示的界面,点击打开或关闭window功能. 3.启动window7自带的IIS功能.如下图所示: 4.如上动作准备 ...