Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLTF KHR_materials_anisotropy support #25580

Merged
merged 48 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e84ea22
plumbing
elalish Feb 28, 2023
aae2b68
refactored tangents
elalish Mar 1, 2023
0bc855c
fix bump map
elalish Mar 1, 2023
0aea9f3
fix bump map again
elalish Mar 1, 2023
fba9c0d
added IBL anisotropy support
elalish Mar 1, 2023
81d2fab
added direct anisotropy support
elalish Mar 2, 2023
3fdb06e
reshuffle chunks
elalish Mar 2, 2023
fd66490
fix clearcoat
elalish Mar 2, 2023
c96774b
fix dangling endif
elalish Mar 2, 2023
d13d0fa
separate physical BRDF from blinnPhong
elalish Mar 3, 2023
e06229b
prod CI
elalish Mar 3, 2023
afd255e
Merge branch 'dev' of github.com:mrdoob/three.js into anisotropy
elalish Mar 3, 2023
878f528
move Schlick to common
elalish Mar 3, 2023
a8f1818
fixed plumbing
elalish Mar 3, 2023
0ef60d7
fixed shader compilation
elalish Mar 3, 2023
2c2b219
fixed mappings
elalish Mar 3, 2023
02822a7
fixed tangents
elalish Mar 4, 2023
aa81f02
changed IBL mapping
elalish Mar 4, 2023
a8fe730
fix typo
elalish Mar 4, 2023
35ba4c2
fixed direct lighting
elalish Mar 7, 2023
bba8dcc
linearized mappings
elalish Mar 8, 2023
d82bd66
merging dev
elalish Mar 8, 2023
c6dd624
added anisotropyDirection
elalish Mar 8, 2023
24e4966
fixed angle direction
elalish Mar 8, 2023
b3d8b7a
added references
elalish Mar 8, 2023
785975f
fix anisotropy map
elalish Mar 8, 2023
2019065
Angle -> Rotation
elalish Mar 9, 2023
287d97b
fixed tangent sign
elalish Mar 10, 2023
6228a02
rename anisotropyMat
elalish Mar 20, 2023
aedce0a
fix 90 deg rotation
elalish Mar 20, 2023
288b008
update to spec
elalish Mar 20, 2023
33830fb
merging dev
elalish Mar 24, 2023
cebace1
updated alphaT mapping
elalish Mar 28, 2023
55601d9
merging dev
elalish Mar 28, 2023
ea0c4b1
Revert "updated alphaT mapping"
elalish Mar 28, 2023
2a48a13
Merge branch 'dev' into anisotropy
mrdoob Mar 31, 2023
f3ef3cd
WebGLProgram: Added missing ANISOTROPYMAP_UV define.
mrdoob Mar 31, 2023
498265f
Reverted builds.
mrdoob Mar 31, 2023
46a7040
WebGLPrograms: Fixed typo.
mrdoob Mar 31, 2023
e18fdf5
update to spec
elalish Apr 3, 2023
0ba4bdf
Merge branch 'dev' of github.com:mrdoob/three.js into anisotropy
elalish Apr 3, 2023
a3c7d9e
updated golden
elalish Apr 3, 2023
eed26c2
merging dev
elalish May 5, 2023
acb1c2e
update texture definition
elalish May 9, 2023
8ac65fc
Merge branch 'dev' of github.com:mrdoob/three.js into anisotropy
elalish May 9, 2023
b47ec43
added example
elalish May 10, 2023
b58f396
add build files
elalish May 10, 2023
26fbe83
added screenshot
elalish May 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions examples/jsm/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ class GLTFExporter {

} );

this.register( function ( writer ) {

return new GLTFMaterialsAnisotropyExtension( writer );

} );

this.register( function ( writer ) {

return new GLTFMaterialsEmissiveStrengthExtension( writer );
Expand Down Expand Up @@ -2804,6 +2810,48 @@ class GLTFMaterialsSheenExtension {

}

/**
* Anisotropy Materials Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy
*/
class GLTFMaterialsAnisotropyExtension {

constructor( writer ) {

this.writer = writer;
this.name = 'KHR_materials_anisotropy';

}

writeMaterial( material, materialDef ) {

if ( ! material.isMeshPhysicalMaterial || material.anisotropy == 0.0 ) return;

const writer = this.writer;
const extensionsUsed = writer.extensionsUsed;

const extensionDef = {};

if ( material.anisotropyMap ) {

const anisotropyMapDef = { index: writer.processTexture( material.anisotropyMap ) };
writer.applyTextureTransform( anisotropyMapDef, material.anisotropyMap );
extensionDef.anisotropyTexture = anisotropyMapDef;

}

extensionDef.anisotropyStrength = material.anisotropyStrength;

materialDef.extensions = materialDef.extensions || {};
materialDef.extensions[ this.name ] = extensionDef;

extensionsUsed[ this.name ] = true;

}

}

/**
* Materials Emissive Strength Extension
*
Expand Down
61 changes: 61 additions & 0 deletions examples/jsm/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ class GLTFLoader extends Loader {

} );

this.register( function ( parser ) {

return new GLTFMaterialsAnisotropyExtension( parser );

} );

this.register( function ( parser ) {

return new GLTFLightsExtension( parser );
Expand Down Expand Up @@ -472,6 +478,7 @@ const EXTENSIONS = {
KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
KHR_MATERIALS_IRIDESCENCE: 'KHR_materials_iridescence',
KHR_MATERIALS_ANISOTROPY: 'KHR_materials_anisotropy',
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
KHR_MATERIALS_VOLUME: 'KHR_materials_volume',
KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
Expand Down Expand Up @@ -1187,6 +1194,60 @@ class GLTFMaterialsSpecularExtension {

}

/**
* Materials anisotropy Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_anisotropy
*/
class GLTFMaterialsAnisotropyExtension {

constructor( parser ) {

this.parser = parser;
this.name = EXTENSIONS.KHR_MATERIALS_ANISOTROPY;

}

getMaterialType( materialIndex ) {

const parser = this.parser;
const materialDef = parser.json.materials[ materialIndex ];

if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;

return MeshPhysicalMaterial;

}

extendMaterialParams( materialIndex, materialParams ) {

const parser = this.parser;
const materialDef = parser.json.materials[ materialIndex ];

if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {

return Promise.resolve();

}

const pending = [];

const extension = materialDef.extensions[ this.name ];

materialParams.anisotropyStrength = extension.anisotropyStrength !== undefined ? extension.anisotropyStrength : 1.0;

if ( extension.anisotropyTexture !== undefined ) {

pending.push( parser.assignTexture( materialParams, 'anisotropyMap', extension.anisotropyTexture ) );

}

return Promise.all( pending );

}

}

/**
* BasisU Texture Extension
*
Expand Down
2 changes: 2 additions & 0 deletions manual/resources/threejs-material-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ const materials = [
'transmissionMap',
'attenuationDistance',
'attenuationColor',
'anisotropy',
'anisotropyMap',
'specularIntensity',
'specularIntensityMap',
'specularColor',
Expand Down
3 changes: 3 additions & 0 deletions src/loaders/MaterialLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class MaterialLoader extends Loader {
if ( json.thickness !== undefined ) material.thickness = json.thickness;
if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;
if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );
if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;
if ( json.fog !== undefined ) material.fog = json.fog;
if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
if ( json.blending !== undefined ) material.blending = json.blending;
Expand Down Expand Up @@ -310,6 +311,8 @@ class MaterialLoader extends Loader {
if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );
if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );

if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );

if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );
if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );

Expand Down
9 changes: 9 additions & 0 deletions src/materials/Material.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ class Material extends EventDispatcher {

}

if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
if ( this.anisotropyStrength !== undefined ) data.anisotropyStrength = this.anisotropyStrength;

if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {

data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;

}

if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
Expand Down
26 changes: 26 additions & 0 deletions src/materials/MeshPhysicalMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@ class MeshPhysicalMaterial extends MeshStandardMaterial {
this.specularColor = new Color( 1, 1, 1 );
this.specularColorMap = null;

this.anisotropyStrength = 1.0;
this.anisotropyMap = null;

this._sheen = 0.0;
this._clearcoat = 0;
this._iridescence = 0;
this._transmission = 0;
this._anisotropy = 0;

this.setValues( parameters );

Expand Down Expand Up @@ -144,6 +148,24 @@ class MeshPhysicalMaterial extends MeshStandardMaterial {

}

get anisotropy() {

return this._anisotropy;

}

set anisotropy( value ) {

if ( this._anisotropy > 0 !== value > 0 ) {

this.version ++;

}

this._anisotropy = value;

}

copy( source ) {

super.copy( source );
Expand Down Expand Up @@ -189,6 +211,10 @@ class MeshPhysicalMaterial extends MeshStandardMaterial {
this.specularColor.copy( source.specularColor );
this.specularColorMap = source.specularColorMap;

this.anisotropy = source.anisotropy;
this.anisotropyStrength = source.anisotropyStrength;
this.anisotropyMap = source.anisotropyMap;

return this;

}
Expand Down
2 changes: 2 additions & 0 deletions src/renderers/shaders/ShaderChunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import clearcoat_pars_fragment from './ShaderChunk/clearcoat_pars_fragment.glsl.
import iridescence_pars_fragment from './ShaderChunk/iridescence_pars_fragment.glsl.js';
import output_fragment from './ShaderChunk/output_fragment.glsl.js';
import packing from './ShaderChunk/packing.glsl.js';
import physical_pars_fragment from './ShaderChunk/physical_pars_fragment.glsl.js';
import premultiplied_alpha_fragment from './ShaderChunk/premultiplied_alpha_fragment.glsl.js';
import project_vertex from './ShaderChunk/project_vertex.glsl.js';
import dithering_fragment from './ShaderChunk/dithering_fragment.glsl.js';
Expand Down Expand Up @@ -203,6 +204,7 @@ export const ShaderChunk = {
iridescence_pars_fragment: iridescence_pars_fragment,
output_fragment: output_fragment,
packing: packing,
physical_pars_fragment: physical_pars_fragment,
premultiplied_alpha_fragment: premultiplied_alpha_fragment,
project_vertex: project_vertex,
dithering_fragment: dithering_fragment,
Expand Down
78 changes: 66 additions & 12 deletions src/renderers/shaders/ShaderChunk/bsdfs.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,37 @@ float D_GGX( const in float alpha, const in float dotNH ) {

}

#ifdef USE_ANISOTROPY
WestLangley marked this conversation as resolved.
Show resolved Hide resolved

float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {

float lambdaV = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );
float lambdaL = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );
float v = 0.5 / ( lambdaV + lambdaL );

return saturate(v);

}

float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {

float a2 = alphaT * alphaB;
highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );
highp float v2 = dot( v, v );
float w2 = a2 / v2;

return a2 * w2 * w2 * ( 1.0 * RECIPROCAL_PI );

}

#endif

// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {
vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another refactor here is to make the Clearcoat BRDF the special function instead of the iridescence BRDF. This is nice because clearcoat always uses the simple version, whereas the base BRDF get adjusted by several things, so far iridescence and anisotropy. This feels cleaner to me, hopefully others agree, especially since I removed a lot of the function inputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, this did also necessitate moving the PhysicalMaterial definition into its own chunk so it could be included earlier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see the problem - okay, coming back tomorrow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I did a different refactor instead due to troubles with include order. Basically bsdfs.glsl.js had mostly Physical BRDFs that are only used by lights_physical_pars_fragment.glsl.js, so I just moved those functions into that file (a little big now, but self-contained). The only other function used broadly was BRDF_Lambert, so I moved that to common.glsl.js. Now bsdfs.glsl.js is just BlinnPhong functions, and no longer imported by meshphysical.

Sorry this makes the PR a bit hard to read - probably best to look at commits individually.


vec3 f0 = material.clearcoatF0;
float f90 = material.clearcoatF90;
float roughness = material.clearcoatRoughness;

float alpha = pow2( roughness ); // UE4's roughness

Expand All @@ -88,28 +117,53 @@ vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 norm

}

#ifdef USE_IRIDESCENCE
vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {

vec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {
vec3 f0 = material.specularColor;
float f90 = material.specularF90;
float roughness = material.roughness;

float alpha = pow2( roughness ); // UE4's roughness
float alpha = pow2( roughness ); // UE4's roughness

vec3 halfDir = normalize( lightDir + viewDir );
vec3 halfDir = normalize( lightDir + viewDir );

float dotNL = saturate( dot( normal, lightDir ) );
float dotNV = saturate( dot( normal, viewDir ) );
float dotNH = saturate( dot( normal, halfDir ) );
float dotVH = saturate( dot( viewDir, halfDir ) );
float dotNL = saturate( dot( normal, lightDir ) );
float dotNV = saturate( dot( normal, viewDir ) );
float dotNH = saturate( dot( normal, halfDir ) );
float dotVH = saturate( dot( viewDir, halfDir ) );

vec3 F = F_Schlick( f0, f90, dotVH );

#ifdef USE_IRIDESCENCE

F = mix( F, material.iridescenceFresnel, material.iridescence );

#endif

vec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );
#ifdef USE_ANISOTROPY

float dotTL = saturate( dot( material.anisotropyT, lightDir ) );
float dotTV = saturate( dot( material.anisotropyT, viewDir ) );
float dotTH = saturate( dot( material.anisotropyT, halfDir ) );
float dotBL = saturate( dot( material.anisotropyB, lightDir ) );
float dotBV = saturate( dot( material.anisotropyB, viewDir ) );
float dotBH = saturate( dot( material.anisotropyB, halfDir ) );

float V = V_GGX_SmithCorrelated_Anisotropic( alpha, material.alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );

float D = D_GGX_Anisotropic( alpha, material.alphaB, dotNH, dotTH, dotBH );

#else

float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );

float D = D_GGX( alpha, dotNH );

return F * ( V * D );
#endif

}
return F * ( V * D );

}

#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,7 @@ export default /* glsl */`
vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;
clearcoatMapN.xy *= clearcoatNormalScale;

#ifdef USE_TANGENT

clearcoatNormal = normalize( vTBN * clearcoatMapN );

#else

clearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );

#endif
clearcoatNormal = normalize( vTBN * clearcoatMapN );

#endif
`;
Loading