高光反射

  • 理论推导
  • 代码实践
    • Phone光照模型
      • 逐顶点
      • 逐像素
    • Blinn-Phong光照模型
    • 内置函数

理论推导

在6.2.4节中,我们给出了基本光照模型中高光反射部分的计算公式
高光反射求的夹角是模型反射光线与视线的夹角,因为视线光线距离反射光线越近,光照强度越高,与漫反射不同,漫反射是求法线与光源方向的夹角,与视野方向无关,所以即使移动镜头摄像机也不会影响表面光照,而高光反射则与视野方向紧密相关,高光反射时摄像机并不能完全收反射光,只能看到部分光照反射,数值与材质光泽度有关

v表示视线方向,r表示反射光线,系数:c分别是是颜色和强度,m材质的高光反射系数,指数mglass指材质光泽度,表示高光反射后所能映入眼睛的视野范围
r向量推导(纯手写)

代码实践

Phone光照模型

逐顶点

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level" {Properties {_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)//控制RGBA颜色_Specular ("Specular", Color) = (1, 1, 1, 1)//控制公式中的高光反射系数(乐乐老师说这是高光反射颜色,希望有懂的解释一下)_Gloss ("Gloss", Range(8.0, 256)) = 20//控制指数m glass}SubShader {Pass { Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"/*对应Properties语义段*/fixed4 _Diffuse;fixed4 _Specular;float _Gloss;//glass的范围比较大,取floatstruct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;fixed3 color : COLOR;};v2f vert(a2v v) {v2f o;//转移顶点到裁剪空间o.pos = UnityObjectToClipPos(v.vertex);// 得到环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;// 转移法线到世界坐标系fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));// 得到世界空间的光线方向fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);// 计算漫反射项(这里如果不加漫反射项,没有受到高光反射的区域会显示成黑色,不被渲染)fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));// 得到世界空间中的反射光线(r向量)fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));// 在世界空间转到裁剪空间fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);// 计算高光反射fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);//三项相加(环境光+漫反射+高光反射)o.color = ambient + diffuse + specular;return o;}fixed4 frag(v2f i) : SV_Target {return fixed4(i.color, 1.0);}ENDCG}} FallBack "Specular"
}

逐像素

我们已经得到了高光反射的效果,但是使用逐顶点高光反射得到的高光效果有比较大的问题,我们可以在图6.10中看出高光部分明显不平滑,因为片元着色器COLOR语义是返回顶点坐标,经过顶点计算的颜色是线性的,而高光反射计算是非线性的,破坏了高光反射本身的非线性关系,所以改用TEXCOORD0语义即从获得纹理颜色的方式改为输出纹理坐标的方式,坐标即像素,故称为逐像素光照

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Unity Shaders Book/Chapter 6/Specular Pixel-Level" {Properties {_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1, 1, 1, 1)_Gloss ("Gloss", Range(8.0, 256)) = 20}SubShader {Pass { Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;//定义一组坐标float3 worldPos : TEXCOORD1;//定义两组坐标};v2f vert(a2v v) {v2f o;// 将模型从模型空间转换到裁剪空间o.pos = UnityObjectToClipPos(v.vertex);// 计算法线o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);// 计算顶点坐标o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}fixed4 frag(v2f i) : SV_Target {// 环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);// 漫反射fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));// 世界空间的光源方向fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));// 世界空间的视野方向fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);// 计算高光fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);return fixed4(ambient + diffuse + specular, 1.0);}ENDCG}} FallBack "Specular"
}


可以看出,细节上更加细腻

Blinn-Phong光照模型

既然高光反射是通过反射光线与视角来判断光照强度,那么我们是否可以通过一种折中的方法,求视角与反射光线的向量和进行计算?实际上Blinn模型就是使用的该方法,它是通过视角v与光线方向l之和归一化得到的,程序中实际上没有归一化,因此得到的光线更亮。

修改逐像素光照的frag部分的计算公式即可

fixed4 frag(v2f i) : SV_Target {// Get ambient termfixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);// Compute diffuse termfixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));// Get the view direction in world spacefixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);// 得到世界坐标与视野方向的向量和halfDirfixed3 halfDir = normalize(worldLightDir + viewDir);// 计算高光反射,其中第三参数为halfDirfixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);return fixed4(ambient + diffuse + specular, 1.0);


可以看出实际上Blinn模型更亮,实际中一般我们会使用此模型,效果比较好。

内置函数

在unity中有许多内置函数,分别可以用于求反射光,求观察方向,用于前向渲染,法线方向转换等,大大的简化了代码的编写,但是理解原理依然十分重要。以下是书中使用内置函数的Blinn模型代码

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'Shader "Unity Shaders Book/Chapter 6/Blinn-Phong Use Built-in Functions" {Properties {_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)_Specular ("Specular", Color) = (1, 1, 1, 1)_Gloss ("Gloss", Range(1.0, 500)) = 20}SubShader {Pass { Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"fixed4 _Diffuse;fixed4 _Specular;float _Gloss;struct a2v {float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float4 worldPos : TEXCOORD1;};v2f vert(a2v v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);// 使用内置函数求世界法线,使用该函数这样我们就不用使用mul数学函数求向量与转换矩阵之积了o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex);return o;}fixed4 frag(v2f i) : SV_Target {fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 worldNormal = normalize(i.worldNormal);//  使用内置函数求世界空间的光源方向// 我们需要一个变量来存储normlize()的结果fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(0, dot(worldNormal, worldLightDir));// 使用函数计算世界空间中的视野方向// 我们需要一个变量来存储normlize()的结果fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);return fixed4(ambient + diffuse + specular, 1.0);}ENDCG}} FallBack "Specular"
}

虽然使用函数简化了所需的计算过程,但是当需要处理更复杂的光照时,如点光源与聚光灯,该计算光源方向的方法的方法就是错误的,这需要先进行判断光源类型,再计算它的光源信息。

shader基础学习摘要(三)高光反射相关推荐

  1. shader基础学习摘要(二) 兰伯特光照模型

    在第6.4节中,书中给出了计算基本光照模型中漫反射光部分的计算公式分别表示为: 目录 漫反射模型 逐像素光照(逐顶点光照改进版) 逐顶点光照(兰伯特原版) 半兰伯特光照模型 漫反射模型 兰伯特定律:反 ...

  2. UE5 Shader基础学习笔记——13-20 DetailNormal/Smoothstep/Length/CeilFloorRound/DDXDDY/SinCos/Power

    UE5 Shader基础学习笔记--13-20 DetailNormal/Smoothstep/Length/CeilFloorRound/DDXDDY/SinCos/Power Lec13 Deta ...

  3. UE5 Shader基础学习笔记——01-12 图形管线/创建shader/数学节点/贴图压缩/LerpDotUV/常用向量/坐标空间/MinMaxClampSaturate/法线贴图混合

    UE5 Shader基础学习笔记--01-12 图形管线/创建shader/数学节点/贴图压缩/LerpDotUV/常用向量/坐标空间/MinMaxClampSaturate/法线贴图混合 Lec01 ...

  4. Python基础学习笔记三

    Python基础学习笔记三 print和import print可以用,分割变量来输出 import copy import copy as co from copy import deepcopy ...

  5. java入门基础学习(三)

    文章目录 (一)有返回值的方法 (二)方法重载 习题 (一)有返回值的方法 格式:public static 返回值数据类型 方法名(参数){方法体return 数据;} 注意:1.返回值数据类型非v ...

  6. Mendix敏捷开发零基础学习《三》-高级 (数据删除保护机制、数据关联删除、Security安全、调用外部接口、调用JAVA代码)

    目录 Mendix敏捷开发零基础学习<三> 一. 数据保护机制(Prevention of Delete) 1.业务需求 2.业务分析 3.项目实现 二.Mendix权限(Security ...

  7. Unity Shader学习记录(6) —— 高光反射光照模型和内置计算函数

    1 高光反射光照模型计算公式 从公式可以看出,要计算高光反射需要知道 4 个参数:入射光线的颜色和强度c,材质的光反射系数 m,视角方向v以及反射方向r.其中,反射方向r可以由表面法线n和光源i计算得 ...

  8. Java基础学习笔记(三)_Java核心技术(高阶)

    本篇文章的学习资源来自Java学习视频教程:Java核心技术(高阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...

  9. MySQL基础学习(三)————SQL语句的常用操作

    文章目录 1.库 1.1库的创建 1.2 库的删除 1.3 库的修改 1.4 库的查找 2.表 2.1 表的创建 2.2 表的删除 2.3 表的修改 2.4 表的查找 3.数据或者记录 3.1 数据的 ...

最新文章

  1. 学习笔记99—word 如何增加底纹
  2. 当一个程序员面临太多选择的时候
  3. c语言编程怎么自学网,c语言函数
  4. spring编程式事务控制
  5. java+log日志服务器_Logserver日志服务器结构
  6. java学习(173):class反射编程方法
  7. Vscode Todo Tree插件
  8. elementUI table 表格表头居中 颜色、内容居左
  9. 为什么越普通的男人越自信?
  10. java前端传汉字到后端出现乱码解决办法
  11. 计算机4000字论文格式,科学论文格式要求4000字
  12. 【Mac】 自带的播放器quicktimeplayer 如何带声音2倍速播放
  13. 计算机科学自考本科的科目,自考本科计算机专业考哪些
  14. matlab kappa风险分析,我为什么反对在属性数据MSA中用Kappa分析(上) | 汽车质量管理笔记...
  15. 运算放大器的差分放大电路
  16. 图片高斯模糊效果的实现
  17. 搜索计算机文件夹的记录怎么删除,怎样删除电脑最近打开的文件或文件夹?
  18. PTA 7-2 一帮一
  19. anchor-free方法总结
  20. Attention专场——(2)Self-Attention 代码解析

热门文章

  1. 怎么恢复win8的开始菜单
  2. switch确定某天是该年第几天
  3. Linux用户管理 day5
  4. Python副业兼职,月赚7800元,一天只要两小时 !
  5. 全网最全的AI绘画提示词网站,看这一篇就够了!
  6. python爬虫利用Scrapy框架爬取汽车之家奔驰图片--实战
  7. [随文杂记]生男好还是生女好?
  8. 针对Win10中Win键+R运行没有历史记录解决方法
  9. 湖南文旅数据中心:湖南文旅数据早知道(9月11日)
  10. Android之来电秀实现(一)