@pmndrs/pointer-events
Version:
framework agnostic pointer-events implementation for threejs
77 lines (76 loc) • 3.04 kB
JavaScript
import { BufferAttribute, Matrix4, Triangle, Vector2, Vector3 } from 'three';
export function updateAndCheckWorldTransformation(object) {
if (object.transformReady === false) {
return false;
}
if (object.parent == null) {
object.matrixWorld.copy(object.matrix);
return true;
}
if (!updateAndCheckWorldTransformation(object.parent)) {
return false;
}
//we can just use parent.matrixWorld here because we already executed `updateAndCheckWorldTransformation` before which has updated parent.matrixWorld
object.matrixWorld.multiplyMatrices(object.parent.matrixWorld, object.matrix);
return true;
}
const triangleHelper1 = new Triangle();
const triangleHelper2 = new Triangle();
const aVec2Helper = new Vector2();
const bVec2Helper = new Vector2();
const cVec2Helper = new Vector2();
const pointHelper = new Vector3();
const inverseMatrix = new Matrix4();
const localPointHelper = new Vector3();
/**
* @requires that `mesh.updateWorldMatrix(true, false)` was executed beforehand
*/
export function getClosestUV(target, point, mesh) {
localPointHelper.copy(point).applyMatrix4(inverseMatrix.copy(mesh.matrixWorld).invert());
const uv = mesh.geometry.attributes.uv;
if (uv == null || !(uv instanceof BufferAttribute)) {
return false;
}
let clostestDistance;
loopThroughTriangles(mesh, (i1, i2, i3) => {
mesh.getVertexPosition(i1, triangleHelper1.a);
mesh.getVertexPosition(i2, triangleHelper1.b);
mesh.getVertexPosition(i3, triangleHelper1.c);
const distance = triangleHelper1.closestPointToPoint(localPointHelper, pointHelper).distanceTo(localPointHelper);
if (clostestDistance != null && distance >= clostestDistance) {
return;
}
clostestDistance = distance;
triangleHelper2.copy(triangleHelper1);
aVec2Helper.fromBufferAttribute(uv, i1);
bVec2Helper.fromBufferAttribute(uv, i2);
cVec2Helper.fromBufferAttribute(uv, i3);
});
if (clostestDistance == null) {
return false;
}
triangleHelper2.closestPointToPoint(localPointHelper, pointHelper);
triangleHelper2.getInterpolation(pointHelper, aVec2Helper, bVec2Helper, cVec2Helper, target);
return true;
}
function loopThroughTriangles(mesh, fn) {
const drawRange = mesh.geometry.drawRange;
if (mesh.geometry.index != null) {
const index = mesh.geometry.index;
const start = Math.max(0, drawRange.start);
const end = Math.min(index.count, drawRange.start + drawRange.count);
for (let i = start; i < end; i += 3) {
fn(index.getX(i), index.getX(i + 1), index.getX(i + 2));
}
return;
}
const position = mesh.geometry.attributes.position;
if (position == null) {
return;
}
const start = Math.max(0, drawRange.start);
const end = Math.min(position.count, drawRange.start + drawRange.count);
for (let i = start; i < end; i += 3) {
fn(i, i + 1, i + 2);
}
}