threejs实例具有不同大小和位置的多个对象

时间:2017-10-31 12:15:33

标签: javascript three.js aframe

就在昨天我开始尝试使用InstancedBufferGeometry方法,因为我希望渲染数千个具有良好性能的对象。 在我的情况下,我想要实例具有彼此不同高度的立方体几何。 我刚试过这段代码

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;
  }
});

但我有这个错误

[.Offscreen-For-WebGL-0x17d96d74a000] GL错误:GL_INVALID_VALUE:glVertexAttribPointer:size GL_INVALID_VALUE (索引):1 [.Offscreen-For-WebGL-0x17d96d74a000] GL错误:GL_INVALID_OPERATION:glDrawElementsInstancedANGLE:附加到启用的attrib 1:无缓冲区

我是三级低级别职能的新兵。我从aframe开始,但不幸的是,我发现在我的情况下,正常使用这个框架并不足以获得良好的表现。

我的目标是在不同的位置拥有不同大小的多个立方体。有什么建议吗?提前谢谢

使用TheJim解决方案。

enter image description here

1 个答案:

答案 0 :(得分:0)

首先,不应重新定义positionShaderMaterial注入了常见属性,包括position,您的定义与此相冲突。如果您想自己定义所有内容,请查看RawShaderMaterial

其次,请记住,您要为一个立方体定义顶点,索引和法线,然后使用着色器/实例来操纵其余部分。只应将特定于实例的数据定义为InstancedBufferAttribute s。

看一下这个例子:

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);

和你一样,我创造了一个立方体(只有一个立方体)。然后我添加名为InstancedBufferAttribute的{​​{1}},它将更改多维数据集的位置(cubePos适用于此示例中的所有顶点)。这类似于您的cubePos属性。

就拉伸立方体而言,看起来您可能已接近translate属性。如果您只是给它一个非内置名称,例如position,它可能会按预期工作。

就个人而言,由于看起来你在两个方向上均匀地拉伸它,我可能只是为每个实例传递一个值,并使用它在两个Y方向上缩放立方体。