1.顶点着色
export default /* glsl */`
#define PHONG
varying vec3 vViewPosition;
#ifndef FLAT_SHADED
varying vec3 vNormal;
#endif
#include <common>
#include <uv_pars_vertex>
#include <uv2_pars_vertex>
#include <displacementmap_pars_vertex>
#include <envmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <shadowmap_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <defaultnormal_vertex>
#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED
vNormal = normalize( transformedNormal );
#endif
#include <begin_vertex>
//内容:
//vec3 transformed = vec3( position );
//
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <displacementmap_vertex>
#include <project_vertex>
//内容:
//vec4 mvPosition = vec4( transformed, 1.0 );
//mvPosition = modelViewMatrix * mvPosition;
//gl_Position = projectionMatrix * mvPosition;
//
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
vViewPosition = - mvPosition.xyz;
#include <worldpos_vertex>
// 内容:求世界坐标
// vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );
//
#include <envmap_vertex>
#include <shadowmap_vertex>
#include <fog_vertex>
}
`;
2.片元着色
#define PHONG
uniform vec3 diffuse;
uniform vec3 emissive;
uniform vec3 specular;
uniform float shininess;
uniform float opacity;
#include <color_pars_fragment>
#ifdef USE_COLOR
varying vec3 vColor;
#endif
#include <uv_pars_fragment>
#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )
varying vec2 vUv;
#endif
#include <map_pars_fragment>
#ifdef USE_MAP
uniform sampler2D map;
#endif
//下面三个比较重要
#include <双向反射函数>
#include <lights_pars_begin>
内容:初始化各类灯光及其根据灯光位置和顶点的距离 返回该顶点实际灯光的强度和颜色
uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];
void getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight )
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight )
uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];
void getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight )
uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];
#include <lights_phong_pars_fragment>
varying vec3 vViewPosition;
struct BlinnPhongMaterial {
vec3 diffuseColor;
vec3 specularColor;
float specularShininess;
float specularStrength;
};
void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
float dotNL = saturate( dot( geometry.normal, directLight.direction ) );//saturate是clamp0-1
vec3 irradiance = dotNL * directLight.color;
#ifndef PHYSICALLY_CORRECT_LIGHTS
irradiance *= PI; // punctual light
#endif
reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );//irradiance * 0.31830988618 * material.diffuseColor;//这里*0.318什么操作
reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;
}
void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {
reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
}
#define RE_Direct RE_Direct_BlinnPhong
#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong
#define Material_LightProbeLOD( material ) (0)
void main() {
vec4 diffuseColor = vec4( diffuse, opacity );
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0), vec3( 0.0 ) );
vec3 totalEmissiveRadiance = emissive;
#include <specularmap_fragment>
内容:高光贴图,好像事取R通道的值
float specularStrength;
#ifdef USE_SPECULARMAP
vec4 texelSpecular = texture2D( specularMap, vUv );
specularStrength = texelSpecular.r;
#else
specularStrength = 1.0;
#endif
#include <normal_fragment_begin>
内容:法向量
vec3 normal = normalize( vNormal );
vec3 geometryNormal = normal;
#include <normal_fragment_maps>
内容:法向贴图
// accumulation
#include <lights_phong_fragment>
BlinnPhongMaterial material;
material.diffuseColor = diffuseColor.rgb;
material.specularColor = specular;
material.specularShininess = shininess;
material.specularStrength = specularStrength;
#include <lights_fragment_begin>
GeometricContext geometry;
geometry.position = - vViewPosition;
geometry.normal = normal;
geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );
IncidentLight directLight;
// 然后以平行光为例
#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )
DirectionalLight directionalLight;
#pragma unroll_loop_start
for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
directionalLight = directionalLights[ i ];
getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );
RE_Direct( directLight, geometry, material, reflectedLight );
}
#pragma unroll_loop_end
#endif
//全篇最重要的:
RE_Direct执行的是上文中提到的RE_Direct_BlinnPhong,其中直接漫反射计算:
BRDF_Diffuse_Lambert
直接高光计算:
vec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {
vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );
//float dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );
//float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );
float dotNH = saturate( dot( geometry.normal, halfDir ) );
float dotLH = saturate( dot( incidentLight.direction, halfDir ) );
vec3 F = F_Schlick( specularColor, dotLH );
float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );
float D = D_BlinnPhong( shininess, dotNH );
return F * ( G * D );
}
这里就是blinnPhong和PBR的区别,PBR这里G、D计算方式有区别
这里
geometry.viewDir 是顶点到世界坐标原点000方向的单位向量 就是视线方向,整体是在世界坐标系中,这里three中视线原点我认为就是世界坐标系的原点
geometry.normal 是顶点的单位法向量
halfDir 是半角向量,视线向量和光线向量的中间值
incidentLight.direction 光线方向向量,就是顶点到光源方向的向量
billn phong BRDF 标准的布林冯模型
float G_BlinnPhong_Implicit( /* const in float dotNL, const in float dotNV */ ) {
// geometry term is (n dot l)(n dot v) / 4(n dot l)(n dot v)
return 0.25;
}
float D_BlinnPhong( const in float shininess, const in float dotNH ) {
return RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );
}
可以对比看下GGX BRDF
float G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {
float a2 = pow2( alpha );
// dotNL and dotNV are explicitly swapped. This is not a mistake.
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; // avoid alpha = 0 with dotNH = 1
return RECIPROCAL_PI * a2 / pow2( denom );
}
#include <lights_fragment_maps>
主要是RE_IndirectDiffuse和RE_IndirectSpecular 间接漫反射和高光
#include <lights_fragment_end>
主要是RE_IndirectDiffuse和RE_IndirectSpecular 间接漫反射和高光
vec3 outgoingLight = reflectedLight.directDiffuse +
reflectedLight.indirectDiffuse + reflectedLight.directSpecular +
reflectedLight.indirectSpecular + totalEmissiveRadiance; gl_FragColor
= vec4( outgoingLight, diffuseColor.a );
综合输出直接间接漫反射、直接间接高光
}