Currently I am trying to generate a new object from an existing one like this. But I would like to generate it not from its current geometry used but from the lowest LOD level available. How could I do this and is there a way to somehow access this LOD geometry? If not is it perhaps possible to manually switch the LOD?
private generateShadowMesh(partMesh: Mesh<BufferGeometry, MeshBasicMaterial>) {
if (!partMesh.parent) {
return;
}
const shadowMaterial = partMesh.material.clone();
shadowMaterial.opacity = 0.2;
shadowMaterial.transparent = true;
this._shadowMesh = new Mesh(partMesh.geometry, shadowMaterial);
this._shadowMesh.name = partMesh.name + "_shadow";
this._shadowMesh.position.copy(partMesh.position);
this._shadowMesh.scale.copy(partMesh.scale);
this._shadowMesh.rotation.copy(partMesh.rotation);
partMesh.parent.add(this._shadowMesh);
let boundingBox = new Box3().setFromObject(partMesh);
let size = new Vector3();
boundingBox.getSize(size);
if (size.length() < 1.0) {
this._shadowMesh.scale.divideScalar(size.length());
}
If you want to instantiate your shadow mesh using the low‐detail (lowest LOD) geometry instead of the one currently rendered, you’ll need to access the LOD data tied to your object. In Needle Engine the LOD system is usually handled via a LODGroup component (see at LODGroup.d.ts.md). That component typically stores an array (often called lodModels) where each slot represents a different LOD level—with the last element usually being the lowest LOD.
For example, if your object has a LODGroup component, you can do something like this:
import { Behaviour, serializable } from "@needle-tools/engine";
import { Mesh, MeshBasicMaterial, BufferGeometry, Box3, Vector3 } from "three";
import { LODGroup } from "@needle-tools/engine"; // Adjust the import path if necessary
export class LowLODShadowGenerator extends Behaviour {
private _shadowMesh?: Mesh;
private generateShadowMesh(partMesh: Mesh<BufferGeometry, MeshBasicMaterial>) {
// Try to get the LODGroup from the partMesh (or its parent)
const lodGroup = partMesh.getComponent(LODGroup);
let baseMesh: Mesh | null = null;
if (lodGroup && lodGroup.lodModels && lodGroup.lodModels.length) {
// Pick the lowest LOD level – usually the last model in the array
const lowestLOD = lodGroup.lodModels[lodGroup.lodModels.length - 1];
if (lowestLOD.renderers.length > 0) {
// Assume the first renderer in the lowest LOD level is the low-poly one
baseMesh = lowestLOD.renderers[0].sharedMesh;
}
}
// Fallback: if no LODGroup is present, use the current mesh geometry
if (!baseMesh) {
baseMesh = partMesh;
}
// Clone the geometry from the chosen low LOD mesh
const lowLODGeometry = (baseMesh.geometry as BufferGeometry).clone();
// Create a shadow material from the partMesh's material
const shadowMaterial = (partMesh.material as MeshBasicMaterial).clone();
shadowMaterial.opacity = 0.2;
shadowMaterial.transparent = true;
// Generate the shadow mesh
this._shadowMesh = new Mesh(lowLODGeometry, shadowMaterial);
this._shadowMesh.name = partMesh.name + "_shadow";
this._shadowMesh.position.copy(partMesh.position);
this._shadowMesh.scale.copy(partMesh.scale);
this._shadowMesh.rotation.copy(partMesh.rotation);
partMesh.parent?.add(this._shadowMesh);
// Optionally adjust scale based on bounding box size
let boundingBox = new Box3().setFromObject(partMesh);
let size = new Vector3();
boundingBox.getSize(size);
if (size.length() < 1.0) {
this._shadowMesh.scale.divideScalar(size.length());
}
}
}
In this example the code first checks if the partMesh has an associated LODGroup. If so, it accesses the lodModels (as defined in the Needle Engine LODGroup component at LODGroup.d.ts.md) and picks the last one as the lowest detail level. From that, you retrieve one of its renderers (assuming that renderers is an array of render data that holds the low LOD mesh) and clone its geometry to generate the new shadow mesh.
If your object is not organized into an LODGroup in your scene, then you’ll likely have to modify your import/export setup from Unity/Blender so that LODs become available at runtime.
Regarding manual LOD‐switching: three.js (and thus Needle Engine) manages LOD switching automatically based on camera distance. If you need to force a specific LOD level manually, you could override that behavior by toggling the visibility of the different LOD meshes in your LOD group. However, using the built-in LODGroup is preferred as it handles these transitions elegantly.
I hope this helps! Let me know if you need further details or have additional questions.
1 replies left - Become PRO for more replies. thread_UV3AAuQTK8QTp8HaCamBKguR Reply to this post directly if you need further help (bottom right button)
Hello, you can load a specific LOD level for a mesh using NEEDLE_progressive.assignMeshLOD(meshInstance, 0) (0 being the lowest lod level).
Note that this is a async callback and it returns a promise with the mesh LOD geometry. It also assigns the geometry to the meshInstance. Just beware that the LODs are also automatically updated during the render loop (depending on your camera view) - of course you can create a new mesh instance with the returned geometry to create your shadow mesh.
For my understanding: What exactly is the shadow mesh doing in your scene and why would you want to use LOD 0 for it?
The shadowmesh signifies the original position, scale and rotation of the mesh once the actual object has been moved.
Since this is a transparent object there is no need for it to be the same quality as the object that is being manipulated. Additionally it is being used later on while raycasting so again simplifying the mesh would be benefitial.
Ok then you can set it to e.g. LOD3 or 4 (you can use the getMeshInformation method to query the lod count, there is a max of 6 level depending on the mesh complexity).
Also note that Needle Engine already uses a lower lod for raycasting and also uses a mesh bvh out of the box which accelerates raycasting (if you use this.context.physics.raycast).