#define PHYSICAL算法
uniform vec3 diffuse; // 漫反射顏色app
uniform vec3 emissive; // 自發光顏色編輯器
uniform float roughness; // 粗糙度ide
uniform float metalness; // 金屬性函數
uniform float opacity; // 透明度工具
#ifndef STANDARD測試
uniform float clearCoat; //編碼
uniform float clearCoatRoughness;spa
#endifcode
varying vec3 vViewPosition; // 攝像機空間的座標
#ifndef FLAT_SHADED
varying vec3 vNormal; // 攝像機空間的法線
#endif
#include <common> // 包含着色器公共模塊(包含經常使用的數學工具函數以及一些常量定義什麼的)
#include <packing> // 數據編碼解碼功能函數
#include <dithering_pars_fragment> // 抖動處理的定義
#include <color_pars_fragment> // 顏色處理的定義
#include <uv_pars_fragment> // uv相關處理的定義
#include <uv2_pars_fragment> // uv2相關處理的定義
#include <map_pars_fragment> // map貼圖相關處理的定義
#include <alphamap_pars_fragment> // alphamap貼圖的處理定義
#include <aomap_pars_fragment> // aomap貼圖的處理定義
#include <lightmap_pars_fragment> // lighmap貼圖處理定義
#include <emissivemap_pars_fragment> // emissivemap貼圖處理的定義
#include <envmap_pars_fragment> // envmap貼圖處理的定義
#include <fog_pars_fragment> // 霧化須要的定義
#include <bsdfs> // brdf相關的功能函數
#include <cube_uv_reflection_fragment> // cubemap反射相關
#include <lights_pars_begin> // 燈光相關定義
#include <lights_pars_maps> // 燈光貼圖相關
#include <lights_physical_pars_fragment> // 燈光相關物理運算
#include <shadowmap_pars_fragment> // shadowmap影子相關運算定義
#include <bumpmap_pars_fragment> // bumpmap相關運算的定義
#include <normalmap_pars_fragment> // normalmap相關運算的定義
#include <roughnessmap_pars_fragment> // roughnessmap相關運算的定義
#include <metalnessmap_pars_fragment> // metalnessmap相關運算的定義
#include <logdepthbuf_pars_fragment> // logdepth相關運算的定義
#include <clipping_planes_pars_fragment> // clipplane裁剪平面相關的定義
void main() {
#include <clipping_planes_fragment> // 裁剪平面裁剪
vec4 diffuseColor = vec4( diffuse, opacity );// 合成rgba四通道漫反射顏色
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
vec3 totalEmissiveRadiance = emissive;
#include <logdepthbuf_fragment> // logdepth運算
#include <map_fragment> // map通道顏色採樣
#include <color_fragment> // color參與計算
#include <alphamap_fragment> // alphamap通道顏色採樣
#include <alphatest_fragment> // alpha測試
#include <roughnessmap_fragment> // 粗糙貼圖採樣
#include <metalnessmap_fragment> // 金屬性貼圖採樣
#include <normal_fragment_begin> // 法線貼圖基本運算
#include <normal_fragment_maps> // 法線經過法線貼圖運算
#include <emissivemap_fragment> // 自發光貼圖採樣
// accumulation
#include <lights_physical_fragment> // 物理光照基礎運算
#include <lights_fragment_begin> // 計算各類燈光入射光和反射光信息
#include <lights_fragment_maps> // 從環境光和光照貼圖獲取輻射
#include <lights_fragment_end> // 根據輻射光取得反射信息
// modulation
#include <aomap_fragment> // 根據AO貼圖調整反射光照強度
// 反射光直接漫反射+間接漫反射+直接高光+間接高光+自發光 = 輸出光照顏色
vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;
gl_FragColor = vec4( outgoingLight, diffuseColor.a );
#include <tonemapping_fragment>// tonemap進行曝光
#include <encodings_fragment> // 顏色編碼
#include <fog_fragment> // 霧化顏色運算
#include <premultiplied_alpha_fragment> // 顏色預乘alpha
#include <dithering_fragment> // 顏色隨機抖動
}
我將這個fragmentshader提取了關於物理材質着色的核心算法方便理解代碼以下:
核心算法只包含直接照明產生的漫反射顏色和高光顏色,直接照明只計算了點光源(沒有計算距離衰減),去掉了各類貼圖採樣數據以最簡化shader代碼
// 由vertexshader傳遞過來的法線,位置,uv varying vec3 vNormal; varying vec3 vPosition; varying vec2 vUv; // 材質參數 uniform vec3 diffuse; // 漫反射 uniform float metallic; // 金屬性 uniform float roughness; // 粗糙度 #if NUM_POINT_LIGHTS > 0 // 點光源信息 struct PointLight { vec3 position; vec3 color; float distance; float decay; }; uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; #endif #if NUM_DIR_LIGHTS > 0 struct DirectionalLight { vec3 direction; vec3 color; }; uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; #endif float pow2( const in float x ) { return x*x; } const float PI = 3.14159265359; #define EPSILON 1e-6 #define MAXIMUM_SPECULAR_COEFFICIENT 0.16 #define DEFAULT_SPECULAR_COEFFICIENT 0.04 #define RECIPROCAL_PI 0.31830988618 // 光照反射信息(直接光的漫反射和高光色) struct ReflectedLight { vec3 directDiffuse; vec3 directSpecular; vec3 indirectDiffuse; }; // 入射光照信息(顏色和方向) struct IncidentLight { vec3 color; vec3 direction; }; // 幾何信息(位置,法線,視角方向) struct GeometricContext { vec3 position; vec3 normal; vec3 viewDir; }; // 物理材質信息 struct PhysicalMaterial { vec3 diffuseColor; float specularRoughness; vec3 specularColor; }; vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) { float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH ); return ( 1.0 - specularColor ) * fresnel + specularColor; } float G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { float a2 = pow2( alpha ); float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); return 0.5 / max( gv + gl, EPSILON ); } float D_GGX( const in float alpha, const in float dotNH ) { float a2 = pow2( alpha ); float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; return RECIPROCAL_PI * a2 / pow2( denom ); } vec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) { float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 ); const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 ); vec4 r = roughness * c0 + c1; float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y; vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; return specularColor * AB.x + AB.y; } vec3 BRDF_Specular_GGX( in GeometricContext geometry, in IncidentLight directLight,const in vec3 specularColor, const in float roughness) { float alpha = pow2( roughness ); vec3 halfDir = normalize( directLight.direction + geometry.viewDir ); float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) ); float dotNH = saturate( dot( geometry.normal, halfDir ) ); float dotLH = saturate( dot( directLight.direction, halfDir ) ); vec3 F = F_Schlick( specularColor, dotLH ); float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV ); float D = D_GGX( alpha, dotNH ); return F * ( G * D ); } vec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) { return RECIPROCAL_PI * diffuseColor; } float clearCoatDHRApprox( const in float roughness, const in float dotNL ) { return DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) ); } void RE_Direct_Physical(in GeometricContext geometry,in PhysicalMaterial material, in IncidentLight directLight,inout ReflectedLight reflectedLight ) { float dotNL = saturate( dot( geometry.normal,directLight.direction ) );// lambert漫反射因子 vec3 irradiance = dotNL * directLight.color; // 輻射 irradiance *= PI; // * PI reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); // 重點就是這裏了,高光算法和blinn-phong差距巨大 reflectedLight.directSpecular += irradiance * BRDF_Specular_GGX( geometry,directLight,material.specularColor,material.specularRoughness); } void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); } vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { vec3 irradiance = ambientLightColor; irradiance *= PI; return irradiance; } #define RE_IndirectDiffuse RE_IndirectDiffuse_Physical void main() { // 存放幾何數據 GeometricContext geometry; geometry.position = vPosition; geometry.normal = normalize(vNormal); geometry.viewDir = normalize(-vPosition); // 由於是相機空間只須要對位置座標取反0-vPosition // 存放物理材質信息 PhysicalMaterial material; material.diffuseColor = diffuse * ( 1.0 - metallic ); // 金屬性越強漫反射顏色越小 material.specularRoughness = clamp( roughness, 0.04, 1.0 ); // 粗燥度 material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuse.rgb, metallic ); // 這裏作了個mix 金屬性爲0高光顏色也不至因而黑色 // 初始化光照反射 ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ),vec3(0.0) ); IncidentLight directLight;// 直接入射光照 #if NUM_POINT_LIGHTS > 0 for(int i = 0; i < NUM_POINT_LIGHTS; ++i) { directLight.color = pointLights[i].color; // 入射光顏色 directLight.direction = normalize(pointLights[i].position - vPosition); // 入射光的方向 RE_Direct_Physical(geometry,material,directLight,reflectedLight); // 計算直接光產生的反射光信息 } #endif #if NUM_DIR_LIGHTS > 0 for(int i = 0; i < NUM_DIR_LIGHTS; ++i) { directLight.color = directionalLights[i].color; // 入射光顏色 directLight.direction = directionalLights[i].direction; RE_Direct_Physical(geometry,material,directLight,reflectedLight); // 計算直接光產生的反射光信息 } #endif vec3 irradiance = getAmbientLightIrradiance( vec3(0.13) ); RE_IndirectDiffuse( irradiance, geometry, material, reflectedLight ); // 反射光信息加合爲最後顏色 vec3 color = reflectedLight.directDiffuse + reflectedLight.directSpecular+reflectedLight.indirectDiffuse; // HDR tonemapping color = saturate(color/(color+vec3(1.0))); // gamma correct color = pow(color, vec3(1.0/2.0)); gl_FragColor = vec4(color, 1.0); }
下面是一個點光源和一個方向光的效果(從左到右粗糙度增強,從下到上金屬性增強):