1

I'm using three.js and instancing (as in this example), but I'm having the same problem others have reported: the objects are randomly clipped and keep disappearing from the camera

The proposed workarounds are to set

my_instanced_object.frustumCulled = false;

but this means rendering every single object per each frame, and with a lot of objects this is killing my framerate.

What are my alternatives to this? How can I have proper frustum culling if I'm using instancing?

I'm adding the code I'm using in case someone wanted to take a look

var geometry = new THREE.InstancedBufferGeometry();
geometry.maxInstancedCount = all_meshes_data.length;

geometry.addAttribute( 'position', mesh.geometry.attributes.position );
geometry.addAttribute( 'normal', mesh.geometry.attributes.normal );
geometry.addAttribute( 'uv', mesh.geometry.attributes.uv );

var offsets = new THREE.InstancedBufferAttribute( new Float32Array( all_meshes_data.length * 3 ), 3, 1 );

for ( var i = 0, ul = all_meshes_data.length; i < ul; i++ ) { // Populate all instancing positions (where to spawn instances)
    offsets.setXYZ( i, all_meshes_data[i].x, all_meshes_data[i].y, all_meshes_data[i].z );
}

geometry.addAttribute( 'offset', offsets );

var instanceMaterial = new THREE.RawShaderMaterial( {
    vertexShader: document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
    transparent: true
} );

geometry.computeVertexNormals();
geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3(), 50 ); // Not working, it works just for a 0;0;0 world positioned mesh that is the 'base' of all of the instanced ones

var instanced_mesh = new THREE.Mesh( geometry, instanceMaterial );

//instanced_mesh.frustumCulled = false; // Works, but the scene becomes very slow (rendering everything even if not in sight)

scene.add( instanced_mesh );
Dean
  • 6,610
  • 6
  • 40
  • 90
  • You shouldn't have lots of objects if you are using instancing -- lots of instances, perhaps. – WestLangley Jul 28 '17 at 18:05
  • yeah, when instancing, they become one "object" "scene node" or whatever you want to call the high level struct. How do you want to cull? Using bounding boxes, using spheres? Is your object dynamic? How do you know that this particular thing is killing your framerate? How many objects are there and how heavy are they geometry/shader wise? How many instance containers do you have? – pailhead Jul 28 '17 at 18:59
  • @WestLangley yep I meant instances – Dean Jul 31 '17 at 07:42
  • @pailhead I'm not sure if culling can work at all with instancing.. it seems that as soon as the 'base object representing all of the instances' that I attached to the scene node goes out of the camera frustum... all of the instances are gone as well even if many of them would still be visible in the camera. I narrowed down the framerate slowness to the part where I spawn all these instances so it must be it. Every mesh is 512 triangles and there are 1056 of them in the scene. – Dean Jul 31 '17 at 07:48
  • Let's say that your instances are static. You're rendering an asteroid field or a forest. You don't have to render the entire entity as one instance call. Take a volume, either a sphere or a box that best fits a segment (1/4 of the forest, 1/16th of the asteroid field). Separate your instances, cull the volume. – pailhead Jul 31 '17 at 19:12
  • Just imagine that your "base object" fits the entire instance cloud. – pailhead Jul 31 '17 at 19:13

1 Answers1

6

If you are using instancing, there are two ways to handle frustum culling.

One is to turn frustum culling off for the object:

object.frustumCulled = false;

The other option is to set the bounding sphere of the geometry manually -- if you know it, or can estimate it:

geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

three.js r.86

WestLangley
  • 102,557
  • 10
  • 276
  • 276
  • 1
    how do you get notified of questions this fast? – pailhead Jul 28 '17 at 18:59
  • Thanks, I was aware of the first workaround but for the second.. unless I set a boundingSphere big enough for all of the instances to be visible (so that's basically like disabling frustum culling altogether), the boundingsphere is not replicated per-instance. Is there any way I can have that boundingsphere replicated per each single instance drawn? (I also added some code I'm using) – Dean Jul 31 '17 at 07:49
  • No. Type `renderer.info` into the console and you should see all instances are rendered in a single draw call. – WestLangley Jul 31 '17 at 15:09
  • @WestLangley Sorry, I was busy with some work. Done! Ty! – Dean Sep 05 '17 at 09:13