SceneOptimizer MergeMeshesOptimization error

Hello babylon, I am trying to use SceneOptimizer to optimize rendering performance, but I am running into a problem when
MergeMeshesOptimization raises the “Positions are required” error when mergemeshesoptimization triggers node merging. There is an empty grid in the scene tree. How can I solve this problem?

Hi @xiehangyun
It would be easier with a PG.
Anyways, where does that empty grid come from? can’t you delete it before optimizing the scene?

1 Like

This is an empty grid created by one of the EnvironmentHelper. I’m working on an online scenario building project, where any GLB model might appear. The inconsistencies found in vertexBuffers in my attempts also result in errors, so I have decided to merge nodes at model load time.

I also have another optimization direction, because there is no need to operate geometry in the project, and some models have a lot of exactly the same geometry. If these geometers are organized in the way of reuse, can the performance be greatly optimized?

// Tidy up all the geometry of the serialization model
serializedGeometry(geometrys: Array<Geometry> = []) {
    for (var i = geometrys.length - 1; i >= 0; i--) {
        if(!geometrys[i]) continue OuterCycle;
        for (var ii = geometrys.length - 1; ii >= 0; ii--) {
            if(!geometrys[i]) continue OuterCycle;
            if(!geometrys[ii]) continue twoCycle;
            // If it's the same geometry skip
            if (geometrys[i] === geometrys[ii]) continue twoCycle;

            // Not the same number of vertices skip
            if (geometrys[i].getTotalVertices() !== geometrys[ii].getTotalVertices()) continue twoCycle;

            // The number of vertices referenced is the same
            if (geometrys[i].getTotalIndices() !== geometrys[ii].getTotalIndices()) continue twoCycle;

            // Compare vertexBuffers
            let iVertexBuffers = geometrys[i].getVertexBuffers() as {
                [key: string]: VertexBuffer;
            let iiVertexBuffers = geometrys[ii].getVertexBuffers() as {
                [key: string]: VertexBuffer;

            // If either of the two is null, skip
            if (!iVertexBuffers || !iiVertexBuffers) continue twoCycle;

            let iVertexBufferKey = Object.keys(iVertexBuffers)
            let iiVertexBufferKey = Object.keys(iiVertexBuffers)
            // Compare whether the attributes are the same
            if (iVertexBufferKey.join('') !== iiVertexBufferKey.join('')) continue twoCycle;

            // Check whether all attribute buffers are the same
            let flag = true;
            // Circular attribute
            for (var keyStr in iVertexBufferKey) {
                // hashCode Check whether the format is the same. If the format is different, break it directly
                if (iVertexBuffers[iVertexBufferKey[keyStr]].hashCode !== iiVertexBuffers[iVertexBufferKey[keyStr]].hashCode) {
                    flag = false
                    break attributeCycle;

                // Check whether the length of buffer data is the same
                let ibufferData = iVertexBuffers[iVertexBufferKey[keyStr]].getData() as Array<number>
                let iibufferData = iiVertexBuffers[iVertexBufferKey[keyStr]].getData() as Array<number>

                if (ibufferData.length !== iibufferData.length) {
                    flag = false;
                    break attributeCycle;

                // Compare whether the buffer data is identical, such as different breaks
                for (var bufferI = 0; bufferI < ibufferData.length; bufferI += Math.floor(ibufferData.length / 10)) {
                    if (ibufferData[bufferI] !== iibufferData[bufferI]) {
                        flag = false
                        break bufferCycle;
                if (!flag) {
                    break attributeCycle;
            if (!flag) continue twoCycle;

            // The final comparison Indices;
            let iIndices = geometrys[i].getIndices() as IndicesArray
            let iiIndices = geometrys[ii].getIndices() as IndicesArray

            // If either of the two is equal to null and not equal, skip
            if(((iIndices === null) ||  (iiIndices === null)) && iiIndices !== iiIndices) continue twoCycle;

            // If not skipped, neither is equal to null or both are equal to null;

            // If neither is equal to null; compare
            if(iIndices !== null) {

                // If the alignment length is not equal, skip
                if(iIndices.length !== iiIndices.length) {
                    flag = false;
                    continue twoCycle;

                // If the length is equal, compare the contents
                for (var indicesI = 0; indicesI < iIndices.length; indicesI += Math.floor(iIndices.length / 10)) {
                    if (iIndices[indicesI] !== iiIndices[indicesI]) {
                        flag = false
                        break indicesCycle;

            if(!flag) continue twoCycle;

            // If all matches are complete, modify the geometrys binding by removing and destroying our geometrys[ii].
            geometrys[ii].meshes.forEach(mesh =>{
            let ToBeDestroyedGeometrys = geometrys[ii];
            continue twoCycle;

This is a way to integrate geometry, and is there any possibility of errors due to lack of alignment.

Based on this, the mesh with the same geometry and material is transformed into an instance mesh to optimize the overall rendering effect.

I like to use instances/thin instances as much as possible. Because of single drawcall, it’s very efficient with cpu and gpu usage.
Merging geometry can be counter performant: all geometry is mixed into multiple large buffers. And you have a stall when the app starts.

Is it possible for multiple grids using the same geometry to increase performance costs.Is it possible that multiple grids using the same geometry will increase the performance cost? Next I plan to instantiate them all to increase the render frame rate.

Meshes having the same geometry and material should be instanced.