@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
JavaScript
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