|
@@ -0,0 +1,212 @@
|
|
|
+/**
|
|
|
+ * Export draco compressed files from threejs geometry objects.
|
|
|
+ *
|
|
|
+ * Draco files are compressed and usually are smaller than conventional 3D file formats.
|
|
|
+ *
|
|
|
+ * The exporter receives a options object containing
|
|
|
+ * - decodeSpeed, indicates how to tune the encoder regarding decode speed (0 gives better speed but worst quality)
|
|
|
+ * - encodeSpeed, indicates how to tune the encoder parameters (0 gives better speed but worst quality)
|
|
|
+ * - encoderMethod
|
|
|
+ * - quantization, indicates the presision of each type of data stored in the draco file in the order (POSITION, NORMAL, COLOR, TEX_COORD, GENERIC)
|
|
|
+ * - exportUvs
|
|
|
+ * - exportNormals
|
|
|
+ *
|
|
|
+ * @class DRACOExporter
|
|
|
+ * @author tentone
|
|
|
+ */
|
|
|
+
|
|
|
+import {
|
|
|
+ BufferGeometry
|
|
|
+} from "../../../build/three.module.js";
|
|
|
+
|
|
|
+/* global DracoEncoderModule */
|
|
|
+
|
|
|
+var DRACOExporter = function () {};
|
|
|
+
|
|
|
+DRACOExporter.prototype = {
|
|
|
+
|
|
|
+ constructor: DRACOExporter,
|
|
|
+
|
|
|
+ parse: function ( geometry, options ) {
|
|
|
+
|
|
|
+
|
|
|
+ if ( DracoEncoderModule === undefined ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.DRACOExporter: required the draco_decoder to work.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( options === undefined ) {
|
|
|
+
|
|
|
+ options = {
|
|
|
+
|
|
|
+ decodeSpeed: 5,
|
|
|
+ encodeSpeed: 5,
|
|
|
+ encoderMethod: DRACOExporter.MESH_EDGEBREAKER_ENCODING,
|
|
|
+ quantization: [ 16, 8, 8, 8, 8 ],
|
|
|
+ exportUvs: true,
|
|
|
+ exportNormals: true,
|
|
|
+ exportColor: false,
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var dracoEncoder = DracoEncoderModule();
|
|
|
+ var encoder = new dracoEncoder.Encoder();
|
|
|
+ var builder = new dracoEncoder.MeshBuilder();
|
|
|
+ var mesh = new dracoEncoder.Mesh();
|
|
|
+
|
|
|
+ if ( geometry.isGeometry === true ) {
|
|
|
+
|
|
|
+ var bufferGeometry = new BufferGeometry();
|
|
|
+ bufferGeometry.fromGeometry( geometry );
|
|
|
+ geometry = bufferGeometry;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( geometry.isBufferGeometry !== true ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.DRACOExporter.parse(geometry, options): geometry is not a THREE.Geometry or BufferGeometry instance.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var vertices = geometry.getAttribute( 'position' );
|
|
|
+ builder.AddFloatAttributeToMesh( mesh, dracoEncoder.POSITION, vertices.count, vertices.itemSize, vertices.array );
|
|
|
+
|
|
|
+ var faces = geometry.getIndex();
|
|
|
+
|
|
|
+ if ( faces !== null ) {
|
|
|
+
|
|
|
+ builder.AddFacesToMesh( mesh, faces.count, faces.array );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ var faces = new ( vertices.count > 65535 ? Uint32Array : Uint16Array )( vertices.count );
|
|
|
+
|
|
|
+ for ( var i = 0; i < faces.length; i ++ ) {
|
|
|
+
|
|
|
+ faces[ i ] = i;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ builder.AddFacesToMesh( mesh, vertices.count, faces );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( options.exportNormals === true ) {
|
|
|
+
|
|
|
+ var normals = geometry.getAttribute( 'normal' );
|
|
|
+
|
|
|
+ if ( normals !== undefined ) {
|
|
|
+
|
|
|
+ builder.AddFloatAttributeToMesh( mesh, dracoEncoder.NORMAL, normals.count, normals.itemSize, normals.array );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( options.exportUvs === true ) {
|
|
|
+
|
|
|
+ var uvs = geometry.getAttribute( 'uv' );
|
|
|
+
|
|
|
+ if ( uvs !== undefined ) {
|
|
|
+
|
|
|
+ builder.AddFloatAttributeToMesh( mesh, dracoEncoder.TEX_COORD, uvs.count, uvs.itemSize, uvs.array );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( options.exportColor === true ) {
|
|
|
+
|
|
|
+ var colors = geometry.getAttribute( 'color' );
|
|
|
+
|
|
|
+ if ( colors !== undefined ) {
|
|
|
+
|
|
|
+ builder.AddFloatAttributeToMesh( mesh, dracoEncoder.COLOR, colors.count, colors.itemSize, colors.array );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //Compress using draco encoder
|
|
|
+
|
|
|
+ var encodedData = new dracoEncoder.DracoInt8Array();
|
|
|
+
|
|
|
+ //Sets the desired encoding and decoding speed for the given options from 0 (slowest speed, but the best compression) to 10 (fastest, but the worst compression).
|
|
|
+
|
|
|
+ encoder.SetSpeedOptions( options.encodeSpeed || 5, options.decodeSpeed || 5 );
|
|
|
+
|
|
|
+ // Sets the desired encoding method for a given geometry.
|
|
|
+
|
|
|
+ if ( options.encoderMethod !== undefined ) {
|
|
|
+
|
|
|
+ encoder.SetEncodingMethod( options.encoderMethod );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // Sets the quantization (number of bits used to represent) compression options for a named attribute.
|
|
|
+ // The attribute values will be quantized in a box defined by the maximum extent of the attribute values.
|
|
|
+ if ( options.quantization !== undefined ) {
|
|
|
+
|
|
|
+ for ( var i = 0; i < 5; i ++ ) {
|
|
|
+
|
|
|
+ if ( options.quantization[ i ] !== undefined ) {
|
|
|
+
|
|
|
+ encoder.SetAttributeQuantization( i, options.quantization[ i ] );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var length = encoder.EncodeMeshToDracoBuffer( mesh, encodedData );
|
|
|
+ dracoEncoder.destroy( mesh );
|
|
|
+
|
|
|
+ if ( length === 0 ) {
|
|
|
+
|
|
|
+ throw new Error( 'THREE.DRACOExporter: Draco encoding failed.' );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //Copy encoded data to buffer.
|
|
|
+ var outputData = new Int8Array( new ArrayBuffer( length ) );
|
|
|
+
|
|
|
+ for ( var i = 0; i < length; i ++ ) {
|
|
|
+
|
|
|
+ outputData[ i ] = encodedData.GetValue( i );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ dracoEncoder.destroy( encodedData );
|
|
|
+ dracoEncoder.destroy( encoder );
|
|
|
+ dracoEncoder.destroy( builder );
|
|
|
+
|
|
|
+ return outputData;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+// Encoder methods
|
|
|
+
|
|
|
+DRACOExporter.MESH_EDGEBREAKER_ENCODING = 1;
|
|
|
+DRACOExporter.MESH_SEQUENTIAL_ENCODING = 0;
|
|
|
+
|
|
|
+// Geometry type
|
|
|
+
|
|
|
+DRACOExporter.POINT_CLOUD = 0;
|
|
|
+DRACOExporter.TRIANGULAR_MESH = 1;
|
|
|
+
|
|
|
+// Attribute type
|
|
|
+
|
|
|
+DRACOExporter.INVALID = - 1;
|
|
|
+DRACOExporter.POSITION = 0;
|
|
|
+DRACOExporter.NORMAL = 1;
|
|
|
+DRACOExporter.COLOR = 2;
|
|
|
+DRACOExporter.TEX_COORD = 3;
|
|
|
+DRACOExporter.GENERIC = 4;
|
|
|
+
|
|
|
+export { DRACOExporter };
|