UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

155 lines (151 loc) 6.02 kB
import { i as TU, B as BU, F as F32 } from './index-By0tcgYN.esm.js'; import { m as mat4Multiply } from './mat4-multiply-fXsV9rc-.esm.js'; function normalizeVec3(x, y, z, epsilon = 1e-10) { const len = Math.hypot(x, y, z); if (len <= epsilon) { return [0, 1, 0]; } return [x / len, y / len, z / len]; } function ensureDetailTarget(engine, owner) { if (owner.detail) { return owner.detail; } const texture = engine._device.createTexture({ label: "pick-detail", size: [1, 1], format: "rgba32uint", usage: TU.RENDER_ATTACHMENT | TU.COPY_SRC }); return owner.detail = { texture, view: texture.createView(), staging: engine._device.createBuffer({ label: "pick-detail-staging", size: 256, usage: BU.COPY_DST | BU.MAP_READ }) }; } function copyDetailTarget(encoder, target) { encoder.copyTextureToBuffer({ texture: target.texture }, { buffer: target.staging, bytesPerRow: 256 }, { width: 1, height: 1 }); } async function readDetailTarget(target) { await target.staging.mapAsync(GPUMapMode.READ); const range = target.staging.getMappedRange(); const u32 = new Uint32Array(range); const primitiveIndex = u32[0] === 4294967295 ? -1 : u32[0]; const f32 = new Float32Array(range); const localPoint = primitiveIndex < 0 ? null : [f32[1], f32[2], f32[3]]; target.staging.unmap(); return { primitiveIndex, localPoint }; } function enableDetailedPicking(picker) { picker._detailedPicking = picker._scene.surface.engine._device.features.has("primitive-index"); } function copyDetailedWorldMatrix(source) { return new F32(source); } function detailedWorldMatrix(baseWorld, mesh, thinInstanceIndex) { const ti = mesh.thinInstances; if (thinInstanceIndex < 0 || !ti) { return baseWorld; } const offset = thinInstanceIndex * 16; const packed = ti.matrices.subarray(offset, offset + 16); const instance = new F32(16); instance[0] = packed[0]; instance[1] = packed[1]; instance[2] = packed[2]; instance[3] = 0; instance[4] = packed[4]; instance[5] = packed[5]; instance[6] = packed[6]; instance[7] = 0; instance[8] = packed[8]; instance[9] = packed[9]; instance[10] = packed[10]; instance[11] = 0; instance[12] = packed[12]; instance[13] = packed[13]; instance[14] = packed[14]; instance[15] = 1; return mat4Multiply(baseWorld, instance); } function transformNormal(world, normal) { return normalizeVec3( world[0] * normal[0] + world[4] * normal[1] + world[8] * normal[2], world[1] * normal[0] + world[5] * normal[1] + world[9] * normal[2], world[2] * normal[0] + world[6] * normal[1] + world[10] * normal[2] ); } function facesPickRay(normal, info) { const ray = info.ray; return !!ray && normal[0] * ray.direction[0] + normal[1] * ray.direction[1] + normal[2] * ray.direction[2] > 0; } function clampTinyBarycentric(value) { return Math.abs(value) < 1e-12 ? 0 : value; } function populateDetailedMeshInfo(info, mesh, faceId, localPoint, positions, normals, world, surfaceNormalsValid) { info.faceId = faceId; const indices = mesh._cpuIndices; if (!positions || !indices || faceId < 0 || faceId * 3 + 2 >= indices.length) { return; } const i0 = indices[faceId * 3]; const i1 = indices[faceId * 3 + 1]; const i2 = indices[faceId * 3 + 2]; if (i0 * 3 + 2 >= positions.length || i1 * 3 + 2 >= positions.length || i2 * 3 + 2 >= positions.length) { return; } const ax = positions[i0 * 3]; const ay = positions[i0 * 3 + 1]; const az = positions[i0 * 3 + 2]; const e0x = positions[i1 * 3] - ax; const e0y = positions[i1 * 3 + 1] - ay; const e0z = positions[i1 * 3 + 2] - az; const e1x = positions[i2 * 3] - ax; const e1y = positions[i2 * 3 + 1] - ay; const e1z = positions[i2 * 3 + 2] - az; const px = localPoint[0] - ax; const py = localPoint[1] - ay; const pz = localPoint[2] - az; const d00 = e0x * e0x + e0y * e0y + e0z * e0z; const d01 = e0x * e1x + e0y * e1y + e0z * e1z; const d11 = e1x * e1x + e1y * e1y + e1z * e1z; const d20 = px * e0x + py * e0y + pz * e0z; const d21 = px * e1x + py * e1y + pz * e1z; const denom = d00 * d11 - d01 * d01; if (Math.abs(denom) <= Number.EPSILON) { return; } const vertex1Weight = (d11 * d20 - d01 * d21) / denom; const vertex2Weight = (d00 * d21 - d01 * d20) / denom; info.bu = clampTinyBarycentric(1 - vertex1Weight - vertex2Weight); info.bv = clampTinyBarycentric(vertex1Weight); if (!surfaceNormalsValid) { info._normalsInvalid = true; return; } if (normals && i0 * 3 + 2 < normals.length && i1 * 3 + 2 < normals.length && i2 * 3 + 2 < normals.length) { const bw = 1 - info.bu - info.bv; let localNormal = normalizeVec3( info.bu * normals[i0 * 3] + info.bv * normals[i1 * 3] + bw * normals[i2 * 3], info.bu * normals[i0 * 3 + 1] + info.bv * normals[i1 * 3 + 1] + bw * normals[i2 * 3 + 1], info.bu * normals[i0 * 3 + 2] + info.bv * normals[i1 * 3 + 2] + bw * normals[i2 * 3 + 2] ); let worldNormal = transformNormal(world, localNormal); if (facesPickRay(worldNormal, info)) { localNormal = [-localNormal[0], -localNormal[1], -localNormal[2]]; worldNormal = [-worldNormal[0], -worldNormal[1], -worldNormal[2]]; } info.pickedNormal = localNormal; info.pickedNormalWorld = worldNormal; } let localFaceNormal = normalizeVec3(e0y * e1z - e0z * e1y, e0z * e1x - e0x * e1z, e0x * e1y - e0y * e1x); let worldFaceNormal = transformNormal(world, localFaceNormal); if (facesPickRay(worldFaceNormal, info)) { localFaceNormal = [-localFaceNormal[0], -localFaceNormal[1], -localFaceNormal[2]]; worldFaceNormal = [-worldFaceNormal[0], -worldFaceNormal[1], -worldFaceNormal[2]]; } info.pickedFaceNormal = localFaceNormal; info.pickedFaceNormalWorld = worldFaceNormal; } export { copyDetailTarget, copyDetailedWorldMatrix, detailedWorldMatrix, enableDetailedPicking, ensureDetailTarget, populateDetailedMeshInfo, readDetailTarget }; //# sourceMappingURL=detailed-picking-CNJ4u4de.esm.js.map