高光反射模型

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编程】之三 光照模型(二)的更多相关文章

  1. 【Aladdin Unity3D Shader编程】之二 光照模型(一)

    光照模型 光照模型就是一个公式,使用这个公式来计算在某个点的光照效果. 在标准光照模型里面,我们把进入摄像机的光分为下面四个部分: 自发光 类似生活中的萤火虫等自己能够发光 高光反射 类似生活中的镜子 ...

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

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

  3. 【Aladdin Unity3D Shader编程】之一 基本入门

    OpenGL.DirectX以及GLSL.HLSL.CG OpenGL和DirectX是图像应用编程接口,用于渲染二维或者三维图形. GLSL着色语言是用来在OpenGL中着色编程的语言,有点在于跨平 ...

  4. 【Aladdin Unity3D Shader编程】之四 贴图纹理

    关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...

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

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

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

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

  7. 转 猫都能学会的Unity3D Shader入门指南(二)

    猫都能学会的Unity3D Shader入门指南(二) 关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己 ...

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

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

  9. Unity3D Shader入门指南(二)

    关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果 ...

随机推荐

  1. “一切都是消息”--MSF(消息服务框架)入门简介

    “一切都是消息”--这是MSF(消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,中文名称:消息服务框架,它是PDF.NET框架的一部分. 1,M ...

  2. 开源纯C#工控网关+组态软件

    一.   前言 在园子潜水也七八年了.说来惭愧,这么多年虽然一直自称.NET铁杆粉丝,然仅限于回几个不痛不痒的贴,既没有发布过代码,也没有写过文章. 看着.NET和C#在国外风生水起,国内却日趋没落, ...

  3. hdu3018欧拉回路题

    Ant Trip Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  4. Ionic3学习笔记(一)安装、项目结构与常用命令

    本文为原创文章,转载请标明出处 目录 安装 项目结构 常用命令 1. 安装 安装Cordova.Ionic npm install -g cordova ionic 创建一个新项目,有blank.ta ...

  5. 写一个ORM框架的第一步

    新一次的内部提升开始了,如果您想写一个框架从Apache Commons DbUtils开始学习是一种不错的选择,我们先学习应用这个小“框架”再把源代码理解,然后写一个属于自己的ORM框架不是梦. 一 ...

  6. linux下c语言的多线程编程

    我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执 ...

  7. 通过js修改网页内容

    js可以通过文本所在标签的id获取该标签对象,然后修改其内容,如: document.getElementById('标签id').innerHTML = '要修改的文本内容'; 该方法可以在要修改的 ...

  8. springboot mybatis优雅的添加多数据源

    springboot的原则是简化配置,本文试图不通过xml配置,使用configuration配置数据源,并进行简单的数据访问. 并且配置了多数据源,在开发过程中这种场景很容易遇到. 1.依赖 spr ...

  9. 人工智能 tensorflow框架-->简介及安装01

    简介:Tensorflow是google于2015年11月开源的第二代机器学习框架. Tensorflow名字理解:图形边中流动的数据叫张量(Tensor),因此叫Tensorflow 既 张量流动 ...

  10. JAVA提高六:泛型

    在面向对象编程语言中,多态算是一种泛化机制.例如,你可以将方法的参数类型设置为基类,那么该方法就可以接受从这个基类中导出的任何类作为参数,这样的方法将会更具有通用性.此外,如果将方法参数声明为接口,将 ...