How to combine several Mesh instances into one Mesh?

I’ve done a SceneGraphVisitor and extracted all spatials with a certain control. I’m trying to get each of their meshes. My question is, with all of these meshes as separate instances, how would I combine them into one? I figured there might be something in the Mesh class called something like addMesh(Mesh mesh) or something like that but all I see is extractVertexData and that throws up exceptions left and right. Any help?

Ok, im not really sure i understood what you try to do? You want to make a visitor for the scenegraph, ok so far all right, and then you want to batch them? If yes take a look at batchnode and at GeometryBatchOptimizer, also related the TextureAtlas utility class.

@vinexgames said:
I've done a SceneGraphVisitor and extracted all spatials with a certain control. I'm trying to get each of their meshes. My question is, with all of these meshes as separate instances, how would I combine them into one? I figured there might be something in the Mesh class called something like addMesh(Mesh mesh) or something like that but all I see is extractVertexData and that throws up exceptions left and right. Any help?


You can either extract the Buffers manually and create a custom mesh.... or... use:

[java]GeometryBatchFactory.optomize(node containing all geometries);[/java]

This will create a single mesh out of all meshes with a common material.
Or...

[java]BatchNode x = new BatchNode();
x.attachChild(child1);
x.attachChild(child2);
x.batch();[/java]

This will create a single mesh out of all meshes using a common material, but keep a reference to each one seperatly so you can update them at some later point... though, I believe you have to re-batch them once you update them.

A faster way of accomplishing the later would be... extract all Buffers as a template, pass them to a custom mesh with a method for adding new instances + new location/rotation. Keep reference of buffer markers for each instance. directly modify the buffers with updated location, rotation.

This way you don't have to rebatch the object after manipulating the one mesh you wanted to update.
1 Like
@t0neg0d said:
though, I believe you have to re-batch them once you update them.

No, you only have to rebatch if you add or remove a geometry to the batchNode.

@t0neg0d said:
A faster way of accomplishing the later would be... extract all Buffers as a template, pass them to a custom mesh with a method for adding new instances + new location/rotation. Keep reference of buffer markers for each instance. directly modify the buffers with updated location, rotation.

That's in 2 sentences what the BatchNode is :p.
@nehon said:
No, you only have to rebatch if you add or remove a geometry to the batchNode.


That's in 2 sentences what the BatchNode is :p.


Lol... I realized that as soon as I read your first reply :P

Also something that I should document somewhere is that there is a SimpleBatchNode, that is more suitable in 80% of situations IMO.

The BatchNode allows you to batch a complete sub-graph and keep the hierarchy of node and geometries, and transform them with the exact same API than if it was not batched.

The SimpleBatchNode only has a child list of geometries and forbid complex sub graphs.



The subtle difference is that each time you translate, rotate, scale the BatchNode itself, the batch mesh’s buffers are updated (thus implying buffers reading/writing).



The SimpleBatchNode however just needs classic node updating.



So basically transforming a SimpleBatchNode is usually much faster than transforming a BatchNode with the same underlying structure.

@nehon said:
The subtle difference is that each time you translate, rotate, scale the BatchNode itself, the batch mesh's buffers are updated (thus implying buffers reading/writing).


What is the reason for doing this? It seems unnecessary since the mesh will end up being a child of the batch node anyway and thus already transformed by its translation, rotation, and scale... or are you saying that the children get rebatched even though they basically end up with the same values?

Actually it’s due to the scene graph update system.

The batchNode is a Node so any transformation will update it’s subgraph.

So basically if you have a sub Node it will update its underlying geometries. This will make the batchNode update the batch mesh.

So basically the transforms are applied twice, once to the real subNode, once to the mesh.



SimpleBatchNode only updates transform of the batches geometries and do not propagate further.

@nehon said:
Actually it's due to the scene graph update system.
The batchNode is a Node so any transformation will update it's subgraph.
So basically if you have a sub Node it will update its underlying geometries. This will make the batchNode update the batch mesh.
So basically the transforms are applied twice, once to the real subNode, once to the mesh.

SimpleBatchNode only updates transform of the batches geometries and do not propagate further.


Must... try... Simple... BatchNode
@nehon said:
Actually it's due to the scene graph update system.
The batchNode is a Node so any transformation will update it's subgraph.
So basically if you have a sub Node it will update its underlying geometries. This will make the batchNode update the batch mesh.
So basically the transforms are applied twice, once to the real subNode, once to the mesh.


So then it's updating the transforms... with exactly the same transforms as last time. (Since they will be transforms without BatchNode's transform). It seems like this case could be detected.
@pspeed said:
So then it's updating the transforms... with exactly the same transforms as last time. (Since they will be transforms without BatchNode's transform). It seems like this case could be detected.

It can be detected, but can't work without modifying the Node class.
At the time I did it, the idea was to not modify Spatial, Node and Geometry, as much as possible. The first implementation was completely stand alone, but had some quirks in the API.
I had to modify Geometry a bit, to make it smoother.
@nehon said:
It can be detected, but can't work without modifying the Node class.
At the time I did it, the idea was to not modify Spatial, Node and Geometry, as much as possible. The first implementation was completely stand alone, but had some quirks in the API.
I had to modify Geometry a bit, to make it smoother.


Considering the expense of resending the mesh data maybe it's worth it to just compare the old and new effective transforms to see if they are different? I don't know the code paths so maybe that's expensive like if you have to check all of the children before you decide to rebatch.

I think I can see the issue now. It's a limitation imposed by using bit masks for dirtiness. Wonder if it would be worth having a different mask for "my transform is dirty" versus "some parent's transform is dirty". All cases where world transform is recalculated could check for both in one mask check just like now... but things like batch node might use it for more discrimination. I don't know if it really solves the problem since I've never looked at batch node.

Yep it would.

Actually all occur in setTransformRefresh. All we would need is another method like setPartialTransformRefresh that would just refresh the transforms of the sub Nodes, but not the sub Geometries.

And the setTransformRefresh of the BatchNode would just call setPartialTransformRefresh on its direct sub Nodes.

So no need of another bitmask and I guess it’s less intrusive.

Sorry @vinexgames, we kind of hijacked your thread.

In your case using GeometryBatchFactory as @t0neg0d mentioned is the best fit IMO.

1 Like
@nehon said:
Yep it would.
Actually all occur in setTransformRefresh. All we would need is another method like setPartialTransformRefresh that would just refresh the transforms of the sub Nodes, but not the sub Geometries.
And the setTransformRefresh of the BatchNode would just call setPartialTransformRefresh on its direct sub Nodes.
So no need of another bitmask and I guess it's less intrusive.


Personally, I'd do setLocalTransformRefresh() and setWorldTransformRefresh() or something and they would set different flags. When setLocalTransformRefresh() is called on any node then it would call setWorldTransformRefresh() on all of its children... which would then propagate down. (Here we see more of the naming problem of calling these "refresh" instead of "dirty"... but oh well.)

So if either flag is set then the world transform needs to be updated but if only the world transform flag is set then you know that it's just because of some parent getting updated. This is not a BatchNode specific thing, necessarily but batch node can use it. Any child with a local transform refresh flag set needs to have its mesh data retransformed.

So, here’s what I end up with.



GeoemtryBatchOptimizer:

http://i.imgur.com/DFwn0.png



The red is the outputted geometry.



BatchNode: I end up with an exception giving me the error “Geometry null has null mesh”