UNPKG

@xeokit/xeokit-sdk

Version:

3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision

227 lines (212 loc) 7.58 kB
import {math} from "../math/math.js"; const translate = math.mat4(); const scale = math.mat4(); /** * @private */ function quantizePositions(positions, aabb, positionsDecodeMatrix) { // http://cg.postech.ac.kr/research/mesh_comp_mobile/mesh_comp_mobile_conference.pdf const lenPositions = positions.length; const quantizedPositions = new Uint16Array(lenPositions); const xmin = aabb[0]; const ymin = aabb[1]; const zmin = aabb[2]; const xwid = (aabb[3] - xmin) || 1; const ywid = (aabb[4] - ymin) || 1; const zwid = (aabb[5] - zmin) || 1; const maxInt = 65525; const xMultiplier = maxInt / xwid; const yMultiplier = maxInt / ywid; const zMultiplier = maxInt / zwid; const verify = (num) => num >= 0 ? num : 0; for (let i = 0; i < lenPositions; i += 3) { quantizedPositions[i + 0] = Math.floor(verify(positions[i + 0] - xmin) * xMultiplier); quantizedPositions[i + 1] = Math.floor(verify(positions[i + 1] - ymin) * yMultiplier); quantizedPositions[i + 2] = Math.floor(verify(positions[i + 2] - zmin) * zMultiplier); } math.identityMat4(translate); math.translationMat4v(aabb, translate); math.identityMat4(scale); math.scalingMat4v([xwid / maxInt, ywid / maxInt, zwid / maxInt], scale); math.mulMat4(translate, scale, positionsDecodeMatrix); return quantizedPositions; } /** * @private * @param aabb * @param positionsDecodeMatrix * @returns {*} */ function createPositionsDecodeMatrix(aabb, positionsDecodeMatrix) { // http://cg.postech.ac.kr/research/mesh_comp_mobile/mesh_comp_mobile_conference.pdf const xmin = aabb[0]; const ymin = aabb[1]; const zmin = aabb[2]; const xwid = (aabb[3] - xmin) || 1; const ywid = (aabb[4] - ymin) || 1; const zwid = (aabb[5] - zmin) || 1; const maxInt = 65525; math.identityMat4(translate); math.translationMat4v(aabb, translate); math.identityMat4(scale); math.scalingMat4v([xwid / maxInt, ywid / maxInt, zwid / maxInt], scale); math.mulMat4(translate, scale, positionsDecodeMatrix); return positionsDecodeMatrix; } /** * @private */ function transformAndOctEncodeNormals(worldNormalMatrix, normals, lenNormals, compressedNormals, lenCompressedNormals) { // http://jcgt.org/published/0003/02/01/ function dot(array, vec3) { return array[0] * vec3[0] + array[1] * vec3[1] + array[2] * vec3[2]; } let oct, dec, best, currentCos, bestCos; let i, ei; let localNormal = new Float32Array([0, 0, 0, 0]); let worldNormal = new Float32Array([0, 0, 0, 0]); for (i = 0; i < lenNormals; i += 3) { localNormal[0] = normals[i]; localNormal[1] = normals[i + 1]; localNormal[2] = normals[i + 2]; math.transformVec3(worldNormalMatrix, localNormal, worldNormal); math.normalizeVec3(worldNormal, worldNormal); // Test various combinations of ceil and floor to minimize rounding errors best = oct = octEncodeVec3(worldNormal, "floor", "floor"); dec = octDecodeVec2(oct); currentCos = bestCos = dot(worldNormal, dec); oct = octEncodeVec3(worldNormal, "ceil", "floor"); dec = octDecodeVec2(oct); currentCos = dot(worldNormal, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } oct = octEncodeVec3(worldNormal, "floor", "ceil"); dec = octDecodeVec2(oct); currentCos = dot(worldNormal, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } oct = octEncodeVec3(worldNormal, "ceil", "ceil"); dec = octDecodeVec2(oct); currentCos = dot(worldNormal, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } compressedNormals[lenCompressedNormals + i + 0] = best[0]; compressedNormals[lenCompressedNormals + i + 1] = best[1]; compressedNormals[lenCompressedNormals + i + 2] = 0.0; // Unused } lenCompressedNormals += lenNormals; return lenCompressedNormals; } /** * @private */ function octEncodeNormals(normals) { // http://jcgt.org/published/0003/02/01/ const lenNormals = normals.length; const compressedNormals = new Int8Array(lenNormals) let oct, dec, best, currentCos, bestCos; for (let i = 0; i < lenNormals; i += 3) { // Test various combinations of ceil and floor to minimize rounding errors best = oct = octEncodeNormal(normals, i, "floor", "floor"); dec = octDecodeVec2(oct); currentCos = bestCos = dot(normals, i, dec); oct = octEncodeNormal(normals, i, "ceil", "floor"); dec = octDecodeVec2(oct); currentCos = dot(normals, i, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } oct = octEncodeNormal(normals, i, "floor", "ceil"); dec = octDecodeVec2(oct); currentCos = dot(normals, i, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } oct = octEncodeNormal(normals, i, "ceil", "ceil"); dec = octDecodeVec2(oct); currentCos = dot(normals, i, dec); if (currentCos > bestCos) { best = oct; bestCos = currentCos; } compressedNormals[i + 0] = best[0]; compressedNormals[i + 1] = best[1]; compressedNormals[i + 2] = 0.0; // Unused } return compressedNormals; } /** * @private */ function octEncodeVec3(p, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes let x = p[0] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); let y = p[1] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); if (p[2] < 0) { let tempx = x; let tempy = y; tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); x = tempx; y = tempy; } return new Int8Array([ Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) ]); } /** * @private */ function octEncodeNormal(array, i, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes let x = array[i] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); let y = array[i + 1] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); if (array[i + 2] < 0) { let tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); let tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); x = tempx; y = tempy; } return new Int8Array([ Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) ]); } /** * @private */ function octDecodeVec2(oct) { // Decode an oct-encoded normal let x = oct[0]; let y = oct[1]; x /= x < 0 ? 127 : 128; y /= y < 0 ? 127 : 128; const z = 1 - Math.abs(x) - Math.abs(y); if (z < 0) { x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); y = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); } const length = Math.sqrt(x * x + y * y + z * z); return [ x / length, y / length, z / length ]; } /** * @private */ function dot(array, i, vec3) { return array[i] * vec3[0] + array[i + 1] * vec3[1] + array[i + 2] * vec3[2]; } export { quantizePositions, createPositionsDecodeMatrix, octEncodeNormals, transformAndOctEncodeNormals, octEncodeVec3, octDecodeVec2 };