protected void doBatch() {
        Map<Material, List<Geometry>> matMap = new HashMap<>();
        int nbGeoms = 0;

        // Recalculate the maxVertCount during gatherGeometries() so it's always
        // accurate.  Keep track of what it used to be so we know if temp arrays need
        // to be reallocated.
        int oldMaxVertCount = maxVertCount;
        maxVertCount = 0;
        gatherGeometries(matMap, this, needsFullRebatch);
        if (needsFullRebatch) {
            for (Batch batch : batches.getArray()) {
                batch.geometry.removeFromParent();
            }
            batches.clear();
            batchesByGeom.clear();
        }

        for (Map.Entry<Material, List<Geometry>> entry : matMap.entrySet()) {
            Mesh m = new Mesh();
            Material material = entry.getKey();
            List<Geometry> list = entry.getValue();
            nbGeoms += list.size();
            String batchName = name + "-batch" + batches.size();
            Batch batch;
            if (!needsFullRebatch) {
                batch = findBatchByMaterial(material);
                if (batch != null) {
                    list.add(0, batch.geometry);
                    batchName = batch.geometry.getName();
                    batch.geometry.removeFromParent();
                } else {
                    batch = new Batch();
                }
            } else {
                batch = new Batch();
            }
            mergeGeometries(m, list);
            m.setDynamic();

            batch.updateGeomList(list);

            batch.geometry = new Geometry(batchName);
            batch.geometry.setMaterial(material);
            this.attachChild(batch.geometry);


            batch.geometry.setMesh(m);
            batch.geometry.getMesh().updateCounts();
            batch.geometry.updateModelBound();
            batches.add(batch);
        }
        if (batches.size() > 0) {
            needsFullRebatch = false;
        }


        if (logger.isLoggable(Level.FINE)) {
            logger.log(Level.FINE, "Batched {0} geometries in {1} batches.", new Object[]{nbGeoms, batches.size()});
        }

        //init the temp arrays if the size has changed
        if (oldMaxVertCount != maxVertCount) {
            initTempFloatArrays();
        }
    }
Batch this batchNode
every geometry of the sub scene graph of this node will be batched into a single mesh that will be rendered in one call
jme3-core/src/main/java/com/jme3/scene/BatchNode.java