drawMesh.js 7.5 KB
import {
    Mesh,
    BufferGeometry,
    Box3,
    Matrix4,
    Vector3,
    MeshStandardMaterial,
    DoubleSide,
    BackSide,
    MeshPhysicalMaterial,
    FrontSide
} from 'three';
import { getSceneMeshMaterials } from '@/utility/constants/materials';
import { STLLoader } from 'three/examples/jsm/loaders/STLLoader';
import { MESH_NAME } from '@/utility/constants/mesh-named';
import { mergeVertices } from '@/utility/jsm/meshEditor/mergeVertics';
import { getGeometryVolume } from '@/utility/jsm/function/getGeometryVolume';
import { buildEdgeMap } from '@/utility/jsm/function/topology';
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
import safeStringify from 'fast-safe-stringify';

import STXLoader from '@/utility/jsm/loader/STXLoader';
import { PointCloudLoader } from '@/utility/jsm/loader/PointCloudLoader';
import { LNXLoader } from '@/utility/jsm/loader/LNXLoader';

import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';

BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
Mesh.prototype.raycast = acceleratedRaycast;

const loader = new STLLoader();
const stxloader = new STXLoader();
const ptsloader = new PointCloudLoader();
const lnxloader = new LNXLoader();

const loadAsync = (url, name, title, extension) => {
    return new Promise((resolve) => {
        if (extension === 'stl') {
            loader.load(url, (geometry) => {
                geometry.name = name;
                geometry.title = title;
                resolve(geometry);
            });
        } else if (extension === 'stx') {
            stxloader.load(url, (stxModel) => {
                stxModel.name = name;
                stxModel.title = title;
                resolve(stxModel);
            });
        } else if (extension === 'pts') {
            ptsloader.load(url, (points) => {
                resolve(points);
            });
        } else if (extension === 'lnx') {
            lnxloader.load(url, (lnxModel) => {
                const { geometry } = lnxModel;
                geometry.title = title;
                resolve(geometry);
            });
        }
    });
};

const transforGeometryToMesh = (
    geometry,
    isOffset = true,
    isMergeVertices = true,
    isSupport = false,
    isStx = false
) => {
    if (isMergeVertices) mergeVertices(geometry);
    geometry.computeVertexNormals();
    geometry.computeBoundsTree();
    geometry.volume = getGeometryVolume(geometry);
    let material = getSceneMeshMaterials();
    let materialSupport = getSceneMeshMaterials(0x636971);
    if (isStx) {
        material = new MeshPhysicalMaterial({
            transmission: 1,
            metalness: 0.11,
            roughness: 0.24,
            envMapIntensity: 0.9,
            clearcoat: 0.9,
            clearcoatRoughness: 1.0,
            transparent: true,
            opacity: 0.5,
            reflectivity: 0.6,
            refractionRatio: 0.985,
            ior: 1.8,
            side: FrontSide
        });
        materialSupport = new MeshPhysicalMaterial({
            transmission: 1,
            metalness: 0.11,
            roughness: 0.24,
            envMapIntensity: 0.9,
            clearcoat: 0.9,
            clearcoatRoughness: 1.0,
            transparent: true,
            opacity: 0.5,
            reflectivity: 0.6,
            refractionRatio: 0.985,
            ior: 1.8,
            side: FrontSide
        });
    }

    const mesh = isSupport ? new Mesh(geometry, [material, materialSupport]) : new Mesh(geometry, material);

    mesh.name = `${MESH_NAME}${geometry.name}`;
    mesh.title = geometry.title;

    const box = new Box3();
    geometry.boundsTree.getBoundingBox(box);
    mesh.box = box;

    const center = box.max.clone().add(box.min).multiplyScalar(0.5);
    const voffset = new Vector3(-center.x, -center.y, -box.min.z);
    const matrix = new Matrix4().setPosition(voffset);
    if (isOffset) geometry.applyMatrix4(matrix);

    geometry.computeBoundsTree();
    geometry.json = safeStringify.stableStringify([geometry.attributes.position]);

    geometry.boundsTree.getBoundingBox(box);
    mesh.box = box;
    geometry.originCenter = box.max.clone().add(box.min).multiplyScalar(0.5);
    mesh.rotateCenter = box.max.clone().add(box.min).multiplyScalar(0.5);
    mesh.finalRotateAngle = { X: 0, Y: 0, Z: 0 };

    mesh.matrixAutoUpdate = false;
    mesh.matrixWorldNeedsUpdate = true;
    delete geometry.name;
    delete geometry.title;

    return mesh;
};

const transforStxModel = (stxModel) => {
    const meshs = [];
    stxModel.mesh.forEach((el) => {
        const { geometry, support, supprtGeometry } = el;
        let mergeGeometrys = null;
        if (support && supprtGeometry) {
            mergeGeometrys = mergeGeometries([support.geometry, supprtGeometry]);
        } else if (support) {
            mergeGeometrys = support.geometry;
        } else {
            mergeGeometrys = supprtGeometry;
        }
        const mergeGeometry = mergeGeometrys ? mergeGeometries([geometry, mergeGeometrys], true) : geometry;
        const isSupports = mergeGeometrys !== null;
        mergeGeometry.name = geometry.name;
        mergeGeometry.title = geometry.name;
        const mesh = transforGeometryToMesh(mergeGeometry, false, false, isSupports, true);
        mesh.meshType = 'stx';
        meshs.push(mesh);
    });
    return meshs;
};

const transforLnxModel = (geometry) => {
    mergeVertices(geometry);
    geometry.computeVertexNormals();
    geometry.computeBoundsTree();

    const mesh = new Mesh(
        geometry,
        new MeshStandardMaterial({
            color: 0x8fc4f2,
            roughness: 0.4,
            metalness: 0.05,
            transparent: true,
            side: DoubleSide
        })
    );
    mesh.name = 'active:aligner';
    mesh.title = geometry.title;
    mesh.renderOrder = 1;
    // mesh.geometry.maps = buildEdgeMap(geometry);

    const box = new Box3();
    geometry.boundsTree.getBoundingBox(box);
    mesh.box = box;

    const backMaterial = new MeshStandardMaterial({
        color: 0x969696,
        transparent: true,
        roughness: 0.37,
        metalness: 0.01,
        side: BackSide
    });
    const meshback = new Mesh(geometry, backMaterial);
    meshback.name = 'active:aligner:back';
    meshback.title = geometry.title;

    return { mesh, meshback };
};

const drawMeshsFromLocalPromise = (bloburls, callback) => {
    const loadAsyncs = [];
    const meshes = [];
    bloburls.forEach((el) => {
        const { url, name, title, extension } = el;
        loadAsyncs.push(loadAsync(url, name, title, extension));
    });
    Promise.all(loadAsyncs).then((geometries) => {
        geometries.forEach((el) => {
            if (el.type === 'BufferGeometry') {
                const mesh = transforGeometryToMesh(el, false, true);
                meshes.push(mesh);
            } else if (el.type === 'StxModel') {
                const stxModels = transforStxModel(el);
                stxModels.forEach((mesh) => {
                    meshes.push(mesh);
                });
            } else if (el.type === 'PtsModel') {
                meshes.push(el);
            } else if (el.type === 'LnxModel') {
                const { mesh, meshback } = transforLnxModel(el.geometry, false, true);
                meshes.push(mesh);
                meshes.push(meshback);
            } else {
                console.log('it is not support this format yet.');
            }
        });
        if (callback) callback(meshes);
    });
};

export { drawMeshsFromLocalPromise };