@@ -47,6 +47,7 @@ function loadMtl(mtlPath, options) {
4747 var overridingNormalTexture = overridingTextures . normalTexture ;
4848 var overridingDiffuseTexture = overridingTextures . baseColorTexture ;
4949 var overridingEmissiveTexture = overridingTextures . emissiveTexture ;
50+ var overridingAlphaTexture = overridingTextures . alphaTexture ;
5051
5152 // Textures that are packed into PBR textures need to be decoded first
5253 var decodeOptions = options . materialsCommon ? undefined : {
@@ -62,6 +63,9 @@ function loadMtl(mtlPath, options) {
6263 var specularShinessTextureOptions = defined ( overridingSpecularShininessTexture ) ? undefined : decodeOptions ;
6364 var emissiveTextureOptions ;
6465 var normalTextureOptions ;
66+ var alphaTextureOptions = {
67+ decode : true
68+ } ;
6569
6670 function createMaterial ( name ) {
6771 material = new Material ( ) ;
@@ -73,6 +77,7 @@ function loadMtl(mtlPath, options) {
7377 material . ambientTexture = overridingAmbientTexture ;
7478 material . normalTexture = overridingNormalTexture ;
7579 material . emissiveTexture = overridingEmissiveTexture ;
80+ material . alphaTexture = overridingAlphaTexture ;
7681 materials . push ( material ) ;
7782 }
7883
@@ -161,16 +166,30 @@ function loadMtl(mtlPath, options) {
161166 if ( ! defined ( overridingNormalTexture ) ) {
162167 material . normalTexture = path . resolve ( mtlDirectory , cleanTextureName ( line . substring ( 9 ) . trim ( ) ) ) ;
163168 }
169+ } else if ( / ^ m a p _ d / i. test ( line ) ) {
170+ if ( ! defined ( overridingAlphaTexture ) ) {
171+ material . alphaTexture = path . resolve ( mtlDirectory , cleanTextureName ( line . substring ( 6 ) . trim ( ) ) ) ;
172+ }
164173 }
165174 }
166175
167176 function loadMaterialTextures ( material ) {
168- loadMaterialTexture ( material , 'diffuseTexture' , diffuseTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
177+ // If an alpha texture is present the diffuse texture needs to be decoded so they can be packed together
178+ var diffuseAlphaTextureOptions = defined ( material . alphaTexture ) ? alphaTextureOptions : diffuseTextureOptions ;
179+
180+ if ( material . diffuseTexture === material . ambientTexture ) {
181+ // OBJ models are often exported with the same texture in the diffuse and ambient slots but this is typically not desirable, particularly
182+ // when saving with PBR materials where the ambient texture is treated as the occlusion texture.
183+ material . ambientTexture = undefined ;
184+ }
185+
186+ loadMaterialTexture ( material , 'diffuseTexture' , diffuseAlphaTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
169187 loadMaterialTexture ( material , 'ambientTexture' , ambientTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
170188 loadMaterialTexture ( material , 'emissiveTexture' , emissiveTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
171189 loadMaterialTexture ( material , 'specularTexture' , specularTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
172190 loadMaterialTexture ( material , 'specularShininessTexture' , specularShinessTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
173191 loadMaterialTexture ( material , 'normalTexture' , normalTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
192+ loadMaterialTexture ( material , 'alphaTexture' , alphaTextureOptions , mtlDirectory , texturePromiseMap , texturePromises , options ) ;
174193 }
175194
176195 return readLines ( mtlPath , parseLine )
@@ -205,6 +224,7 @@ function Material() {
205224 this . specularTexture = undefined ; // map_Ks
206225 this . specularShininessTexture = undefined ; // map_Ns
207226 this . normalTexture = undefined ; // map_Bump
227+ this . alphaTexture = undefined ; // map_d
208228}
209229
210230loadMtl . getDefaultMaterial = function ( options ) {
@@ -354,6 +374,68 @@ function getMinimumDimensions(textures, options) {
354374 return [ width , height ] ;
355375}
356376
377+ function isChannelSingleColor ( buffer ) {
378+ var first = buffer . readUInt8 ( 0 ) ;
379+ var length = buffer . length ;
380+ for ( var i = 1 ; i < length ; ++ i ) {
381+ if ( buffer [ i ] !== first ) {
382+ return false ;
383+ }
384+ }
385+ return true ;
386+ }
387+
388+ function createDiffuseAlphaTexture ( diffuseTexture , alphaTexture , options ) {
389+ var packDiffuse = defined ( diffuseTexture ) ;
390+ var packAlpha = defined ( alphaTexture ) ;
391+
392+ if ( ! packDiffuse ) {
393+ return undefined ;
394+ }
395+
396+ if ( ! packAlpha ) {
397+ return diffuseTexture ;
398+ }
399+
400+ if ( ! defined ( diffuseTexture . pixels ) || ! defined ( alphaTexture . pixels ) ) {
401+ options . logger ( 'Could not get decoded texture data for ' + diffuseTexture . path + ' or ' + alphaTexture . path + '. The material will be created without an alpha texture.' ) ;
402+ return diffuseTexture ;
403+ }
404+
405+ var packedTextures = [ diffuseTexture , alphaTexture ] ;
406+ var dimensions = getMinimumDimensions ( packedTextures , options ) ;
407+ var width = dimensions [ 0 ] ;
408+ var height = dimensions [ 1 ] ;
409+ var pixelsLength = width * height ;
410+ var pixels = Buffer . alloc ( pixelsLength * 4 , 0xFF ) ; // Initialize with 4 channels
411+ var scratchChannel = Buffer . alloc ( pixelsLength ) ;
412+
413+ // Write into the R, G, B channels
414+ var redChannel = getTextureChannel ( diffuseTexture , 0 , width , height , scratchChannel ) ;
415+ writeChannel ( pixels , redChannel , 0 ) ;
416+ var greenChannel = getTextureChannel ( diffuseTexture , 1 , width , height , scratchChannel ) ;
417+ writeChannel ( pixels , greenChannel , 1 ) ;
418+ var blueChannel = getTextureChannel ( diffuseTexture , 2 , width , height , scratchChannel ) ;
419+ writeChannel ( pixels , blueChannel , 2 ) ;
420+
421+ // First try reading the alpha component from the alpha channel, but if it is a single color read from the red channel instead.
422+ var alphaChannel = getTextureChannel ( alphaTexture , 3 , width , height , scratchChannel ) ;
423+ if ( isChannelSingleColor ( alphaChannel ) ) {
424+ alphaChannel = getTextureChannel ( alphaTexture , 0 , width , height , scratchChannel ) ;
425+ }
426+ writeChannel ( pixels , alphaChannel , 3 ) ;
427+
428+ var texture = new Texture ( ) ;
429+ texture . name = diffuseTexture . name ;
430+ texture . extension = '.png' ;
431+ texture . pixels = pixels ;
432+ texture . width = width ;
433+ texture . height = height ;
434+ texture . transparent = true ;
435+
436+ return texture ;
437+ }
438+
357439function createMetallicRoughnessTexture ( metallicTexture , roughnessTexture , occlusionTexture , options ) {
358440 if ( defined ( options . overridingTextures . metallicRoughnessOcclusionTexture ) ) {
359441 return metallicTexture ;
@@ -499,9 +581,11 @@ function createSpecularGlossinessMaterial(material, options) {
499581 var normalTexture = material . normalTexture ;
500582 var occlusionTexture = material . ambientTexture ;
501583 var diffuseTexture = material . diffuseTexture ;
584+ var alphaTexture = material . alphaTexture ;
502585 var specularTexture = material . specularTexture ;
503586 var glossinessTexture = material . specularShininessTexture ;
504587 var specularGlossinessTexture = createSpecularGlossinessTexture ( specularTexture , glossinessTexture , options ) ;
588+ var diffuseAlphaTexture = createDiffuseAlphaTexture ( diffuseTexture , alphaTexture , options ) ;
505589
506590 var emissiveFactor = material . emissiveColor . slice ( 0 , 3 ) ;
507591 var diffuseFactor = material . diffuseColor ;
@@ -524,10 +608,15 @@ function createSpecularGlossinessMaterial(material, options) {
524608 glossinessFactor = 1.0 ;
525609 }
526610
527- var alpha = material . alpha ;
528- diffuseFactor [ 3 ] = alpha ;
611+ var transparent = false ;
612+ if ( defined ( alphaTexture ) ) {
613+ transparent = true ;
614+ } else {
615+ var alpha = material . alpha ;
616+ diffuseFactor [ 3 ] = alpha ;
617+ transparent = alpha < 1.0 ;
618+ }
529619
530- var transparent = alpha < 1.0 ;
531620 if ( defined ( diffuseTexture ) ) {
532621 transparent = transparent || diffuseTexture . transparent ;
533622 }
@@ -539,7 +628,7 @@ function createSpecularGlossinessMaterial(material, options) {
539628 name : material . name ,
540629 extensions : {
541630 KHR_materials_pbrSpecularGlossiness : {
542- diffuseTexture : diffuseTexture ,
631+ diffuseTexture : diffuseAlphaTexture ,
543632 specularGlossinessTexture : specularGlossinessTexture ,
544633 diffuseFactor : diffuseFactor ,
545634 specularFactor : specularFactor ,
@@ -560,9 +649,11 @@ function createMetallicRoughnessMaterial(material, options) {
560649 var normalTexture = material . normalTexture ;
561650 var occlusionTexture = material . ambientTexture ;
562651 var baseColorTexture = material . diffuseTexture ;
652+ var alphaTexture = material . alphaTexture ;
563653 var metallicTexture = material . specularTexture ;
564654 var roughnessTexture = material . specularShininessTexture ;
565655 var metallicRoughnessTexture = createMetallicRoughnessTexture ( metallicTexture , roughnessTexture , occlusionTexture , options ) ;
656+ var diffuseAlphaTexture = createDiffuseAlphaTexture ( baseColorTexture , alphaTexture , options ) ;
566657
567658 if ( options . packOcclusion ) {
568659 occlusionTexture = metallicRoughnessTexture ;
@@ -589,10 +680,15 @@ function createMetallicRoughnessMaterial(material, options) {
589680 roughnessFactor = 1.0 ;
590681 }
591682
592- var alpha = material . alpha ;
593- baseColorFactor [ 3 ] = alpha ;
683+ var transparent = false ;
684+ if ( defined ( alphaTexture ) ) {
685+ transparent = true ;
686+ } else {
687+ var alpha = material . alpha ;
688+ baseColorFactor [ 3 ] = alpha ;
689+ transparent = alpha < 1.0 ;
690+ }
594691
595- var transparent = alpha < 1.0 ;
596692 if ( defined ( baseColorTexture ) ) {
597693 transparent = transparent || baseColorTexture . transparent ;
598694 }
@@ -603,7 +699,7 @@ function createMetallicRoughnessMaterial(material, options) {
603699 return {
604700 name : material . name ,
605701 pbrMetallicRoughness : {
606- baseColorTexture : baseColorTexture ,
702+ baseColorTexture : diffuseAlphaTexture ,
607703 metallicRoughnessTexture : metallicRoughnessTexture ,
608704 baseColorFactor : baseColorFactor ,
609705 metallicFactor : metallicFactor ,
@@ -647,8 +743,9 @@ function convertTraditionalToMetallicRoughness(material) {
647743}
648744
649745function createMaterialsCommonMaterial ( material , options ) {
746+ var diffuseAlphaTexture = createDiffuseAlphaTexture ( material . diffuseTexture , material . alphaTexture , options ) ;
650747 var ambient = defaultValue ( material . ambientTexture , material . ambientColor ) ;
651- var diffuse = defaultValue ( material . diffuseTexture , material . diffuseColor ) ;
748+ var diffuse = defaultValue ( diffuseAlphaTexture , material . diffuseColor ) ;
652749 var emission = defaultValue ( material . emissiveTexture , material . emissiveColor ) ;
653750 var specular = defaultValue ( material . specularTexture , material . specularColor ) ;
654751
@@ -658,7 +755,9 @@ function createMaterialsCommonMaterial(material, options) {
658755
659756 var transparent ;
660757 var transparency = 1.0 ;
661- if ( defined ( material . diffuseTexture ) ) {
758+ if ( defined ( material . alphaTexture ) ) {
759+ transparent = true ;
760+ } else if ( defined ( material . diffuseTexture ) ) {
662761 transparency = alpha ;
663762 transparent = material . diffuseTexture . transparent || ( transparency < 1.0 ) ;
664763 } else {
0 commit comments