Initial commit

This commit is contained in:
ChKendel
2026-01-31 21:50:25 +01:00
commit c65f983229
1088 changed files with 452910 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import F_Schlick from './F_Schlick.js';
import V_GGX_SmithCorrelated from './V_GGX_SmithCorrelated.js';
import D_GGX from './D_GGX.js';
import { transformedNormalView } from '../../accessors/NormalNode.js';
import { positionViewDirection } from '../../accessors/PositionNode.js';
import { iridescence } from '../../core/PropertyNode.js';
import { tslFn } from '../../shadernode/ShaderNode.js';
// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
const BRDF_GGX = tslFn( ( inputs ) => {
const { lightDirection, f0, f90, roughness, iridescenceFresnel } = inputs;
const normalView = inputs.normalView || transformedNormalView;
const alpha = roughness.pow2(); // UE4's roughness
const halfDir = lightDirection.add( positionViewDirection ).normalize();
const dotNL = normalView.dot( lightDirection ).clamp();
const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
const dotNH = normalView.dot( halfDir ).clamp();
const dotVH = positionViewDirection.dot( halfDir ).clamp();
let F = F_Schlick( { f0, f90, dotVH } );
if ( iridescenceFresnel ) {
F = iridescence.mix( F, iridescenceFresnel );
}
const V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } );
const D = D_GGX( { alpha, dotNH } );
return F.mul( V ).mul( D );
} ); // validated
export default BRDF_GGX;

View File

@@ -0,0 +1,9 @@
import { tslFn } from '../../shadernode/ShaderNode.js';
const BRDF_Lambert = tslFn( ( inputs ) => {
return inputs.diffuseColor.mul( 1 / Math.PI ); // punctual light
} ); // validated
export default BRDF_Lambert;

View File

@@ -0,0 +1,57 @@
import { transformedNormalView } from '../../accessors/NormalNode.js';
import { positionViewDirection } from '../../accessors/PositionNode.js';
import { sheen, sheenRoughness } from '../../core/PropertyNode.js';
import { tslFn, float } from '../../shadernode/ShaderNode.js';
// https://github.com/google/filament/blob/master/shaders/src/brdf.fs
const D_Charlie = tslFn( ( { roughness, dotNH } ) => {
const alpha = roughness.pow2();
// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"
const invAlpha = float( 1.0 ).div( alpha );
const cos2h = dotNH.pow2();
const sin2h = cos2h.oneMinus().max( 0.0078125 ); // 2^(-14/2), so sin2h^2 > 0 in fp16
return float( 2.0 ).add( invAlpha ).mul( sin2h.pow( invAlpha.mul( 0.5 ) ) ).div( 2.0 * Math.PI );
} ).setLayout( {
name: 'D_Charlie',
type: 'float',
inputs: [
{ name: 'roughness', type: 'float' },
{ name: 'dotNH', type: 'float' }
]
} );
// https://github.com/google/filament/blob/master/shaders/src/brdf.fs
const V_Neubelt = tslFn( ( { dotNV, dotNL } ) => {
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
return float( 1.0 ).div( float( 4.0 ).mul( dotNL.add( dotNV ).sub( dotNL.mul( dotNV ) ) ) );
} ).setLayout( {
name: 'V_Neubelt',
type: 'float',
inputs: [
{ name: 'dotNV', type: 'float' },
{ name: 'dotNL', type: 'float' }
]
} );
const BRDF_Sheen = tslFn( ( { lightDirection } ) => {
const halfDir = lightDirection.add( positionViewDirection ).normalize();
const dotNL = transformedNormalView.dot( lightDirection ).clamp();
const dotNV = transformedNormalView.dot( positionViewDirection ).clamp();
const dotNH = transformedNormalView.dot( halfDir ).clamp();
const D = D_Charlie( { roughness: sheenRoughness, dotNH } );
const V = V_Neubelt( { dotNV, dotNL } );
return sheen.mul( D ).mul( V );
} );
export default BRDF_Sheen;

View File

@@ -0,0 +1,30 @@
import { tslFn, vec2, vec4 } from '../../shadernode/ShaderNode.js';
// Analytical approximation of the DFG LUT, one half of the
// split-sum approximation used in indirect specular lighting.
// via 'environmentBRDF' from "Physically Based Shading on Mobile"
// https://www.unrealengine.com/blog/physically-based-shading-on-mobile
const DFGApprox = tslFn( ( { roughness, dotNV } ) => {
const c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );
const c1 = vec4( 1, 0.0425, 1.04, - 0.04 );
const r = roughness.mul( c0 ).add( c1 );
const a004 = r.x.mul( r.x ).min( dotNV.mul( - 9.28 ).exp2() ).mul( r.x ).add( r.y );
const fab = vec2( - 1.04, 1.04 ).mul( a004 ).add( r.zw );
return fab;
} ).setLayout( {
name: 'DFGApprox',
type: 'vec2',
inputs: [
{ name: 'roughness', type: 'float' },
{ name: 'dotNV', type: 'vec3' }
]
} );
export default DFGApprox;

View File

@@ -0,0 +1,23 @@
import { tslFn } from '../../shadernode/ShaderNode.js';
// Microfacet Models for Refraction through Rough Surfaces - equation (33)
// http://graphicrants.blogspot.com/2013/08/specular-brdf-reference.html
// alpha is "roughness squared" in Disneys reparameterization
const D_GGX = tslFn( ( { alpha, dotNH } ) => {
const a2 = alpha.pow2();
const denom = dotNH.pow2().mul( a2.oneMinus() ).oneMinus(); // avoid alpha = 0 with dotNH = 1
return a2.div( denom.pow2() ).mul( 1 / Math.PI );
} ).setLayout( {
name: 'D_GGX',
type: 'float',
inputs: [
{ name: 'alpha', type: 'float' },
{ name: 'dotNH', type: 'float' }
]
} ); // validated
export default D_GGX;

View File

@@ -0,0 +1,13 @@
import DFGApprox from './DFGApprox.js';
import { tslFn } from '../../shadernode/ShaderNode.js';
const EnvironmentBRDF = tslFn( ( inputs ) => {
const { dotNV, specularColor, specularF90, roughness } = inputs;
const fab = DFGApprox( { dotNV, roughness } );
return specularColor.mul( fab.x ).add( specularF90.mul( fab.y ) );
} );
export default EnvironmentBRDF;

View File

@@ -0,0 +1,16 @@
import { tslFn } from '../../shadernode/ShaderNode.js';
const F_Schlick = tslFn( ( { f0, f90, 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.pdf
const fresnel = dotVH.mul( - 5.55473 ).sub( 6.98316 ).mul( dotVH ).exp2();
return f0.mul( fresnel.oneMinus() ).add( f90.mul( fresnel ) );
} ); // validated
export default F_Schlick;

View File

@@ -0,0 +1,21 @@
import { tslFn, vec3 } from '../../shadernode/ShaderNode.js';
const Schlick_to_F0 = tslFn( ( { f, f90, dotVH } ) => {
const x = dotVH.oneMinus().saturate();
const x2 = x.mul( x );
const x5 = x.mul( x2, x2 ).clamp( 0, .9999 );
return f.sub( vec3( f90 ).mul( x5 ) ).div( x5.oneMinus() );
} ).setLayout( {
name: 'Schlick_to_F0',
type: 'vec3',
inputs: [
{ name: 'f', type: 'vec3' },
{ name: 'f90', type: 'float' },
{ name: 'dotVH', type: 'float' }
]
} );
export default Schlick_to_F0;

View File

@@ -0,0 +1,28 @@
import { div } from '../../math/OperatorNode.js';
import { EPSILON } from '../../math/MathNode.js';
import { tslFn } from '../../shadernode/ShaderNode.js';
// Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
const V_GGX_SmithCorrelated = tslFn( ( inputs ) => {
const { alpha, dotNL, dotNV } = inputs;
const a2 = alpha.pow2();
const gv = dotNL.mul( a2.add( a2.oneMinus().mul( dotNV.pow2() ) ).sqrt() );
const gl = dotNV.mul( a2.add( a2.oneMinus().mul( dotNL.pow2() ) ).sqrt() );
return div( 0.5, gv.add( gl ).max( EPSILON ) );
} ).setLayout( {
name: 'V_GGX_SmithCorrelated',
type: 'float',
inputs: [
{ name: 'alpha', type: 'float' },
{ name: 'dotNL', type: 'float' },
{ name: 'dotNV', type: 'float' }
]
} ); // validated
export default V_GGX_SmithCorrelated;