我相信"实例化"如此处所述,提供了一种方法,例如,200个顶点模型的所有顶点/指标都有一个属性:
换句话说,这提供了一种只有一个平移或方向属性数组的方法,该数组将应用于模型的所有200个顶点。因此"实例化"这些模型中10K的场景只需要10K属性,而不是2000K。
显然是三个InstancedBufferGeometry& InstancedBufferAttribute对象提供了这个,但除了对象的稀疏描述之外,我还没有找到文档。我相信他们使用的是ShaderMaterial,这很好,尽管除了在" vanilla"中使用GLSL之外还有其他方法。 three.js所
有人可以解释它们如何工作以及如何在Three.js中使用它们吗?
答案 0 :(得分:13)
简要说明:
THREE.InstancedBufferGeometry
和THREE.BufferGeometry
之间的主要区别在于前者可以使用特殊属性(THREE.InstancedBufferAttributes
),每个实例将使用。
想象一下,您正在创建一个您想要拥有多个实例的盒子。顶点,法线和UV缓冲区都是标准THREE.BufferAttribute
个对象,因为它们描述了基本形状。但是为了将每个实例移动到自己的位置,您需要定义一个THREE.InstancedBufferAttribute
来保存位置(示例通常将此属性命名为#34; offset
")。
THREE.InstancedBufferAttributes
中的顶点引用数量描述了您拥有的实例数量。例如,在offset
中放置9个值表示将有3个实例(这包括原始形状)。您还可以通过设置THREE.InstancedBuferGeometry.maxInstancedCount
值来控制绘制的数量。
最后,你将需要一个着色器来帮助控制实例属性。
小例子:
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>
&#13;
答案 1 :(得分:3)
这个问题有点令人困惑,但是我会尽力而为。
我认为你混淆了一些事情,我在three.js用户中看到了很多。首先,我认为属性术语是错误的。您不是要创建成千上万的属性,而是像网格这样的实体可能有一个属性 - position
,或多个uv
,normal
,aMyAttribute
等。
事实上,webgl可以解决的属性数量最多,但不同但是球场是16,而不是数千。
属性可以包含用于定义200&#34;顶点&#34;的数据。但这也是相对的,它们可以有2个组件,可以有4个组件。
制作多个&#34;对象&#34;超出你的&#34; 200顶点模型&#34;你没有倍增你的几何。属性数量没有增加,我实际上不确定制服会发生什么,但就gpu而言,它仍然保持200个顶点。 Javascript仍包含一些属性和统一位置,以及一些Geometry
类的实例。
你做的是&#34;节点/对象&#34;,在javascript中你会有多个说Mesh
个对象。这将包含各种其他类型,矩阵,向量,四元数等。
当您调用渲染函数时,渲染器将为每个节点发出一个绘制调用。每次执行此操作时,都需要设置webgl的状态以处理该特定的绘制调用。如果这是散布在场景周围的同一物体,那么唯一不同的是位置/旋转/比例的制服。如果它们有材料,那么它可以是颜色的均匀或不同的纹理。无论哪种方式,这都会产生开销,并减慢速度。
让我们说你的模型是一棵树。从中创建一个林并渲染a forest
而不是many trees
将消除这种开销,仍然会进行相同数量的着色器处理。每棵树的每个顶点都需要在其上运行着色器。
这当然会增加你的属性所拥有的数据。现在,不是在一些方便的对象空间(更好地称之为&#34;树空间&#34;)中保持200个顶点,而是需要在&#34;林空间&#34;中保持200 x N个顶点。 IE浏览器。 tree 0
的顶点存在于森林中的某个位置,而tree N
的相同顶点存在于森林中的其他位置。如果要为每个树创建一个新几何体,将变换烘焙到其顶点,然后与另一个树合并,依此类推,则会发生这种情况。
Instancing让您可以更聪明地了解这种情况。您可以拥有原始树的200个顶点,以及描述它们被绘制N次的位置的属性,而不是保持共享属性(它是同一个树)的所有单个顶点。因此,您可以构建一个仅包含转换的属性,而不是合并几何,并在它们上单独烘焙转换。
您很可能无法使用香草材料,因为他们不知道如何处理您的自定义属性。但是,对于three.js处理着色器的方式,注入一些逻辑和扩展现有材料并不困难。