/** * Builds one or many THREE.Mesh from one raw set of Arraybuffers, materialGroup descriptions and further parameters. * Supports vertex, vertexColor, normal, uv and index buffers. * @class */ THREE.LoaderSupport.MeshBuilder = (function () { var LOADER_MESH_BUILDER_VERSION = '1.2.0'; var Validator = THREE.LoaderSupport.Validator; function MeshBuilder() { console.info( 'Using THREE.LoaderSupport.MeshBuilder version: ' + LOADER_MESH_BUILDER_VERSION ); this.logging = { enabled: true, debug: false }; this.callbacks = new THREE.LoaderSupport.Callbacks(); this.materials = []; } /** * Enable or disable logging in general (except warn and error), plus enable or disable debug logging. * @memberOf THREE.LoaderSupport.MeshBuilder * * @param {boolean} enabled True or false. * @param {boolean} debug True or false. */ MeshBuilder.prototype.setLogging = function ( enabled, debug ) { this.logging.enabled = enabled === true; this.logging.debug = debug === true; }; /** * Initializes the MeshBuilder (currently only default material initialisation). * @memberOf THREE.LoaderSupport.MeshBuilder * */ MeshBuilder.prototype.init = function () { var defaultMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } ); defaultMaterial.name = 'defaultMaterial'; var defaultVertexColorMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } ); defaultVertexColorMaterial.name = 'defaultVertexColorMaterial'; defaultVertexColorMaterial.vertexColors = THREE.VertexColors; var defaultLineMaterial = new THREE.LineBasicMaterial(); defaultLineMaterial.name = 'defaultLineMaterial'; var defaultPointMaterial = new THREE.PointsMaterial( { size: 1 } ); defaultPointMaterial.name = 'defaultPointMaterial'; var runtimeMaterials = {}; runtimeMaterials[ defaultMaterial.name ] = defaultMaterial; runtimeMaterials[ defaultVertexColorMaterial.name ] = defaultVertexColorMaterial; runtimeMaterials[ defaultLineMaterial.name ] = defaultLineMaterial; runtimeMaterials[ defaultPointMaterial.name ] = defaultPointMaterial; this.updateMaterials( { cmd: 'materialData', materials: { materialCloneInstructions: null, serializedMaterials: null, runtimeMaterials: runtimeMaterials } } ); }; /** * Set materials loaded by any supplier of an Array of {@link THREE.Material}. * @memberOf THREE.LoaderSupport.MeshBuilder * * @param {THREE.Material[]} materials Array of {@link THREE.Material} */ MeshBuilder.prototype.setMaterials = function ( materials ) { var payload = { cmd: 'materialData', materials: { materialCloneInstructions: null, serializedMaterials: null, runtimeMaterials: Validator.isValid( this.callbacks.onLoadMaterials ) ? this.callbacks.onLoadMaterials( materials ) : materials } }; this.updateMaterials( payload ); }; MeshBuilder.prototype._setCallbacks = function ( callbacks ) { if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress ); if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter ); if ( Validator.isValid( callbacks.onLoad ) ) this.callbacks.setCallbackOnLoad( callbacks.onLoad ); if ( Validator.isValid( callbacks.onLoadMaterials ) ) this.callbacks.setCallbackOnLoadMaterials( callbacks.onLoadMaterials ); }; /** * Delegates processing of the payload (mesh building or material update) to the corresponding functions (BW-compatibility). * @memberOf THREE.LoaderSupport.MeshBuilder * * @param {Object} payload Raw Mesh or Material descriptions. * @returns {THREE.Mesh[]} mesh Array of {@link THREE.Mesh} or null in case of material update */ MeshBuilder.prototype.processPayload = function ( payload ) { if ( payload.cmd === 'meshData' ) { return this.buildMeshes( payload ); } else if ( payload.cmd === 'materialData' ) { this.updateMaterials( payload ); return null; } }; /** * Builds one or multiple meshes from the data described in the payload (buffers, params, material info). * @memberOf THREE.LoaderSupport.MeshBuilder * * @param {Object} meshPayload Raw mesh description (buffers, params, materials) used to build one to many meshes. * @returns {THREE.Mesh[]} mesh Array of {@link THREE.Mesh} */ MeshBuilder.prototype.buildMeshes = function ( meshPayload ) { var meshName = meshPayload.params.meshName; var bufferGeometry = new THREE.BufferGeometry(); bufferGeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.vertices ), 3 ) ); if ( Validator.isValid( meshPayload.buffers.indices ) ) { bufferGeometry.setIndex( new THREE.BufferAttribute( new Uint32Array( meshPayload.buffers.indices ), 1 )); } var haveVertexColors = Validator.isValid( meshPayload.buffers.colors ); if ( haveVertexColors ) { bufferGeometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.colors ), 3 ) ); } if ( Validator.isValid( meshPayload.buffers.normals ) ) { bufferGeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.normals ), 3 ) ); } else { bufferGeometry.computeVertexNormals(); } if ( Validator.isValid( meshPayload.buffers.uvs ) ) { bufferGeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( meshPayload.buffers.uvs ), 2 ) ); } var material, materialName, key; var materialNames = meshPayload.materials.materialNames; var createMultiMaterial = meshPayload.materials.multiMaterial; var multiMaterials = []; for ( key in materialNames ) { materialName = materialNames[ key ]; material = this.materials[ materialName ]; if ( createMultiMaterial ) multiMaterials.push( material ); } if ( createMultiMaterial ) { material = multiMaterials; var materialGroups = meshPayload.materials.materialGroups; var materialGroup; for ( key in materialGroups ) { materialGroup = materialGroups[ key ]; bufferGeometry.addGroup( materialGroup.start, materialGroup.count, materialGroup.index ); } } var meshes = []; var mesh; var callbackOnMeshAlter = this.callbacks.onMeshAlter; var callbackOnMeshAlterResult; var useOrgMesh = true; var geometryType = Validator.verifyInput( meshPayload.geometryType, 0 ); if ( Validator.isValid( callbackOnMeshAlter ) ) { callbackOnMeshAlterResult = callbackOnMeshAlter( { detail: { meshName: meshName, bufferGeometry: bufferGeometry, material: material, geometryType: geometryType } } ); if ( Validator.isValid( callbackOnMeshAlterResult ) ) { if ( ! callbackOnMeshAlterResult.isDisregardMesh() && callbackOnMeshAlterResult.providesAlteredMeshes() ) { for ( var i in callbackOnMeshAlterResult.meshes ) { meshes.push( callbackOnMeshAlterResult.meshes[ i ] ); } } useOrgMesh = false; } } if ( useOrgMesh ) { if ( meshPayload.computeBoundingSphere ) bufferGeometry.computeBoundingSphere(); if ( geometryType === 0 ) { mesh = new THREE.Mesh( bufferGeometry, material ); } else if ( geometryType === 1) { mesh = new THREE.LineSegments( bufferGeometry, material ); } else { mesh = new THREE.Points( bufferGeometry, material ); } mesh.name = meshName; meshes.push( mesh ); } var progressMessage; if ( Validator.isValid( meshes ) && meshes.length > 0 ) { var meshNames = []; for ( var i in meshes ) { mesh = meshes[ i ]; meshNames[ i ] = mesh.name; } progressMessage = 'Adding mesh(es) (' + meshNames.length + ': ' + meshNames + ') from input mesh: ' + meshName; progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } else { progressMessage = 'Not adding mesh: ' + meshName; progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)'; } var callbackOnProgress = this.callbacks.onProgress; if ( Validator.isValid( callbackOnProgress ) ) { var event = new CustomEvent( 'MeshBuilderEvent', { detail: { type: 'progress', modelName: meshPayload.params.meshName, text: progressMessage, numericalValue: meshPayload.progress.numericalValue } } ); callbackOnProgress( event ); } return meshes; }; /** * Updates the materials with contained material objects (sync) or from alteration instructions (async). * @memberOf THREE.LoaderSupport.MeshBuilder * * @param {Object} materialPayload Material update instructions */ MeshBuilder.prototype.updateMaterials = function ( materialPayload ) { var material, materialName; var materialCloneInstructions = materialPayload.materials.materialCloneInstructions; if ( Validator.isValid( materialCloneInstructions ) ) { var materialNameOrg = materialCloneInstructions.materialNameOrg; var materialOrg = this.materials[ materialNameOrg ]; if ( Validator.isValid( materialNameOrg ) ) { material = materialOrg.clone(); materialName = materialCloneInstructions.materialName; material.name = materialName; var materialProperties = materialCloneInstructions.materialProperties; for ( var key in materialProperties ) { if ( material.hasOwnProperty( key ) && materialProperties.hasOwnProperty( key ) ) material[ key ] = materialProperties[ key ]; } this.materials[ materialName ] = material; } else { console.warn( 'Requested material "' + materialNameOrg + '" is not available!' ); } } var materials = materialPayload.materials.serializedMaterials; if ( Validator.isValid( materials ) && Object.keys( materials ).length > 0 ) { var loader = new THREE.MaterialLoader(); var materialJson; for ( materialName in materials ) { materialJson = materials[ materialName ]; if ( Validator.isValid( materialJson ) ) { material = loader.parse( materialJson ); if ( this.logging.enabled ) console.info( 'De-serialized material with name "' + materialName + '" will be added.' ); this.materials[ materialName ] = material; } } } materials = materialPayload.materials.runtimeMaterials; if ( Validator.isValid( materials ) && Object.keys( materials ).length > 0 ) { for ( materialName in materials ) { material = materials[ materialName ]; if ( this.logging.enabled ) console.info( 'Material with name "' + materialName + '" will be added.' ); this.materials[ materialName ] = material; } } }; /** * Returns the mapping object of material name and corresponding jsonified material. * * @returns {Object} Map of Materials in JSON representation */ MeshBuilder.prototype.getMaterialsJSON = function () { var materialsJSON = {}; var material; for ( var materialName in this.materials ) { material = this.materials[ materialName ]; materialsJSON[ materialName ] = material.toJSON(); } return materialsJSON; }; /** * Returns the mapping object of material name and corresponding material. * * @returns {Object} Map of {@link THREE.Material} */ MeshBuilder.prototype.getMaterials = function () { return this.materials; }; return MeshBuilder; })();