Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
875 views
in Technique[技术] by (71.8m points)

performance - How to use Three.js InstancedBufferGeometry & InstancedBufferAttribute?

I believe "instancing" as described here provides a way to have one attribute for all the vertices/indicies of a, for example, 200 vertex model:

http://blog.tojicode.com/2013/07/webgl-instancing-with.html

In other words, this gives a way to have just one translation or orientation attribute array which would be applied to all 200 vertices of the model. And thus "instancing" a scene of 10K of these models would require only 10K attributes, not 2000K.

Apparently Three's InstancedBufferGeometry & InstancedBufferAttribute objects provide this but I haven't found documentation, other than sparse descriptions of the objects. I believe they use a ShaderMaterial, which is fine, although there may a way other than using GLSL in "vanilla" Three.js.

Could someone explain how they work and how to use them in Three.js?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

Please log in or register to answer this question.

1 Answer

0 votes
by (71.8m points)

I stumbled upon your question when seeking this answer myself. Here are just two examples (directly from threejs.org/examples) which use instancing:

A brief explanation:

The main difference between THREE.InstancedBufferGeometry and THREE.BufferGeometry is that the former can use special attributes (THREE.InstancedBufferAttributes) which will be used for each instance.

Imagine you're creating a box, for which you want to have several instances. The vertex, normal, and UV buffers would all be standard THREE.BufferAttribute objects because they describe the base shape. But in order to move each instance to its own position, you need to define a THREE.InstancedBufferAttribute to hold the locations (the examples usually name this attribute "offset").

The number of vertex references in your THREE.InstancedBufferAttributes describes how many instances you'll have. For example, putting 9 values in offset indicates there will be 3 instances (this includes the original shape). You can also control how many of these are drawn by setting the THREE.InstancedBuferGeometry.maxInstancedCount value.

Finally, you will need a shader to help control the instanced attributes.

Small Example:

var cubeGeo = new THREE.InstancedBufferGeometry().copy(new THREE.BoxBufferGeometry(10, 10, 10));
//cubeGeo.maxInstancedCount = 8;

cubeGeo.addAttribute("cubePos", new THREE.InstancedBufferAttribute(new Float32Array([
  25, 25, 25,
  25, 25, -25, -25, 25, 25, -25, 25, -25,
  25, -25, 25,
  25, -25, -25, -25, -25, 25, -25, -25, -25
]), 3, 1));

var vertexShader = [
  "precision highp float;",
  "",
  "uniform mat4 modelViewMatrix;",
  "uniform mat4 projectionMatrix;",
  "",
  "attribute vec3 position;",
  "attribute vec3 cubePos;",
  "",
  "void main() {",
  "",
  "gl_Position = projectionMatrix * modelViewMatrix * vec4( cubePos + position, 1.0 );",
  "",
  "}"
].join("
");
var fragmentShader = [
  "precision highp float;",
  "",
  "void main() {",
  "",
  "gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);",
  "",
  "}"
].join("
");

var mat = new THREE.RawShaderMaterial({
  uniforms: {},
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  side: THREE.DoubleSide,
  transparent: false
});

var mesh = new THREE.Mesh(cubeGeo, mat);

scene.add(mesh);
html * {
  padding: 0;
  margin: 0;
  width: 100%;
  overflow: hidden;
}

#host {
  width: 100%;
  height: 100%;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="host"></div>

<script>
  var WIDTH = window.innerWidth,
    HEIGHT = window.innerHeight,
    FOV = 35,
    NEAR = 1,
    FAR = 1000;

  var renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(WIDTH, HEIGHT);
  document.getElementById('host').appendChild(renderer.domElement);

  var stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);


  var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 250;

  var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
  trackballControl.rotateSpeed = 5.0; // need to speed it up a little

  var scene = new THREE.Scene();

  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  scene.add(light);

  function render() {
    if (typeof updateVertices !== "undefined") {
      updateVertices();
    }
    renderer.render(scene, camera);
    stats.update();
  }

  function animate() {
    requestAnimationFrame(animate);
    trackballControl.update();
    render();
  }

  animate();
</script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to JiKe DevOps Community for programmer and developer-Open, Learning and Share
...