Refactor material conversion.

This commit is contained in:
Viktor Kovacs 2023-10-21 18:10:45 +02:00
parent 7420e4dfeb
commit 077d46d112
2 changed files with 87 additions and 171 deletions

View File

@ -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);
}

View File

@ -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);
}
}
}