@smoud/tiny
Version:
Fast and tiny JavaScript library for HTML5 game and playable ads creation.
125 lines (109 loc) • 4.98 kB
JavaScript
import { Mesh } from './Mesh.js';
const mat4Length = 16;
function InstancedMesh(geometry, material, count) {
count = count !== undefined ? count : 1;
if (!geometry.attributes.instanceMatrix) {
var instanceMatrix = new Float32Array( count * mat4Length );
var instanceColor = new Float32Array( count * 3 );
instanceColor.fill(1);
geometry.setAttribute('instanceMatrix', new Tiny.Float32Attribute(instanceMatrix, mat4Length));
geometry.setAttribute('instanceColor', new Tiny.Float32Attribute(instanceColor, 3));
geometry.attributes.instanceMatrix.instanced = 1;
geometry.attributes.instanceColor.instanced = 1;
}
geometry.isInstanced = true;
geometry.instancedCount = count;
Mesh.call(this, geometry, material);
// Skip renderer frustum culling
this.frustumCulled = false;
this.isInstancedMesh = true;
}
InstancedMesh.prototype = Object.assign(Object.create(Mesh.prototype), {
constructor: InstancedMesh,
setMatrixAt: function (index, matrix) {
this.geometry.attributes.instanceMatrix.set(matrix.elements, index * mat4Length);
},
setColorAt: function (index, color) {
this.geometry.attributes.instanceColor.set(color.toArray(), index * 3);
},
draw: function ({camera, directionalLight, ambientLight} = {}) {
if (this.dynamic) {
this.needsUpdate = true;
}
Mesh.prototype.draw.call(this, {camera, directionalLight, ambientLight});
}
});
// @TODO add later
// addFrustumCull() {
// this.instanceTransforms = null;
// this.instanceLightmapScaleOffset = null;
// this.totalInstanceCount = 0;
// this.frustumCullFunction = null;
// this.instanceRenderList = null;
//
// // Get instanced mesh
// if (!this.geometry.attributes.instanceMatrix)
// console.error(`mesh ${this.name ? `"${this.name}" ` : ``}missing instanceMatrix attribute; unable to frustum cull`);
//
// // Make list of transforms from instanceMatrix
// const matrixData = this.geometry.attributes.instanceMatrix.data;
// this.instanceTransforms = [];
// for (let i = 0, j = 0; i < matrixData.length; i += mat4Length, j++) {
// const transform = new Object3D();
// transform.index = j;
// transform.matrix.fromArray(matrixData, i);
// transform.decompose();
// this.instanceTransforms.push(transform);
// // Add transforms to parent to update world matrices
// transform.setParent(this.parent);
// }
// this.totalInstanceCount = this.instanceTransforms.length;
//
// // Check for lightmap attributes - attach to transform
// if (!!this.geometry.attributes.lightmapScaleOffset) {
// const lightmapData = this.geometry.attributes.lightmapScaleOffset.data;
// for (let i = 0, j = 0; i < lightmapData.length; i += 4, j++) {
// this.instanceTransforms[j].lightmapData = new Vec4().fromArray(lightmapData, i);
// }
// }
//
// this.frustumCullFunction = ({ camera }) => {
// // frustum cull transforms each frame - pass world matrix
// this.instanceRenderList = [];
// this.instanceTransforms.forEach((transform) => {
// if (!camera.frustumIntersectsMesh(this, transform.worldMatrix)) return;
// this.instanceRenderList.push(transform);
// });
//
// // update instanceMatrix and instancedCount with visible
// this.instanceRenderList.forEach((transform, i) => {
// transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * mat4Length);
//
// // Update lightmap attr
// if (transform.lightmapData) {
// transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4);
// this.geometry.attributes.lightmapScaleOffset.needsUpdate = true;
// }
// });
// this.geometry.instancedCount = this.instanceRenderList.length;
// this.geometry.attributes.instanceMatrix.needsUpdate = true;
// };
//
// this.onBeforeRender(this.frustumCullFunction);
// }
//
// removeFrustumCull() {
// this.offBeforeRender(this.frustumCullFunction);
// this.geometry.instancedCount = this.totalInstanceCount;
// this.instanceTransforms.forEach((transform, i) => {
// transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * mat4Length);
//
// // Update lightmap attr
// if (transform.lightmapData) {
// transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4);
// this.geometry.attributes.lightmapScaleOffset.needsUpdate = true;
// }
// });
// this.geometry.attributes.instanceMatrix.needsUpdate = true;
// }
export { InstancedMesh };