Unity Shader-兰伯特光照模型与Diffuse Shader
简介
漫反射和镜面反射
镜面反射,是指若反射面比较光滑,当平行入射的光线射到这个反射面时,仍会平行地向一个方向反射出来,这种反射就属于镜面反射,其反射波的方向与反射平面的法线夹角(反射角),与入射波方向与该反射平面法线的夹角(入射角)相等,且入射波、反射波,及平面法线同处于一个平面内。
兰伯特光照模型
逐顶点计算着色shader
Shader "ApcShader/DiffusePerVetex"
{//属性Properties{_Diffuse("Diffuse", Color) = (1,1,1,1)}//子着色器 SubShader{Pass{//定义TagsTags{ "RenderType" = "Opaque" }CGPROGRAM//引入头文件#include "Lighting.cginc"//定义Properties中的变量fixed4 _Diffuse;//定义结构体:应用阶段到vertex shader阶段的数据,如果定义了struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;};//定义结构体:vertex shader阶段输出的内容struct v2f{float4 pos : SV_POSITION;fixed4 color : COLOR;};//定义顶点shaderv2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//把法线转化到世界空间float3 worldNormal = mul(v.normal, (float3x3)_World2Object);//归一化法线worldNormal = normalize(worldNormal);//把光照方向归一化fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//根据兰伯特模型计算顶点的光照信息,dot可能有负值,小于0的部分可以理解为看不见,直接取0fixed3 lambert = max(0.0, dot(worldNormal, worldLightDir));//最终输出颜色为lambert光强*材质diffuse颜色*光颜色o.color = fixed4(lambert * _Diffuse.xyz * _LightColor0.xyz, 1.0);return o;}//定义片元shaderfixed4 frag(v2f i) : SV_Target{return i.color;}//使用vert函数和frag函数#pragma vertex vert#pragma fragment frag ENDCG}}//前面的Shader失效的话,使用默认的DiffuseFallBack "Diffuse"
}
我们放置两个基本几何体,看一下shader的效果:
逐像素计算着色shader
Shader "ApcShader/DiffusePerPixel"
{//属性Properties{_Diffuse("Diffuse", Color) = (1,1,1,1)}//子着色器 SubShader{Pass{//定义TagsTags{ "RenderType" = "Opaque" }CGPROGRAM//引入头文件#include "Lighting.cginc"//定义Properties中的变量fixed4 _Diffuse;//定义结构体:应用阶段到vertex shader阶段的数据struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;};//定义结构体:vertex shader阶段输出的内容struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;};//定义顶点shaderv2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//把法线转化到世界空间o.worldNormal = mul(v.normal, (float3x3)_World2Object);return o;}//定义片元shaderfixed4 frag(v2f i) : SV_Target{//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的fixed3 worldNormal = normalize(i.worldNormal);//把光照方向归一化fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//根据兰伯特模型计算像素的光照信息,小于0的部分理解为看不见,置为0fixed3 lambert = max(0.0, dot(worldNormal, worldLightDir));//最终输出颜色为lambert光强*材质diffuse颜色*光颜色fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz;return fixed4(diffuse, 1.0);}//使用vert函数和frag函数#pragma vertex vert#pragma fragment frag ENDCG}}//前面的Shader失效的话,使用默认的DiffuseFallBack "Diffuse"
}
还是一个立方体和一个圆柱体,采用了逐像素着色后的结果:
从vertex阶段到fragment阶段发生了什么
半兰伯特光照模型
Shader "ApcShader/HalfLambert"
{//属性Properties{_Diffuse("Diffuse", Color) = (1,1,1,1)}//子着色器 SubShader{Pass{//定义TagsTags{ "RenderType" = "Opaque" }CGPROGRAM//引入头文件#include "Lighting.cginc"//定义Properties中的变量fixed4 _Diffuse;//定义结构体:应用阶段到vertex shader阶段的数据struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;};//定义结构体:vertex shader阶段输出的内容struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;};//定义顶点shaderv2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//把法线转化到世界空间o.worldNormal = mul(v.normal, (float3x3)_World2Object);return o;}//定义片元shaderfixed4 frag(v2f i) : SV_Target{//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的fixed3 worldNormal = normalize(i.worldNormal);//把光照方向归一化fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//半兰伯特光照,将原来(-1,1)区间的光照条件转化到了(0,1)区间,既保证了结果的正确,又整体提升了亮度,保证非受光面也能有光,而不是全黑fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;//最终输出颜色为lambert光强*材质diffuse颜色*光颜色fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz;return fixed4(diffuse, 1.0);}//使用vert函数和frag函数#pragma vertex vert#pragma fragment frag ENDCG}}//前面的Shader失效的话,使用默认的DiffuseFallBack "Diffuse"
}
看一下兰伯特光照模型和半兰伯特光照模型的对比:
带有纹理的半兰伯特光照shader
Shader "ApcShader/DiffuseWithTex"
{//属性Properties{_Diffuse("Diffuse", Color) = (1,1,1,1)_MainTex("Base 2D", 2D) = "white"{}}//子着色器 SubShader{Pass{//定义TagsTags{ "RenderType" = "Opaque" }CGPROGRAM//引入头文件#include "Lighting.cginc"//定义Properties中的变量fixed4 _Diffuse;sampler2D _MainTex;//使用了TRANSFROM_TEX宏就需要定义XXX_STfloat4 _MainTex_ST;//定义结构体:应用阶段到vertex shader阶段的数据struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};//定义结构体:vertex shader阶段输出的内容struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;//转化纹理坐标float2 uv : TEXCOORD1;};//定义顶点shaderv2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//把法线转化到世界空间o.worldNormal = mul(v.normal, (float3x3)_World2Object);//通过TRANSFORM_TEX宏转化纹理坐标,主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}//定义片元shaderfixed4 frag(v2f i) : SV_Target{//unity自身的diffuse也是带了环境光,这里我们也增加一下环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;//归一化法线,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出的fixed3 worldNormal = normalize(i.worldNormal);//把光照方向归一化fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//根据半兰伯特模型计算像素的光照信息fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;//最终输出颜色为lambert光强*材质diffuse颜色*光颜色fixed3 diffuse = lambert * _Diffuse.xyz * _LightColor0.xyz + ambient;//进行纹理采样fixed4 color = tex2D(_MainTex, i.uv);return fixed4(diffuse * color.rgb, 1.0);}//使用vert函数和frag函数#pragma vertex vert#pragma fragment frag ENDCG}}//前面的Shader失效的话,使用默认的DiffuseFallBack "Diffuse"
}
Shader "ApcShader/DiffuseWithTexX"
{//属性Properties{_Diffuse("Diffuse", Color) = (1,1,1,1)_MainTex("Base 2D", 2D) = "white"{}}//子着色器 SubShader{Pass{//定义TagsTags{ "RenderType" = "Opaque" }CGPROGRAM//引入头文件#include "Lighting.cginc"//定义Properties中的变量fixed4 _Diffuse;sampler2D _MainTex;//使用了TRANSFROM_TEX宏就需要定义XXX_STfloat4 _MainTex_ST;//定义结构体:应用阶段到vertex shader阶段的数据,如果定义了struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;float4 texcoord : TEXCOORD0;};//定义结构体:vertex shader阶段输出的内容struct v2f{float4 pos : SV_POSITION;fixed4 color : COLOR;//转化纹理坐标float2 uv : TEXCOORD1;};//定义顶点shaderv2f vert(a2v v){v2f o;o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//unity自身的diffuse也是带了环境光,这里我们也增加一下环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Diffuse.xyz;//把法线转化到世界空间float3 worldNormal = mul(v.normal, (float3x3)_World2Object);//归一化法线worldNormal = normalize(worldNormal);//把光照方向归一化fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//根据兰伯特模型计算顶点的光照信息,dot可能有负值,小于0的部分可以理解为看不见,直接取0fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir) + 0.5;//最终输出颜色为lambert光强*材质diffuse颜色*光颜色o.color = fixed4(lambert * _Diffuse.xyz * _LightColor0.xyz + ambient, 1.0);//通过TRANSFORM_TEX宏转化纹理坐标,主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);return o;}//定义片元shaderfixed4 frag(v2f i) : SV_Target{return i.color * tex2D(_MainTex, i.uv);}//使用vert函数和frag函数#pragma vertex vert#pragma fragment frag ENDCG}}//前面的Shader失效的话,使用默认的DiffuseFallBack "Diffuse"
}
TRANSFORM_TEX宏
在添加了纹理之后,主要使用了一个宏和一个采样函数。采样函数顾名思义,tex2D,就是通过传入的纹理坐标,来获得纹理采样点所对应的颜色值。下面重点看一下Unity为我们提供的TRANSFORM_TEX宏,我们从UnityCG.cginc中可以找到这个宏的定义如下:
// Transforms 2D UV by scale/bias property
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
如果我们使用了这个宏,就需要在shader中定义我们要采样的纹理的一个系数,命名方式为 纹理名_ST,float4类型。那么这个值是什么呢?
Unity Shader-兰伯特光照模型与Diffuse Shader相关推荐
- Unity Shader漫反射光照模型与半兰伯特光照模型
文章目录 一.基础光照模型中漫反射部分的计算公式 二.逐顶点光照实现 逐顶点代码 逐顶点效果图 三.逐像素光照模型实现 逐像素代码 逐像素效果图 四.半兰伯特光照模型实现 广义半兰伯特光照模型公式 半 ...
- Unity shader学习-漫反射-兰伯特光照模型和半兰伯特光照模型
兰伯特漫反射公式:Diffuse = 直射光颜色 *物体颜色* max(0,cos夹角(光和法线的夹角) ) 下面给出顶点漫反射代码: Shader "Unlit/005" { ...
- shader基础学习摘要(二) 兰伯特光照模型
在第6.4节中,书中给出了计算基本光照模型中漫反射光部分的计算公式分别表示为: 目录 漫反射模型 逐像素光照(逐顶点光照改进版) 逐顶点光照(兰伯特原版) 半兰伯特光照模型 漫反射模型 兰伯特定律:反 ...
- 9.半兰伯特光照模型
前情提要:前面一节的漫反射实际上是根据兰伯特光照模型来进行实现的 但这种做法有个缺点就是顶点法线和光的夹角大于90度的时候的成色是完全黑的这和我们生活中见到的事物是不一样的.所以就有了新的光照模型-- ...
- 庄懂老师TA学习笔记 - 半兰伯特光照模型
先看一下兰伯特光照模型的公式 Max(0, nDir ·lDir) 通过公式我们知道,当法线方向和光照方向的反方向的角度大于90度时,点乘就会出现负数的结果,所以我们使用与0取最大值来排除掉这些没有实 ...
- 兰伯特光照模型(Lambert Lighting)和半兰伯特光照模型(Half-Lanbert)
关于漫反射 光打到凹凸不平的平面上,光线会被反射到四面八方,被称为漫反射 关于这种模型,由于光线由于分散,所以进入人眼的光线强度和观察角度没有区别 在A点和B点接收到的光线强度是一样的 在漫反射下,光 ...
- 伪兰伯特光照模型处理阴影过渡
默认shader的光照过渡太明显,不够柔和,使用伪兰伯特光照模型进行处理 伪兰伯特 默认材质 Shader "Custom/SimulateLambert" {Properties ...
- 光照模型-兰伯特光照模型
兰伯特光照模型理论基础
- Shader学习第六篇:Lambert (兰伯特)光照模型
漫反射的定义 漫反射是投射在粗糙表面上的光向各个方向反射的现象.当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同 ...
最新文章
- 【新鲜出炉】25套的精美 Web 应用程序图标素材
- python 基础教程:对 property 属性的讲解及用法
- python画海绵宝宝_脑洞大开的万圣节,10招带你和宝宝花式玩南瓜
- 第二讲:第一个Python程序(干货)
- Servlet API
- Selenium WebDriver的TestNG注释完整指南
- golang 切片 接口_Go编程模式:切片,接口,时间和性能
- Java快速入门学习笔记5 | Java语言中的while循环语句
- hdu 1542 Atlantis (线段树+扫描线)
- 从服务器上下载下来的代码,部署到本地时,Url自动带www前缀
- java字符串替换一部分_字符串中部分字符替换
- mysql 分析explain命令执行sql的计划
- 嵌入式系统应用开发学习笔记(五):HLS
- maya! board_3D角色模型很难做?Maya、Zbrush人头建模终极秘笈
- 工具说明书 - 英语语法检查工具Grammarly
- Code::Blocks 的配色方案
- Android插件化动态加载apk
- 山东科技大学OJ题库 1013-多少张钞票
- Lua程序设计 | 字符串、表、函数与IO
- 《电气工程制图与读图》
热门文章
- miui10.2.2 或以上的小米手机上照片旋转问题及解决
- mybatisplus报 Invalid bound statement (not found):
- 常用sql server 脚本
- 键盘·由于其配置信息(注册表中的)不完整或已损坏,Windows 无法启动这个硬件设备。 (代码19)
- Python 利用opencv给白底照片换色,全网唯一
- GeneXus学习笔记-Excel导出
- lol服务器维护8.21,lol8.21版本更新了什么 lol8.21版本更新内容一览
- Android无法打开相册查看视频
- php一句话木马调用cmd命令,一句话木马(webshell)是如何执行命令的
- 大学计算机D(VB.NET)