### Reference Code Example in Docs Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md Reference a code example in your documentation using the component with the 'path' prop. The 'path' prop is the directory path relative to src/examples. ```html ``` ```markdown | Prop | Type | Default | Description | | ---------------- | ------- | -------- | --------------------------------------- | | `path` | string | required | Directory path relative to src/examples | | `hideCode` | boolean | `false` | Hides the source code section | | `hidePreview` | boolean | `false` | Hides the example preview | | `hideStackblitz` | boolean | `false` | Hides "Open in Stackblitz" button | ``` -------------------------------- ### Install via npm Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx Use this command to install the package using npm. ```sh npm install @three.ez/instanced-mesh ``` -------------------------------- ### Create Code Example Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md Create a new example directory and write your Three.js code in index.ts. Maximum 2 levels of nesting are allowed. ```bash code src/examples/myExample/index.ts ``` ```typescript import { Scene, PerspectiveCamera } from 'three'; // Your Three.js example code here ``` -------------------------------- ### Install @three.ez/instanced-mesh Source: https://context7.com/agargaro/instanced-mesh/llms.txt Install the InstancedMesh2 package and its peer dependency, three.js. CDN importmap is also provided. ```bash npm install @three.ez/instanced-mesh # peer dependency npm install three ``` ```html ``` -------------------------------- ### Install via pnpm Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx Use this command to install the package using pnpm. ```sh pnpm add @three.ez/instanced-mesh ``` -------------------------------- ### Install via yarn Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx Use this command to install the package using yarn. ```sh yarn add @three.ez/instanced-mesh ``` -------------------------------- ### Set and Get Instance Opacity Source: https://context7.com/agargaro/instanced-mesh/llms.txt Demonstrates setting and getting per-instance opacity values (0-1) using `setOpacityAt` and `getOpacityAt`. Requires a transparent material and `sortObjects = true` for correct rendering. ```typescript import { MeshStandardMaterial } from 'three'; const iMesh = new InstancedMesh2( geometry, new MeshStandardMaterial({ transparent: true }), { capacity: 200 } ); iMesh.addInstances(200, (obj, i) => { obj.position.set(i * 1.2, 0, 0); }); iMesh.sortObjects = true; // required for correct transparency iMesh.setOpacityAt(0, 0.1); iMesh.setOpacityAt(1, 0.5); iMesh.setOpacityAt(2, 1.0); console.log(iMesh.getOpacityAt(0)); // 0.1 ``` -------------------------------- ### Add Documentation Pages Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md Specify the directory based on content type (guides, reference, tutorials, concepts) and include required frontmatter with title and description. ```bash src/content/docs/guides/ # For how-to guides src/content/docs/reference/ # For technical reference src/content/docs/tutorials/ # For tutorials src/content/docs/concepts/ # For explanations ``` ```markdown --- title: Your Page Title description: Brief description --- ``` -------------------------------- ### Set and Get Instance Matrix Source: https://context7.com/agargaro/instanced-mesh/llms.txt Demonstrates low-level manipulation of an instance's transform using `setMatrixAt` and `getMatrixAt` with `Matrix4`. ```typescript import { Matrix4, Vector3, Quaternion } from 'three'; const m = new Matrix4(); m.compose( new Vector3(5, 0, 0), new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 4), new Vector3(2, 2, 2) ); iMesh.setMatrixAt(0, m); // Read back const readback = new Matrix4(); iMesh.getMatrixAt(0, readback); console.log(readback.elements[12]); // 5 (translation X) ``` -------------------------------- ### Set and Get Instance Color Source: https://context7.com/agargaro/instanced-mesh/llms.txt Shows how to set and retrieve per-instance colors using various formats (CSS string, hex, `Color` instance) with `setColorAt` and `getColorAt`. ```typescript import { Color } from 'three'; // Set colors during creation iMesh.addInstances(3, (obj, i) => { obj.color = ['red', 'lime', 'blue'][i]; // CSS color string }); // Update individual instance color later iMesh.setColorAt(1, 0x00ff00); iMesh.setColorAt(2, new Color(0, 0, 1)); // Read const col = new Color(); iMesh.getColorAt(0, col); console.log(col.getHexString()); // 'ff0000' ``` -------------------------------- ### Install via CDN with Import Map Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/01-installation.mdx Include this script tag in your HTML file to load the library directly from a CDN. This sets up import aliases for three.js and related libraries. ```html ``` -------------------------------- ### Development Scripts Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/CONTRIBUTE.md Run development and build scripts using npm. 'npm run dev' provides hot reload, 'npm run start' for production preview, and 'npm run build' for production build. ```bash npm run dev # Dev mode with hot reload npm run start # Production preview npm run build # Production build ``` -------------------------------- ### Set and Get Instance Visibility Source: https://context7.com/agargaro/instanced-mesh/llms.txt Explains how to hide or show individual instances using `setVisibilityAt` and `getVisibilityAt` without removing them from the mesh. ```typescript // Hide every other instance for (let i = 0; i < iMesh.instancesCount; i += 2) { iMesh.setVisibilityAt(i, false); } // Re-show instance 4 iMesh.setVisibilityAt(4, true); console.log(iMesh.getVisibilityAt(4)); // true console.log(iMesh.getVisibilityAt(0)); // false ``` -------------------------------- ### Tweening Instanced Entity Properties Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/04-tween.mdx This example demonstrates how to apply tween animations to properties of instanced entities. It assumes you have already created an array of instances. Note that the 'color' property cannot be tweened. ```javascript ``` -------------------------------- ### setMatrixAt and getMatrixAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Low-level methods for directly setting or getting the Matrix4 transformation for a specific instance by its ID. ```APIDOC ## setMatrixAt(id, matrix) / getMatrixAt(id, matrix?) ### Description Provides low-level access to read or write the `Matrix4` for a specific instance using its ID. Useful for migrating from `InstancedMesh` or when transforms are computed externally. ### Parameters - **id** (number): The ID of the instance. - **matrix** (Matrix4): The `Matrix4` object to set or read. ### Usage #### `setMatrixAt(id, matrix)` Sets the transformation matrix for the specified instance. ```ts import { Matrix4, Vector3, Quaternion } from 'three'; const m = new Matrix4(); m.compose( new Vector3(5, 0, 0), new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 4), new Vector3(2, 2, 2) ); iMesh.setMatrixAt(0, m); ``` #### `getMatrixAt(id, matrix?)` Reads the transformation matrix of the specified instance. If a `matrix` object is provided, it will be populated with the instance's matrix; otherwise, a new `Matrix4` will be returned. ```ts const readback = new Matrix4(); iMesh.getMatrixAt(0, readback); console.log(readback.elements[12]); // 5 (translation X) ``` ``` -------------------------------- ### initSkeleton and setBonesAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Enables GPU skeletal animation for instances. `initSkeleton` sets up the necessary structures, and `setBonesAt` updates the bone matrices for individual instances. ```APIDOC ## `initSkeleton(skeleton)` / `setBonesAt(id, updateBonesMatrices?)` ### Description Enables GPU skeletal animation across all instances. Each instance can be posed independently by calling `setBonesAt` with the current animation state. Bone matrices are stored per-instance in a `boneTexture`. ### Method `initSkeleton`, `setBonesAt` ### Parameters #### `initSkeleton` - **skeleton** (Skeleton) - The skeleton to use for animation. #### `setBonesAt` - **id** (number) - The index of the instance. - **updateBonesMatrices** (boolean, optional) - Whether to update the bone matrices. ### Request Example ```ts import { InstancedMesh2, createInstancedMesh2From } from '@three.ez/instanced-mesh'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { AnimationMixer, Clock } from 'three'; const loader = new GLTFLoader(); const gltf = await loader.loadAsync('character.glb'); const skinnedMesh = gltf.scene.getObjectByProperty('isSkinnedMesh', true); // createInstancedMesh2From detects SkinnedMesh and calls initSkeleton automatically const iMesh = createInstancedMesh2From(skinnedMesh, { capacity: 3000, createEntities: true, }); const mixer = new AnimationMixer(skinnedMesh); const action = mixer.clipAction(gltf.animations[0]); action.play(); const clock = new Clock(); iMesh.addInstances(3000, (obj, i) => { obj.position.set((i % 50) * 2, 0, Math.floor(i / 50) * 2); }); // Frustum enter: update only visible instances' bones iMesh.onFrustumEnter = (index) => { iMesh.setBonesAt(index, true); // snapshot current skeleton pose to this instance return true; }; renderer.setAnimationLoop(() => { const delta = clock.getDelta(); mixer.update(delta); // advance animation on shared skeleton renderer.render(scene, camera); }); scene.add(iMesh); ``` ``` -------------------------------- ### initUniformsPerInstance, setUniformAt, and getUniformAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Manages per-instance GPU shader uniforms. `initUniformsPerInstance` defines the schema for uniforms, while `setUniformAt` and `getUniformAt` allow individual instance uniform manipulation. ```APIDOC ## `initUniformsPerInstance(schema)` / `setUniformAt(id, name, value)` / `getUniformAt(id, name)` ### Description Assigns per-instance GPU shader uniforms stored in a `SquareDataTexture`. The `schema` defines which uniforms live in the `vertex` and/or `fragment` shader stage and their GLSL type (`'float'`, `'vec2'`, `'vec3'`, `'vec4'`, `'mat3'`, `'mat4'`). Uniforms are automatically injected into the material's shader. ### Method `initUniformsPerInstance`, `setUniformAt`, `getUniformAt` ### Parameters #### `initUniformsPerInstance` - **schema** (object) - Defines the uniforms and their types for vertex and/or fragment shaders. #### `setUniformAt` - **id** (number) - The index of the instance. - **name** (string) - The name of the uniform. - **value** (any) - The value to set for the uniform. #### `getUniformAt` - **id** (number) - The index of the instance. - **name** (string) - The name of the uniform. ### Request Example ```ts import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { BoxGeometry, MeshLambertMaterial, Vector2, Color } from 'three'; const iMesh = new InstancedMesh2( new BoxGeometry(), new MeshLambertMaterial(), { capacity: 256 * 256 } ); // Define per-instance uniforms: a UV offset (vec2) and metalness (float) iMesh.initUniformsPerInstance({ fragment: { offset: 'vec2', metalness: 'float', emissive: 'vec3', }, }); iMesh.addInstances(256 * 256, (obj, i) => { obj.position.set(i % 256, 0, Math.floor(i / 256)); obj.setUniform('offset', new Vector2(Math.random(), Math.random())); obj.setUniform('metalness', Math.random()); obj.setUniform('emissive', new Color(Math.random(), Math.random(), Math.random())); }); // Read a uniform back const uv = iMesh.getUniformAt(0, 'offset') as Vector2; console.log(uv.x, uv.y); // Update a single instance's uniform later iMesh.setUniformAt(42, 'metalness', 0.9); ``` ``` -------------------------------- ### Initialize Skeleton and Set Bones Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Apply skeletal animations to instances by initializing the skeleton and then setting the bones for each instance. The mixer needs to be updated with time for animations to progress. ```typescript myInstancedMesh.initSkeleton(skeleton); mixer.update(time); myInstancedMesh.setBonesAt(index); ``` -------------------------------- ### Instantiate and Add Instances with InstancedMesh2 Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Initialize InstancedMesh2 with geometry and material, then add a specified number of instances, configuring each instance's properties using a callback function. ```typescript const myInstancedMesh = new InstancedMesh2(geometry, material); myInstancedMesh.addInstances(count, (obj, index) => { obj.position.x = index; }); ``` -------------------------------- ### Initialize InstancedMesh2 Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/getting-started/02-first-instancedmesh2.mdx Create a new InstancedMesh2 instance. Requires a geometry and a material. ```typescript const iMesh = new InstancedMesh2(geometry, material); ``` -------------------------------- ### createInstancedMesh2From Source: https://context7.com/agargaro/instanced-mesh/llms.txt Factory utility to create an InstancedMesh2 from an existing Mesh, InstancedMesh, or SkinnedMesh. It copies geometry, material, matrices, colors, and skeleton. ```APIDOC ## `createInstancedMesh2From(mesh, params?)` Factory utility that creates an `InstancedMesh2` from an existing `Mesh`, `InstancedMesh`, or `SkinnedMesh`, copying geometry, material, matrices, colors, and skeleton. ### Parameters - **mesh** (Mesh | InstancedMesh | SkinnedMesh) - The source mesh to copy from. - **params** (object, optional) - Configuration options for the new InstancedMesh2. - **capacity** (number) - The maximum number of instances. - **createEntities** (boolean) - Whether to create entity objects for each instance. ``` -------------------------------- ### Create and Animate Instanced Entities Source: https://context7.com/agargaro/instanced-mesh/llms.txt Initializes an InstancedMesh2 with entity creation enabled and demonstrates animating individual instances by updating their transforms and calling `updateMatrix()`. ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { TorusKnotGeometry, MeshStandardMaterial } from 'three'; const iMesh = new InstancedMesh2( new TorusKnotGeometry(), new MeshStandardMaterial(), { createEntities: true, capacity: 100 } ); iMesh.addInstances(100, (obj, i) => { obj.position.set(i * 3, 0, 0); obj.color = 0xff0000 + i * 100; }); // Animate in render loop function animate() { requestAnimationFrame(animate); for (const instance of iMesh.instances) { if (!instance.active) continue; instance.rotateY(0.01); instance.translateX(0.001); instance.updateMatrix(); // flush to matricesTexture } renderer.render(scene, camera); } animate(); // Toggle visibility iMesh.instances[10].visible = false; // Adjust opacity (requires sorting + transparent material for best results) iMesh.instances[20].opacity = 0.4; // Remove via entity iMesh.instances[30].remove(); ``` -------------------------------- ### Create InstancedMesh2 Instance Source: https://context7.com/agargaro/instanced-mesh/llms.txt Basic construction of InstancedMesh2 with optional parameters for capacity, entity creation, and renderer injection. The renderer must be injected if the index buffer needs to initialize immediately. ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { WebGLRenderer, Scene, PerspectiveCamera, BoxGeometry, MeshStandardMaterial, DirectionalLight } from 'three'; const renderer = new WebGLRenderer({ antialias: true }); document.body.appendChild(renderer.domElement); const scene = new Scene(); const camera = new PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000); camera.position.set(0, 20, 60); // Basic construction — capacity defaults to 1000 const iMesh = new InstancedMesh2( new BoxGeometry(), new MeshStandardMaterial({ color: 0x44aa88 }), { capacity: 10000, // pre-allocate for 10k instances createEntities: false, // no per-instance Object3D wrappers (lower memory) renderer, // inject renderer so index buffer initialises immediately } ); scene.add(iMesh, new DirectionalLight('white', 2)); renderer.setAnimationLoop(() => { renderer.render(scene, camera); }); ``` -------------------------------- ### Initialize Per-Instance Uniforms for Shaders Source: https://context7.com/agargaro/instanced-mesh/llms.txt Define and assign custom shader uniforms that vary per instance using `initUniformsPerInstance`, `setUniformAt`, and `getUniformAt`. This allows for per-instance color, UV offsets, or other data. ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { BoxGeometry, MeshLambertMaterial, Vector2, Color } from 'three'; const iMesh = new InstancedMesh2( new BoxGeometry(), new MeshLambertMaterial(), { capacity: 256 * 256 } ); // Define per-instance uniforms: a UV offset (vec2) and metalness (float) iMesh.initUniformsPerInstance({ fragment: { offset: 'vec2', metalness: 'float', emissive: 'vec3', }, }); iMesh.addInstances(256 * 256, (obj, i) => { obj.position.set(i % 256, 0, Math.floor(i / 256)); obj.setUniform('offset', new Vector2(Math.random(), Math.random())); obj.setUniform('metalness', Math.random()); obj.setUniform('emissive', new Color(Math.random(), Math.random(), Math.random())); }); // Read a uniform back const uv = iMesh.getUniformAt(0, 'offset') as Vector2; console.log(uv.x, uv.y); // Update a single instance's uniform later iMesh.setUniformAt(42, 'metalness', 0.9); ``` -------------------------------- ### Add Custom Data to Instances (JavaScript) Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/05-custom-data.mdx This JavaScript snippet demonstrates how to assign custom data, such as a UUID, to each instance during creation with `addInstances`. ```javascript const iMesh = new InstancedMesh2(geo, mat, { createEntities: true }); iMesh.addInstances(count, (obj, index) => { obj.uuid = MathUtils.generateUUID(); }); ``` -------------------------------- ### updateInstances and updateInstancesPosition Source: https://context7.com/agargaro/instanced-mesh/llms.txt These methods provide a convenient way to iterate over all active instances, apply a callback function, and automatically handle matrix updates. ```APIDOC ## updateInstances(onUpdate) / updateInstancesPosition(onUpdate) ### Description Iterates through all active instances, applies a callback function to each, and automatically calls `updateMatrix()` or `updateMatrixPosition()`. ### Parameters - **onUpdate** (function): A callback function that receives the instance object as an argument. ### Usage #### `updateInstances(onUpdate)` Use this when you need to update transforms (position, rotation, scale). ```ts iMesh.updateInstances((obj) => { obj.rotateY(0.01); // updateMatrix() is called automatically }); ``` #### `updateInstancesPosition(onUpdate)` Use this when you only need to update the position. This is faster as it skips rotation and scale recalculations. ```ts iMesh.updateInstancesPosition((obj) => { obj.position.y = Math.sin(Date.now() * 0.001 + obj.id * 0.1); // updateMatrixPosition() is called automatically }); ``` ``` -------------------------------- ### Animate All Instances using updateInstances Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/02-animation.mdx The recommended method for animating all active instances. This method automatically handles matrix updates. Be aware that if instances are not created as an array, transformations might reset. ```typescript this.updateInstances((obj) => { instance.scale.x += 0.1; }); ``` -------------------------------- ### InstancedMesh2 Constructor Source: https://context7.com/agargaro/instanced-mesh/llms.txt Creates a new InstancedMesh2 instance. It requires a geometry and material, and accepts an optional params object to configure initial capacity, entity creation, and renderer injection. ```APIDOC ## new InstancedMesh2(geometry, material, params?) ### Description Creates an instanced mesh. `geometry` and `material` are mandatory (same types as three.js `Mesh`). The optional `params` object (`InstancedMesh2Params`) controls initial capacity, entity creation, Euler support, and renderer injection. ### Parameters - **geometry** (THREE.BufferGeometry) - The geometry to be instanced. - **material** (THREE.Material) - The material to be used for the instances. - **params** (InstancedMesh2Params, optional) - Configuration options for the InstancedMesh2. - **capacity** (number, optional) - The initial capacity for instances. Defaults to 1000. - **createEntities** (boolean, optional) - Whether to create per-instance Object3D wrappers. Defaults to true. - **renderer** (THREE.WebGLRenderer, optional) - The renderer to inject for immediate index buffer initialization. ### Request Example ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { WebGLRenderer, Scene, PerspectiveCamera, BoxGeometry, MeshStandardMaterial, DirectionalLight } from 'three'; const renderer = new WebGLRenderer({ antialias: true }); document.body.appendChild(renderer.domElement); const scene = new Scene(); const camera = new PerspectiveCamera(60, innerWidth / innerHeight, 0.1, 1000); camera.position.set(0, 20, 60); // Basic construction — capacity defaults to 1000 const iMesh = new InstancedMesh2( new BoxGeometry(), new MeshStandardMaterial({ color: 0x44aa88 }), { capacity: 10000, // pre-allocate for 10k instances createEntities: false, // no per-instance Object3D wrappers (lower memory) renderer, // inject renderer so index buffer initialises immediately } ); scene.add(iMesh, new DirectionalLight('white', 2)); renderer.setAnimationLoop(() => { renderer.render(scene, camera); }); ``` ``` -------------------------------- ### `computeBVH(params?)` / `disposeBVH()` Source: https://context7.com/agargaro/instanced-mesh/llms.txt Builds a dynamic Bounding Volume Hierarchy (BVH) for efficient frustum culling and raycasting. The BVH updates automatically when instances move if `autoUpdateBVH` is true. ```APIDOC ## `computeBVH(params?)` / `disposeBVH()` Builds a dynamic Bounding Volume Hierarchy (BVH) over all instances for O(log n) frustum culling and raycasting instead of O(n) linear scans. The BVH updates automatically when instances move (`autoUpdateBVH = true`). Call after populating instances for best build quality. ```ts import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { OctahedronGeometry, MeshLambertMaterial, Vector3 } from 'three'; type Data = { dir: Vector3 }; const iMesh = new InstancedMesh2( new OctahedronGeometry(1, 2), new MeshLambertMaterial(), { capacity: 50000, createEntities: true } ); iMesh.addInstances(50000, (obj) => { obj.dir = new Vector3().randomDirection(); obj.position.randomDirection().multiplyScalar(Math.random() * 3000); obj.scale.setScalar(1 + Math.random() * 4); }); // Build BVH after all instances are placed iMesh.computeBVH({ margin: 75, // tolerance for moving objects (0 = static) getBBoxFromBSphere: true, // faster bbox approx (geometry must be origin-centered) accurateCulling: true, // re-check margin nodes precisely }); // Animate — BVH nodes update automatically via updateMatrixPosition renderer.setAnimationLoop((delta) => { for (const obj of iMesh.instances) { if (!obj.active) continue; obj.position.addScaledVector(obj.dir, delta * 10); obj.updateMatrixPosition(); // triggers bvh.move(id) internally } renderer.render(scene, camera); }); // Intersect a box with the BVH import { Box3 } from 'three'; const queryBox = new Box3().setFromCenterAndSize( new Vector3(0, 0, 0), new Vector3(100, 100, 100) ); iMesh.bvh.intersectBox(queryBox, (id) => { console.log('Instance inside box:', id); return true; // continue iterating }); // Teardown iMesh.disposeBVH(); ``` ``` -------------------------------- ### Initialize InstancedMesh2 with Capacity Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/00-add-remove.mdx Set the initial buffer capacity when creating a new InstancedMesh2 to pre-allocate memory. Buffers expand automatically if capacity is not specified. ```typescript const iMesh = new InstancedMesh2(geo, mat, { capacity: 10000 }); ``` -------------------------------- ### Enable GPU Skeletal Animation for Instanced Meshes Source: https://context7.com/agargaro/instanced-mesh/llms.txt Use `createInstancedMesh2From` with a `SkinnedMesh` or manually call `initSkeleton` to enable GPU skeletal animation. `setBonesAt` updates bone matrices per instance, and `onFrustumEnter` can optimize updates for visible instances. ```typescript import { InstancedMesh2, createInstancedMesh2From } from '@three.ez/instanced-mesh'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { AnimationMixer, Clock } from 'three'; const loader = new GLTFLoader(); const gltf = await loader.loadAsync('character.glb'); const skinnedMesh = gltf.scene.getObjectByProperty('isSkinnedMesh', true); // createInstancedMesh2From detects SkinnedMesh and calls initSkeleton automatically const iMesh = createInstancedMesh2From(skinnedMesh, { capacity: 3000, createEntities: true, }); const mixer = new AnimationMixer(skinnedMesh); const action = mixer.clipAction(gltf.animations[0]); action.play(); const clock = new Clock(); iMesh.addInstances(3000, (obj, i) => { obj.position.set((i % 50) * 2, 0, Math.floor(i / 50) * 2); }); // Frustum enter: update only visible instances' bones iMesh.onFrustumEnter = (index) => { iMesh.setBonesAt(index, true); // snapshot current skeleton pose to this instance return true; }; renderer.setAnimationLoop(() => { const delta = clock.getDelta(); mixer.update(delta); // advance animation on shared skeleton renderer.render(scene, camera); }); scene.add(iMesh); ``` -------------------------------- ### addInstances Source: https://context7.com/agargaro/instanced-mesh/llms.txt Adds a specified number of new instances to the mesh. An optional callback function can be provided to configure each new instance upon creation. Buffers will automatically expand if the current capacity is exceeded. ```APIDOC ## addInstances(count, onCreation?) ### Description Adds `count` new instances to the mesh. The optional `onCreation` callback receives a temporary `InstancedEntity` (`obj`) and the instance `index`; set transforms and custom data here. Buffers expand automatically if capacity is exceeded. ### Parameters - **count** (number) - The number of instances to add. - **onCreation** (function, optional) - A callback function executed for each newly created instance. It receives the `InstancedEntity` object and its `index`. - **obj** (InstancedEntity) - The temporary entity object for the instance. - **index** (number) - The index of the newly created instance. ### Request Example ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { SphereGeometry, MeshLambertMaterial } from 'three'; type CustomData = { speed: number }; const iMesh = new InstancedMesh2( new SphereGeometry(0.5, 16, 8), new MeshLambertMaterial(), { capacity: 5000, createEntities: true } ); // Add 5000 instances; obj is InstancedEntity & CustomData iMesh.addInstances(5000, (obj, index) => { // Position in a grid obj.position.set( (index % 100) * 2 - 100, 0, Math.floor(index / 100) * 2 - 50 ); obj.quaternion.random(); obj.scale.setScalar(0.5 + Math.random()); obj.color = Math.random() * 0xffffff; obj.speed = Math.random() * 2; // custom field // updateMatrix() is called automatically after onCreation returns }); console.log(iMesh.instancesCount); // 5000 ``` ``` -------------------------------- ### setOpacityAt and getOpacityAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Methods for setting and retrieving the per-instance opacity. Opacity is stored in the alpha channel of the colors texture and requires specific material and sorting settings for correct rendering. ```APIDOC ## setOpacityAt(id, value) / getOpacityAt(id) ### Description Sets per-instance opacity (0–1). Stored in the alpha channel of `colorsTexture`. For correct visual output, combine with `sortObjects = true` and a transparent material. ### Parameters - **id** (number): The ID of the instance. - **value** (number): The opacity value (0.0 to 1.0). ### Usage #### `setOpacityAt(id, value)` Sets the opacity for the specified instance. ```ts import { MeshStandardMaterial } from 'three'; const iMesh = new InstancedMesh2( geometry, new MeshStandardMaterial({ transparent: true }), { capacity: 200 } ); iMesh.addInstances(200, (obj, i) => { obj.position.set(i * 1.2, 0, 0); }); iMesh.sortObjects = true; // required for correct transparency iMesh.setOpacityAt(0, 0.1); iMesh.setOpacityAt(1, 0.5); iMesh.setOpacityAt(2, 1.0); ``` #### `getOpacityAt(id)` Retrieves the opacity of the specified instance. ```ts console.log(iMesh.getOpacityAt(0)); // 0.1 ``` ``` -------------------------------- ### Initialize and Set Per-Instance Uniforms Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Assign unique shader uniforms to each instance. This works with all materials. Uniforms can be initialized for fragment or vertex shaders and then set per instance by index or directly on the instance object. ```typescript myInstancedMesh.initUniformsPerInstance({ fragment: { metalness: 'float', roughness: 'float', emissive: 'vec3' } }); myInstancedMesh.setUniformAt(index, 'metalness', 0.5); myInstancedMesh.instances[0].setUniform('emissive', new Color('white')); // if instances array is created ``` -------------------------------- ### setColorAt and getColorAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Methods for setting and retrieving the per-instance color. Supports various color representations and initializes a colors texture if needed. ```APIDOC ## setColorAt(id, color) / getColorAt(id, color?) ### Description Sets or reads the per-instance color. Accepts any `ColorRepresentation` (hex number, CSS string, `Color` instance). Internally initializes a `colorsTexture` on first use. ### Parameters - **id** (number): The ID of the instance. - **color** (ColorRepresentation): The color to set. Can be a hex number, CSS string, or `THREE.Color` instance. - **color?** (Color): Optional `THREE.Color` instance to read the color into. ### Usage #### `setColorAt(id, color)` Sets the color for the specified instance. ```ts import { Color } from 'three'; // Set colors during creation iMesh.addInstances(3, (obj, i) => { obj.color = ['red', 'lime', 'blue'][i]; // CSS color string }); // Update individual instance color later iMesh.setColorAt(1, 0x00ff00); iMesh.setColorAt(2, new Color(0, 0, 1)); ``` #### `getColorAt(id, color?)` Reads the color of the specified instance. If a `Color` object is provided, it will be populated with the instance's color; otherwise, a new `Color` instance will be returned. ```ts const col = new Color(); iMesh.getColorAt(0, col); console.log(col.getHexString()); // 'ff0000' ``` ``` -------------------------------- ### Custom Frustum Enter Callback Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/06-frustum-culling.mdx Implement a callback function that is executed for each instance entering the camera's frustum. Return true to render the instance; this is useful for conditional rendering based on distance. ```typescript iMesh.onFrustumEnter = (index, camera) => { // render only if not too far away return iMesh.getPositionAt(index).distanceTo(camera.position) <= maxDistance; }; ``` -------------------------------- ### InstancedMesh2 with Dynamic Capacity Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Instantiate InstancedMesh2 with a specified capacity. Use addInstances to add new instances, which will expand the buffer if necessary. removeInstances and clearInstances manage existing instances. ```typescript const myInstancedMesh = new InstancedMesh2(geometry, material, { capacity: count }); myInstancedMesh.addInstances(count, (obj, index) => { ... }); // add instances and expand buffer if necessary myInstancedMesh.removeInstances(id0, id1, ...); myInstancedMesh.clearInstances(); // remove all instances ``` -------------------------------- ### Create InstancedMesh2 from Existing Mesh Source: https://context7.com/agargaro/instanced-mesh/llms.txt Use this factory utility to upgrade an existing InstancedMesh, Mesh, or SkinnedMesh to InstancedMesh2, copying geometry, material, and instance data. Set 'capacity' for the new mesh and 'createEntities' if per-instance access is needed. ```typescript import { createInstancedMesh2From } from '@three.ez/instanced-mesh'; import { InstancedMesh, BoxGeometry, MeshStandardMaterial, Matrix4 } from 'three'; // Existing InstancedMesh with 500 pre-placed instances const old = new InstancedMesh(new BoxGeometry(), new MeshStandardMaterial(), 500); for (let i = 0; i < 500; i++) { const m = new Matrix4().makeTranslation(i, 0, 0); old.setMatrixAt(i, m); old.setColorAt(i, { r: Math.random(), g: Math.random(), b: Math.random() }); } old.instanceMatrix.needsUpdate = true; // Upgrade to InstancedMesh2 — matrices and colors are copied const iMesh = createInstancedMesh2From(old, { capacity: 1000, createEntities: true, }); // Now has all InstancedMesh2 features iMesh.computeBVH(); iMesh.sortObjects = true; console.log(iMesh.instancesCount); // 500 ``` -------------------------------- ### Enable InstancedEntity Creation Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/01-Instancedentity.mdx Set the `createEntities` flag to `true` in the InstancedMesh2 constructor parameters to automatically generate InstancedEntity objects for each instance. ```typescript const iMesh = new InstancedMesh2(geo, mat, { createEntities: true }); ``` -------------------------------- ### copyTo Source: https://context7.com/agargaro/instanced-mesh/llms.txt Copies an instance's world-space transform into a standard three.js Object3D (position, quaternion, scale). ```APIDOC ## `copyTo(id, target)` / `InstancedEntity.copyTo(target)` Copies an instance's world-space transform into a standard three.js `Object3D` (position, quaternion, scale). ### Parameters - **id** (number) - The index of the instance to copy. - **target** (Object3D) - The target Object3D to copy the transform to. ### Usage ```ts import { Object3D } from 'three'; const dummy = new Object3D(); // Copy instance 7's transform to dummy iMesh.copyTo(7, dummy); console.log(dummy.position); // Via entity (if createEntities: true) iMesh.instances[7].copyTo(dummy); ``` ``` -------------------------------- ### setVisibilityAt and getVisibilityAt Source: https://context7.com/agargaro/instanced-mesh/llms.txt Methods to control the visibility of individual instances, allowing them to be hidden or shown without removal. ```APIDOC ## setVisibilityAt(id, visible) / getVisibilityAt(id) ### Description Hides or shows individual instances without removing them. Hidden instances are excluded from the render index every frame. ### Parameters - **id** (number): The ID of the instance. - **visible** (boolean): `true` to show the instance, `false` to hide it. ### Usage #### `setVisibilityAt(id, visible)` Sets the visibility state for the specified instance. ```ts // Hide every other instance for (let i = 0; i < iMesh.instancesCount; i += 2) { iMesh.setVisibilityAt(i, false); } // Re-show instance 4 iMesh.setVisibilityAt(4, true); ``` #### `getVisibilityAt(id)` Retrieves the visibility state of the specified instance. ```ts console.log(iMesh.getVisibilityAt(4)); // true console.log(iMesh.getVisibilityAt(0)); // false ``` ``` -------------------------------- ### InstancedEntity Properties and Methods Source: https://context7.com/agargaro/instanced-mesh/llms.txt Each instance in InstancedMesh2 (when createEntities is true) is an InstancedEntity object with transform properties (position, scale, quaternion, rotation), visibility, color, opacity, and helper methods. Remember to call updateMatrix() or updateMatrixPosition() after changing transforms. ```APIDOC ## InstancedEntity ### Description Object3D-like instance manipulation for individual entities within an InstancedMesh. ### Properties - **position** (Vector3): The position of the instance. - **scale** (Vector3): The scale of the instance. - **quaternion** (Quaternion): The quaternion representing the rotation of the instance. - **rotation** (Euler): The Euler rotation of the instance (optional). - **visible** (boolean): Whether the instance is visible. - **color** (ColorRepresentation): The color of the instance. - **opacity** (number): The opacity of the instance (0-1). ### Methods - **updateMatrix()**: Updates the instance's transformation matrix. Call after changing transforms. - **updateMatrixPosition()**: Updates only the position part of the transformation matrix. Faster when only position changes. - **remove()**: Removes the instance. ### Example Usage ```ts iMesh.instances[id].position.set(x, y, z); iMesh.instances[id].rotateY(0.01); iMesh.instances[id].updateMatrix(); iMesh.instances[id].visible = false; iMesh.instances[id].color = 0xff0000; iMesh.instances[id].opacity = 0.5; iMesh.instances[id].remove(); ``` ``` -------------------------------- ### Set Per-Instance Opacity Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Adjust the opacity of individual instances. For best results, enable instance sorting and disable depth writing on the material. ```typescript myInstancedMesh.setOpacityAt(index, 0.5); myInstancedMesh.instances[0].opacity = 0.5; // if instances array is created ``` -------------------------------- ### Compute and Dispose BVH for InstancedMesh2 Source: https://context7.com/agargaro/instanced-mesh/llms.txt Build a dynamic Bounding Volume Hierarchy (BVH) for efficient frustum culling and raycasting. The BVH updates automatically if `autoUpdateBVH` is true. Call `computeBVH` after populating instances. Use `disposeBVH` for cleanup. ```typescript import { InstancedMesh2 } from '@three.ez/instanced-mesh'; import { OctahedronGeometry, MeshLambertMaterial, Vector3 } from 'three'; type Data = { dir: Vector3 }; const iMesh = new InstancedMesh2( new OctahedronGeometry(1, 2), new MeshLambertMaterial(), { capacity: 50000, createEntities: true } ); iMesh.addInstances(50000, (obj) => { obj.dir = new Vector3().randomDirection(); obj.position.randomDirection().multiplyScalar(Math.random() * 3000); obj.scale.setScalar(1 + Math.random() * 4); }); // Build BVH after all instances are placed iMesh.computeBVH({ margin: 75, // tolerance for moving objects (0 = static) getBBoxFromBSphere: true, // faster bbox approx (geometry must be origin-centered) accurateCulling: true, // re-check margin nodes precisely }); // Animate — BVH nodes update automatically via updateMatrixPosition renderer.setAnimationLoop((delta) => { for (const obj of iMesh.instances) { if (!obj.active) continue; obj.position.addScaledVector(obj.dir, delta * 10); obj.updateMatrixPosition(); // triggers bvh.move(id) internally } renderer.render(scene, camera); }); // Intersect a box with the BVH import { Box3 } from 'three'; const queryBox = new Box3().setFromCenterAndSize( new Vector3(0, 0, 0), new Vector3(100, 100, 100) ); iMesh.bvh.intersectBox(queryBox, (id) => { console.log('Instance inside box:', id); return true; // continue iterating }); // Teardown iMesh.disposeBVH(); ``` -------------------------------- ### InstancedMesh2 with Object3D-like Instances Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Create InstancedMesh2 with entities that mimic Object3D behavior. Transformations on these entities require an explicit call to updateMatrix(). ```typescript const myInstancedMesh = new InstancedMesh2(geometry, material, { createEntities: true }); myInstancedMesh.instances[0].customData = {}; myInstancedMesh.instances[0].position.random(); myInstancedMesh.instances[0].rotateX(Math.PI); myInstancedMesh.instances[0].updateMatrix(); // necessary after transformations ``` -------------------------------- ### dispose Source: https://context7.com/agargaro/instanced-mesh/llms.txt Releases all GPU resources (textures) allocated by the InstancedMesh2. ```APIDOC ## `dispose()` Releases all GPU resources (textures) allocated by the `InstancedMesh2`. ### Usage ```ts // Cleanup on scene teardown iMesh.dispose(); scene.remove(iMesh); ``` ``` -------------------------------- ### Update All Instances with Callback Source: https://context7.com/agargaro/instanced-mesh/llms.txt Uses `updateInstances` to apply a transformation to all active instances, automatically calling `updateMatrix()`. ```typescript // Rotate all instances every frame scene.addEventListener('before-render', () => { iMesh.updateInstances((obj) => { obj.rotateY(0.01); // updateMatrix() is called automatically }); }); ``` -------------------------------- ### `sortObjects` / `createRadixSort(target)` Source: https://context7.com/agargaro/instanced-mesh/llms.txt Enables depth-based sorting before each render, which is useful for transparency and overdraw reduction. `createRadixSort` provides a faster sort implementation. ```APIDOC ## `sortObjects` / `createRadixSort(target)` `sortObjects` (default `false`) enables depth-based sorting before each render — useful for transparency and overdraw reduction. `createRadixSort` provides a faster sort implementation based on three.js's radix sort utility. ```ts import { InstancedMesh2, createRadixSort } from '@three.ez/instanced-mesh'; import { MeshStandardMaterial, SphereGeometry } from 'three'; const iMesh = new InstancedMesh2( new SphereGeometry(1), new MeshStandardMaterial({ transparent: true, opacity: 0.6 }), { capacity: 5000 } ); iMesh.sortObjects = true; iMesh.customSort = createRadixSort(iMesh); // ~3× faster than default sort iMesh.addInstances(5000, (obj, i) => { obj.position.set( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); obj.color = Math.random() * 0xffffff; }); ``` ``` -------------------------------- ### Enable Instance Sorting Source: https://github.com/agargaro/instanced-mesh/blob/master/docs/src/content/docs/basics/07-sorting.mdx Set `iMesh.sortObjects` to `true` to enable automatic sorting of instances. This is useful for avoiding GPU overdraw and correctly rendering transparent objects. The default value is `false`. ```typescript iMesh.sortObjects = true; // default is false ``` -------------------------------- ### Add Shadow Level of Detail (LOD) Source: https://github.com/agargaro/instanced-mesh/blob/master/README.md Optimize shadow rendering by adding simplified geometries for instances that cast shadows, based on their distance from the camera. ```typescript myInstancedMesh.addShadowLOD(geometryMid); myInstancedMesh.addShadowLOD(geometryLow, 100); ```