-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
Implemented THREE.InstancedMesh #17505
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Nice! The API look OK to me. Would these additions be possible? var mesh = new THREE.InstancedMesh( geometry, material, count );
mesh.setPositionAt( i, x, y, z );
mesh.setScaleAt( i, x, y, z );
mesh.setRotationAt( i, x, y, z );Or perhaps: var v = new Vector3();
mesh.getPositionAt( i, v );
v.multiplyScalar( 2 );
mesh.setPositionAt( i, v ); |
|
This is great. 👍 |
|
Awesome! A few questions:
For reference, this is the hacky solution i made for looper https://github.com/spite/looper/blob/master/modules/instanced.js |
|
More context: #5171 |
|
Will the instance matrices not respect parent transforms? |
I don't think the instancing API support that, but we could pass a integer attribute to the shader by default? What would you like to do with it? |
Yeah. Supporting all the material properties sounds hard, but maybe color per instance to start with?
I think abstracting shrinking should be easy. Expanding... not so much.
I want to do performance tests comparing passing matrices to the shader vs passing position/quaternion/scale? Part of the reason we don't have a instancing abstraction yet is because every time we try we go down the rabbit hole of "using matrices is wasteful when I only want to modify the position". |
It does already. |
|
Nice work! And I'm very glad to know that somehow I helped to get I know it's very advanced one but are you interested in If you do, I'll share my idea when I have time. (Sorry I'm busy now!) |
|
@takahirox |
|
@takahirox Okay, lets leave that idea/discussion for a different PR, but let met know if the current design won't work well with what |
|
@mrdoob Yes, I wasn't going to try to add SkinnedMesh support into this PR but I just wanted to share my experience for future improvement.
IIRC, in WebGL2
That sounds cool! |
Or maybe suggest people to use WebGL 2 for that use case 😛 |
From my perspective per-vertex transform is preferable, personally. It's just a bunch of multiplications and additions, fast stuff. If instances have dynamic transforms - it takes the load of computing the matrix off the CPU, and added GPU cost is very low. In addition there's less memory load, so you might end up with similar performance due to lower memory footprint (i.e. better caching). |
|
Separate concern. I would prefer if there was a way to re-size number of instances. My current implementation allows that using fairly standard over-allocation and re-allocation approach. Here's my current API: |
|
Some thoughts for instance matrix API. In #16161 I added Pros is easy for users to control instance transform with familiar Cons is memory consumption overhead due to Even if this type of "easy to use API" won't get in core to avoid overhead, we may add helper under example. |
|
I think instancing is an advanced performance API, as such, I see 2 main issues to keep in mind:
If you are using instances - API doesn't have to be "comfortable", I believe. It should be as comfortable as it makes sense to do it, but not at the cost of performance attributes. These are my thoughts. |
|
BTW I want to make clear one thing. @Usnul Yeah I can understand and I know slow instancing doesn't make sense. So I lastly suggested adding helper under example (if needed) not doing in core. I suppose it may be useful for some users who aren't familiar with instancing or 3D, probably helper + instancing is still faster than without instancing. |
|
Maybe it would be good to add a second demo that demonstrates raycasting with |
|
Super long time ago there was this PR suggested, it's been working in the wild more or less like this since then, might be worth comparing notes: |
an integer would work. I'm thinking about setting different properties, like different colors or modify the vertices depending on the instance. You can set different properties using the position of the vertices, but that may be not enough, or doesn't work for some effect. Does it make sense? |
| precision: precision, | ||
| isWebGL2: capabilities.isWebGL2, | ||
|
|
||
| instancing: object.isInstancedMesh === true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there other cases where reusing a single material on multiple objects would create multiple shader programs? Wondering if this should require a material.instancing flag or something, similar to .skinning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I have not tested this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave that for the next cycle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've pointed out the similar stuff here, probably material can't be shared between regular mesh and instanced mesh.
And wondering if material can have multiple shader programs depending on some conditions, like SkinnedMesh, InstancedMesh, or so on. We can remove .skinning or such other properties from material and material can be shared between them.
Related #16356
NodeMaterial actually provides a pretty decent instancing API. Modifying the transform of each instance is not as intuitive as the InstancedMesh API you've created here, but there's much more flexibility in terms of modifying any and all material properties: const geometry = // ... create BufferGeometry using InstancedBufferAttribute ...
const material = new StandardNodeMaterial();
const instanceID = new AttributeNode( 'instanceID', 'float' );
const instanceCount = = new FloatNode( 100 );
// Set instance positions based on instance ID.
const rootPosition = new PositionNode();
material.position = new JoinNode(
new SwitchNode( rootPosition, 'xy' ),
new OperatorNode( new SwitchNode( rootPosition, 'z' ), instanceID, OperatorNode.MUL )
);
// Set per-instance material properties from attributes.
material.color = new AttributeNode( 'instanceColor', 'vec3' );
material.roughness = new AttributeNode( 'instanceRoughness', 'float' );Example: https://three-shadenodeloader.donmccurdy.com Not sure exactly what that means for this PR, except that it would be nice if the two techniques were compatible. If instance ID and instance count from InstancedMesh were available to NodeMaterial in some reliable way, that would be a good start. 🙂 |
|
I assume it uses https://github.com/mrdoob/three.js/blob/dev/src/renderers/WebGLRenderer.js#L866-L878 |
|
Yep! I think it would still work, except that |
|
Out of curiosity. No |
|
Let's add the documentation and the TS declaration file in |
|
Opened an issue as a reminder #17621 |
|
the current frustum culling strategy will cut off the whole |
|
@hjlld yes, that's known issue. |
|
But |
|
@mrdoob you might find it interesting to have a look at how I do culling for instanced meshed in meep I don't think that you can just copy my solution, since it has a fairly large foundation in spatial indices, object pools and other stuff. But it might give you some good ideas. There are 2 parts to it, one is a compact representation for the instances, using a binary table with each row being a separate instance, second is a BVH for culling. PS: Word "Foliage" in the name is purely historical, that's what I was creating the system for, it is entirely just an |
|
I resolve this by following: Because bounding info is totally on CPU side in my project, so i split them from geometries to an indivitual map. Then i set all |
|
@hjlld That sounds demanding for something to be done every frame. |
|
When will r110 be released? very much look forward to, urgently need to use. |
October 30. But just to be clear, |
Wonderful job! Great guys! |
|
|
||
| } | ||
|
|
||
| mesh.instanceMatrix.needsUpdate = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: I've used THREE.InstancedMesh in a new project and realized it makes sense to add the following line when creating the mesh if instanceMatrix is updated per frame like in this example.
mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );|
Hi @mrdoob, Is there any possible ways to implement the instancing for lines and sprites?. |
|
@nivashmani91 Please read #25078 for more information about that topic. |

First version of
THREE.InstancedMesh:Not super happy with the API yet... But it works 🙂
It's currently uploading
4 * 4 + 3 * 3 = 25floats per instance.If we uploaded position, quaternion and scale it would be
3 + 4 + 3 = 10floats per instance but we'll have to run this per vertex.Used #16141 and #16161 as reference, thanks @takahirox!