|
@@ -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 ) {
|
|
|
|