UNPKG

@smoud/tiny

Version:

Fast and tiny JavaScript library for HTML5 game and playable ads creation.

125 lines (109 loc) 4.98 kB
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 };