如何使用 Three.js InstancedBufferGeometry &InstancedBufferAttribute? [英] How to use Three.js InstancedBufferGeometry & InstancedBufferAttribute?

查看:79
本文介绍了如何使用 Three.js InstancedBufferGeometry &InstancedBufferAttribute?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信这里描述的实例化"提供了一种为所有顶点/索引拥有一个属性的方法,例如,200 个顶点模型:

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-instance-with.html

换句话说,这提供了一种方法,可以将一个平移或方向属性数组应用于模型的所有 200 个顶点.因此,实例化"这些模型中 10K 的场景只需要 10K 属性,而不是 2000K.

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.

显然是 Three 的 InstancedBufferGeometry &InstancedBufferAttribute 对象提供了这个,但除了对象的稀疏描述之外,我还没有找到文档.我相信他们使用 ShaderMaterial,这很好,尽管除了在vanilla" Three.js 中使用 GLSL 之外,还有其他方法.

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.

有人能解释一下它们是如何工作的以及如何在 Three.js 中使用它们吗?

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

推荐答案

我自己在寻找这个答案时偶然发现了你的问题.以下是两个使用实例化的示例(直接来自 threejs.org/examples):

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

简要说明:

THREE.InstancedBufferGeometryTHREE.BufferGeometry 的主要区别在于前者可以使用特殊属性(THREE.InstancedBufferAttributes)用于每个实例.

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.

假设您正在创建一个盒子,您希望为其拥有多个实例.顶点、法线和 UV 缓冲区都是标准的 THREE.BufferAttribute 对象,因为它们描述了基本形状.但是为了将每个实例移动到它自己的位置,您需要定义一个 THREE.InstancedBufferAttribute 来保存位置(示例通常将此属性命名为offset").

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").

THREE.InstancedBufferAttributes 中顶点引用的数量描述了您将拥有多少个实例.例如,在 offset 中放置 9 个值表示将有 3 个实例(这包括原始形状).您还可以通过设置 THREE.InstancedBuferGeometry.maxInstancedCount 值来控制绘制的数量.

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.

小例子:

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("\n");
var fragmentShader = [
  "precision highp float;",
  "",
  "void main() {",
  "",
  "	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);",
  "",
  "}"
].join("\n");

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>

这篇关于如何使用 Three.js InstancedBufferGeometry &amp;InstancedBufferAttribute?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆