Browse Source

Merge pull request #13681 from fernandojsg/fixempty

GLTFExporter: Prevent exporting empty geometry
Mr.doob 7 years ago
parent
commit
66ee44e4d6

+ 49 - 22
examples/js/exporters/GLTFExporter.js

@@ -149,7 +149,7 @@ THREE.GLTFExporter.prototype = {
 				var value = text.charCodeAt( i );
 
 				// Replacing multi-byte character with space(0x20).
-				array[ i ] = value > 0xFF ? 0x20 : value
+				array[ i ] = value > 0xFF ? 0x20 : value;
 
 			}
 
@@ -425,12 +425,6 @@ THREE.GLTFExporter.prototype = {
 		 */
 		function processAccessor( attribute, geometry, start, count ) {
 
-			if ( ! outputJSON.accessors ) {
-
-				outputJSON.accessors = [];
-
-			}
-
 			var types = {
 
 				1: 'SCALAR',
@@ -484,6 +478,13 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
+			// Skip creating an accessor if the attribute doesn't have data to export
+			if ( count === 0 ) {
+
+				return null;
+
+			}
+
 			var minMax = getMinMax( attribute, start, count );
 
 			var bufferViewTarget;
@@ -510,6 +511,12 @@ THREE.GLTFExporter.prototype = {
 
 			};
 
+			if ( ! outputJSON.accessors ) {
+
+				outputJSON.accessors = [];
+
+			}
+
 			outputJSON.accessors.push( gltfAccessor );
 
 			return outputJSON.accessors.length - 1;
@@ -872,12 +879,6 @@ THREE.GLTFExporter.prototype = {
 		 */
 		function processMesh( mesh ) {
 
-			if ( ! outputJSON.meshes ) {
-
-				outputJSON.meshes = [];
-
-			}
-
 			var geometry = mesh.geometry;
 
 			var mode;
@@ -963,12 +964,24 @@ THREE.GLTFExporter.prototype = {
 
 				if ( attributeName.substr( 0, 5 ) !== 'MORPH' ) {
 
-					attributes[ attributeName ] = processAccessor( attribute, geometry );
+					var accessor = processAccessor( attribute, geometry );
+					if ( accessor !== null ) {
+
+						attributes[ attributeName ] = accessor;
+
+					}
 
 				}
 
 			}
 
+			// Skip if no exportable attributes found
+			if ( Object.keys( attributes ).length === 0 ) {
+
+				return null;
+
+			}
+
 			// Morph targets
 			if ( mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0 ) {
 
@@ -1057,6 +1070,8 @@ THREE.GLTFExporter.prototype = {
 			var forceIndices = options.forceIndices;
 			var isMultiMaterial = Array.isArray( mesh.material );
 
+			if ( isMultiMaterial && mesh.geometry.groups.length === 0 ) return null;
+
 			if ( ! forceIndices && geometry.index === null && isMultiMaterial ) {
 
 				// temporal workaround.
@@ -1083,7 +1098,7 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
-			var materials = isMultiMaterial ? mesh.material : [ mesh.material ] ;
+			var materials = isMultiMaterial ? mesh.material : [ mesh.material ];
 			var groups = isMultiMaterial ? mesh.geometry.groups : [ { materialIndex: 0, start: undefined, count: undefined } ];
 
 			for ( var i = 0, il = groups.length; i < il; i ++ ) {
@@ -1095,17 +1110,17 @@ THREE.GLTFExporter.prototype = {
 
 				if ( targets.length > 0 ) primitive.targets = targets;
 
-				var material = processMaterial( materials[ groups[ i ].materialIndex ] );
-
-				if ( material !== null ) {
+				if ( geometry.index !== null ) {
 
-					primitive.material = material;
+					primitive.indices = processAccessor( geometry.index, geometry, groups[ i ].start, groups[ i ].count );
 
 				}
 
-				if ( geometry.index !== null ) {
+				var material = processMaterial( materials[ groups[ i ].materialIndex ] );
 
-					primitive.indices = processAccessor( geometry.index, geometry, groups[ i ].start, groups[ i ].count );
+				if ( material !== null ) {
+
+					primitive.material = material;
 
 				}
 
@@ -1121,6 +1136,12 @@ THREE.GLTFExporter.prototype = {
 
 			gltfMesh.primitives = primitives;
 
+			if ( ! outputJSON.meshes ) {
+
+				outputJSON.meshes = [];
+
+			}
+
 			outputJSON.meshes.push( gltfMesh );
 
 			return outputJSON.meshes.length - 1;
@@ -1420,7 +1441,13 @@ THREE.GLTFExporter.prototype = {
 
 			if ( object.isMesh || object.isLine || object.isPoints ) {
 
-				gltfNode.mesh = processMesh( object );
+				var mesh = processMesh( object );
+
+				if ( mesh !== null ) {
+
+					gltfNode.mesh = mesh;
+
+				}
 
 			} else if ( object.isCamera ) {
 

+ 36 - 1
test/unit/example/exporters/GLTFExporter.tests.js

@@ -19,7 +19,7 @@ export default QUnit.module( 'Exporters', () => {
 
       var done = assert.async();
 
-      var object = new THREE.Object3D()
+      var object = new THREE.Object3D();
 
       var exporter = new THREE.GLTFExporter();
 
@@ -120,6 +120,41 @@ export default QUnit.module( 'Exporters', () => {
 
     } );
 
+    QUnit.test( 'parse - empty buffergeometry', ( assert ) => {
+
+      var done = assert.async();
+
+      var scene = new THREE.Scene();
+      var geometry = new THREE.BufferGeometry();
+      var numElements = 6;
+
+      var positions = new Float32Array( ( numElements ) * 3 );
+      var colors = new Float32Array( ( numElements ) * 3 );
+
+      geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+      geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
+      geometry.setDrawRange( 0, 0 );
+
+      var empty = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { side: THREE.DoubleSide, vertexColors: THREE.VertexColors } ) );
+      empty.name = 'Custom buffered empty (drawrange)';
+      scene.add( empty );
+
+      var exporter = new THREE.GLTFExporter();
+
+      exporter.parse( scene, function ( gltf ) {
+
+        assert.equal( gltf.meshes, undefined, 'empty meshes');
+        assert.equal( gltf.materials, undefined, 'empty materials');
+        assert.equal( gltf.bufferViews, undefined, 'empty bufferViews');
+        assert.equal( gltf.buffers, undefined, 'buffers');
+        assert.equal( gltf.accessors, undefined, 'accessors');
+        assert.equal( gltf.nodes[0].mesh, undefined, 'nodes[0].mesh');
+
+        done();
+
+      });
+
+    } );
 
   } );