Skip to content

Commit dab285d

Browse files
authored
Merge pull request #13831 from donmccurdy/feat-gltfloader-texturetransform
GLTFLoader: Implement KHR_texture_transform extension.
2 parents 80cd24c + 5e6cbc5 commit dab285d

File tree

3 files changed

+112
-26
lines changed

3 files changed

+112
-26
lines changed

docs/examples/loaders/GLTFLoader.html

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,20 @@ <h2>Extensions</h2>
3232
<li>KHR_materials_pbrSpecularGlossiness</li>
3333
<li>KHR_materials_unlit</li>
3434
<li>KHR_lights_punctual (experimental)</li>
35+
<li>KHR_texture_transform<sup>*</sup></li>
36+
<li>MSFT_texture_dds</li>
3537
</ul>
3638

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

3951
<code>
@@ -85,30 +97,30 @@ <h2>Browser compatibility</h2>
8597
providing a Promise replacement.</p>
8698

8799
<h2>Textures</h2>
88-
100+
89101
<p>Textures containing color information (.map, .emissiveMap, and .specularMap) always use sRGB colorspace in
90102
glTF, while vertex colors and material properties (.color, .emissive, .specular) use linear colorspace. In a
91103
typical rendering workflow, textures are converted to linear colorspace by the renderer, lighting calculations
92104
are made, then final output is converted back to sRGB and displayed on screen. Unless you need post-processing
93105
in linear colorspace, always configure [page:WebGLRenderer] as follows when using glTF:</p>
94-
106+
95107
<code>
96108
renderer.gammaOutput = true;
97109
renderer.gammaFactor = 2.2;
98110
</code>
99-
111+
100112
<p>GLTFLoader will automatically configure textures referenced from a .gltf or .glb file correctly, with the
101113
assumption that the renderer is set up as shown above. When loading textures externally (e.g., using
102114
[page:TextureLoader]) and applying them to a glTF model, colorspace and orientation must be given:</p>
103-
115+
104116
<code>
105117
// If texture is used for color information, set colorspace.
106118
texture.encoding = THREE.sRGBEncoding;
107119

108120
// UVs use the convention that (0, 0) corresponds to the upper left corner of a texture.
109121
texture.flipY = false;
110-
</code>
111-
122+
</code>
123+
112124
<h2>Custom extensions</h2>
113125

114126
<p>

docs/page.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,14 @@ span.param {
130130
a.param:hover {
131131
color: #777;
132132
}
133+
134+
sup, sub {
135+
/* prevent superscript and subscript elements from affecting line-height */
136+
vertical-align: baseline;
137+
position: relative;
138+
top: -0.4em;
139+
}
140+
141+
sub {
142+
top: 0.4em;
143+
}

examples/js/loaders/GLTFLoader.js

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,19 @@ THREE.GLTFLoader = ( function () {
181181
break;
182182

183183
case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
184-
extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
184+
extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
185185
break;
186186

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

191191
case EXTENSIONS.MSFT_TEXTURE_DDS:
192-
extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension();
192+
extensions[ EXTENSIONS.MSFT_TEXTURE_DDS ] = new GLTFTextureDDSExtension( json );
193+
break;
194+
195+
case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
196+
extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
193197
break;
194198

195199
default:
@@ -282,6 +286,7 @@ THREE.GLTFLoader = ( function () {
282286
KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
283287
KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
284288
KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
289+
KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
285290
MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
286291
};
287292

@@ -409,7 +414,7 @@ THREE.GLTFLoader = ( function () {
409414

410415
if ( metallicRoughness.baseColorTexture !== undefined ) {
411416

412-
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
417+
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
413418

414419
}
415420

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

564569
};
565570

571+
/**
572+
* Texture Transform Extension
573+
*
574+
* Specification:
575+
*/
576+
function GLTFTextureTransformExtension( json ) {
577+
578+
this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM;
579+
580+
}
581+
582+
GLTFTextureTransformExtension.prototype.extendTexture = function ( texture, transform ) {
583+
584+
texture = texture.clone();
585+
586+
if ( transform.offset !== undefined ) {
587+
588+
texture.offset.fromArray( transform.offset );
589+
590+
}
591+
592+
if ( transform.rotation !== undefined ) {
593+
594+
texture.rotation = transform.rotation;
595+
596+
}
597+
598+
if ( transform.scale !== undefined ) {
599+
600+
texture.repeat.fromArray( transform.scale );
601+
602+
}
603+
604+
if ( transform.texCoord !== undefined ) {
605+
606+
console.warn( 'THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.' );
607+
608+
}
609+
610+
texture.needsUpdate = true;
611+
612+
return texture;
613+
614+
};
615+
566616
/**
567617
* Specular-Glossiness Extension
568618
*
@@ -692,7 +742,7 @@ THREE.GLTFLoader = ( function () {
692742

693743
if ( pbrSpecularGlossiness.diffuseTexture !== undefined ) {
694744

695-
pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture.index ) );
745+
pending.push( parser.assignTexture( params, 'map', pbrSpecularGlossiness.diffuseTexture ) );
696746

697747
}
698748

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

709759
if ( pbrSpecularGlossiness.specularGlossinessTexture !== undefined ) {
710760

711-
var specGlossIndex = pbrSpecularGlossiness.specularGlossinessTexture.index;
712-
pending.push( parser.assignTexture( params, 'glossinessMap', specGlossIndex ) );
713-
pending.push( parser.assignTexture( params, 'specularMap', specGlossIndex ) );
761+
var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture;
762+
pending.push( parser.assignTexture( params, 'glossinessMap', specGlossMapDef ) );
763+
pending.push( parser.assignTexture( params, 'specularMap', specGlossMapDef ) );
714764

715765
}
716766

@@ -2146,15 +2196,29 @@ THREE.GLTFLoader = ( function () {
21462196
/**
21472197
* Asynchronously assigns a texture to the given material parameters.
21482198
* @param {Object} materialParams
2149-
* @param {string} textureName
2150-
* @param {number} textureIndex
2151-
* @return {Promise<THREE.Texture>}
2199+
* @param {string} mapName
2200+
* @param {Object} mapDef
2201+
* @return {Promise}
21522202
*/
2153-
GLTFParser.prototype.assignTexture = function ( materialParams, textureName, textureIndex ) {
2203+
GLTFParser.prototype.assignTexture = function ( materialParams, mapName, mapDef ) {
2204+
2205+
var parser = this;
2206+
2207+
return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
2208+
2209+
if ( parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] ) {
2210+
2211+
var transform = mapDef.extensions !== undefined ? mapDef.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] : undefined;
21542212

2155-
return this.getDependency( 'texture', textureIndex ).then( function ( texture ) {
2213+
if ( transform ) {
2214+
2215+
texture = parser.extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ].extendTexture( texture, transform );
2216+
2217+
}
2218+
2219+
}
21562220

2157-
materialParams[ textureName ] = texture;
2221+
materialParams[ mapName ] = texture;
21582222

21592223
} );
21602224

@@ -2213,7 +2277,7 @@ THREE.GLTFLoader = ( function () {
22132277

22142278
if ( metallicRoughness.baseColorTexture !== undefined ) {
22152279

2216-
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
2280+
pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture ) );
22172281

22182282
}
22192283

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

22232287
if ( metallicRoughness.metallicRoughnessTexture !== undefined ) {
22242288

2225-
var textureIndex = metallicRoughness.metallicRoughnessTexture.index;
2226-
pending.push( parser.assignTexture( materialParams, 'metalnessMap', textureIndex ) );
2227-
pending.push( parser.assignTexture( materialParams, 'roughnessMap', textureIndex ) );
2289+
pending.push( parser.assignTexture( materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture ) );
2290+
pending.push( parser.assignTexture( materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture ) );
22282291

22292292
}
22302293

@@ -2256,7 +2319,7 @@ THREE.GLTFLoader = ( function () {
22562319

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

2259-
pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture.index ) );
2322+
pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture ) );
22602323

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

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

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

2273-
pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture.index ) );
2336+
pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture ) );
22742337

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

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

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

2291-
pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture.index ) );
2354+
pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture ) );
22922355

22932356
}
22942357

0 commit comments

Comments
 (0)