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

Add specular to MeshPhysicalMaterial and GLTFLoader KHR_materials_specular support #22156

Merged
merged 8 commits into from
Jul 28, 2021
1 change: 1 addition & 0 deletions docs/examples/en/loaders/GLTFLoader.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ <h2>Extensions</h2>
<li>KHR_materials_clearcoat</li>
<li>KHR_materials_ior</li>
<li>KHR_materials_pbrSpecularGlossiness</li>
<li>KHR_materials_specular</li>
<li>KHR_materials_transmission</li>
<li>KHR_materials_unlit</li>
<li>KHR_materials_volume</li>
Expand Down
1 change: 1 addition & 0 deletions docs/examples/zh/loaders/GLTFLoader.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ <h2>扩展</h2>
<li>KHR_materials_clearcoat</li>
<li>KHR_materials_ior</li>
<li>KHR_materials_pbrSpecularGlossiness</li>
<li>KHR_materials_specular</li>
<li>KHR_materials_transmission</li>
<li>KHR_materials_unlit</li>
<li>KHR_materials_volume</li>
Expand Down
78 changes: 77 additions & 1 deletion examples/jsm/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ class GLTFLoader extends Loader {

} );

this.register( function ( parser ) {

return new GLTFMaterialsSpecularExtension( parser );

} );

this.register( function ( parser ) {

return new GLTFLightsExtension( parser );
Expand Down Expand Up @@ -421,6 +427,7 @@ const EXTENSIONS = {
KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
KHR_MATERIALS_IOR: 'KHR_materials_ior',
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission',
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
KHR_MATERIALS_VOLUME: 'KHR_materials_volume',
Expand Down Expand Up @@ -861,6 +868,73 @@ class GLTFMaterialsIorExtension {

}

/**
* Materials specular Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular
*/
class GLTFMaterialsSpecularExtension {

constructor( parser ) {

this.parser = parser;
this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR;

}

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.specularIntensity = extension.specularFactor !== undefined ? extension.specularFactor : 1.0;

if ( extension.specularTexture !== undefined ) {

pending.push( parser.assignTexture( materialParams, 'specularIntensityMap', extension.specularTexture ) );

}

const colorArray = extension.specularColorFactor || [ 1, 1, 1 ];
materialParams.specularTint = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );

if ( extension.specularColorTexture !== undefined ) {

pending.push( parser.assignTexture( materialParams, 'specularTintMap', extension.specularColorTexture ).then( function ( texture ) {

texture.encoding = sRGBEncoding;

} ) );

}

return Promise.all( pending );

}

}

/**
* BasisU Texture Extension
*
Expand Down Expand Up @@ -2780,7 +2854,7 @@ class GLTFParser {
* @param {Object} materialParams
* @param {string} mapName
* @param {Object} mapDef
* @return {Promise}
* @return {Promise<Texture>}
*/
assignTexture( materialParams, mapName, mapDef ) {

Expand Down Expand Up @@ -2812,6 +2886,8 @@ class GLTFParser {

materialParams[ mapName ] = texture;

return texture;

} );

}
Expand Down
Binary file modified examples/models/gltf/IridescentDishWithOlives.glb
Binary file not shown.
Binary file modified examples/screenshots/webgl_loader_gltf_transmission.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 8 additions & 3 deletions examples/webgl_loader_gltf_transmission.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader + <a href="https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission" target="_blank" rel="noopener">KHR_materials_transmission</a> extension<br />
Iridescent Dish With Olives by <a href="https://github.com/echadwick-wayfair" target="_blank" rel="noopener">Eric Chadwick</a><br />
<a href="https://hdrihaven.com/hdri/?h=quarry_01" target="_blank" rel="noopener">Quarry</a> by <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
<a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> by <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
</div>

<script type="module">
Expand All @@ -22,6 +22,8 @@
import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
import { RGBELoader } from './jsm/loaders/RGBELoader.js';

import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';

let camera, scene, renderer, clock, mixer;

init();
Expand All @@ -42,7 +44,7 @@
new RGBELoader()
.setDataType( THREE.FloatType )
.setPath( 'textures/equirectangular/' )
.load( 'quarry_01_1k.hdr', function ( texture ) {
.load( 'royal_esplanade_1k.hdr', function ( texture ) {

texture.mapping = THREE.EquirectangularReflectionMapping;

Expand All @@ -51,7 +53,10 @@

// model

const loader = new GLTFLoader().setPath( 'models/gltf/' );
const loader = new GLTFLoader()
.setPath( 'models/gltf/' )
.setDRACOLoader( new DRACOLoader().setDecoderPath( 'js/libs/draco/gltf/' ) );

loader.load( 'IridescentDishWithOlives.glb', function ( gltf ) {

mixer = new THREE.AnimationMixer( gltf.scene );
Expand Down
20 changes: 20 additions & 0 deletions examples/webgl_materials_physical_transmission.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
roughness: 0,
reflectivity: 0.5,
thickness: 0.01,
specularIntensity: 1,
specularTint: 0xffffff,
envMapIntensity: 1,
lightIntensity: 1,
exposure: 1
Expand Down Expand Up @@ -89,6 +91,8 @@
envMap: hdrEquirect,
envMapIntensity: params.envMapIntensity,
transmission: params.transmission, // use material.transmission for glass materials
specularIntensity: params.specularIntensity,
specularTint: params.specularTint,
opacity: params.opacity,
side: THREE.DoubleSide,
transparent: true
Expand Down Expand Up @@ -166,6 +170,22 @@

} );

gui.add( params, 'specularIntensity', 0, 1, 0.01 )
.onChange( function () {

material.specularIntensity = params.specularIntensity;
render();

} );

gui.addColor( params, 'specularTint' )
.onChange( function () {

material.specularTint.set( params.specularTint );
render();

} );

gui.add( params, 'envMapIntensity', 0, 1, 0.01 )
.name( 'envMap intensity' )
.onChange( function () {
Expand Down
4 changes: 4 additions & 0 deletions src/loaders/MaterialLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class MaterialLoader extends Loader {
if ( json.sheen !== undefined ) material.sheen = new Color().setHex( json.sheen );
if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );
if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );
if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;
if ( json.specularTint !== undefined && material.specularTint !== undefined ) material.specularTint.setHex( json.specularTint );
if ( json.shininess !== undefined ) material.shininess = json.shininess;
if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
Expand Down Expand Up @@ -258,6 +260,8 @@ class MaterialLoader extends Loader {
if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;

if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );
if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );
if ( json.specularTintMap !== undefined ) material.specularTintMap = getTexture( json.specularTintMap );

if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );
if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;
Expand Down
4 changes: 4 additions & 0 deletions src/materials/Material.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ class Material extends EventDispatcher {
if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;

if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
if ( this.specularTint && this.specularTint.isColor ) data.specularTint = this.specularTint.getHex();
if ( this.shininess !== undefined ) data.shininess = this.shininess;
if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
Expand Down Expand Up @@ -243,6 +245,8 @@ class Material extends EventDispatcher {

if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
if ( this.specularTintMap && this.specularTintMap.isTexture ) data.specularTintMap = this.specularTintMap.toJSON( meta ).uuid;

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

Expand Down
17 changes: 16 additions & 1 deletion src/materials/MeshPhysicalMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ import * as MathUtils from '../math/MathUtils.js';
* thickness: <float>,
* thicknessMap: new THREE.Texture( <Image> ),
* attenuationDistance: <float>,
* attenuationColor: <Color>
* attenuationColor: <Color>,
*
* specularIntensity: <float>,
* specularIntensityhMap: new THREE.Texture( <Image> ),
* specularTint: <Color>,
* specularTintMap: new THREE.Texture( <Image> )
* }
*/

Expand Down Expand Up @@ -74,6 +79,11 @@ class MeshPhysicalMaterial extends MeshStandardMaterial {
this.attenuationDistance = 0.0;
this.attenuationColor = new Color( 1, 1, 1 );

this.specularIntensity = 1.0;
this.specularIntensityMap = null;
this.specularTint = new Color( 1, 1, 1 );
this.specularTintMap = null;

this.setValues( parameters );

}
Expand Down Expand Up @@ -116,6 +126,11 @@ class MeshPhysicalMaterial extends MeshStandardMaterial {
this.attenuationDistance = source.attenuationDistance;
this.attenuationColor.copy( source.attenuationColor );

this.specularIntensity = source.specularIntensity;
this.specularIntensityMap = source.specularIntensityMap;
this.specularTint.copy( source.specularTint );
this.specularTintMap = source.specularTintMap;

return this;

}
Expand Down
10 changes: 5 additions & 5 deletions src/renderers/shaders/ShaderChunk/bsdfs.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ vec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {

} // validated

vec3 F_Schlick( const in vec3 specularColor, const in float dotVH ) {
vec3 F_Schlick( const in vec3 f0, const in vec3 f90, const in float dotVH ) {

// Original approximation by Christophe Schlick '94
// float fresnel = pow( 1.0 - dotVH, 5.0 );
Expand All @@ -65,7 +65,7 @@ vec3 F_Schlick( const in vec3 specularColor, const in float dotVH ) {
// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
float fresnel = exp2( ( -5.55473 * dotVH - 6.98316 ) * dotVH );

return ( 1.0 - specularColor ) * fresnel + specularColor;
return ( f90 - f0 ) * fresnel + f0;

} // validated

Expand Down Expand Up @@ -125,7 +125,7 @@ float D_GGX( const in float alpha, const in float dotNH ) {
}

// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility
vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {
vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in vec3 f90, const in float roughness ) {

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

Expand All @@ -136,7 +136,7 @@ vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 view
float dotNH = saturate( dot( normal, halfDir ) );
float dotLH = saturate( dot( incidentLight.direction, halfDir ) );

vec3 F = F_Schlick( specularColor, dotLH );
vec3 F = F_Schlick( f0, f90, dotLH );

float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );

Expand Down Expand Up @@ -318,7 +318,7 @@ vec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in Ge
float dotNH = saturate( dot( geometry.normal, halfDir ) );
float dotLH = saturate( dot( incidentLight.direction, halfDir ) );

vec3 F = F_Schlick( specularColor, dotLH );
vec3 F = F_Schlick( specularColor, vec3( 1.0 ), dotLH );

float G = G_BlinnPhong_Implicit( /* dotNL, dotNV */ );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,39 @@ material.specularRoughness = min( material.specularRoughness, 1.0 );

#ifdef REFLECTIVITY

material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );
#ifdef SPECULAR

vec3 specularIntensityFactor = vec3( specularIntensity );
vec3 specularTintFactor = specularTint;

#ifdef USE_SPECULARINTENSITYMAP

specularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;

#endif

#ifdef USE_SPECULARTINTMAP

specularTintFactor *= specularTintMapTexelToLinear( texture2D( specularTintMap, vUv ) ).rgb;

#endif

material.specularColorF90 = mix( specularIntensityFactor, vec3( 1.0 ), metalnessFactor );

#else

vec3 specularIntensityFactor = vec3( 1.0 );
vec3 specularTintFactor = vec3( 1.0 );
material.specularColorF90 = vec3( 1.0 );

#endif

material.specularColor = mix( min( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ) * specularTintFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );

#else

material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );
material.specularColorF90 = vec3( 1.0 );

#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ struct PhysicalMaterial {
vec3 diffuseColor;
float specularRoughness;
vec3 specularColor;
vec3 specularColorF90;

#ifdef CLEARCOAT
float clearcoat;
Expand Down Expand Up @@ -93,7 +94,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC

float clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );

reflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );
reflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), vec3( 1.0 ), material.clearcoatRoughness );

#else

Expand All @@ -109,7 +110,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
material.sheenColor
);
#else
reflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);
reflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularColorF90, material.specularRoughness);
#endif

reflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
Expand Down
Loading