ThreeJS 物理材質shader源碼分析(像素着色器)

再此以前推薦一款GLTF物理材質在線編輯器https://tinygltf.xyz/

像素着色器(meshphysical_frag.glsl)

#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);
}

下面是一個點光源和一個方向光的效果(從左到右粗糙度增強,從下到上金屬性增強): 

 

 

 

 

 

 

 

 

相關文章
相關標籤/搜索