@three.ez/instanced-mesh
Version:
Enhanced InstancedMesh with frustum culling, fast raycasting (using BVH), sorting, visibility management and more.
128 lines • 4.42 kB
JavaScript
import { ShaderMaterial } from 'three';
import { InstancedMesh2 } from '../InstancedMesh2.js';
InstancedMesh2.prototype.getObjectLODIndexForDistance = function (levels, distance) {
for (let i = levels.length - 1; i > 0; i--) {
const level = levels[i];
const levelDistance = level.distance - (level.distance * level.hysteresis);
if (distance >= levelDistance)
return i;
}
return 0;
};
InstancedMesh2.prototype.setFirstLODDistance = function (distance = 0, hysteresis = 0) {
if (this._parentLOD) {
throw new Error('Cannot create LOD for this InstancedMesh2.');
}
if (!this.LODinfo) {
this.LODinfo = { render: null, shadowRender: null, objects: [this] };
}
if (!this.LODinfo.render) {
this.LODinfo.render = {
levels: [{ distance, hysteresis, object: this }],
count: [0]
};
}
return this;
};
InstancedMesh2.prototype.addLOD = function (geometry, material, distance = 0, hysteresis = 0) {
if (this._parentLOD) {
throw new Error('Cannot create LOD for this InstancedMesh2.');
}
if (!this.LODinfo?.render && distance === 0) {
throw new Error('Cannot set distance to 0 for the first LOD. Use "setFirstLODDistance" before use "addLOD".');
}
this.setFirstLODDistance(0, hysteresis);
this.addLevel(this.LODinfo.render, geometry, material, distance, hysteresis);
return this;
};
InstancedMesh2.prototype.addShadowLOD = function (geometry, distance = 0, hysteresis = 0) {
if (this._parentLOD) {
throw new Error('Cannot create LOD for this InstancedMesh2.');
}
if (!this.LODinfo) {
this.LODinfo = { render: null, shadowRender: null, objects: [this] };
}
if (!this.LODinfo.shadowRender) {
this.LODinfo.shadowRender = { levels: [], count: [] };
}
const object = this.addLevel(this.LODinfo.shadowRender, geometry, null, distance, hysteresis);
object.castShadow = true;
this.castShadow = true;
return this;
};
InstancedMesh2.prototype.addLevel = function (renderList, geometry, material, distance, hysteresis) {
const objectsList = this.LODinfo.objects;
const levels = renderList.levels;
let index;
let object;
distance = distance ** 2; // to avoid to use Math.sqrt every time
const objIndex = objectsList.findIndex((e) => e.geometry === geometry);
if (objIndex === -1) {
const params = { capacity: this._capacity, renderer: this._renderer };
object = new InstancedMesh2(geometry, material ?? new ShaderMaterial(), params, this);
object.frustumCulled = false;
this.patchLevel(object);
objectsList.push(object);
this.add(object); // TODO handle render order?
}
else {
object = objectsList[objIndex];
if (material)
object.material = material;
}
for (index = 0; index < levels.length; index++) {
if (distance < levels[index].distance)
break;
}
levels.splice(index, 0, { distance, hysteresis, object });
renderList.count.push(0);
return object;
};
InstancedMesh2.prototype.patchLevel = function (obj) {
Object.defineProperty(obj, '_lastRenderInfo', {
get() {
return this._parentLOD._lastRenderInfo;
}
});
Object.defineProperty(obj, 'matricesTexture', {
get() {
return this._parentLOD.matricesTexture;
}
});
Object.defineProperty(obj, 'colorsTexture', {
get() {
return this._parentLOD.colorsTexture;
}
});
Object.defineProperty(obj, 'uniformsTexture', {
get() {
return this._parentLOD.uniformsTexture;
}
});
Object.defineProperty(obj, 'morphTexture', {
get() {
return this._parentLOD.morphTexture;
}
});
Object.defineProperty(obj, 'boneTexture', {
get() {
return this._parentLOD.boneTexture;
}
});
Object.defineProperty(obj, 'skeleton', {
get() {
return this._parentLOD.skeleton;
}
});
Object.defineProperty(obj, 'bindMatrixInverse', {
get() {
return this._parentLOD.bindMatrixInverse;
}
});
Object.defineProperty(obj, 'bindMatrix', {
get() {
return this._parentLOD.bindMatrix;
}
});
};
//# sourceMappingURL=LOD.js.map