解读Unity中的CG编写Shader系列八(镜面反射)
转自http://www.itnose.net/detail/6117378.html
讨论完漫反射之后,接下来肯定就是镜面反射了
在开始镜面反射shader的coding之前,要扩充一下前面提到的知识,加深理解镜面反射与漫反射的区别。
引用一下一位前人博文中的一些基础概念,特别是关于冯氏反射模型的:
平行光(directional light) 一种是从特定方向射入并只会照亮面对入射方向的物体,我们称之为平行光(directional light)。
环境光(ambient light) 另一种光是来自所有方向并且会照亮所有物体,不管这些物体的朝向如何,我们称之为环境光(ambient light)。当然在真实世界里,这只是平行光照到其他物体上,比如空气、灰尘等等,然后反射出来的散射而已。但是在这里,我们需要把它单独作为一个光照模型列出来。
漫反射(Diffuse)
无论光的入射角度如何,都会向所有方向发生反射。反射光的亮度只和光线的入射角度有关,与观察角度无关。光线越平行于物体表面,则反射光越弱,表面越暗;光线越垂直于表面,反射光越强,表面越亮。漫反射是我们通常想到一个物体受到光照时需要首先想到的。
镜面反射(Specular)
这就像镜子一样,反射光将按照和入射角相同的角度反射出来。这种情况下,你看到的物体反射出来的光的亮度,取决于你的眼睛和光反射的方向是否在同一直线上;也就是说,反射光的亮度不仅与光线的入射角有关,还与你的视线和物体表面之间的角度有关。镜面反射通常会造成物体表面上的“闪烁”和“高光”现象,镜面反射的强度也与物体的材质有关,无光泽的木材很少会有镜面反射发生,而高光泽的金属则会有大量镜面反射。
P.S.:可以看出除了环境光是我们计算机图形学中抽象出来的虚拟现象,其他3种现象都是真实存在的
冯氏反射模型(Phong Rlection Model)
发生漫反射光的RBG值。
发生镜面反射光的RGB值。
其次所有材质都有以下四个属性
反射的环境光RGB值
反射的漫反射光RGB值
反射的镜面反射光RGB值
物体的反光度,它决定了镜面反射的细节
每条光线我们都需要知道两个属性,每个物体表面上的点都需要4个属性
![]() |
镜面反射与观察视角的联系系列6中我已经说明了材料表面的平整程度决定了镜面反射的明显与否,现实生活中找不到绝对平的物体表面,所以我们引入一个概念,每一种材料的表面的平整程度为Nshininess, n越大越平整,越小越粗糙,理想状态下n无穷大的时候是绝对的镜面反射,也就是前面引用的文字中所说的你想看到光源,则必须从光线的反射角完全重合去看。


编写Shader
float3 ambientLighting = float3(UNITY_LIGHTMODEL_AMBIENT) * float3(_Color);
漫反射光 diffuseReflection 上文中已经计算好。
Shader "Custom/CustomSpecular" {
Properties {
_Color ("Diffuse Material Color", Color) = (,,,)
_SpecColor ("Specular Material Color", Color) = (,,,)
//材料表面的光泽程度,根据前文所述,此参数无穷大时,材料完全不会产生镜面反射
_Shininess ("Shininess", Float) =
}
SubShader {
Pass{
Tags { "LightMode" = "ForwardBase" } CGPROGRAM //定义顶点着色器与片段着色器入口
#pragma vertex vert
#pragma fragment frag
//获取property中定义的材料颜色
uniform float4 _Color;
uniform float4 _SpecColor;
uniform float _Shininess; // 光源的位置或者方向
//uniform float4 _WorldSpaceLightPos0; // 光源的颜色 (from "Lighting.cginc")
uniform float4 _LightColor0; //定义顶点着色器的输入参数结构体
//我们只需要每个顶点的位置与对应的法向量
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
//定义顶点着色的输出结构体/片段着色的输入结构体
//已经计算好的颜色
struct vertexOutput {
float4 pos : SV_POSITION;
float4 col : COLOR;
}; //顶点着色器
vertexOutput vert (vertexInput input) {
vertexOutput output;
//对象坐标系到世界坐标系的变换矩阵
//_Object2World与_World2Object均为unity提供的内置uniform参数
float4x4 modelMatrix = _Object2World;
//世界坐标系到对象坐标系的变换矩阵
float4x4 modelMatrixInverse = _World2Object; //法向量N变化至对象坐标系
float3 normalDirection = normalize(float3(mul(float4(input.normal, 0.0), modelMatrixInverse))); //平行光源的入射向量L直接由uniform_WorldSpaceLightPos0给出
float3 lightDirection =normalize(float3(_WorldSpaceLightPos0)); //观察向量V由摄像机坐标与顶点坐标矢量相减
float3 viewDirection = normalize(float3(float4(_WorldSpaceCameraPos, 1.0)
- mul(modelMatrix, input.vertex))); //镜面反射光的计算
float3 specularReflection=float3(_LightColor0)*float3(_SpecColor)*pow(max(0.0,dot(reflect(-lightDirection, normalDirection),viewDirection)),_Shininess); //前文计算好的漫反射光
float3 diffuseReflection=float3(_LightColor0) * float3(_Color)* max(0.0, dot(normalDirection, lightDirection)); //环境光直接获取
float3 ambientLighting = float3(UNITY_LIGHTMODEL_AMBIENT) * float3(_Color); //根据冯氏反射模型将上述3个RGB颜色向量相加,然后补充A: output.col = float4(ambientLighting + diffuseReflection+ specularReflection, 1.0);
//国际惯例,顶点变化三步曲
output.pos = mul(UNITY_MATRIX_MVP, input.vertex); return output;
} //片段着色器,老规矩,把顶点着色器的输出参数作为片段着色器的输入参数
float4 frag(vertexOutput input): COLOR
{
return input.col; } ENDCG
}
}
FallBack "Diffuse"
}
用新的shader再创建一个材质球,再创建一个球体,与之前的2个球体进行比较。(本例的shader还是只有一个ForwardBase的单光源Shader,但是相信看到这里您应该会把这个例子也做成多光源了)



解读Unity中的CG编写Shader系列八(镜面反射)的更多相关文章
- [转]解读Unity中的CG编写Shader系列9——镜面反射
讨论完漫反射之后,接下来肯定就是镜面反射了在开始镜面反射shader的coding之前,要扩充一下前面提到的知识,加深理解镜面反射与漫反射的区别.注:这篇文章实现的镜面反射是逐顶点着色(per-ver ...
- 解读Unity中的CG编写Shader系列八(多光源漫反射)
转自http://www.itnose.net/detail/6117338.html 前文中完成最简单的漫反射shader只是单个光源下的漫反射,而往往场景中不仅仅只有一个光源,那么多个光源的情况下 ...
- [转]解读Unity中的CG编写Shader系列7——漫反射
如果前面几个系列文章的内容过于冗长缺乏趣味着实见谅,由于时间原因前面的混合部分还没有写完,等以后再补充,现在开始关于反射的内容了.折射与反射在物理世界中,光的反射与折射往往是同时存在的,光源由真空或者 ...
- 解读Unity中的CG编写Shader系列七(不透明度与混合)
转自http://www.itnose.net/detail/6098539.html 1.不透明度 当我们要将两个半透的纹理贴图到一个材质球上的时候就遇到混合的问题,由于前面的知识我们已经知道了片段 ...
- 解读Unity中的CG编写Shader系列三
转自http://www.itnose.net/detail/6096068.html 在上一个例子中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上.这篇文章 ...
- [转]解读Unity中的CG编写Shader系列6——不透明度与混合
1.不透明度当我们要将两个半透的纹理贴图到一个材质球上的时候就遇到混合的问题,由于前面的知识我们已经知道了片段着色器以及后面的环节的主要工作是输出颜色与深度到帧缓存中,所以两个纹理在每个像素上的颜色到 ...
- [转]解读Unity中的CG编写Shader系列3——表面剔除与剪裁模式
在上一个例子中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上.这篇文章将要在此基础上研究片段的擦除(discarding fragments)和前面剪裁.后面 ...
- 解读Unity中的CG编写Shader系列3——表面剔除与剪裁模式
在上一个样例中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上. 这篇文章将要在此基础上研究片段的擦除(discarding fragments)和前面剪裁.后 ...
- 解读Unity中的CG编写Shader系列十 (光滑的镜面反射(冯氏着色))
前文完成了最基本的镜面反射着色器,单平行光源下的逐顶点着色(per-vertex lighting),又称为古罗着色(Gouraud shading).这篇文章作为后续讨论更光滑的镜面反射方式,逐像素 ...
随机推荐
- PhpStorm 快捷键
不容易记住的: Ctrl + Shift + F 查找文本,在项目目录或指定的目录 Ctrl + Shift + R 查找文本并替换,在项目目录或指定的目录 Ctrl + E 打开最近关闭的 ...
- [百度地图] MultiZMap 修改使用;
MultiZMap修改说明 MultiZMap 是基于百度地图API 封装的一些常用功能类库:主要以prototype方式实现:并且实现了一些辅助的功能,比如添加 Marker 功能,事件管理等: 以 ...
- 如何确定C#代码是在编译时执行还是在运行时执行
突然想起那个"switch..case..."的case标签都可以判断哪些类型... 就先搞了一个错误的demo... class Program { static void Ma ...
- 删除某一BSC在某一时间段内的数据
DELETE FROM cdl_raw_do_12501_ztev8_sht_201509 WHERE call_start_time >= STR_TO_DATE( '2015-09-14 2 ...
- java的封装
- Ubuntu 14 安装 Chrome/Chromium flash播放器
在命令终端中执行如下命令即可: sudo apt-get install pepperflashplugin-nonfree sudo update-pepperflashplugin-nonfree ...
- mysql的隐式转化
MySQL隐式转化整理 前几天在微博上看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下.希望对大家有所帮 ...
- 通过Android录音进行简单音频分析
Android录音有MediaRecorder和AudioRecord两种方式,前者使用方便,可以直接生成录音文件,但是录音格式为aac和amr等等,都经过压缩处理,不方便进行音频分析. 而用Audi ...
- zabbix 3.0.4 监控windows 服务
下载客户端 http://www.zabbix.com/download.php http://www.zabbix.com/downloads/3.0.4/zabbix_agents_3.0.4.w ...
- [Effective JavaScript 笔记]全书总结
这本书中就像它前言中说的那样,这本书不是给初学者的.需要一定的基础,而且有一定的编码实践,才能很好的理解书里讲到的内容.学习一门编程语言,需要熟悉它的语法.形式和结构,这样才会编写合法的.符合语义的. ...