如何使用 Three.js InstancedBufferGeometry &InstancedBufferAttribute? [英] How to use 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:
- https://threejs.org/examples/?q=instanc#webgl_buffergeometry_instancing
- https://threejs.org/examples/?q=instanc#webgl_buffergeometry_instancing_dynamic
简要说明:
THREE.InstancedBufferGeometry
和 THREE.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 &InstancedBufferAttribute?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!