@@ -23,26 +23,21 @@ define([
23
23
/**
24
24
* @private
25
25
*/
26
- function processPbrMetallicRoughness ( gltf , options ) {
26
+ function processPbrMaterials ( gltf , options ) {
27
27
options = defaultValue ( options , { } ) ;
28
28
29
- var hasPbrMetallicRoughness = false ;
30
- ForEach . material ( gltf , function ( material ) {
31
- if ( isPbrMaterial ( material ) ) {
32
- hasPbrMetallicRoughness = true ;
33
- }
34
- } ) ;
35
-
36
- if ( ! hasPbrMetallicRoughness ) {
37
- return gltf ;
38
- }
39
-
40
29
// No need to create new techniques if they already exist,
41
30
// the shader should handle these values
42
31
if ( hasExtension ( gltf , 'KHR_techniques_webgl' ) ) {
43
32
return gltf ;
44
33
}
45
34
35
+ // All materials in glTF are PBR by default,
36
+ // so we should apply PBR unless no materials are found.
37
+ if ( gltf . materials . length === 0 ) {
38
+ return gltf ;
39
+ }
40
+
46
41
if ( ! defined ( gltf . extensions ) ) {
47
42
gltf . extensions = { } ;
48
43
}
@@ -60,25 +55,24 @@ define([
60
55
shaders : [ ] ,
61
56
techniques : [ ]
62
57
} ;
58
+
63
59
gltf . extensionsUsed . push ( 'KHR_techniques_webgl' ) ;
64
60
gltf . extensionsRequired . push ( 'KHR_techniques_webgl' ) ;
65
61
66
62
var primitiveByMaterial = ModelUtility . splitIncompatibleMaterials ( gltf ) ;
67
63
68
64
ForEach . material ( gltf , function ( material , materialIndex ) {
69
- if ( isPbrMaterial ( material ) ) {
70
- var generatedMaterialValues = { } ;
71
- var technique = generateTechnique ( gltf , material , materialIndex , generatedMaterialValues , primitiveByMaterial , options ) ;
72
-
73
- if ( ! defined ( material . extensions ) ) {
74
- material . extensions = { } ;
75
- }
65
+ var generatedMaterialValues = { } ;
66
+ var technique = generateTechnique ( gltf , material , materialIndex , generatedMaterialValues , primitiveByMaterial , options ) ;
76
67
77
- material . extensions . KHR_techniques_webgl = {
78
- values : generatedMaterialValues ,
79
- technique : technique
80
- } ;
68
+ if ( ! defined ( material . extensions ) ) {
69
+ material . extensions = { } ;
81
70
}
71
+
72
+ material . extensions . KHR_techniques_webgl = {
73
+ values : generatedMaterialValues ,
74
+ technique : technique
75
+ } ;
82
76
} ) ;
83
77
84
78
// If any primitives have semantics that aren't declared in the generated
@@ -88,15 +82,9 @@ define([
88
82
return gltf ;
89
83
}
90
84
91
- function isPbrMaterial ( material ) {
92
- return defined ( material . pbrMetallicRoughness ) ||
93
- defined ( material . normalTexture ) ||
94
- defined ( material . occlusionTexture ) ||
95
- defined ( material . emissiveTexture ) ||
96
- defined ( material . emissiveFactor ) ||
97
- defined ( material . alphaMode ) ||
98
- defined ( material . alphaCutoff ) ||
99
- defined ( material . doubleSided ) ;
85
+ function isSpecularGlossinessMaterial ( material ) {
86
+ return defined ( material . extensions ) &&
87
+ defined ( material . extensions . KHR_materials_pbrSpecularGlossiness ) ;
100
88
}
101
89
102
90
function generateTechnique ( gltf , material , materialIndex , generatedMaterialValues , primitiveByMaterial , options ) {
@@ -107,16 +95,30 @@ define([
107
95
var shaders = techniquesWebgl . shaders ;
108
96
var programs = techniquesWebgl . programs ;
109
97
98
+ var useSpecGloss = isSpecularGlossinessMaterial ( material ) ;
99
+
110
100
var uniformName ;
101
+ var parameterName ;
111
102
var pbrMetallicRoughness = material . pbrMetallicRoughness ;
112
- if ( defined ( pbrMetallicRoughness ) ) {
113
- for ( var parameterName in pbrMetallicRoughness ) {
103
+ if ( defined ( pbrMetallicRoughness ) && ! useSpecGloss ) {
104
+ for ( parameterName in pbrMetallicRoughness ) {
114
105
if ( pbrMetallicRoughness . hasOwnProperty ( parameterName ) ) {
115
106
uniformName = 'u_' + parameterName ;
116
107
generatedMaterialValues [ uniformName ] = pbrMetallicRoughness [ parameterName ] ;
117
108
}
118
109
}
119
110
}
111
+
112
+ if ( useSpecGloss ) {
113
+ var pbrSpecularGlossiness = material . extensions . KHR_materials_pbrSpecularGlossiness ;
114
+ for ( parameterName in pbrSpecularGlossiness ) {
115
+ if ( pbrSpecularGlossiness . hasOwnProperty ( parameterName ) ) {
116
+ uniformName = 'u_' + parameterName ;
117
+ generatedMaterialValues [ uniformName ] = pbrSpecularGlossiness [ parameterName ] ;
118
+ }
119
+ }
120
+ }
121
+
120
122
for ( var additional in material ) {
121
123
if ( material . hasOwnProperty ( additional ) && ( ( additional . indexOf ( 'Texture' ) >= 0 ) || additional . indexOf ( 'Factor' ) >= 0 ) ) {
122
124
uniformName = 'u_' + additional ;
@@ -538,8 +540,40 @@ define([
538
540
fragmentShader += ' vec3 baseColor = baseColorWithAlpha.rgb;\n' ;
539
541
540
542
if ( hasNormals ) {
541
- // Add metallic-roughness to fragment shader
542
- if ( defined ( generatedMaterialValues . u_metallicRoughnessTexture ) ) {
543
+ if ( useSpecGloss ) {
544
+ if ( defined ( generatedMaterialValues . u_specularGlossinessTexture ) ) {
545
+ fragmentShader += ' vec4 specularGlossiness = SRGBtoLINEAR4(texture2D(u_specularGlossinessTexture, ' + v_texcoord + '));\n' ;
546
+ fragmentShader += ' vec3 specular = specularGlossiness.rgb;\n' ;
547
+ fragmentShader += ' float glossiness = specularGlossiness.a;\n' ;
548
+ if ( defined ( generatedMaterialValues . u_specularFactor ) ) {
549
+ fragmentShader += ' specular *= u_specularFactor;\n' ;
550
+ }
551
+ if ( defined ( generatedMaterialValues . u_glossinessFactor ) ) {
552
+ fragmentShader += ' glossiness *= u_glossinessFactor;\n' ;
553
+ }
554
+ } else {
555
+ if ( defined ( generatedMaterialValues . u_specularFactor ) ) {
556
+ fragmentShader += ' vec3 specular = clamp(u_specularFactor, vec3(0.0), vec3(1.0));\n' ;
557
+ } else {
558
+ fragmentShader += ' vec3 specular = vec3(1.0);\n' ;
559
+ }
560
+ if ( defined ( generatedMaterialValues . u_glossinessFactor ) ) {
561
+ fragmentShader += ' float glossiness = clamp(u_glossinessFactor, 0.0, 1.0);\n' ;
562
+ } else {
563
+ fragmentShader += ' float glossiness = 1.0;\n' ;
564
+ }
565
+ }
566
+ if ( defined ( generatedMaterialValues . u_diffuseTexture ) ) {
567
+ fragmentShader += ' vec4 diffuse = SRGBtoLINEAR4(texture2D(u_diffuseTexture, ' + v_texcoord + '));\n' ;
568
+ if ( defined ( generatedMaterialValues . u_diffuseFactor ) ) {
569
+ fragmentShader += ' diffuse *= u_diffuseFactor;\n' ;
570
+ }
571
+ } else if ( defined ( generatedMaterialValues . u_diffuseFactor ) ) {
572
+ fragmentShader += ' vec4 diffuse = clamp(u_diffuseFactor, vec4(0.0), vec4(1.0));\n' ;
573
+ } else {
574
+ fragmentShader += ' vec4 diffuse = vec4(1.0);\n' ;
575
+ }
576
+ } else if ( defined ( generatedMaterialValues . u_metallicRoughnessTexture ) ) {
543
577
fragmentShader += ' vec3 metallicRoughness = texture2D(u_metallicRoughnessTexture, ' + v_texcoord + ').rgb;\n' ;
544
578
fragmentShader += ' float metalness = clamp(metallicRoughness.b, 0.0, 1.0);\n' ;
545
579
fragmentShader += ' float roughness = clamp(metallicRoughness.g, 0.04, 1.0);\n' ;
@@ -561,6 +595,7 @@ define([
561
595
fragmentShader += ' float roughness = 1.0;\n' ;
562
596
}
563
597
}
598
+
564
599
fragmentShader += ' vec3 v = -normalize(v_positionEC);\n' ;
565
600
566
601
// Generate fragment shader's lighting block
@@ -583,11 +618,19 @@ define([
583
618
fragmentShader += ' float NdotH = clamp(dot(n, h), 0.0, 1.0);\n' ;
584
619
fragmentShader += ' float LdotH = clamp(dot(l, h), 0.0, 1.0);\n' ;
585
620
fragmentShader += ' float VdotH = clamp(dot(v, h), 0.0, 1.0);\n' ;
586
-
587
621
fragmentShader += ' vec3 f0 = vec3(0.04);\n' ;
622
+ // Whether the material uses metallic-roughness or specular-glossiness changes how the BRDF inputs are computed.
623
+ // It does not change the implementation of the BRDF itself.
624
+ if ( useSpecGloss ) {
625
+ fragmentShader += ' float roughness = 1.0 - glossiness;\n' ;
626
+ fragmentShader += ' vec3 diffuseColor = diffuse.rgb * (1.0 - max(max(specular.r, specular.g), specular.b));\n' ;
627
+ fragmentShader += ' vec3 specularColor = specular;\n' ;
628
+ } else {
629
+ fragmentShader += ' vec3 diffuseColor = baseColor * (1.0 - metalness) * (1.0 - f0);\n' ;
630
+ fragmentShader += ' vec3 specularColor = mix(f0, baseColor, metalness);\n' ;
631
+ }
632
+
588
633
fragmentShader += ' float alpha = roughness * roughness;\n' ;
589
- fragmentShader += ' vec3 diffuseColor = baseColor * (1.0 - metalness) * (1.0 - f0);\n' ;
590
- fragmentShader += ' vec3 specularColor = mix(f0, baseColor, metalness);\n' ;
591
634
fragmentShader += ' float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);\n' ;
592
635
fragmentShader += ' vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0));\n' ;
593
636
fragmentShader += ' vec3 r0 = specularColor.rgb;\n' ;
@@ -725,8 +768,19 @@ define([
725
768
return WebGLConstants . SAMPLER_2D ;
726
769
case 'u_emissiveFactor' :
727
770
return WebGLConstants . FLOAT_VEC3 ;
771
+ // Specular Glossiness Types
772
+ case 'u_diffuseFactor' :
773
+ return WebGLConstants . FLOAT_VEC4 ;
774
+ case 'u_specularFactor' :
775
+ return WebGLConstants . FLOAT_VEC3 ;
776
+ case 'u_glossinessFactor' :
777
+ return WebGLConstants . FLOAT ;
778
+ case 'u_diffuseTexture' :
779
+ return WebGLConstants . SAMPLER_2D ;
780
+ case 'u_specularGlossinessTexture' :
781
+ return WebGLConstants . SAMPLER_2D ;
728
782
}
729
783
}
730
784
731
- return processPbrMetallicRoughness ;
785
+ return processPbrMaterials ;
732
786
} ) ;
0 commit comments