Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

can't get a Three.js InstancedBufferGeometry to appear in a scene

I can't seem to get an InstancedBufferGeometry to appear in a scene anymore. I've tried the following technique:

let bg = BoxBufferGeometry(3,3,3),
    ig : InstancedBufferGeometry = new InstancedBufferGeometry(),
    mesh : Mesh;

    ig.index = bg.index;
    ig.attributes.position = bg.attributes.position;
    ig.attributes.uv = bg.attributes.uv;
    
    //ig.copy( bg ); <- also tried this
    
    ig.instanceCount = Infinity; <- otherwise this populates as undefined

    var offsets = [];
    var orientations = [];
    var vector = new Vector4();
    var x, y, z, w;

for ( var i = 0; i < 1000; i ++ ) {

    // offsets
    x = Math.random() * 100 - 50;
    y = Math.random() * 100 - 50;
    z = Math.random() * 100 - 50;

    vector.set( x, y, z, 0 ).normalize();
    vector.multiplyScalar( 5 );

    offsets.push( x + vector.x, y + vector.y, z + vector.z );

    // orientations
    x = Math.random() * 2 - 1;
    y = Math.random() * 2 - 1;
    z = Math.random() * 2 - 1;
    w = Math.random() * 2 - 1;

    vector.set( x, y, z, w ).normalize();
    orientations.push( vector.x, vector.y, vector.z, vector.w );
}

var offsetAttribute = new InstancedBufferAttribute( new Float32Array( offsets ), 3 );
var orientationAttribute = new InstancedBufferAttribute( new Float32Array( orientations ), 4 ).setUsage( DynamicDrawUsage );

ig.setAttribute( 'offset', offsetAttribute );
ig.setAttribute( 'orientation', orientationAttribute );

let m = new MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, flatShading: true } );

mesh = new Mesh( ig, m );
scene.add(mesh);

I don't get any errors and the mesh does appear in the scene when I inspect. I've tried all combinations of attributes in the IBG.

enter image description here

Will this approach no longer work? (It worked in r97... I know, ages ago. )

question from:https://stackoverflow.com/questions/65839289/cant-get-a-three-js-instancedbuffergeometry-to-appear-in-a-scene

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

let m = new MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, flatShading: true } );

When using InstancedBufferGeometry, you can't create a mesh with built-in materials like MeshPhongMaterial. Instead you have to create a custom shader that utilizes the instanced attributes. Example:

var camera, scene, renderer;

init();
animate();

function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.z = 100;

  scene = new THREE.Scene();

  var geometry = new THREE.BoxBufferGeometry();

  var ig = new THREE.InstancedBufferGeometry();
  ig.index = geometry.index;
  ig.attributes.position = geometry.attributes.position;

  var offsets = [];
  var orientations = [];
  var vector = new THREE.Vector4();
  var x, y, z, w;

  for (var i = 0; i < 1000; i++) {

    // offsets
    x = Math.random() * 100 - 50;
    y = Math.random() * 100 - 50;
    z = Math.random() * 100 - 50;

    vector.set(x, y, z, 0).normalize();

    offsets.push(x + vector.x, y + vector.y, z + vector.z);

    // orientations
    x = Math.random() * 2 - 1;
    y = Math.random() * 2 - 1;
    z = Math.random() * 2 - 1;
    w = Math.random() * 2 - 1;

    vector.set(x, y, z, w).normalize();
    orientations.push(vector.x, vector.y, vector.z, vector.w);
  }

  var offsetAttribute = new THREE.InstancedBufferAttribute(new Float32Array(offsets), 3);
  var orientationAttribute = new THREE.InstancedBufferAttribute(new Float32Array(orientations), 4);

  ig.setAttribute('offset', offsetAttribute);
  ig.setAttribute('orientation', orientationAttribute);

  var material = new THREE.RawShaderMaterial({
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent,
    side: THREE.DoubleSide
  });

  mesh = new THREE.Mesh(ig, material);
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

}

function animate() {

  requestAnimationFrame(animate);
  renderer.render(scene, camera);

}
body {
      margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.124/build/three.js"></script>

<script id="vertexShader" type="x-shader/x-vertex">
        precision highp float;

        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;

        attribute vec3 position;
        attribute vec3 offset;
        attribute vec4 orientation;

        void main(){

            vec3 pos = offset + position;
            vec3 vcV = cross( orientation.xyz, pos );
            pos = vcV * ( 2.0 * orientation.w ) + ( cross( orientation.xyz, vcV ) * 2.0 + pos );

            gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1.0 );

        }

    </script>

    <script id="fragmentShader" type="x-shader/x-fragment">

        precision highp float;

        void main() {

            gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);

        }

    </script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...