diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index c06171be28449b..1d075284f68d61 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -603,6 +603,158 @@ THREE.GLTFLoader = ( function () { * * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness */ + + /** + * A sub class of THREE.StandardMaterial with some of the functionality + * changed via the `onBeforeCompile` callback + * @pailhead + */ + + function GLTFMeshStandardSGMaterial( params ) { + + THREE.MeshStandardMaterial.call( this ); + + this.isGLTFSpecularGlossinessMaterial = true; + + //various chunks that need replacing + var specularMapParsFragmentChunk = [ + '#ifdef USE_SPECULARMAP', + ' uniform sampler2D specularMap;', + '#endif' + ].join( '\n' ); + + var glossinessMapParsFragmentChunk = [ + '#ifdef USE_GLOSSINESSMAP', + ' uniform sampler2D glossinessMap;', + '#endif' + ].join( '\n' ); + + var specularMapFragmentChunk = [ + 'vec3 specularFactor = specular;', + '#ifdef USE_SPECULARMAP', + ' vec4 texelSpecular = texture2D( specularMap, vUv );', + ' texelSpecular = sRGBToLinear( texelSpecular );', + ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' specularFactor *= texelSpecular.rgb;', + '#endif' + ].join( '\n' ); + + var glossinessMapFragmentChunk = [ + 'float glossinessFactor = glossiness;', + '#ifdef USE_GLOSSINESSMAP', + ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', + ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' glossinessFactor *= texelGlossiness.a;', + '#endif' + ].join( '\n' ); + + var lightPhysicalFragmentChunk = [ + 'PhysicalMaterial material;', + 'material.diffuseColor = diffuseColor.rgb;', + 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', + 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );', + 'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.', + 'material.specularRoughness += geometryRoughness;', + 'material.specularRoughness = min( material.specularRoughness, 1.0 );', + 'material.specularColor = specularFactor.rgb;', + ].join( '\n' ); + + var uniforms = { + specular: { value: new THREE.Color().setHex( 0xffffff ) }, + glossiness: { value: 1 }, + specularMap: { value: null }, + glossinessMap: { value: null } + }; + + this._extraUniforms = uniforms; + + // please see #14031 or #13198 for an alternate approach + this.onBeforeCompile = function ( shader ) { + + for ( var uniformName in uniforms ) { + + shader.uniforms[ uniformName ] = uniforms[ uniformName ]; + + } + + shader.fragmentShader = shader.fragmentShader.replace( 'uniform float roughness;', 'uniform vec3 specular;' ); + shader.fragmentShader = shader.fragmentShader.replace( 'uniform float metalness;', 'uniform float glossiness;' ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', specularMapParsFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', glossinessMapParsFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', specularMapFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', glossinessMapFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', lightPhysicalFragmentChunk ); + + }; + + /*eslint-disable*/ + Object.defineProperties( + this, + { + specular: { + get: function () { return uniforms.specular.value; }, + set: function ( v ) { uniforms.specular.value = v; } + }, + specularMap: { + get: function () { return uniforms.specularMap.value; }, + set: function ( v ) { uniforms.specularMap.value = v; } + }, + glossiness: { + get: function () { return uniforms.glossiness.value; }, + set: function ( v ) { uniforms.glossiness.value = v; } + }, + glossinessMap: { + get: function () { return uniforms.glossinessMap.value; }, + set: function ( v ) { + + uniforms.glossinessMap.value = v; + //how about something like this - @pailhead + if ( v ) { + + this.defines.USE_GLOSSINESSMAP = ''; + // set USE_ROUGHNESSMAP to enable vUv + this.defines.USE_ROUGHNESSMAP = ''; + + } else { + + delete this.defines.USE_ROUGHNESSMAP; + delete this.defines.USE_GLOSSINESSMAP; + + } + + } + } + } + ); + + /*eslint-enable*/ + delete this.metalness; + delete this.roughness; + delete this.metalnessMap; + delete this.roughnessMap; + + this.setValues( params ); + + } + + GLTFMeshStandardSGMaterial.prototype = Object.create( THREE.MeshStandardMaterial.prototype ); + GLTFMeshStandardSGMaterial.prototype.constructor = GLTFMeshStandardSGMaterial; + + GLTFMeshStandardSGMaterial.prototype.copy = function ( source ) { + + THREE.MeshStandardMaterial.prototype.copy.call( this, source ); + this.specularMap = source.specularMap; + this.specular.copy( source.specular ); + this.glossinessMap = source.glossinessMap; + this.glossiness = source.glossiness; + delete this.metalness; + delete this.roughness; + delete this.metalnessMap; + delete this.roughnessMap; + return this; + + }; + function GLTFMaterialsPbrSpecularGlossinessExtension() { return { @@ -638,7 +790,7 @@ THREE.GLTFLoader = ( function () { getMaterialType: function () { - return THREE.ShaderMaterial; + return GLTFMeshStandardSGMaterial; }, @@ -646,76 +798,6 @@ THREE.GLTFLoader = ( function () { var pbrSpecularGlossiness = materialDef.extensions[ this.name ]; - var shader = THREE.ShaderLib[ 'standard' ]; - - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - var specularMapParsFragmentChunk = [ - '#ifdef USE_SPECULARMAP', - ' uniform sampler2D specularMap;', - '#endif' - ].join( '\n' ); - - var glossinessMapParsFragmentChunk = [ - '#ifdef USE_GLOSSINESSMAP', - ' uniform sampler2D glossinessMap;', - '#endif' - ].join( '\n' ); - - var specularMapFragmentChunk = [ - 'vec3 specularFactor = specular;', - '#ifdef USE_SPECULARMAP', - ' vec4 texelSpecular = texture2D( specularMap, vUv );', - ' texelSpecular = sRGBToLinear( texelSpecular );', - ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' specularFactor *= texelSpecular.rgb;', - '#endif' - ].join( '\n' ); - - var glossinessMapFragmentChunk = [ - 'float glossinessFactor = glossiness;', - '#ifdef USE_GLOSSINESSMAP', - ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', - ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' glossinessFactor *= texelGlossiness.a;', - '#endif' - ].join( '\n' ); - - var lightPhysicalFragmentChunk = [ - 'PhysicalMaterial material;', - 'material.diffuseColor = diffuseColor.rgb;', - 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', - 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );', - 'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.', - 'material.specularRoughness += geometryRoughness;', - 'material.specularRoughness = min( material.specularRoughness, 1.0 );', - 'material.specularColor = specularFactor.rgb;', - ].join( '\n' ); - - var fragmentShader = shader.fragmentShader - .replace( 'uniform float roughness;', 'uniform vec3 specular;' ) - .replace( 'uniform float metalness;', 'uniform float glossiness;' ) - .replace( '#include ', specularMapParsFragmentChunk ) - .replace( '#include ', glossinessMapParsFragmentChunk ) - .replace( '#include ', specularMapFragmentChunk ) - .replace( '#include ', glossinessMapFragmentChunk ) - .replace( '#include ', lightPhysicalFragmentChunk ); - - delete uniforms.roughness; - delete uniforms.metalness; - delete uniforms.roughnessMap; - delete uniforms.metalnessMap; - - uniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) }; - uniforms.glossiness = { value: 0.5 }; - uniforms.specularMap = { value: null }; - uniforms.glossinessMap = { value: null }; - - materialParams.vertexShader = shader.vertexShader; - materialParams.fragmentShader = fragmentShader; - materialParams.uniforms = uniforms; - materialParams.defines = { 'STANDARD': '' }; - materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 ); materialParams.opacity = 1.0; @@ -758,233 +840,54 @@ THREE.GLTFLoader = ( function () { }, - createMaterial: function ( params ) { - - // setup material properties based on MeshStandardMaterial for Specular-Glossiness - - var material = new THREE.ShaderMaterial( { - defines: params.defines, - vertexShader: params.vertexShader, - fragmentShader: params.fragmentShader, - uniforms: params.uniforms, - fog: true, - lights: true, - opacity: params.opacity, - transparent: params.transparent - } ); + createMaterial: function ( materialParams ) { - material.isGLTFSpecularGlossinessMaterial = true; + var material = new GLTFMeshStandardSGMaterial( materialParams ); + material.fog = true; - material.color = params.color; + material.color = materialParams.color; - material.map = params.map === undefined ? null : params.map; + material.map = materialParams.map === undefined ? null : materialParams.map; material.lightMap = null; material.lightMapIntensity = 1.0; - material.aoMap = params.aoMap === undefined ? null : params.aoMap; + material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap; material.aoMapIntensity = 1.0; - material.emissive = params.emissive; + material.emissive = materialParams.emissive; material.emissiveIntensity = 1.0; - material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap; + material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap; - material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap; + material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap; material.bumpScale = 1; - material.normalMap = params.normalMap === undefined ? null : params.normalMap; + material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap; material.normalMapType = THREE.TangentSpaceNormalMap; - if ( params.normalScale ) material.normalScale = params.normalScale; + if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale; material.displacementMap = null; material.displacementScale = 1; material.displacementBias = 0; - material.specularMap = params.specularMap === undefined ? null : params.specularMap; - material.specular = params.specular; + material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap; + material.specular = materialParams.specular; - material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap; - material.glossiness = params.glossiness; + material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap; + material.glossiness = materialParams.glossiness; material.alphaMap = null; - material.envMap = params.envMap === undefined ? null : params.envMap; + material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap; material.envMapIntensity = 1.0; material.refractionRatio = 0.98; - material.extensions.derivatives = true; - return material; }, - /** - * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can - * copy only properties it knows about or inherits, and misses many properties that would - * normally be defined by MeshStandardMaterial. - * - * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of - * loading a glTF model, but cloning later (e.g. by the user) would require these changes - * AND also updating `.onBeforeRender` on the parent mesh. - * - * @param {THREE.ShaderMaterial} source - * @return {THREE.ShaderMaterial} - */ - cloneMaterial: function ( source ) { - - var target = source.clone(); - - target.isGLTFSpecularGlossinessMaterial = true; - - var params = this.specularGlossinessParams; - - for ( var i = 0, il = params.length; i < il; i ++ ) { - - var value = source[ params[ i ] ]; - target[ params[ i ] ] = ( value && value.isColor ) ? value.clone() : value; - - } - - return target; - - }, - - // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer. - refreshUniforms: function ( renderer, scene, camera, geometry, material ) { - - if ( material.isGLTFSpecularGlossinessMaterial !== true ) { - - return; - - } - - var uniforms = material.uniforms; - var defines = material.defines; - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value.copy( material.color ); - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - uniforms.map.value = material.map; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; - - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map - - var uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.glossinessMap ) { - - uvScaleMap = material.glossinessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - if ( material.envMap ) { - - uniforms.envMap.value = material.envMap; - uniforms.envMapIntensity.value = material.envMapIntensity; - - uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; - - uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel; - - } - - uniforms.specular.value.copy( material.specular ); - uniforms.glossiness.value = material.glossiness; - - uniforms.glossinessMap.value = material.glossinessMap; - - uniforms.emissiveMap.value = material.emissiveMap; - uniforms.bumpMap.value = material.bumpMap; - uniforms.normalMap.value = material.normalMap; - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) { - - defines.USE_GLOSSINESSMAP = ''; - // set USE_ROUGHNESSMAP to enable vUv - defines.USE_ROUGHNESSMAP = ''; - - } - - if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) { - - delete defines.USE_GLOSSINESSMAP; - delete defines.USE_ROUGHNESSMAP; - - } - - } - }; } @@ -2079,9 +1982,7 @@ THREE.GLTFLoader = ( function () { if ( ! cachedMaterial ) { - cachedMaterial = material.isGLTFSpecularGlossinessMaterial - ? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material ) - : material.clone(); + cachedMaterial = material.clone(); if ( useSkinning ) cachedMaterial.skinning = true; if ( useVertexTangents ) cachedMaterial.vertexTangents = true; @@ -2106,13 +2007,6 @@ THREE.GLTFLoader = ( function () { } - if ( material.isGLTFSpecularGlossinessMaterial ) { - - // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update - mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms; - - } - // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 if ( material.normalScale && ! useVertexTangents ) { @@ -2259,7 +2153,7 @@ THREE.GLTFLoader = ( function () { var material; - if ( materialType === THREE.ShaderMaterial ) { + if ( materialType === GLTFMeshStandardSGMaterial ) { material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams ); @@ -2274,7 +2168,6 @@ THREE.GLTFLoader = ( function () { // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. if ( material.map ) material.map.encoding = THREE.sRGBEncoding; if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding; - if ( material.specularMap ) material.specularMap.encoding = THREE.sRGBEncoding; assignExtrasToUserData( material, materialDef ); @@ -3023,16 +2916,6 @@ THREE.GLTFLoader = ( function () { node = mesh.clone(); node.name += '_instance_' + instanceNum; - // onBeforeRender copy for Specular-Glossiness - node.onBeforeRender = mesh.onBeforeRender; - - for ( var i = 0, il = node.children.length; i < il; i ++ ) { - - node.children[ i ].name += '_instance_' + instanceNum; - node.children[ i ].onBeforeRender = mesh.children[ i ].onBeforeRender; - - } - } else { node = mesh; diff --git a/examples/jsm/loaders/GLTFLoader.js b/examples/jsm/loaders/GLTFLoader.js index 78520334af96f8..463539cbfaee8a 100644 --- a/examples/jsm/loaders/GLTFLoader.js +++ b/examples/jsm/loaders/GLTFLoader.js @@ -56,8 +56,6 @@ import { RGBFormat, RepeatWrapping, Scene, - ShaderLib, - ShaderMaterial, Skeleton, SkinnedMesh, Sphere, @@ -66,7 +64,6 @@ import { TextureLoader, TriangleFanDrawMode, TriangleStripDrawMode, - UniformsUtils, Vector2, Vector3, VectorKeyframeTrack, @@ -671,6 +668,158 @@ var GLTFLoader = ( function () { * * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness */ + + /** + * A sub class of StandardMaterial with some of the functionality + * changed via the `onBeforeCompile` callback + * @pailhead + */ + + function GLTFMeshStandardSGMaterial( params ) { + + MeshStandardMaterial.call( this ); + + this.isGLTFSpecularGlossinessMaterial = true; + + //various chunks that need replacing + var specularMapParsFragmentChunk = [ + '#ifdef USE_SPECULARMAP', + ' uniform sampler2D specularMap;', + '#endif' + ].join( '\n' ); + + var glossinessMapParsFragmentChunk = [ + '#ifdef USE_GLOSSINESSMAP', + ' uniform sampler2D glossinessMap;', + '#endif' + ].join( '\n' ); + + var specularMapFragmentChunk = [ + 'vec3 specularFactor = specular;', + '#ifdef USE_SPECULARMAP', + ' vec4 texelSpecular = texture2D( specularMap, vUv );', + ' texelSpecular = sRGBToLinear( texelSpecular );', + ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' specularFactor *= texelSpecular.rgb;', + '#endif' + ].join( '\n' ); + + var glossinessMapFragmentChunk = [ + 'float glossinessFactor = glossiness;', + '#ifdef USE_GLOSSINESSMAP', + ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', + ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' glossinessFactor *= texelGlossiness.a;', + '#endif' + ].join( '\n' ); + + var lightPhysicalFragmentChunk = [ + 'PhysicalMaterial material;', + 'material.diffuseColor = diffuseColor.rgb;', + 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', + 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );', + 'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.', + 'material.specularRoughness += geometryRoughness;', + 'material.specularRoughness = min( material.specularRoughness, 1.0 );', + 'material.specularColor = specularFactor.rgb;', + ].join( '\n' ); + + var uniforms = { + specular: { value: new Color().setHex( 0xffffff ) }, + glossiness: { value: 1 }, + specularMap: { value: null }, + glossinessMap: { value: null } + }; + + this._extraUniforms = uniforms; + + // please see #14031 or #13198 for an alternate approach + this.onBeforeCompile = function ( shader ) { + + for ( var uniformName in uniforms ) { + + shader.uniforms[ uniformName ] = uniforms[ uniformName ]; + + } + + shader.fragmentShader = shader.fragmentShader.replace( 'uniform float roughness;', 'uniform vec3 specular;' ); + shader.fragmentShader = shader.fragmentShader.replace( 'uniform float metalness;', 'uniform float glossiness;' ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', specularMapParsFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', glossinessMapParsFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', specularMapFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', glossinessMapFragmentChunk ); + shader.fragmentShader = shader.fragmentShader.replace( '#include ', lightPhysicalFragmentChunk ); + + }; + + /*eslint-disable*/ + Object.defineProperties( + this, + { + specular: { + get: function () { return uniforms.specular.value; }, + set: function ( v ) { uniforms.specular.value = v; } + }, + specularMap: { + get: function () { return uniforms.specularMap.value; }, + set: function ( v ) { uniforms.specularMap.value = v; } + }, + glossiness: { + get: function () { return uniforms.glossiness.value; }, + set: function ( v ) { uniforms.glossiness.value = v; } + }, + glossinessMap: { + get: function () { return uniforms.glossinessMap.value; }, + set: function ( v ) { + + uniforms.glossinessMap.value = v; + //how about something like this - @pailhead + if ( v ) { + + this.defines.USE_GLOSSINESSMAP = ''; + // set USE_ROUGHNESSMAP to enable vUv + this.defines.USE_ROUGHNESSMAP = ''; + + } else { + + delete this.defines.USE_ROUGHNESSMAP; + delete this.defines.USE_GLOSSINESSMAP; + + } + + } + } + } + ); + + /*eslint-enable*/ + delete this.metalness; + delete this.roughness; + delete this.metalnessMap; + delete this.roughnessMap; + + this.setValues( params ); + + } + + GLTFMeshStandardSGMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); + GLTFMeshStandardSGMaterial.prototype.constructor = GLTFMeshStandardSGMaterial; + + GLTFMeshStandardSGMaterial.prototype.copy = function ( source ) { + + MeshStandardMaterial.prototype.copy.call( this, source ); + this.specularMap = source.specularMap; + this.specular.copy( source.specular ); + this.glossinessMap = source.glossinessMap; + this.glossiness = source.glossiness; + delete this.metalness; + delete this.roughness; + delete this.metalnessMap; + delete this.roughnessMap; + return this; + + }; + function GLTFMaterialsPbrSpecularGlossinessExtension() { return { @@ -706,7 +855,7 @@ var GLTFLoader = ( function () { getMaterialType: function () { - return ShaderMaterial; + return GLTFMeshStandardSGMaterial; }, @@ -714,76 +863,6 @@ var GLTFLoader = ( function () { var pbrSpecularGlossiness = materialDef.extensions[ this.name ]; - var shader = ShaderLib[ 'standard' ]; - - var uniforms = UniformsUtils.clone( shader.uniforms ); - - var specularMapParsFragmentChunk = [ - '#ifdef USE_SPECULARMAP', - ' uniform sampler2D specularMap;', - '#endif' - ].join( '\n' ); - - var glossinessMapParsFragmentChunk = [ - '#ifdef USE_GLOSSINESSMAP', - ' uniform sampler2D glossinessMap;', - '#endif' - ].join( '\n' ); - - var specularMapFragmentChunk = [ - 'vec3 specularFactor = specular;', - '#ifdef USE_SPECULARMAP', - ' vec4 texelSpecular = texture2D( specularMap, vUv );', - ' texelSpecular = sRGBToLinear( texelSpecular );', - ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' specularFactor *= texelSpecular.rgb;', - '#endif' - ].join( '\n' ); - - var glossinessMapFragmentChunk = [ - 'float glossinessFactor = glossiness;', - '#ifdef USE_GLOSSINESSMAP', - ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', - ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' glossinessFactor *= texelGlossiness.a;', - '#endif' - ].join( '\n' ); - - var lightPhysicalFragmentChunk = [ - 'PhysicalMaterial material;', - 'material.diffuseColor = diffuseColor.rgb;', - 'vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );', - 'float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );', - 'material.specularRoughness = max( 1.0 - glossinessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap.', - 'material.specularRoughness += geometryRoughness;', - 'material.specularRoughness = min( material.specularRoughness, 1.0 );', - 'material.specularColor = specularFactor.rgb;', - ].join( '\n' ); - - var fragmentShader = shader.fragmentShader - .replace( 'uniform float roughness;', 'uniform vec3 specular;' ) - .replace( 'uniform float metalness;', 'uniform float glossiness;' ) - .replace( '#include ', specularMapParsFragmentChunk ) - .replace( '#include ', glossinessMapParsFragmentChunk ) - .replace( '#include ', specularMapFragmentChunk ) - .replace( '#include ', glossinessMapFragmentChunk ) - .replace( '#include ', lightPhysicalFragmentChunk ); - - delete uniforms.roughness; - delete uniforms.metalness; - delete uniforms.roughnessMap; - delete uniforms.metalnessMap; - - uniforms.specular = { value: new Color().setHex( 0x111111 ) }; - uniforms.glossiness = { value: 0.5 }; - uniforms.specularMap = { value: null }; - uniforms.glossinessMap = { value: null }; - - materialParams.vertexShader = shader.vertexShader; - materialParams.fragmentShader = fragmentShader; - materialParams.uniforms = uniforms; - materialParams.defines = { 'STANDARD': '' }; - materialParams.color = new Color( 1.0, 1.0, 1.0 ); materialParams.opacity = 1.0; @@ -826,233 +905,54 @@ var GLTFLoader = ( function () { }, - createMaterial: function ( params ) { - - // setup material properties based on MeshStandardMaterial for Specular-Glossiness - - var material = new ShaderMaterial( { - defines: params.defines, - vertexShader: params.vertexShader, - fragmentShader: params.fragmentShader, - uniforms: params.uniforms, - fog: true, - lights: true, - opacity: params.opacity, - transparent: params.transparent - } ); + createMaterial: function ( materialParams ) { - material.isGLTFSpecularGlossinessMaterial = true; + var material = new GLTFMeshStandardSGMaterial( materialParams ); + material.fog = true; - material.color = params.color; + material.color = materialParams.color; - material.map = params.map === undefined ? null : params.map; + material.map = materialParams.map === undefined ? null : materialParams.map; material.lightMap = null; material.lightMapIntensity = 1.0; - material.aoMap = params.aoMap === undefined ? null : params.aoMap; + material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap; material.aoMapIntensity = 1.0; - material.emissive = params.emissive; + material.emissive = materialParams.emissive; material.emissiveIntensity = 1.0; - material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap; + material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap; - material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap; + material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap; material.bumpScale = 1; - material.normalMap = params.normalMap === undefined ? null : params.normalMap; + material.normalMap = materialParams.normalMap === undefined ? null : materialParams.normalMap; material.normalMapType = TangentSpaceNormalMap; - if ( params.normalScale ) material.normalScale = params.normalScale; + if ( materialParams.normalScale ) material.normalScale = materialParams.normalScale; material.displacementMap = null; material.displacementScale = 1; material.displacementBias = 0; - material.specularMap = params.specularMap === undefined ? null : params.specularMap; - material.specular = params.specular; + material.specularMap = materialParams.specularMap === undefined ? null : materialParams.specularMap; + material.specular = materialParams.specular; - material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap; - material.glossiness = params.glossiness; + material.glossinessMap = materialParams.glossinessMap === undefined ? null : materialParams.glossinessMap; + material.glossiness = materialParams.glossiness; material.alphaMap = null; - material.envMap = params.envMap === undefined ? null : params.envMap; + material.envMap = materialParams.envMap === undefined ? null : materialParams.envMap; material.envMapIntensity = 1.0; material.refractionRatio = 0.98; - material.extensions.derivatives = true; - return material; }, - /** - * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can - * copy only properties it knows about or inherits, and misses many properties that would - * normally be defined by MeshStandardMaterial. - * - * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of - * loading a glTF model, but cloning later (e.g. by the user) would require these changes - * AND also updating `.onBeforeRender` on the parent mesh. - * - * @param {ShaderMaterial} source - * @return {ShaderMaterial} - */ - cloneMaterial: function ( source ) { - - var target = source.clone(); - - target.isGLTFSpecularGlossinessMaterial = true; - - var params = this.specularGlossinessParams; - - for ( var i = 0, il = params.length; i < il; i ++ ) { - - var value = source[ params[ i ] ]; - target[ params[ i ] ] = ( value && value.isColor ) ? value.clone() : value; - - } - - return target; - - }, - - // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer. - refreshUniforms: function ( renderer, scene, camera, geometry, material ) { - - if ( material.isGLTFSpecularGlossinessMaterial !== true ) { - - return; - - } - - var uniforms = material.uniforms; - var defines = material.defines; - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value.copy( material.color ); - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - uniforms.map.value = material.map; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; - - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map - - var uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.glossinessMap ) { - - uvScaleMap = material.glossinessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - if ( material.envMap ) { - - uniforms.envMap.value = material.envMap; - uniforms.envMapIntensity.value = material.envMapIntensity; - - uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; - - uniforms.maxMipLevel.value = renderer.properties.get( material.envMap ).__maxMipLevel; - - } - - uniforms.specular.value.copy( material.specular ); - uniforms.glossiness.value = material.glossiness; - - uniforms.glossinessMap.value = material.glossinessMap; - - uniforms.emissiveMap.value = material.emissiveMap; - uniforms.bumpMap.value = material.bumpMap; - uniforms.normalMap.value = material.normalMap; - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) { - - defines.USE_GLOSSINESSMAP = ''; - // set USE_ROUGHNESSMAP to enable vUv - defines.USE_ROUGHNESSMAP = ''; - - } - - if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) { - - delete defines.USE_GLOSSINESSMAP; - delete defines.USE_ROUGHNESSMAP; - - } - - } - }; } @@ -2147,9 +2047,7 @@ var GLTFLoader = ( function () { if ( ! cachedMaterial ) { - cachedMaterial = material.isGLTFSpecularGlossinessMaterial - ? extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].cloneMaterial( material ) - : material.clone(); + cachedMaterial = material.clone(); if ( useSkinning ) cachedMaterial.skinning = true; if ( useVertexTangents ) cachedMaterial.vertexTangents = true; @@ -2174,13 +2072,6 @@ var GLTFLoader = ( function () { } - if ( material.isGLTFSpecularGlossinessMaterial ) { - - // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update - mesh.onBeforeRender = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].refreshUniforms; - - } - // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 if ( material.normalScale && ! useVertexTangents ) { @@ -2327,7 +2218,7 @@ var GLTFLoader = ( function () { var material; - if ( materialType === ShaderMaterial ) { + if ( materialType === GLTFMeshStandardSGMaterial ) { material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams ); @@ -2342,7 +2233,6 @@ var GLTFLoader = ( function () { // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. if ( material.map ) material.map.encoding = sRGBEncoding; if ( material.emissiveMap ) material.emissiveMap.encoding = sRGBEncoding; - if ( material.specularMap ) material.specularMap.encoding = sRGBEncoding; assignExtrasToUserData( material, materialDef ); @@ -3091,16 +2981,6 @@ var GLTFLoader = ( function () { node = mesh.clone(); node.name += '_instance_' + instanceNum; - // onBeforeRender copy for Specular-Glossiness - node.onBeforeRender = mesh.onBeforeRender; - - for ( var i = 0, il = node.children.length; i < il; i ++ ) { - - node.children[ i ].name += '_instance_' + instanceNum; - node.children[ i ].onBeforeRender = mesh.children[ i ].onBeforeRender; - - } - } else { node = mesh;