@needle-tools/gltf-progressive
Version:
three.js support for loading glTF or GLB files that contain progressive loading data
83 lines (82 loc) • 3.2 kB
JavaScript
import { BufferGeometry, Mesh } from "three";
export const isSSR = typeof window === "undefined" && typeof document === "undefined";
const $raycastmesh = Symbol("needle:raycast-mesh");
/**
* The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
* @param obj the object to get the raycast mesh from
* @returns the raycast mesh or null if not set
*/
export function getRaycastMesh(obj) {
if (obj?.[$raycastmesh] instanceof BufferGeometry) {
return obj[$raycastmesh];
}
return null;
}
/**
* Set the raycast mesh for an object.
* The raycast mesh is a low poly version of the mesh used for raycasting. It is set when a mesh that has LOD level with more vertices is discovered for the first time
* @param obj the object to set the raycast mesh for
* @param geom the raycast mesh
*/
export function registerRaycastMesh(obj, geom) {
if (obj.type === "Mesh" || obj.type === "SkinnedMesh") {
const existing = getRaycastMesh(obj);
if (!existing) {
const clone = shallowCloneGeometry(geom);
// remove LODs userdata to not update the geometry if the raycast mesh is rendered in the scene
clone.userData = { isRaycastMesh: true };
obj[$raycastmesh] = clone;
}
}
}
/**
* Call this method to enable raycasting with the lowpoly raycast meshes (if available) for all meshes in the scene.
* This is useful for performance optimization when the scene contains high poly meshes that are not visible to the camera.
* @example
* ```ts
* // call to enable raycasting with low poly raycast meshes
* useRaycastMeshes();
*
* // then use the raycaster as usual
* const raycaster = new Raycaster();
* raycaster.setFromCamera(mouse, camera);
* const intersects = raycaster.intersectObjects(scene.children, true);
* ```
*/
export function useRaycastMeshes(enabled = true) {
if (enabled) {
// if the method is already patched we don't need to do it again
if (_originalRaycastMethod)
return;
const originalMethod = _originalRaycastMethod = Mesh.prototype.raycast;
Mesh.prototype.raycast = function (raycaster, intersects) {
const self = this;
const raycastMesh = getRaycastMesh(self);
let prevGeomtry;
if (raycastMesh && self.isMesh) {
prevGeomtry = self.geometry;
self.geometry = raycastMesh;
}
originalMethod.call(this, raycaster, intersects);
if (prevGeomtry) {
self.geometry = prevGeomtry;
}
};
}
else {
if (!_originalRaycastMethod)
return;
Mesh.prototype.raycast = _originalRaycastMethod;
_originalRaycastMethod = null;
}
}
let _originalRaycastMethod = null;
/** Creates a clone without copying the data */
function shallowCloneGeometry(geom) {
const clone = new BufferGeometry();
for (const key in geom.attributes) {
clone.setAttribute(key, geom.getAttribute(key));
}
clone.setIndex(geom.getIndex());
return clone;
}