UNPKG

angular-3d-viewer

Version:
446 lines (391 loc) 13.4 kB
import { WaitWhile } from '../core/taskrunner.js'; import { Direction } from '../geometry/geometry.js'; import { Matrix } from '../geometry/matrix.js'; import { Transformation } from '../geometry/transformation.js'; import { Base64DataURIToArrayBuffer, CreateObjectUrl, GetFileExtensionFromMimeType } from '../io/bufferutils.js'; import { GetFileExtension, GetFileName } from '../io/fileutils.js'; import { PhongMaterial, TextureMap } from '../model/material.js'; import { Node } from '../model/node.js'; import { ConvertThreeColorToColor, ConvertThreeGeometryToMesh, ThreeLinearToSRGBColorConverter, ThreeSRGBToLinearColorConverter } from '../threejs/threeutils.js'; import { ImporterBase } from './importerbase.js'; import * as THREE from 'three'; import { TGALoader } from 'three/examples/jsm/loaders/TGALoader.js'; import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'; import { ColladaLoader } from 'three/examples/jsm/loaders/ColladaLoader.js'; import { VRMLLoader } from 'three/examples/jsm/loaders/VRMLLoader.js'; import { ThreeMFLoader } from 'three/examples/jsm/loaders/3MFLoader.js'; import { AMFLoader } from 'three/examples/jsm/loaders/AMFLoader.js'; export class ImporterThreeBase extends ImporterBase { constructor () { super (); this.colorConverter = null; } CreateLoader (manager) { return null; } GetMainObject (loadedObject) { return loadedObject; } IsMeshVisible (mesh) { return true; } ClearContent () { this.loader = null; this.materialIdToIndex = null; this.objectUrlToFileName = null; } ResetContent () { this.loader = null; this.materialIdToIndex = new Map (); this.objectUrlToFileName = new Map (); } ImportContent (fileContent, onFinish) { this.LoadModel (fileContent, onFinish); } LoadModel (fileContent, onFinish) { let isAllLoadersDone = false; let loadingManager = new THREE.LoadingManager (() => { isAllLoadersDone = true; }); const mainFileUrl = CreateObjectUrl (fileContent); loadingManager.setURLModifier ((url) => { if (url === mainFileUrl) { return url; } const name = GetFileName (url); const extension = GetFileExtension (url); if (extension.length > 0) { const buffer = this.callbacks.getFileBuffer (url); if (buffer !== null) { let objectUrl = CreateObjectUrl (buffer); this.objectUrlToFileName.set (objectUrl, name); return objectUrl; } } return url; }); const threeLoader = this.CreateLoader (loadingManager); if (threeLoader === null) { onFinish (); return; } threeLoader.load (mainFileUrl, (object) => { WaitWhile (() => { if (isAllLoadersDone) { this.OnThreeObjectsLoaded (object, onFinish); return false; } return true; }); }, () => { }, (err) => { this.SetError (err); onFinish (); } ); } OnThreeObjectsLoaded (loadedObject, onFinish) { function GetObjectTransformation (threeObject) { let matrix = new Matrix ().CreateIdentity (); threeObject.updateMatrix (); if (threeObject.matrix !== undefined && threeObject.matrix !== null) { matrix.Set (threeObject.matrix.elements); } return new Transformation (matrix); } function AddObject (importer, model, threeObject, parentNode) { let node = new Node (); if (threeObject.name !== undefined) { node.SetName (threeObject.name); } node.SetTransformation (GetObjectTransformation (threeObject)); parentNode.AddChildNode (node); for (let childObject of threeObject.children) { AddObject (importer, model, childObject, node); } if (threeObject.isMesh && importer.IsMeshVisible (threeObject)) { let mesh = importer.ConvertThreeMesh (threeObject); let meshIndex = model.AddMesh (mesh); node.AddMeshIndex (meshIndex); } } let mainObject = this.GetMainObject (loadedObject); let rootNode = this.model.GetRootNode (); rootNode.SetTransformation (GetObjectTransformation (mainObject)); for (let childObject of mainObject.children) { AddObject (this, this.model, childObject, rootNode); } onFinish (); } ConvertThreeMesh (threeMesh) { let mesh = null; if (Array.isArray (threeMesh.material)) { mesh = ConvertThreeGeometryToMesh (threeMesh.geometry, null, this.colorConverter); if (threeMesh.geometry.attributes.color === undefined || threeMesh.geometry.attributes.color === null) { let materialIndices = []; for (let i = 0; i < threeMesh.material.length; i++) { const material = threeMesh.material[i]; const materialIndex = this.FindOrCreateMaterial (material); materialIndices.push (materialIndex); } for (let i = 0; i < threeMesh.geometry.groups.length; i++) { let group = threeMesh.geometry.groups[i]; let groupEnd = null; if (group.count === Infinity) { groupEnd = mesh.TriangleCount (); } else { groupEnd = group.start / 3 + group.count / 3; } for (let j = group.start / 3; j < groupEnd; j++) { let triangle = mesh.GetTriangle (j); triangle.SetMaterial (materialIndices[group.materialIndex]); } } } } else { const materialIndex = this.FindOrCreateMaterial (threeMesh.material); mesh = ConvertThreeGeometryToMesh (threeMesh.geometry, materialIndex, this.colorConverter); } if (threeMesh.name !== undefined && threeMesh.name !== null) { mesh.SetName (threeMesh.name); } return mesh; } FindOrCreateMaterial (threeMaterial) { if (this.materialIdToIndex.has (threeMaterial.id)) { return this.materialIdToIndex.get (threeMaterial.id); } let material = this.ConvertThreeMaterial (threeMaterial); let materialIndex = null; if (material !== null) { materialIndex = this.model.AddMaterial (material); } this.materialIdToIndex.set (threeMaterial.id, materialIndex); return materialIndex; } ConvertThreeMaterial (threeMaterial) { function CreateTexture (threeMap, objectUrlToFileName) { function GetDataUrl (img) { if (img.data !== undefined && img.data !== null) { let imageData = new ImageData (img.width, img.height); let imageSize = img.width * img.height * 4; for (let i = 0; i < imageSize; i++) { imageData.data[i] = img.data[i]; } return THREE.ImageUtils.getDataURL (imageData); } else { return THREE.ImageUtils.getDataURL (img); } } if (threeMap === undefined || threeMap === null) { return null; } if (threeMap.image === undefined || threeMap.image === null) { return null; } try { const dataUrl = GetDataUrl (threeMap.image); const base64Buffer = Base64DataURIToArrayBuffer (dataUrl); let texture = new TextureMap (); let textureName = null; if (objectUrlToFileName.has (threeMap.image.src)) { textureName = objectUrlToFileName.get (threeMap.image.src); } else if (threeMap.name !== undefined && threeMap.name !== null) { textureName = threeMap.name + '.' + GetFileExtensionFromMimeType (base64Buffer.mimeType); } else { textureName = 'Embedded_' + threeMap.id.toString () + '.' + GetFileExtensionFromMimeType (base64Buffer.mimeType); } texture.name = textureName; texture.mimeType = base64Buffer.mimeType; texture.buffer = base64Buffer.buffer; texture.rotation = threeMap.rotation; texture.offset.x = threeMap.offset.x; texture.offset.y = threeMap.offset.y; texture.scale.x = threeMap.repeat.x; texture.scale.y = threeMap.repeat.y; return texture; } catch (err) { return null; } } if (threeMaterial.name === THREE.Loader.DEFAULT_MATERIAL_NAME) { return null; } let material = new PhongMaterial (); material.name = threeMaterial.name; material.color = this.ConvertThreeColor (threeMaterial.color); material.opacity = threeMaterial.opacity; material.transparent = threeMaterial.transparent; material.alphaTest = threeMaterial.alphaTest; if (threeMaterial.type === 'MeshPhongMaterial') { material.specular = this.ConvertThreeColor (threeMaterial.specular); material.shininess = threeMaterial.shininess / 100.0; } material.diffuseMap = CreateTexture (threeMaterial.map, this.objectUrlToFileName); material.normalMap = CreateTexture (threeMaterial.normalMap, this.objectUrlToFileName); material.bumpMap = CreateTexture (threeMaterial.bumpMap, this.objectUrlToFileName); return material; } ConvertThreeColor (threeColor) { if (this.colorConverter !== null) { threeColor = this.colorConverter.Convert (threeColor); } return ConvertThreeColorToColor (threeColor); } } export class ImporterThreeFbx extends ImporterThreeBase { constructor () { super (); this.colorConverter = new ThreeLinearToSRGBColorConverter (); } CanImportExtension (extension) { return extension === 'fbx'; } GetUpDirection () { return Direction.Y; } CreateLoader (manager) { manager.addHandler (/\.tga$/i, new TGALoader (manager)); return new FBXLoader (manager); } GetMainObject (loadedObject) { return loadedObject; } } export class ImporterThreeDae extends ImporterThreeBase { constructor () { super (); } CanImportExtension (extension) { return extension === 'dae'; } GetUpDirection () { return Direction.Y; } CreateLoader (manager) { manager.addHandler (/\.tga$/i, new TGALoader (manager)); return new ColladaLoader (manager); } GetMainObject (loadedObject) { return loadedObject.scene; } } export class ImporterThreeWrl extends ImporterThreeBase { constructor () { super (); this.colorConverter = new ThreeLinearToSRGBColorConverter (); } CanImportExtension (extension) { return extension === 'wrl'; } GetUpDirection () { return Direction.Y; } CreateLoader (manager) { return new VRMLLoader (manager); } GetMainObject (loadedObject) { return loadedObject; } IsMeshVisible (mesh) { let isVisible = true; if (Array.isArray (mesh.material)) { for (let i = 0; i < mesh.material.length; i++) { if (mesh.material[i].side === THREE.BackSide) { isVisible = false; break; } } } else { isVisible = (mesh.material.side !== THREE.BackSide); } return isVisible; } } export class ImporterThree3mf extends ImporterThreeBase { constructor () { super (); this.colorConverter = new ThreeSRGBToLinearColorConverter (); } CanImportExtension (extension) { return extension === '3mf'; } GetUpDirection () { return Direction.Z; } CreateLoader (manager) { return new ThreeMFLoader (manager); } GetMainObject (loadedObject) { return loadedObject; } } export class ImporterThreeAmf extends ImporterThreeBase { constructor () { super (); } CanImportExtension (extension) { return extension === 'amf'; } GetUpDirection () { return Direction.Z; } CreateLoader (manager) { return new AMFLoader (manager); } GetMainObject (loadedObject) { return loadedObject; } }