问题
just yesterday i started to tried the InstancedBufferGeometry method because i want to render thousand of objects with a good performance. In my case i want to instance cube geometries with different heights of each other. At moment i tried this code
AFRAME.registerComponent('instancing', {
schema: {
count: {type: 'int', default: 10000}
},
init: function () {
this.count = this.data.count;
this.model = null;
},
update: function () {
if (this.model !== null) { return; }
var data = this.data;
var el = this.el;
var count = this.count;
var geometry = new THREE.InstancedBufferGeometry();
geometry.copy(new THREE.BoxBufferGeometry(10, 5, 10));
var translateArray = new Float32Array(count*3);
var vectorArray = new Float32Array(count*3);
var colorArray = new Float32Array(count*3);
var vertices = new Float32Array(count * 24);
for(var i = 0; i < count; i++){
var y = Math.floor((Math.random() * 200) + 50);
vertices[i*3+0] = 10;
vertices[i*3+1] = y;
vertices[i*3+2] = 10;
vertices[i*24+3] = 10;
vertices[i*24+4] = y;
vertices[i*24+5] = -10;
vertices[i*24+6] = 10;
vertices[i*24+7] = -y;
vertices[i*24+8] = 10;
vertices[i*24+9] = 10;
vertices[i*24+10] = -y;
vertices[i*24+11] = -10;
vertices[i*24+12] = -10;
vertices[i*24+13] = y;
vertices[i*24+14] = -10;
vertices[i*24+15] = -10;
vertices[i*24+16] = y;
vertices[i*24+17] = 10;
vertices[i*24+18] = -10;
vertices[i*24+19] = -y;
vertices[i*24+20] = -10;
vertices[i*24+21] = -10;
vertices[i*24+22] = -y;
vertices[i*24+23] = 10;
}
for (var i = 0; i < count; i++) {
translateArray[i*3+0] = (Math.random() - 0.5) * 100.0;
translateArray[i*3+1] = (Math.random() - 0.5) * 100.0;
translateArray[i*3+2] = (Math.random() - 0.5) * 100.0;
}
for (var i = 0; i < count; i++) {
vectorArray[i*3+0] = (Math.random() - 0.5) * 100.0;
vectorArray[i*3+1] = (Math.random() + 1.5) * 100.0;
vectorArray[i*3+2] = (Math.random() - 0.5) * 100.0;
}
for (var i = 0; i < count; i++) {
colorArray[i*3+0] = Math.random();
colorArray[i*3+1] = Math.random();
colorArray[i*3+2] = Math.random();
}
geometry.addAttribute('position', new THREE.InstancedBufferAttribute(vertices, 24, 1));
geometry.addAttribute('translate', new THREE.InstancedBufferAttribute(translateArray, 3, 1));
geometry.addAttribute('vector', new THREE.InstancedBufferAttribute(vectorArray, 3, 1));
geometry.addAttribute('color', new THREE.InstancedBufferAttribute(colorArray, 3, 1));
var material = new THREE.ShaderMaterial({
uniforms: {
time: {value: 0}
},
vertexShader: [
'attribute vec3 translate;',
'attribute vec3 vector;',
'attribute vec3 color;',
'uniform float time;',
'varying vec3 vColor;',
'const float g = 9.8 * 1.5;',
'void main() {',
' vec3 offset;',
' offset.xz = vector.xz * time;',
' offset.y = vector.y * time - 0.5 * g * time * time;',
' gl_Position = projectionMatrix * modelViewMatrix * vec4( position + translate + offset, 1.0 );',
' vColor = color;',
'}'
].join('\n'),
fragmentShader: [
'varying vec3 vColor;',
'void main() {',
' gl_FragColor = vec4( vColor, 1.0 );',
'}'
].join('\n')
});
var mesh = new THREE.Mesh(geometry, material);
this.model = mesh;
el.setObject3D('mesh', mesh);
el.emit('model-loaded', {format:'mesh', model: mesh});
},
tick: function(time, delta) {
if (this.model === null) { return; }
var mesh = this.model;
mesh.material.uniforms.time.value = (mesh.material.uniforms.time.value + delta / 1000) % 30.0;
}
});
but i have this error
[.Offscreen-For-WebGL-0x17d96d74a000]GL ERROR :GL_INVALID_VALUE : glVertexAttribPointer: size GL_INVALID_VALUE (index):1 [.Offscreen-For-WebGL-0x17d96d74a000]GL ERROR :GL_INVALID_OPERATION : glDrawElementsInstancedANGLE: attached to enabled attrib 1 : no buffer
im a recruit to threejs low level functions. i started with aframe but unfortunately i see that in my case the normal use of this framework is not sufficent to have good performances.
my goal is to have multiple cubes with different sizes in different positions. any suggestion? thanks in advance
with TheJim solution.
回答1:
First, position
should not be re-defined. ShaderMaterial
injects common attributes, including position
, and your definition conflicts with that. If you'd like to define everything yourself, look into RawShaderMaterial.
Second, remember, you're defining the vertices, indices, and normals for ONE cube, then using shaders/instancing to manipulate the rest. Only instance-specific data should be defined as InstancedBufferAttribute
s.
Take a look at this 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("\n");
var fragmentShader = [
"precision highp float;",
"",
"void main() {",
"",
" gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);",
"",
"}"
].join("\n");
var mat = new THREE.RawShaderMaterial({
uniforms: {},
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true
});
var mesh = new THREE.Mesh(cubeGeo, mat);
scene.add(mesh);
Like you, I've created a cube (just one cube). I then add an InstancedBufferAttribute
named cubePos
which will change the positions of the cubes (cubePos
applies to ALL vertices in this example). This is similar to your translate
attribute.
As far as stretching the cubes, it looks like you may be close with your position
attribute. It may work as you expect if you simply give it a name that is not built-in, like stretch
.
Personally, since it looks like you're stretching it equally in both directions, I'd probably just pass in a single value per instance, and use it to scale the cube in both Y directions.
来源:https://stackoverflow.com/questions/47035184/threejs-instance-multiple-objects-with-different-sizes-and-positions