ShaderForge学习笔记:Diffuse(漫反射)通道
发表于2018-07-17
ShaderForge是一款为Unity所用的、基于节点操作的Shader插件。所以这个ShaderForge学习笔记系列希望可以帮到大家。这一篇就来介绍下Diffuse(漫反射)通道的使用。
ShaderForge Diffuse通道
一、官方介绍
漫反射通道的数据是你的着色器的主要颜色。漫反射颜色会接收到光照,光照强度会沿着灯光方向衰弱,并形成阴影。
二、通道的输入
1. Diffuse
可以是颜色也可以是贴图
2. DiffusePower
默认值为1,对Diffuse的方向光强度做DiffusePower的幂次方处理,调节光影对比
三、漫反射简介
一束平行光入射到凹凸不平的表面上,光线被反射向四面八方的现象叫做漫反射。
当一束平行光触及光滑物体表面时,光线则发生规律性反射,反射后的光线也相互平行,这种规律性反射称为光的单向反射或镜面反射。但物体的光滑程度是相对的,而一般物体的表面多粗糙不平,入射线虽然为平行光线,但反射后的光线则向各个方向分散,此种现象为光的漫反射。
现实中的物体,如植物、墙壁、衣服等,其表面粗看起来似乎是平滑,但用放大镜仔细观察,就会看到其表面是凹凸不平的,人眼之所以能看清物体的全貌,主要是靠漫反射光在眼内的成像。
漫反射的特点
1.光照强度与观察角度没有关系
从各个角度观看灯光时,它都具有相同明显的强度
2.光照强度跟灯光的入射角有关系
如果改变光的入射光方向可以看到模型表面的光照强度发生了变化
四、漫反射光照模型-Lambert(兰伯特)光照模型
lambert光照模型属于经验模型,主要用来简单模拟粗糙物体表面的光照现象。
此模型假设物体表面为理想漫反射体(也就是只产生漫反射现象,也成为Lambert反射体),同时,场景中存在两种光,一种为环境光,一种为方向光,然后我们分别计算这两种光照射到粗糙物体表面所产生的光照现象,最后再将两个结果相加,得出反射后的光强值。
首先是计算环境光的公式:
I_inDirectionDiffuse = K_d * I_a;
其中,K_d为粗糙物体表面材质对光的反射系数,这个系数由程序编写者在宿主程序中给出,I_a为环境光的光强,也就是环境光的颜色数值,一般是一个float3型的变量
然后是计算方向光的公式:
I_directionDiffuse = K_d * I_l * max(0,dot(N, L));
其中I_l为方向光的光强,也就是其颜色值;N为顶点的单位法向量;L为入射光的单位法向量(注意,光照向量是从顶点指向光源的向量;也就是,它与线的传播方向正好相反)。
这个公式与计算环境光的不同,对于环境光,我们不关心它的方向,因为环境光也没有方向,它给予物体的光照在各个顶点处均是一样的。而方向光则需要关注其方向,例如一个聚光灯,灯从不同的角度来照射物体所产生的效果也是不一样的,光线方向越靠近法线,漫反射出来的光就越强,反之则越弱。 方向光的漫反射强度遵循Lambert余弦定理。
综上,得出漫反射后的光强为:
I_diff = K_d * I_a + K_d * I_l * max(0,dot(N, L));
Lambert 余弦定理
模型表面的明亮度直接取决于光线向量(light vector)和表面法线(normal)两个向量将夹角的余弦值。
f(θ) = max(cosθ,0) = max(L•n,0)
关于Lambert余弦定理的推导可参考:DirectX11 兰伯特余弦定理(Lambert)
五、自定义UnityShader实现漫反射(Diffuse)效果
写法
Shader "Hidden/NewImageEffectShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _DiffusePower("Diffuse Power", Float) = 1.0 } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 normalDir : TEXCOORD1; }; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; // 将物体法线从物体坐标系转换到世界坐标系 o.normalDir = UnityObjectToWorldNormal(v.normal); return o; } sampler2D _MainTex; float _DiffusePower; fixed4 frag (v2f i) : SV_Target { // 法线方向 float3 normalDirection = normalize(i.normalDir); // 灯光方向 float lightDirection = normalize(_WorldSpaceLightPos0.xyz); // 灯光颜色 float3 lightColor = _LightColor0.rgb; // 计算灯光衰减 float attenuation = LIGHT_ATTENUATION(i); float3 attenColor = attenuation * _LightColor0.xyz; // 基于兰伯特模型计算灯光 float NdotL = max(0,dot(normalDirection,lightDirection)); // 方向光 float3 directionDiffuse = pow(NdotL, _DiffusePower) * attenColor; // 环境光 float3 inDirectionDiffuse = float3(0,0,0)+UNITY_LIGHTMODEL_AMBIENT.rgb; // 灯光与材质球表面颜色进行作用 float3 texColor = tex2D(_MainTex, i.uv).rgb; float3 diffuseColor = texColor *(directionDiffuse+inDirectionDiffuse); float4 finalColor = float4(diffuseColor,1); return finalColor; } ENDCG } } }
效果展示
来自:https://blog.csdn.net/v_xchen_v/article/details/79039067