Don P
Don P

Reputation: 63627

Create an InstancedBufferGeometry from existing geometry in Three.js

How can you create an InstancedBufferGeometry from existing geometry?

I have a tube I've created as a buffer geometry. I'd like to create 100 instances of it, but unsure of the correct syntax with the latest Three.js version. InstancedBufferGeometry docs

This works in an example from an old version of three (v0.107.0), but no longer.

const curve = new THREE.LineCurve3(
  new THREE.Vector3(0, 0, 0),
  new THREE.Vector3(0, 0, -1)
);

let baseGeom = new THREE.TubeBufferGeometry(curve, 25, 1, 8, false);
let instanceGeo = new THREE.InstancedBufferGeometry().copy(baseGeo);

const material = new THREE.MeshStandardMaterial({
  color: "rgba(100,0,50,1)"
});

const mesh = new THREE.Mesh(instanceGeo, material;

Codesandbox in case you want to try it out - see CarLights.js for the use of InstancedBufferGeometry:

https://codesandbox.io/s/wip-akira-lights-d4h7k?file=/src/CarLights.js

Upvotes: 1

Views: 669

Answers (1)

prisoner849
prisoner849

Reputation: 17586

This way it shows 100 instances of TubeGeometry:

import * as THREE from "three";

class CarLights {
  constructor(scene, options = { nPairs: 100 }) {
    this.scene = scene;
    this.options = options;

    const curve = new THREE.LineCurve3(
      new THREE.Vector3(0, 0, 0),
      new THREE.Vector3(0, 0, -1)
    );

    const geo = new THREE.TubeBufferGeometry(curve, 25, 1, 8, false);
    const geoInstance = new THREE.InstancedBufferGeometry().copy(geo);
    geoInstance.instanceCount = 100;

    const mat = new THREE.MeshBasicMaterial({
      color: "rgba(100,0,50,1)",
      onBeforeCompile: shader => {
        shader.vertexShader = `
          attribute vec3 instPos;
          ${shader.vertexShader}
        `.replace(
          `#include <begin_vertex>`,
          `#include <begin_vertex>
            transformed += instPos;
          `
        );
        //console.log(shader.vertexShader);
      }
    });

    let instPos = [];
    let vec3 = new THREE.Vector3();
    for(let i = 0; i < 100; i++){
      vec3.random().subScalar(0.5).multiplyScalar(20);
      instPos.push(vec3.x, vec3.y, vec3.z);
    }
    geoInstance.setAttribute("instPos", new THREE.InstancedBufferAttribute(new Float32Array(instPos), 3));

    const mesh = new THREE.Mesh(geoInstance, mat);
    scene.add(mesh);
  }
}

export default CarLights;

Upvotes: 1

Related Questions