Blinn–Phong reflection model
平滑着色 | 平直着色 |
---|---|
![]() | ![]() |
![]() | ![]() |
顶点 |
// 法线
vNormal = normalMatrix * normal;
vNormal = normalize( vNormal );
// 点光位置
vPointLightPosition = (viewMatrix * vec4( pointLightPosition, 1.0 )).xyz;
//顶点位置
vec3 transformed = vec3( position );
vec4 mvPosition = vec4( transformed, 1.0 );
mvPosition = modelViewMatrix * mvPosition;
vViewPosition = - mvPosition.xyz;
片元
不同着色方式法线设置
#ifdef FLAT_SHADEDvec3 fdx = dFdx( vViewPosition );vec3 fdy = dFdy( vViewPosition );vec3 normal = normalize( cross( fdx, fdy ) );#elsevec3 normal = vNormal ;normal = normalize( vNormal );#endifvec3 geometryPosition = - vViewPosition;
vec3 geometryNormal = normal;
vec3 geometryViewDir = normalize( vViewPosition );//光线方向
vec3 lVector = vPointLightPosition - geometryPosition;
vec3 lightDirection = normalize( lVector );
//直接反射高光颜色
vec3 phongColor = BRDF_BlinnPhong( lightDirection, geometryViewDir, geometryNormal, vec3(1), 30.);
全部代码
import * as THREE from "three";const bsdfs_glsl = /* glsl */ `float pow2( const in float x ) { return x*x; }vec3 pow2( const in vec3 x ) { return x*x; }float pow4( const in float x ) { float x2 = x*x; return x2*x2; }// 距离衰减float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );if ( cutoffDistance > 0.0 ) {distanceFalloff *= pow2( clamp( 1.0 - pow4( lightDistance / cutoffDistance ) ,0. ,1.) );}return distanceFalloff;}// common.glsl.jsvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {// Original approximation by Christophe Schlick '94// float fresnel = pow( 1.0 - dotVH, 5.0 );// Optimized variant (presented by Epic at SIGGRAPH '13)// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdffloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );}float F_Schlick( const in float f0, const in float f90, const in float dotVH ) {// Original approximation by Christophe Schlick '94// float fresnel = pow( 1.0 - dotVH, 5.0 );// Optimized variant (presented by Epic at SIGGRAPH '13)// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdffloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );}// bsdfs.glsl.jsfloat 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 );}vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {vec3 halfDir = normalize( lightDir + viewDir );float dotNH = clamp( dot( normal, halfDir ) ,0.,1.);float dotVH = clamp( dot( viewDir, halfDir ) ,0.,1.);vec3 F = F_Schlick( specularColor, 1.0, dotVH );float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );float D = D_BlinnPhong( shininess, dotNH );return F * ( G * D );}
`;export class SpecularShaderMaterial extends THREE.ShaderMaterial {constructor(params?: ConstructorParameters<typeof THREE.ShaderMaterial>[0] & {pointLightPosition: THREE.Vector3;pointLightDistance: number;pointLightDecay: number;}) {super({uniforms: {pointLightPosition: {value: params!.pointLightPosition,},pointLightDistance: {value: params?.pointLightDistance ?? 100,},pointLightDecay: {value: params?.pointLightDecay ?? 2,},},defines: {RECIPROCAL_PI: 1 / Math.PI,// 平直着色 关闭则 平滑着色FLAT_SHADED: false,},vertexShader: /* glsl */ `varying vec3 vNormal;varying vec3 vertexPosition;uniform vec3 pointLightPosition;varying vec3 vPointLightPosition;varying vec3 vViewPosition;void main() {vNormal = normalMatrix * normal;vNormal = normalize( vNormal );vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);gl_Position = projectionMatrix * modelViewPosition;vertexPosition = modelViewPosition.xyz;vPointLightPosition = (viewMatrix * vec4( pointLightPosition, 1.0 )).xyz;vec3 transformed = vec3( position );vec4 mvPosition = vec4( transformed, 1.0 );mvPosition = modelViewMatrix * mvPosition;vViewPosition = - mvPosition.xyz;}`,fragmentShader: /* glsl */ `varying vec3 vNormal; varying vec3 vertexPosition;varying vec3 vPointLightPosition;uniform vec3 pointLightPosition;uniform float pointLightDistance;uniform float pointLightDecay;varying vec3 vViewPosition;${bsdfs_glsl}void main() {#ifdef FLAT_SHADEDvec3 fdx = dFdx( vViewPosition );vec3 fdy = dFdy( vViewPosition );vec3 normal = normalize( cross( fdx, fdy ) );#elsevec3 normal = vNormal ;normal = normalize( vNormal );#endifvec3 geometryPosition = - vViewPosition;vec3 geometryNormal = normal;vec3 geometryViewDir = normalize( vViewPosition );// 取自 getPointLightInfo// vec3 lVector = pointLightPosition - geometryPosition;vec3 lVector = vPointLightPosition - geometryPosition;vec3 lightDirection = normalize( lVector );float lightDistance = length( lVector );vec3 lightColor = vec3( 1. );lightColor *= getDistanceAttenuation( lightDistance, pointLightDistance, pointLightDecay );// 取自 RE_Direct_BlinnPhongfloat dotNL = clamp( dot( geometryNormal, lightDirection ) ,0. ,1. );vec3 irradiance = dotNL * lightColor;// vec3 reflectedLightDirectSpecular = irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;vec3 phongColor = BRDF_BlinnPhong( lightDirection, geometryViewDir, geometryNormal, vec3(1), 30.);// gl_FragColor = vec4(vec3( irradiance ) , 1. );gl_FragColor = vec4(vec3( phongColor ) , 1. );// gl_FragColor = vec4(vec3( lightDirection ) , 1. );// gl_FragColor = vec4(vec3( pointLightPosition ) , 1. );// gl_FragColor = vec4(vec3( vPointLightPosition ) , 1. );// gl_FragColor = vec4(vec3( normal ) , 1. );// gl_FragColor = vec4(vec3( lightColor ) , 1. );// gl_FragColor = vec4(vec3( irradiance ) , 1. );}`,});}
}