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?
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> = []) {
OuterCycle:
for (var i = geometrys.length - 1; i >= 0; i--) {
if(!geometrys[i]) continue OuterCycle;
twoCycle:
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
attributeCycle:
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
bufferCycle:
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
indicesCycle:
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 =>{
geometrys[i].applyToMesh(mesh)
})
let ToBeDestroyedGeometrys = geometrys[ii];
geometrys.splice(ii,1)
ToBeDestroyedGeometrys.dispose();
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.