Browse Source

GLTFExporter: Ensure normalized normal attribute

Takahiro 7 years ago
parent
commit
e10ace162f
1 changed files with 93 additions and 0 deletions
  1. 93 0
      examples/js/exporters/GLTFExporter.js

+ 93 - 0
examples/js/exporters/GLTFExporter.js

@@ -103,6 +103,7 @@ THREE.GLTFExporter.prototype = {
 		var extensionsUsed = {};
 		var cachedData = {
 
+			attributes: new Map(),
 			materials: new Map(),
 			textures: new Map()
 
@@ -202,6 +203,86 @@ THREE.GLTFExporter.prototype = {
 
 		}
 
+		/**
+		 * Checks if normal attribute values are normalized.
+		 *
+		 * @param {THREE.BufferAttribute} normal
+		 * @returns {Boolean}
+		 *
+		 */
+		function isNormalizedNormalAttribute( normal ) {
+
+			if ( cachedData.attributes.has( normal ) ) {
+
+				return false;
+
+			}
+
+			for ( var i = 0, il = normal.array.length; i < il; i += 3 ) {
+
+				var x = normal.array[ i + 0 ];
+				var y = normal.array[ i + 1 ];
+				var z = normal.array[ i + 2 ];
+
+				var length = Math.sqrt( x * x + y * y + z * z );
+
+				// 0.0005 is from glTF-validator
+				if ( Math.abs( length - 1.0 ) > 0.0005 ) return false;
+
+			}
+
+			return true;
+
+		}
+
+		/**
+		 * Creates normalized normal buffer attribute.
+		 *
+		 * @param {THREE.BufferAttribute} normal
+		 * @returns {THREE.BufferAttribute}
+		 *
+		 */
+		function createNormalizedNormalAttribute( normal ) {
+
+			if ( cachedData.attributes.has( normal ) ) {
+
+				return cachedData.textures.get( normal );
+
+			}
+
+			var attribute = normal.clone();
+
+			var array = attribute.array;
+
+			var v = new THREE.Vector3();
+
+			for ( var i = 0, il = array.length; i < il; i += 3 ) {
+
+				v.set( array[ i ], array[ i + 1 ], array[ i + 2 ] );
+
+				if ( v.x === 0 && v.y === 0 && v.z === 0 ) {
+
+					// if values can't be normalized set (1, 0, 0)
+					v.setX( 1.0 );
+
+				} else {
+
+					v.normalize();
+
+				}
+
+				array[ i ] = v.x;
+				array[ i + 1 ] = v.y;
+				array[ i + 2 ] = v.z;
+
+			}
+
+			cachedData.attributes.set( normal, attribute );
+
+			return attribute;
+
+		}
+
 		/**
 		 * Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
 		 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
@@ -944,6 +1025,16 @@ THREE.GLTFExporter.prototype = {
 
 			};
 
+			var originalNormal = geometry.getAttribute( 'normal' );
+
+			if ( originalNormal !== undefined && ! isNormalizedNormalAttribute( originalNormal ) ) {
+
+				console.warn( 'THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.' );
+
+				geometry.addAttribute( 'normal', createNormalizedNormalAttribute( originalNormal ) );
+
+			}
+
 			// @QUESTION Detect if .vertexColors = THREE.VertexColors?
 			// For every attribute create an accessor
 			for ( var attributeName in geometry.attributes ) {
@@ -975,6 +1066,8 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
+			if ( originalNormal !== undefined ) geometry.addAttribute( 'normal', originalNormal );
+
 			// Skip if no exportable attributes found
 			if ( Object.keys( attributes ).length === 0 ) {