diff --git a/source/engine/threejs/threeconverter.js b/source/engine/threejs/threeconverter.js index e996d11..37c1f78 100644 --- a/source/engine/threejs/threeconverter.js +++ b/source/engine/threejs/threeconverter.js @@ -97,50 +97,31 @@ export class ThreeNodeTree } } -export function ConvertModelToThreeObject (model, params, output, callbacks) +export class ThreeMaterialHandler { - function CreateThreeMaterial (stateHandler, model, materialIndex, shadingType, params, output) + constructor (model, stateHandler, conversionParams, conversionOutput) { - function SetTextureParameters (texture, threeTexture) - { - threeTexture.wrapS = THREE.RepeatWrapping; - threeTexture.wrapT = THREE.RepeatWrapping; - threeTexture.rotation = texture.rotation; - threeTexture.offset.x = texture.offset.x; - threeTexture.offset.y = texture.offset.y; - threeTexture.repeat.x = texture.scale.x; - threeTexture.repeat.y = texture.scale.y; - } + this.model = model; + this.stateHandler = stateHandler; + this.conversionParams = conversionParams; + this.conversionOutput = conversionOutput; - function LoadTexture (stateHandler, threeMaterial, texture, output, onTextureLoaded) - { - if (texture === null || !texture.IsValid ()) { - return; - } - let loader = new THREE.TextureLoader (); - stateHandler.OnTextureNeeded (); - let textureObjectUrl = null; - if (texture.mimeType !== null) { - textureObjectUrl = CreateObjectUrlWithMimeType (texture.buffer, texture.mimeType); - } else { - textureObjectUrl = CreateObjectUrl (texture.buffer); - } - output.objectUrls.push (textureObjectUrl); - loader.load (textureObjectUrl, - (threeTexture) => { - SetTextureParameters (texture, threeTexture); - threeMaterial.needsUpdate = true; - onTextureLoaded (threeTexture); - stateHandler.OnTextureLoaded (); - }, - null, - (err) => { - stateHandler.OnTextureLoaded (); - } - ); - } + this.shadingType = GetShadingType (model); + this.modelToThreeMaterial = new Map (); + } - let material = model.GetMaterial (materialIndex); + GetThreeMaterial (modelMaterialIndex) + { + if (!this.modelToThreeMaterial.has (modelMaterialIndex)) { + let threeMaterial = this.CreateThreeMaterial (modelMaterialIndex); + this.modelToThreeMaterial.set (modelMaterialIndex, threeMaterial); + } + return this.modelToThreeMaterial.get (modelMaterialIndex); + } + + CreateThreeMaterial (materialIndex) + { + let material = this.model.GetMaterial (materialIndex); let baseColor = ConvertColorToThreeColor (material.color); if (material.vertexColors) { baseColor.setRGB (1.0, 1.0, 1.0); @@ -155,12 +136,12 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) side : THREE.DoubleSide }; - if (params.forceMediumpForMaterials) { + if (this.conversionParams.forceMediumpForMaterials) { materialParams.precision = 'mediump'; } let threeMaterial = null; - if (shadingType === ShadingType.Phong) { + if (this.shadingType === ShadingType.Phong) { threeMaterial = new THREE.MeshPhongMaterial (materialParams); if (material.type === MaterialType.Phong) { let specularColor = ConvertColorToThreeColor (material.specular); @@ -169,16 +150,16 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } threeMaterial.specular = specularColor; threeMaterial.shininess = material.shininess * 100.0; - LoadTexture (stateHandler, threeMaterial, material.specularMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.specularMap, (threeTexture) => { threeMaterial.specularMap = threeTexture; }); } - } else if (shadingType === ShadingType.Physical) { + } else if (this.shadingType === ShadingType.Physical) { threeMaterial = new THREE.MeshStandardMaterial (materialParams); if (material.type === MaterialType.Physical) { threeMaterial.metalness = material.metalness; threeMaterial.roughness = material.roughness; - LoadTexture (stateHandler, threeMaterial, material.metalnessMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.metalnessMap, (threeTexture) => { threeMaterial.metalness = 1.0; threeMaterial.roughness = 1.0; threeMaterial.metalnessMap = threeTexture; @@ -190,30 +171,72 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let emissiveColor = ConvertColorToThreeColor (material.emissive); threeMaterial.emissive = emissiveColor; - LoadTexture (stateHandler, threeMaterial, material.diffuseMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.diffuseMap, (threeTexture) => { if (!material.multiplyDiffuseMap) { threeMaterial.color.setRGB (1.0, 1.0, 1.0); } threeMaterial.map = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.bumpMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.bumpMap, (threeTexture) => { threeMaterial.bumpMap = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.normalMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.normalMap, (threeTexture) => { threeMaterial.normalMap = threeTexture; }); - LoadTexture (stateHandler, threeMaterial, material.emissiveMap, output, (threeTexture) => { + this.LoadTexture (threeMaterial, material.emissiveMap, (threeTexture) => { threeMaterial.emissiveMap = threeTexture; }); if (material.isDefault) { - output.defaultMaterial = threeMaterial; + this.conversionOutput.defaultMaterial = threeMaterial; } return threeMaterial; } - function CreateThreeTriangleMesh (meshInstance, modelThreeMaterials) + LoadTexture (threeMaterial, texture, onTextureLoaded) + { + function SetTextureParameters (texture, threeTexture) + { + threeTexture.wrapS = THREE.RepeatWrapping; + threeTexture.wrapT = THREE.RepeatWrapping; + threeTexture.rotation = texture.rotation; + threeTexture.offset.x = texture.offset.x; + threeTexture.offset.y = texture.offset.y; + threeTexture.repeat.x = texture.scale.x; + threeTexture.repeat.y = texture.scale.y; + } + + if (texture === null || !texture.IsValid ()) { + return; + } + let loader = new THREE.TextureLoader (); + this.stateHandler.OnTextureNeeded (); + let textureObjectUrl = null; + if (texture.mimeType !== null) { + textureObjectUrl = CreateObjectUrlWithMimeType (texture.buffer, texture.mimeType); + } else { + textureObjectUrl = CreateObjectUrl (texture.buffer); + } + this.conversionOutput.objectUrls.push (textureObjectUrl); + loader.load (textureObjectUrl, + (threeTexture) => { + SetTextureParameters (texture, threeTexture); + threeMaterial.needsUpdate = true; + onTextureLoaded (threeTexture); + this.stateHandler.OnTextureLoaded (); + }, + null, + (err) => { + this.stateHandler.OnTextureLoaded (); + } + ); + } +} + +export function ConvertModelToThreeObject (model, conversionParams, conversionOutput, callbacks) +{ + function CreateThreeTriangleMesh (meshInstance, materialHandler) { let mesh = meshInstance.mesh; let triangleCount = mesh.TriangleCount (); @@ -249,7 +272,8 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let meshHasVertexColors = (mesh.VertexColorCount () > 0); let meshHasUVs = (mesh.TextureUVCount () > 0); - for (let triangleIndex of triangleIndices) { + for (let i = 0; i < triangleIndices.length; i++) { + let triangleIndex = triangleIndices[i]; let triangle = mesh.GetTriangle (triangleIndex); let v0 = mesh.GetVertex (triangle.v0); @@ -290,8 +314,9 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) let modelMaterialIndex = triangle.mat; if (!modelToThreeMaterials.has (modelMaterialIndex)) { + let threeMaterial = materialHandler.GetThreeMaterial (modelMaterialIndex); modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); - meshThreeMaterials.push (modelThreeMaterials[modelMaterialIndex]); + meshThreeMaterials.push (threeMaterial); meshOriginalMaterials.push (modelMaterialIndex); if (i > 0) { groups[groups.length - 1].end = i - 1; @@ -372,113 +397,6 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) threeMaterials : null }; return threeLine; - // let triangleIndices = []; - // for (let i = 0; i < triangleCount; i++) { - // triangleIndices.push (i); - // } - // triangleIndices.sort ((a, b) => { - // let aTriangle = mesh.GetTriangle (a); - // let bTriangle = mesh.GetTriangle (b); - // return aTriangle.mat - bTriangle.mat; - // }); - - // let threeGeometry = new THREE.BufferGeometry (); - // let meshThreeMaterials = []; - // let meshOriginalMaterials = []; - // let modelToThreeMaterials = new Map (); - - // let vertices = []; - // let vertexColors = []; - // let normals = []; - // let uvs = []; - - // let groups = []; - // groups.push ({ - // start : 0, - // end : -1 - // }); - - // let meshHasVertexColors = (mesh.VertexColorCount () > 0); - // let meshHasUVs = (mesh.TextureUVCount () > 0); - // for (let i = 0; i < triangleIndices.length; i++) { - // let triangleIndex = triangleIndices[i]; - // let triangle = mesh.GetTriangle (triangleIndex); - - // let v0 = mesh.GetVertex (triangle.v0); - // let v1 = mesh.GetVertex (triangle.v1); - // let v2 = mesh.GetVertex (triangle.v2); - // vertices.push (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); - - // if (triangle.HasVertexColors ()) { - // let vc0 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c0)); - // let vc1 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c1)); - // let vc2 = ConvertColorToThreeColor (mesh.GetVertexColor (triangle.c2)); - // vertexColors.push ( - // vc0.r, vc0.g, vc0.b, - // vc1.r, vc1.g, vc1.b, - // vc2.r, vc2.g, vc2.b - // ); - // } else if (meshHasVertexColors) { - // vertexColors.push ( - // 0.0, 0.0, 0.0, - // 0.0, 0.0, 0.0, - // 0.0, 0.0, 0.0 - // ); - // } - - // let n0 = mesh.GetNormal (triangle.n0); - // let n1 = mesh.GetNormal (triangle.n1); - // let n2 = mesh.GetNormal (triangle.n2); - // normals.push (n0.x, n0.y, n0.z, n1.x, n1.y, n1.z, n2.x, n2.y, n2.z); - - // if (triangle.HasTextureUVs ()) { - // let u0 = mesh.GetTextureUV (triangle.u0); - // let u1 = mesh.GetTextureUV (triangle.u1); - // let u2 = mesh.GetTextureUV (triangle.u2); - // uvs.push (u0.x, u0.y, u1.x, u1.y, u2.x, u2.y); - // } else if (meshHasUVs) { - // uvs.push (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); - // } - - // let modelMaterialIndex = triangle.mat; - // if (!modelToThreeMaterials.has (modelMaterialIndex)) { - // modelToThreeMaterials.set (modelMaterialIndex, meshThreeMaterials.length); - // meshThreeMaterials.push (modelThreeMaterials[modelMaterialIndex]); - // meshOriginalMaterials.push (modelMaterialIndex); - // if (i > 0) { - // groups[groups.length - 1].end = i - 1; - // groups.push ({ - // start : groups[groups.length - 1].end + 1, - // end : -1 - // }); - // } - // } - // } - - // groups[groups.length - 1].end = triangleCount - 1; - - // threeGeometry.setAttribute ('position', new THREE.Float32BufferAttribute (vertices, 3)); - // if (vertexColors.length !== 0) { - // threeGeometry.setAttribute ('color', new THREE.Float32BufferAttribute (vertexColors, 3)); - // } - // threeGeometry.setAttribute ('normal', new THREE.Float32BufferAttribute (normals, 3)); - // if (uvs.length !== 0) { - // threeGeometry.setAttribute ('uv', new THREE.Float32BufferAttribute (uvs, 2)); - // } - // for (let i = 0; i < groups.length; i++) { - // let group = groups[i]; - // threeGeometry.addGroup (group.start * 3, (group.end - group.start + 1) * 3, i); - // } - - // let threeMesh = new THREE.Mesh (threeGeometry, meshThreeMaterials); - // threeMesh.name = mesh.GetName (); - // threeMesh.userData = { - // originalMeshInstance : meshInstance, - // originalMaterials : meshOriginalMaterials, - // threeMaterials : null - // }; - - // return threeMesh; } function ConvertMesh (threeObject, meshInstance, modelThreeMaterials) @@ -498,7 +416,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } } - function ConvertNodeHierarchy (threeRootNode, model, modelThreeMaterials, stateHandler) + function ConvertNodeHierarchy (threeRootNode, model, materialHandler, stateHandler) { let nodeTree = new ThreeNodeTree (model, threeRootNode); let threeNodeItems = nodeTree.GetNodeItems (); @@ -507,7 +425,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) runTask : (firstMeshInstanceIndex, lastMeshInstanceIndex, onReady) => { for (let meshInstanceIndex = firstMeshInstanceIndex; meshInstanceIndex <= lastMeshInstanceIndex; meshInstanceIndex++) { let nodeItem = threeNodeItems[meshInstanceIndex]; - ConvertMesh (nodeItem.threeNode, nodeItem.meshInstance, modelThreeMaterials); + ConvertMesh (nodeItem.threeNode, nodeItem.meshInstance, materialHandler); } onReady (); }, @@ -518,14 +436,7 @@ export function ConvertModelToThreeObject (model, params, output, callbacks) } let stateHandler = new ThreeConversionStateHandler (callbacks); - let shadingType = GetShadingType (model); - - let modelThreeMaterials = []; - for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) { - let threeMaterial = CreateThreeMaterial (stateHandler, model, materialIndex, shadingType, params, output); - modelThreeMaterials.push (threeMaterial); - } - + let materialHandler = new ThreeMaterialHandler (model, stateHandler, conversionParams, conversionOutput); let threeObject = new THREE.Object3D (); - ConvertNodeHierarchy (threeObject, model, modelThreeMaterials, stateHandler); + ConvertNodeHierarchy (threeObject, model, materialHandler, stateHandler); } diff --git a/source/website/website.js b/source/website/website.js index 89db998..1ad72cf 100644 --- a/source/website/website.js +++ b/source/website/website.js @@ -877,9 +877,14 @@ export class Website } } else { let userDataArr = GetMeshUserDataArray (viewer, meshInstanceId); + let addedMaterialIndices = new Set (); for (let userData of userDataArr) { for (let materialIndex of userData.originalMaterials) { + if (addedMaterialIndices.has (materialIndex)) { + continue; + } usedMaterials.push (GetMaterialReferenceInfo (model, materialIndex)); + addedMaterialIndices.add (materialIndex); } } }