The BatchManager documentation is pretty confusing. On the one hand, the BatchManager seems to do everything automatically, on the other, you seem to have to do it yourself.
I’m generating a map of blocks that is 23 x 23 x 20. I’ve created a batch group and given each mesh the group id. Each block uses one texture and isStatic is set to true. After the map is generated I call this.app.batcher.markGroupDirty(this.blockBatchGroupId);
With lighting switched off, I’m still getting 7735 draw calls, which is the same number as if I don’t call markGroupDirty.
Is the batch manager actually doing anything? What have I done wrong?
This didn’t make any difference. I’ve noticed a few things. I’ve created a block programmatically with manually created vertices etc. If I put only 3 identical blocks in scene, the profiler says that the scene has got 6 draw calls and is using 6 materials. Each block uses only one material/texture. That material thing is probably why the batching isn’t working, but why isn’t there only 1 material?
The example that you gave creates elements using a render component, but mine are using a model component. Will that make any difference?
Ok I’ve switched over to a render component and there’s no change. The profiler suggests that there is a unique material for every block.
Is there something fundamentally wrong in what I’m doing here? I have a bunch of block types that are either a custom mesh created in code, loaded from an fbx, or a primitive.
I create an object that maps material names to material resources.
I store the custom blocks in an entity variable.
Each time I need to add one of those custom blocks, I take the appropriate entity and clone it, then place it at the right location.
Here’s the code I use to create the most common block:
ReadMap.prototype.createStoneBlockAsset = function() // Create custom box for stone block
{
const StoneBoxVertices = [...];
const StoneBoxIndices = [...];
const StoneBoxNormals = [...];
const StoneBoxUvs = [...];
^^ above values removed for brevity
// Create mesh
let stoneBoxMesh = new pc.Mesh(this.app.graphicsDevice);
stoneBoxMesh.setPositions(StoneBoxVertices);
stoneBoxMesh.setIndices(StoneBoxIndices);
stoneBoxMesh.setNormals(StoneBoxNormals);
stoneBoxMesh.setUvs(0, StoneBoxUvs);
stoneBoxMesh.update();
// Create the mesh instance
let node = new pc.GraphNode();
let meshInstance = new pc.MeshInstance(node, stoneBoxMesh, this.sceneMaterials.stone1);
// Add a render compoonent
let stoneBlockAsset = new pc.Entity(); // Create an Entity
stoneBlockAsset.addComponent('render', { type: 'asset', batchGroupId: this.blockBatchGroupId });
stoneBlockAsset.render.meshInstances = [meshInstance];
stoneBlockAsset.render.castShadows = true;
stoneBlockAsset.render.receiveShadows = true;
stoneBlockAsset.render.isStatic = true;
stoneBlockAsset.render.layers = [this.app.scene.layers.getLayerByName('World').id];
stoneBlockAsset.render.enabled = true;
return stoneBlockAsset;
};
Then when I add a block to the scene:
ReadMap.prototype.makeAsset = function(x, y, z, assetType, materialObject, isFloorObject)
{
switch (assetType) {
case 'stoneblock':
let newStoneBlock = this.stoneBlockAsset.clone();
newStoneBlock.setPosition(x, y, z);
this.app.root.addChild(newStoneBlock);
return newStoneBlock;
----8<---- rest of function cut ----8<----
I’ve tried all sorts and I still can’t get the number of draw calls down. Is there anything i can do? How do I make the project publically viewable for someone to check it?
I’d suggest to start with the simplest test case / project and go from there. Create a single mesh, single material, add them to a group and batch them. Similar to what the engine example I linked does. That way you will be able to see at what point it stops working.
I honestly can’t really tell you what was wrong with it. But what I do know is that I replaced all model components with render components and that seemed to resolve the problems.
There is still one questionable thing in the profiler and that is that the number of materials seems to always match the number of draw calls. I don’t know if that’s a problem in the engine or just in the profiler.
I’ve set up some attributes on the script attached to Root. Launch the scene with the Profiler enabled then see what happens to the number of materials when you change the attributes.
I have new batching problem and it looks like a clear bug in PlayCanvas.
I have a series of map files. One of these files is parsed and the level populated with blocks. There is only ever one scene.
When I create my level during initialization, everything is fine. However, if I instead show a front end, then trigger the scene creation, then tell the batch manager to update, none of the batch groups are drawn. I am currently trying to destroy all existing batch groups, then destroying all of the level’s entities, then recreating the batchGroups, then parsing the new map file.
None of the batchGroups gets deleted…because they all have an internal id of 0 (see attached screenshot).
The batch group ID is a number which gets incremented each time a new batch group is created. The first batch group has ID of 0, so that by itself is not a bug, it’s a valid ID.
what is the ‘id’ of the group you’re trying to remove?
You can see in the screenshot that there are multiple batchGroups and all of them have an id of zero that I’ve circled in red.
Also in the screenshot, in the playcanvas-stable-dbg.js code where you can see the breakpoint, that code never finds a valid batchGroupId to destroy the group because this._batchIds[i].batchGroupId is always zero. It probably only ever deletes the first one created.
In the screenshot there’s a single batchGroup, and it contains multiple batches. They have the same ID as they are part of the same batch group.
For example, if you have many objects in the scene, some with materialA and some with materialB. You create a single batch group … it will have ID of 0. When you add all these meshes to it, internally when it creates batches, it will create two batches - one for each material, but both batches will have ID of 0 as they are part of the same group.
my suggestion would be to build your version of the engine, and add logging to both Batch and BatchGroup class (constructor - log ID and meshinstance array and similar), and perhaps even in some places in BatchManager, to see what is going on.
You can also put breakpoints in those places, but that could be more time consuming to step code each time you try some changes.