Three.js 中的光照模型
Three.js 的一个伟大抽象就是统一了所有材质的光照模型, 无论 PBR 或者 Phong。都只用两个函数给全部囊括了。
就是 RE_Direct
(直接反射) 和 RE_IndirectDiffuse
(间接反射)。真正做到了大一统。下面以Phong为例,具体看一下如何落地。
省流版本:
// 直接反射
RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );
// 间接反射
vec3 irradiance = getAmbientLightIrradiance( ambientLightColor );
RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );
vec3 outgoingLight =
// 直接漫反射
reflectedLight.directDiffuse +
// 间接漫反射
reflectedLight.indirectDiffuse +
// 直接高光
reflectedLight.directSpecular +
// 间接高光
reflectedLight.indirectSpecular;
1、一些概念
Incident
, 入射光Irradiance
, 辐照度, 量化接收光源能量的多少直接光照
, 是指光源直接照射到物体表面产生的光照效果间接光照
, 是指光源经过其他物体反射或散射后照射到物体表面的光照效果。
2、RE_Direct
RE_Direct
计算直接光照的反射效果, 包括直接漫反射和直接高光反射。
3、RE_IndirectDiffuse
RE_IndirectDiffuse_BlinnPhong
函数用于计算间接漫反射的效果。包括间接漫反射和间接高光反射。
4、Phone 实现细节
片元着色器:
varying vec3 vViewPosition;
//
#define RE_Direct RE_Direct_BlinnPhong
#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong
// 直接反射 + 间接反射总结果
struct ReflectedLight {
// 直接漫反射
vec3 directDiffuse;
// 直接高光
vec3 directSpecular;
// 间接漫反射
vec3 indirectDiffuse;
// 间接高光
vec3 indirectSpecular;
};
// 入射光参数
struct IncidentLight {
vec3 color;
vec3 direction;
bool visible;
};
struct BlinnPhongMaterial {
vec3 diffuseColor;
vec3 specularColor;
float specularShininess;
float specularStrength;
};
void RE_Direct_BlinnPhong(
const in IncidentLight directLight,
const in vec3 geometryPosition,
const in vec3 geometryNormal,
const in vec3 geometryViewDir,
const in vec3 geometryClearcoatNormal,
const in BlinnPhongMaterial material,
inout ReflectedLight reflectedLight
) {
float dotNL = saturate( dot( geometryNormal, directLight.direction ) );
vec3 irradiance = dotNL * directLight.color;
reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;
}
void RE_IndirectDiffuse_BlinnPhong(
const in vec3 irradiance,
const in vec3 geometryPosition,
const in vec3 geometryNormal,
const in vec3 geometryViewDir,
const in vec3 geometryClearcoatNormal,
const in BlinnPhongMaterial material,
inout ReflectedLight reflectedLight
) {
reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
}
uniform vec3 diffuse;
uniform float opacity;
uniform vec3 specular;
uniform vec3 ambientLightColor;
struct BlinnPhongMaterial {
vec3 diffuseColor;
vec3 specularColor;
float specularShininess;
float specularStrength;
};
// 方向光信息
struct DirectionalLight {
vec3 direction;
vec3 color;
};
uniform DirectionalLight directionalLights[ 1 ];
// 入射的方向光转为通用的入射光信息
void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {
light.color = directionalLight.color;
light.direction = directionalLight.direction;
light.visible = true;
}
vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
vec3 irradiance = ambientLightColor;
return irradiance;
}
void main() {
vec4 diffuseColor = vec4( diffuse, opacity );
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
vec4 sampledDiffuseColor = texture2D( map, vMapUv );
diffuseColor *= sampledDiffuseColor;
float specularStrength = 1.0;
BlinnPhongMaterial material;
material.diffuseColor = diffuseColor.rgb;
material.specularColor = specular;
material.specularShininess = shininess;
material.specularStrength = specularStrength;
vec3 geometryPosition = - vViewPosition;
vec3 geometryNormal = normal;
vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );
vec3 geometryClearcoatNormal = vec3( 0.0 );
// 入射光信息
IncidentLight directLight;
// 方向光
DirectionalLight directionalLight;
directionalLight = directionalLights[ 0 ];
getDirectionalLightInfo( directionalLight, directLight );
// 直接反射
RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );
// 间接反射
vec3 irradiance = getAmbientLightIrradiance( ambientLightColor );
RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );
vec3 outgoingLight =
// 直接漫反射
reflectedLight.directDiffuse +
// 间接漫反射
reflectedLight.indirectDiffuse +
// 直接高光
reflectedLight.directSpecular +
// 间接高光
reflectedLight.indirectSpecular;
}
顶点着色器:
vec3 transformed = vec3( position );
vec4 mvPosition = vec4( transformed, 1.0 );
mvPosition = modelViewMatrix * mvPosition;
gl_Position = projectionMatrix * mvPosition;
vViewPosition = - mvPosition.xyz;