import { Points, Mesh, MeshBasicMaterial, MeshStandardMaterial, VertexColors, TrianglesDrawMode, DoubleSide } from 'three' import { scene } from '../renderer' import DRACOLoader from '../../util/vendor/DRACOLoader' import GeometryHelper from '../../util/vendor/geometryHelper' import { getBboxScaleAndCentroid } from './util' import { FACE_SCALE } from '../constants' DRACOLoader.setDecoderPath('/assets/js/vendor/draco/') const dracoLoader = new DRACOLoader() DRACOLoader.getDecoderModule() dracoLoader.setVerbosity(1) dracoLoader.setDrawMode(TrianglesDrawMode) export function load(name) { dracoLoader.setSkipDequantization('position', true) return new Promise((resolve, reject) => { const loaded = geometry => resolve(geometry) const progress = () => {} const error = () => reject() dracoLoader.load('/assets/data/faces/' + name + '.drc', loaded, progress, error) }) } export function update(name) { load(name) } export function createFaceMeshes(geometry) { return { blank: createBlankFace(geometry), wireframe: createWireframeFace(geometry), solid: createSolidFace(geometry), } } export function remove() { removeMesh('blank') removeMesh('wireframe') removeMesh('solid') } export function removeMesh(name) { const selectedObject = scene.getObjectByName(name) scene.remove(selectedObject) } function createBlankFace(geometry) { const material = new MeshStandardMaterial({ color: 0xFFFFFF, metalness: 0.2, roughness: 0.5, alphaTest: 0.01, }) material.wireframe = false material.transparent = true material.opacity = 0 material.side = DoubleSide return appendFace('blank', geometry, material) } function createWireframeFace(geometry) { const material = new MeshBasicMaterial({ vertexColors: VertexColors, alphaTest: 0.01, }) material.wireframe = true material.transparent = true material.opacity = 0 return appendFace('wireframe', geometry, material) } function createSolidFace(geometry) { const material = new MeshBasicMaterial({ vertexColors: VertexColors }) material.transparent = true material.opacity = 0 material.side = DoubleSide return appendFace('solid', geometry, material) } function appendFace(name, bufferGeometry, material) { // If the position attribute is quantized, modify the material to perform // dequantization on the GPU. if (bufferGeometry.attributes.position.isQuantized) { setDequantizationForMaterial(material, bufferGeometry) } let geometry // Point cloud does not have face indices. if (bufferGeometry.index === null) { geometry = new Points(bufferGeometry, material) } else { if (bufferGeometry.attributes.normal === undefined) { const geometryHelper = new GeometryHelper() geometryHelper.computeVertexNormals(bufferGeometry) } geometry = new Mesh(bufferGeometry, material) geometry.drawMode = dracoLoader.drawMode } // Compute range of the geometry coordinates for proper rendering. bufferGeometry.computeBoundingBox() const bbox = bufferGeometry.boundingBox const { scale, midX, midY, midZ } = getBboxScaleAndCentroid(bbox, bufferGeometry.attributes.position) geometry.scale.multiplyScalar(scale * FACE_SCALE) geometry.position.x = -midX * scale geometry.position.y = -midY * scale geometry.position.z = -midZ * scale geometry.frustumCulled = false // geometry.castShadow = true // geometry.receiveShadow = true const selectedObject = scene.getObjectByName(name) scene.remove(selectedObject) geometry.name = name scene.add(geometry) return geometry } function setDequantizationForMaterial(material, bufferGeometry) { material.onBeforeCompile = (shader) => { // Add uniform variables needed for dequantization. const posAttribute = bufferGeometry.attributes.position shader.uniforms.normConstant = { value: posAttribute.maxRange / (1 << posAttribute.numQuantizationBits) } shader.uniforms.minPos = { value: posAttribute.minValues } shader.vertexShader = 'uniform float maxRange;\n' + 'uniform float normConstant;\n' + 'uniform vec3 minPos;\n' + shader.vertexShader shader.vertexShader = shader.vertexShader.replace( '#include ', 'vec3 transformed = minPos + position * normConstant;' ) } }