diff --git a/docs/api/en/materials/Material.html b/docs/api/en/materials/Material.html index 3da14df4bbfd3f..c4fe7d942fc2f1 100644 --- a/docs/api/en/materials/Material.html +++ b/docs/api/en/materials/Material.html @@ -261,6 +261,13 @@

[property:Integer vertexColors]

Other options are [page:Materials THREE.VertexColors] and [page:Materials THREE.FaceColors].

+

[property:Boolean vertexTangents]

+

+ Defines whether precomputed vertex tangents, which must be provided in a vec4 "tangent" attribute, + are used. When disabled, tangents are derived automatically. Using precomputed tangents will give + more accurate normal map details in some cases, such as with mirrored UVs. Default is false. +

+

[property:Boolean visible]

Defines whether this material is visible. Default is *true*. diff --git a/docs/api/zh/materials/Material.html b/docs/api/zh/materials/Material.html index c9ab32be01d709..96ae0d7299d464 100644 --- a/docs/api/zh/materials/Material.html +++ b/docs/api/zh/materials/Material.html @@ -217,6 +217,10 @@

[property:Integer vertexColors]

其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。

+

[property:Boolean vertexTangents]

+

TODO. +

+

[property:Boolean visible]

此材质是否可见。默认为*true*。

diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index 11ce8917abfced..38273829b31336 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -1202,6 +1202,7 @@ THREE.GLTFLoader = ( function () { var ATTRIBUTES = { POSITION: 'position', NORMAL: 'normal', + TANGENT: 'tangent', TEXCOORD_0: 'uv', TEXCOORD_1: 'uv2', COLOR_0: 'color', @@ -2409,14 +2410,6 @@ THREE.GLTFLoader = ( function () { if ( materialDef.name !== undefined ) material.name = materialDef.name; - // Normal map textures use OpenGL conventions: - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#materialnormaltexture - if ( material.normalScale ) { - - material.normalScale.y = - material.normalScale.y; - - } - // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. if ( material.map ) material.map.encoding = THREE.sRGBEncoding; if ( material.emissiveMap ) material.emissiveMap.encoding = THREE.sRGBEncoding; @@ -2774,6 +2767,7 @@ THREE.GLTFLoader = ( function () { var materials = isMultiMaterial ? mesh.material : [ mesh.material ]; + var useVertexTangents = geometry.attributes.tangent !== undefined; var useVertexColors = geometry.attributes.color !== undefined; var useFlatShading = geometry.attributes.normal === undefined; var useSkinning = mesh.isSkinnedMesh === true; @@ -2826,12 +2820,13 @@ THREE.GLTFLoader = ( function () { } // Clone the material if it will be modified - if ( useVertexColors || useFlatShading || useSkinning || useMorphTargets ) { + if ( useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets ) { var cacheKey = 'ClonedMaterial:' + material.uuid + ':'; if ( material.isGLTFSpecularGlossinessMaterial ) cacheKey += 'specular-glossiness:'; if ( useSkinning ) cacheKey += 'skinning:'; + if ( useVertexTangents ) cacheKey += 'vertex-tangents:'; if ( useVertexColors ) cacheKey += 'vertex-colors:'; if ( useFlatShading ) cacheKey += 'flat-shading:'; if ( useMorphTargets ) cacheKey += 'morph-targets:'; @@ -2846,6 +2841,7 @@ THREE.GLTFLoader = ( function () { : material.clone(); if ( useSkinning ) cachedMaterial.skinning = true; + if ( useVertexTangents ) cachedMaterial.vertexTangents = true; if ( useVertexColors ) cachedMaterial.vertexColors = THREE.VertexColors; if ( useFlatShading ) cachedMaterial.flatShading = true; if ( useMorphTargets ) cachedMaterial.morphTargets = true; diff --git a/src/core/BufferGeometry.js b/src/core/BufferGeometry.js index c196dbdf6787b4..5a1ec264505aa9 100644 --- a/src/core/BufferGeometry.js +++ b/src/core/BufferGeometry.js @@ -154,6 +154,18 @@ BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototy } + var tangent = this.attributes.tangent; + + if ( tangent !== undefined ) { + + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + + // Tangent is vec4, but the '.w' component is a sign value (+1/-1). + normalMatrix.applyToBufferAttribute( tangent ); + tangent.needsUpdate = true; + + } + if ( this.boundingBox !== null ) { this.computeBoundingBox(); diff --git a/src/materials/Material.d.ts b/src/materials/Material.d.ts index 52f8061dd53645..5f704b8233f5ff 100644 --- a/src/materials/Material.d.ts +++ b/src/materials/Material.d.ts @@ -44,6 +44,7 @@ export interface MaterialParameters { side?: Side; transparent?: boolean; vertexColors?: Colors; + vertexTangents?: boolean; visible?: boolean; } @@ -234,6 +235,11 @@ export class Material extends EventDispatcher { */ vertexColors: Colors; + /** + * Defines whether precomputed vertex tangents are used. Default is false. + */ + vertexTangents: boolean; + /** * Defines whether this material is visible. Default is true. */ diff --git a/src/materials/Material.js b/src/materials/Material.js index b099f3753d4caa..97f4a2d11ad8c2 100644 --- a/src/materials/Material.js +++ b/src/materials/Material.js @@ -24,6 +24,7 @@ function Material() { this.blending = NormalBlending; this.side = FrontSide; this.flatShading = false; + this.vertexTangents = false; this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors this.opacity = 1; diff --git a/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl.js index f76965917952a0..7286cbaa5e7332 100644 --- a/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/beginnormal_vertex.glsl.js @@ -1,3 +1,9 @@ export default /* glsl */` vec3 objectNormal = vec3( normal ); + +#ifdef USE_TANGENT + + vec3 objectTangent = vec3( tangent.xyz ); + +#endif `; diff --git a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js index 671f9328b7ba39..7e02c01a7191bd 100644 --- a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js @@ -5,5 +5,17 @@ vec3 transformedNormal = normalMatrix * objectNormal; transformedNormal = - transformedNormal; +#endif + +#ifdef USE_TANGENT + + vec3 transformedTangent = normalMatrix * objectTangent; + + #ifdef FLIP_SIDED + + transformedTangent = - transformedTangent; + + #endif + #endif `; diff --git a/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js b/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js index 4cbfb3d388063f..3d6d128e4338e4 100644 --- a/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js @@ -17,5 +17,19 @@ export default /* glsl */` #endif + #ifdef USE_TANGENT + + vec3 tangent = normalize( vTangent ); + vec3 bitangent = normalize( vBitangent ); + + #ifdef DOUBLE_SIDED + + tangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 ); + bitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 ); + + #endif + + #endif + #endif `; diff --git a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js index cdcfc9e522e960..9ec57d6327b110 100644 --- a/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js +++ b/src/renderers/shaders/ShaderChunk/normal_fragment_maps.glsl.js @@ -21,7 +21,18 @@ export default /* glsl */` #else // tangent-space normal map - normal = perturbNormal2Arb( -vViewPosition, normal ); + #ifdef USE_TANGENT + + mat3 vTBN = mat3( tangent, bitangent, normal ); + vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0; + mapN.xy = normalScale * mapN.xy; + normal = normalize( vTBN * mapN ); + + #else + + normal = perturbNormal2Arb( -vViewPosition, normal ); + + #endif #endif diff --git a/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl.js index 5b833c4e33ed71..2b8e5cc84c7e51 100644 --- a/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/skinnormal_vertex.glsl.js @@ -10,5 +10,11 @@ export default /* glsl */` objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; + #ifdef USE_TANGENT + + objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; + + #endif + #endif `; diff --git a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js index 4a5dde0bd7ee7b..d909ad10d82793 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js @@ -18,6 +18,13 @@ varying vec3 vViewPosition; varying vec3 vNormal; + #ifdef USE_TANGENT + + varying vec3 vTangent; + varying vec3 vBitangent; + + #endif + #endif #include diff --git a/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl.js index 2d6b4b3ee2d993..36410c0ba5aa46 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical_vert.glsl.js @@ -7,6 +7,13 @@ varying vec3 vViewPosition; varying vec3 vNormal; + #ifdef USE_TANGENT + + varying vec3 vTangent; + varying vec3 vBitangent; + + #endif + #endif #include @@ -37,6 +44,13 @@ void main() { vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + + #endif + #endif #include diff --git a/src/renderers/shaders/ShaderLib/normal_frag.glsl.js b/src/renderers/shaders/ShaderLib/normal_frag.glsl.js index df890a26843ed2..9c57a54a9e465d 100644 --- a/src/renderers/shaders/ShaderLib/normal_frag.glsl.js +++ b/src/renderers/shaders/ShaderLib/normal_frag.glsl.js @@ -13,6 +13,13 @@ uniform float opacity; varying vec3 vNormal; + #ifdef USE_TANGENT + + varying vec3 vTangent; + varying vec3 vBitangent; + + #endif + #endif #include diff --git a/src/renderers/shaders/ShaderLib/normal_vert.glsl.js b/src/renderers/shaders/ShaderLib/normal_vert.glsl.js index b2543f046ecb7f..6f0c3d9a499275 100644 --- a/src/renderers/shaders/ShaderLib/normal_vert.glsl.js +++ b/src/renderers/shaders/ShaderLib/normal_vert.glsl.js @@ -11,6 +11,13 @@ export default /* glsl */` varying vec3 vNormal; + #ifdef USE_TANGENT + + varying vec3 vTangent; + varying vec3 vBitangent; + + #endif + #endif #include @@ -33,6 +40,13 @@ void main() { vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + + #endif + #endif #include diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index 8f0076f503b676..882dc87382ddda 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -359,6 +359,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters, parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + + parameters.vertexTangents ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', @@ -390,6 +392,12 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters, 'attribute vec3 normal;', 'attribute vec2 uv;', + '#ifdef USE_TANGENT', + + ' attribute vec4 tangent;', + + '#endif', + '#ifdef USE_COLOR', ' attribute vec3 color;', @@ -466,6 +474,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters, parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + + parameters.vertexTangents ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index f013bef53c7a5b..4ece68a5827d94 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -31,7 +31,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { "precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding", "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap", "roughnessMap", "metalnessMap", "gradientMap", - "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", + "alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp", "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", "maxBones", "useVertexTexture", "morphTargets", "morphNormals", "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", @@ -163,6 +163,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { combine: material.combine, + vertexTangents: material.vertexTangents, vertexColors: material.vertexColors, fog: !! fog,