本文主要是介绍【shaderforge学习笔记】 Diffuse(漫反射)通道,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Shaderforge Diffuse通道
一、官方介绍
漫反射通道的数据是你的着色器的主要颜色。漫反射颜色会接收到光照,光照强度会沿着灯光方向衰弱,并形成阴影。
二、通道的输入
1. Diffuse
可以是颜色也可以是贴图
2. DiffusePower
默认值为1,对Diffuse的方向光强度做DiffusePower的幂次方处理,调节光影对比
三、漫反射简介
一束平行光入射到凹凸不平的表面上,光线被反射向四面八方的现象叫做漫反射。
当一束平行光触及光滑物体表面时,光线则发生规律性反射,反射后的光线也相互平行,这种规律性反射称为光的单向反射或镜面反射。但物体的光滑程度是相对的,而一般物体的表面多粗糙不平,入射线虽然为平行光线,但反射后的光线则向各个方向分散,此种现象为光的漫反射。
现实中的物体,如植物、墙壁、衣服等,其表面粗看起来似乎是平滑,但用放大镜仔细观察,就会看到其表面是凹凸不平的,人眼之所以能看清物体的全貌,主要是靠漫反射光在眼内的成像。
漫反射的特点
- 光照强度与观察角度没有关系
从各个角度观看灯光时,它都具有相同明显的强度 - 光照强度跟灯光的入射角有关系
如果改变光的入射光方向可以看到模型表面的光照强度发生了变化
四、漫反射光照模型-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}}
}
效果展示
参考
Unity Shader-兰伯特光照模型与Diffuse Shader
这篇关于【shaderforge学习笔记】 Diffuse(漫反射)通道的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!