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

GLTFLoader: Implement KHR_texture_transform extension. #13831

Merged
merged 6 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 18 additions & 6 deletions docs/examples/loaders/GLTFLoader.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,20 @@ <h2>Extensions</h2>
<li>KHR_materials_pbrSpecularGlossiness</li>
<li>KHR_materials_unlit</li>
<li>KHR_lights_punctual (experimental)</li>
<li>KHR_texture_transform<sup>*</sup></li>
<li>MSFT_texture_dds</li>
</ul>

<p><i>
<sup>*</sup>UV transforms are supported, with several key limitations. Transforms applied to
a texture using the first UV slot (all textures except aoMap and lightMap) must share the same
transform, or no transfor at all. The aoMap and lightMap textures cannot be transformed. No
more than one transform may be used per material. Each use of a texture with a unique
transform will result in an additional GPU texture upload. See
#[link:https://github.com/mrdoob/three.js/pull/13831 13831] and
#[link:https://github.com/mrdoob/three.js/issues/12788 12788].
</i></p>

<h2>Example</h2>

<code>
Expand Down Expand Up @@ -85,30 +97,30 @@ <h2>Browser compatibility</h2>
providing a Promise replacement.</p>

<h2>Textures</h2>

<p>Textures containing color information (.map, .emissiveMap, and .specularMap) always use sRGB colorspace in
glTF, while vertex colors and material properties (.color, .emissive, .specular) use linear colorspace. In a
typical rendering workflow, textures are converted to linear colorspace by the renderer, lighting calculations
are made, then final output is converted back to sRGB and displayed on screen. Unless you need post-processing
in linear colorspace, always configure [page:WebGLRenderer] as follows when using glTF:</p>

<code>
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2;
</code>

<p>GLTFLoader will automatically configure textures referenced from a .gltf or .glb file correctly, with the
assumption that the renderer is set up as shown above. When loading textures externally (e.g., using
[page:TextureLoader]) and applying them to a glTF model, colorspace and orientation must be given:</p>

<code>
// If texture is used for color information, set colorspace.
texture.encoding = THREE.sRGBEncoding;

// UVs use the convention that (0, 0) corresponds to the upper left corner of a texture.
texture.flipY = false;
</code>
</code>

<h2>Custom extensions</h2>

<p>
Expand Down
11 changes: 11 additions & 0 deletions docs/page.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,14 @@ span.param {
a.param:hover {
color: #777;
}

sup, sub {
/* prevent superscript and subscript elements from affecting line-height */
vertical-align: baseline;
position: relative;
top: -0.4em;
}

sub {
top: 0.4em;
}
103 changes: 83 additions & 20 deletions examples/js/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,19 @@ THREE.GLTFLoader = ( function () {
break;

case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
break;

case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
extensions[ extensionName ] = new GLTFDracoMeshCompressionExtension( json, this.dracoLoader );
break;

case EXTENSIONS.MSFT_TEXTURE_DDS:
extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension( json );
break;

case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
break;

default:
Expand Down Expand Up @@ -282,6 +286,7 @@ THREE.GLTFLoader = ( function () {
KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
};

Expand Down Expand Up @@ -409,7 +414,7 @@ THREE.GLTFLoader = ( function () {

if ( metallicRoughness.baseColorTexture !== undefined ) {

pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );

}

Expand Down Expand Up @@ -563,6 +568,51 @@ THREE.GLTFLoader = ( function () {

};

/**
* Texture Transform Extension
*
* Specification:
*/
function GLTFTextureTransformExtension( json ) {

this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;

}

GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) {

texture = texture.clone();

if ( transform.offset !== undefined ) {

texture.offset.fromArray( transform.offset );

}

if ( transform.rotation !== undefined ) {

texture.rotation = transform.rotation;

}

if ( transform.scale !== undefined ) {

texture.repeat.fromArray( transform.scale );

}

if ( transform.texCoord !== undefined ) {

console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );

}

texture.needsUpdate = true;

return texture;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

@donmccurdy donmccurdy Aug 7, 2018

Choose a reason for hiding this comment

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

Yeah, I forgot that could be overridden. But I'm not sure how we should handle it at this stage... all we can really do is print a warning, except in very lucky cases where we can just swap the UV orders.

I think we should just log a warning for now, and if #14572 is merged (not ready yet) we can actually handle this correctly when useNodes=true.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed with warning for now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added the warning. 👍


};

/**
* Specular-Glossiness Extension
*
Expand Down Expand Up @@ -692,7 +742,7 @@ THREE.GLTFLoader = ( function () {

if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {

pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture.index ) );
pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture ) );

}

Expand All @@ -708,9 +758,9 @@ THREE.GLTFLoader = ( function () {

if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {

var specGlossIndex = pbrSpecularGlossiness.specularGlossinessTexture.index;
pending.push( parser.assignTexture( params, 'glossinessMap', specGlossIndex ) );
pending.push( parser.assignTexture( params, 'specularMap', specGlossIndex ) );
var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
pending.push( parser.assignTexture( params, 'glossinessMap', specGlossMapDef ) );
pending.push( parser.assignTexture( params, 'specularMap', specGlossMapDef ) );

}

Expand Down Expand Up @@ -2146,15 +2196,29 @@ THREE.GLTFLoader = ( function () {
/**
* Asynchronously assigns a texture to the given material parameters.
* @param {Object} materialParams
* @param {string} textureName
* @param {number} textureIndex
* @return {Promise<THREE.Texture>}
* @param {string} mapName
* @param {Object} mapDef
* @return {Promise}
*/
GLTFParser.prototype.assignTexture = function ( materialParams, textureName, textureIndex ) {
GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) {

var parser = this;

return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {

if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {

var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;

return this.getDependency( 'texture', textureIndex ).then( function ( texture ) {
if ( transform ) {

texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );

}

}

materialParams[ textureName ] = texture;
materialParams[ mapName ] = texture;

} );

Expand Down Expand Up @@ -2213,7 +2277,7 @@ THREE.GLTFLoader = ( function () {

if ( metallicRoughness.baseColorTexture !== undefined ) {

pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );

}

Expand All @@ -2222,9 +2286,8 @@ THREE.GLTFLoader = ( function () {

if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {

var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
pending.push( parser.assignTexture( materialParams, 'metalnessMap', textureIndex ) );
pending.push( parser.assignTexture( materialParams, 'roughnessMap', textureIndex ) );
pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );

}

Expand Down Expand Up @@ -2256,7 +2319,7 @@ THREE.GLTFLoader = ( function () {

if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {

pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture.index ) );
pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );

materialParams.normalScale = new THREE.Vector2( 1, 1 );

Expand All @@ -2270,7 +2333,7 @@ THREE.GLTFLoader = ( function () {

if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {

pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture.index ) );
pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );

if ( materialDef.occlusionTexture.strength !== undefined ) {

Expand All @@ -2288,7 +2351,7 @@ THREE.GLTFLoader = ( function () {

if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial ) {

pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture.index ) );
pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );

}

Expand Down